(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i { if(shape != undefined) { var matrix = shape.matrix(); var gsize = this.previewGridSize; var startX = (this.preview.width - gsize*shape.getColumnCount()) / 2; var startY = ((this.preview.height - gsize*shape.getRowCount()) / 2 / 4)*(index*2+1); for(var i = 0;i { if(shape != undefined) { var matrix = shape.matrix(); var gsize = this.holdGridSize; var startX = (this.hold.width - gsize*shape.getColumnCount()) / 2; var startY = ((this.hold.height - gsize*shape.getRowCount()) / 2 / 4)*(index*2+1); for(var i = 0;i -1; if(!isFirefox) { for(var i = 0; i < 4; i++) if((gp = window.navigator.getGamepads()[i]) != undefined) // dumb gamepad update. fix. gamepadAPI.controller = gp; } gamepadAPI.buttonsCache = []; for (var k = 0; k < gamepadAPI.buttonsStatus.length; k++) { gamepadAPI.buttonsCache[k] = gamepadAPI.buttonsStatus[k]; } gamepadAPI.buttonsStatus = []; var c = gamepadAPI.controller || {}; var pressed = []; if (c.buttons) { for (var b = 0, t = c.buttons.length; b < t; b++) { if (c.buttons[b].pressed) { pressed.push(gamepadAPI.buttons[b]); } } } var axes = []; if (c.axes) { for (var a = 0, x = c.axes.length; a < x; a++) { axes.push(c.axes[a].toFixed(2)); } } gamepadAPI.axesStatus = axes; gamepadAPI.buttonsStatus = pressed; return pressed; }, buttonPressed: function(button, hold) { var newPress = false; for (var i = 0, s = gamepadAPI.buttonsStatus.length; i < s; i++) { if (gamepadAPI.buttonsStatus[i] == button) { newPress = true; if (!hold) { for (var j = 0, p = gamepadAPI.buttonsCache.length; j < p; j++) { if (gamepadAPI.buttonsCache[j] == button) { newPress = false; } } } } } return newPress; }, buttons: [ // XBox360 layout 'A', 'B', 'X', 'Y', 'LB', 'RB', 'Axis-Left', 'DPad-Right', 'Back', 'Start', 'Power', 'Axis-Right','DPad-Up', 'DPad-Down' , 'DPad-Left','DPad-Right' ], /* 'DPad-Up', 'DPad-Down', 'DPad-Left', 'DPad-Right', 'Start', 'Back', 'Axis-Left', 'Axis-Right', 'LB', 'RB', 'Power', 'A', 'B', 'X', 'Y', ],*/ buttonsCache: [], buttonsStatus: [], axesStatus: [] }; window.addEventListener("gamepadconnected", gamepadAPI.connect); window.addEventListener("gamepaddisconnected", gamepadAPI.disconnect); module.exports = gamepadAPI; // export gamepadAPI; },{}],4:[function(require,module,exports){ var gamepad = require('./gamepad.js'); var utils = require('./utils.js'); // import * as gamepad from './gamepad.js'; var UserInputs = { init() { this.settingsList = this.keyboardKeySettings.concat(this.keyboardShiftEvents.concat(this.keyboardKeyEvents.concat(this.gamepadSettings.concat(this.gamepadShiftEvents.concat(this.gamepadButtonEvents))))); //;["Soft Drop Rate [1 - 100]"].concat(this.keyboardSettings.concat(this.gamepadSettings)); this.gamepadShiftTimer = new Date(); this.gamepadButtonTimer = new Date(); this.keyboardKeyTimer = new Date(); this.keyboardShiftTimer = new Date(); this.settingsMap = new Map(); this.gamepadEventMap = new Map(); ///this.gamepadEventMap = new Map(); // var init = utils.getCookie("init"); // if(init == "") for(var i in this.settingsList) utils.setCookie(this.settingsList[i], this.settingsDefault[i], 30); // cookies expire in 30 days // else // for(var i in this.settingsList) // this.settingsDefault[i] = utils.getCookie(this.settingsList[i]); for(var i in this.settingsList) this.settingsMap.set(this.settingsList[i], this.settingsDefault[i]); this.gamepadEvents = this.gamepadShiftEvents.concat(this.gameButtonsEvents); var mapIdx = [14, 7, 13, 5, 4, 1, 2, 12, 8, 3]; for(var i in mapIdx) { this.gamepadEventMap.set(this.gamepadEvents[i], gamepad.buttons[mapIdx[i]]); } document.addEventListener('keydown', this.keyDown.bind(this)); document.addEventListener('keyup', this.keyUp.bind(this)); }, updateGamepad() { this.gpButtons = gamepad.update(); }, gamepadEnabled() { return gamepad.controller || false; }, processGamepadInput() { this.gamepadButtonEvents.forEach(gamepadButton => this.gamepadButtonsDown(this.settingsMap.get(gamepadButton))); }, processGamepadDPad() { this.gamepadShiftEvents.forEach(dpadButton => this.gamepadDPadDown(this.settingsMap.get(dpadButton))); }, // Single press gamepad buttons gamepadButtonsDown(finds) { var DAS = 167.0; var ARR = 300.0; var isContained = this.gpButtons.includes(finds); var isPrevContained = this.prevGpButtons.includes(finds); if(isPrevContained != isContained ) { // Not being held yet this.gamepadButtonTimer = new Date(); this.isPassedDelayGamepadShift = false; // Add button to queue on pressed input if(isContained) this.gamepadQueue.push(finds); } var deltaTime = (new Date()).getTime() - this.gamepadButtonTimer.getTime(); if (!this.isPassedDelayGamepadShift) { if (deltaTime >= DAS) { this.gamepadButtonTimer = new Date(); this.isPassedDelayGamepadShift = true; } } else { if (deltaTime >= ARR && isContained) { this.gamepadQueue.push(finds); this.gamepadButtonTimer = new Date(); } } }, // Direction Pad gamepadDPadDown(finds) { var DAS = parseInt(this.settingsMap.get("Gamepad DAS")); var ARR = parseInt(this.settingsMap.get("Gamepad ARR")); var isContained = this.gpButtons.includes(finds); var isPrevContained = this.prevGpButtons.includes(finds); if(isPrevContained != isContained ) { // Not being held yet this.gamepadShiftTimer = new Date(); this.isDelayedPassedGamepadShift = false; // Add button to queue on pressed input if(isContained) this.gamepadQueue.push(finds); } var deltaTime = (new Date()).getTime() - this.gamepadShiftTimer.getTime(); if (!this.isDelayedPassedGamepadShift) { if (deltaTime >= DAS) { this.gamepadShiftTimer = new Date(); this.isDelayedPassedGamepadShift = true; } } else { if (deltaTime >= ARR && isContained) { this.gamepadQueue.push(finds); this.gamepadShiftTimer = new Date(); } } return; }, processKeys() { this.keyboardKeyEvents.forEach( key => this.settingsMap.get(key).split(',').forEach( idx => this.processKeyDown( parseInt(idx) ) ) ); }, // keyboard keys z,x,space processKeyDown(key) { var DAS = 167.0; var ARR = 300.0; if(this.prevKeyboardKeys[key] != this.keyboardKeys[key]) { // Not being held yet this.keyboardKeyTimer = new Date(); this.isPassedDelayKeyboardKey = false; // Add shift to queue on pressed input if(this.keyboardKeys[key] == true) this.inputQueue.push(key); } var deltaTime = (new Date()).getTime() - this.keyboardKeyTimer.getTime(); if (!this.isPassedDelayKeyboardKey) { if (deltaTime >= DAS) { this.keyboardKeyTimer = new Date(); this.keyboardButtonsDeciframes = 0; this.isPassedDelayKeyboardKey = true; } } else { if (deltaTime >= ARR && this.keyboardKeys[key] == true) { this.inputQueue.push(key); this.keyboardKeyTimer = new Date(); } } }, // Process applicable key inputs processKeyShift() { this.keyboardShiftEvents.forEach(arrowKey => arrowKey.split(',').forEach(option => this.processKeyboardArrowKeys(parseInt(this.settingsMap.get(option))))); }, // Direction arrows processKeyboardArrowKeys(key) { var DAS = parseInt(this.settingsMap.get("Keyboard DAS")); var ARR = parseInt(this.settingsMap.get("Keyboard ARR")); if(this.prevKeyboardKeys[key] != this.keyboardKeys[key]) { // Not being held yet this.isPassedDelayKeyboardShift = false; this.keyboardShiftTimer = new Date(); // Do shift if key has been pushed down if(this.keyboardKeys[key] == true) this.inputQueue.push(key); } var deltaTime = (new Date()).getTime() - this.keyboardShiftTimer.getTime(); if (!this.isPassedDelayKeyboardShift) { if (deltaTime >= DAS) { this.keyboardShiftTimer = new Date(); this.isPassedDelayKeyboardShift = true; } } else if(deltaTime >= ARR && this.keyboardKeys[key] == true) { this.inputQueue.push(key); this.keyboardShiftTimer = new Date(); } }, keyDown(event) { if(event.keyCode != 38) if (! ((event.keyCode >= 48 && event.keyCode <= 57) || (event.keyCode >= 96 && event.keyCode <= 105) || event.keyCode == 8)) event.preventDefault(); this.keyboardKeys[event.keyCode] = true; this.isKeyBoardKeyDown = true; }, keyUp(event) { this.isKeyDown = false; this.keyboardKeys[event.keyCode] = false; this.isKeyBoardKeyDown = false; }, gamepadClear() { //this.gpButtons = []; //this.gamepadQueue = []; }, saveButtons() { this.prevGpButtons = this.gpButtons; }, saveKeyboardKeys() { //this.prevKeyboardKeys = utils.deepClone(this.keyboardKeys); this.prevKeyboardKeys = {...this.keyboardKeys}; }, // button states isPassedDelayKeyboardShift: false, isPassedDelayKeyboardKey: false, isPassedDelayGamepadShift: false, isPassedDelayGamepadButton: false, // buttons state contatiners gpButtons: [], prevGpButtons:[], keyboardKeys: [], prevKeyboardKeys: [], // button pressed containers inputQueue: [], gamepadQueue: [], keyboardKeySettings: ["Keyboard DAS", "Keyboard ARR"], keyboardShiftEvents: ["Keyboard Left", "Keyboard Right", "Keyboard Down", "Keyboard Up"], keyboardKeyEvents: ["Keyboard Harddrop", "Keyboard Hold", "Keyboard Rotateccw", "Keyboard Rotate", "Keyboard Pophold", "Keyboard Reset", "Keyboard Background"], gamepadSettings: ["Gamepad DAS", "Gamepad ARR"], gamepadShiftEvents: ["Gamepad Left", "Gamepad Right","Gamepad Down"], gamepadButtonEvents: ["Gamepad Harddrop", "Gamepad Hold", "Gamepad Rotateccw", "Gamepad Rotate", "Gamepad Pophold", "Gamepad Reset", "Gamepad Background"], settingsList: [], settingsDefault: [ "167.0", "33.0", "37", "39", "40", "38", "32", "16", "90", "88", "17", "82", "81", "167.0", "33.0", "DPad-Left", "DPad-Right", "DPad-Down", "RB", "LB", "A", "B", "DPad-Up", "Back", ""], settingsMap: [] }; module.exports = UserInputs; // export UserInputs; },{"./gamepad.js":3,"./utils.js":8}],5:[function(require,module,exports){ var utils = require('./utils.js'); var consts = require('./consts.js'); var shapes = require('./shapes.js'); var views = require('./views.js'); var canvas = require('./canvas.js'); var inputs = require('./input.js'); var openers = require('./openers.js'); // import * as utils from './utils.js'; // import * as consts from './const.js'; // import * as shapes from './shapes.js'; // import * as views from './views.js'; // import * as canvas from './canvas.js'; // import * as inputs from './input.js'; // import * as openers from './openers.js'; //import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r125/build/three.module.js'; /** Init game matrix */ var initMatrix = function(rowCount, columnCount) { var result = []; for (var i = 0; i < rowCount; i++) { var row = []; result.push(row); for (var j = 0; j < columnCount; j++) { row.push(0); } } return result; }; /** Clear game matrix */ var clearMatrix = function(matrix) { for (var i = 0; i < matrix.length; i++) { for (var j = 0; j < matrix[i].length; j++) { matrix[i][j] = 0; } } }; /** Check all full rows in game matrix return rows number array. eg: [18,19]; */ var checkFullRows = function(matrix) { var rowNumbers = []; for (var i = 0; i < matrix.length; i++) { var row = matrix[i]; var full = true; for (var j = 0; j < row.length; j++) { full = full && row[j] !== 0; } if (full) { rowNumbers.push(i); } } return rowNumbers; }; /** Remove one row from game matrix. copy each previous row data to next row which row number less than row; */ var removeOneRow = function(matrix, row) { var colCount = matrix[0].length; for (var i = row; i >= 0; i--) { for (var j = 0; j < colCount; j++) { if (i > 0) { matrix[i][j] = matrix[i - 1][j]; } else { matrix[i][j] = 0; } } } }; /** Remove rows from game matrix by row numbers. */ var removeRows = function(matrix, rows) { for (var i in rows) { removeOneRow(matrix, rows[i]); } }; /** Check game data to determin wether the game is over */ var checkGameOver = function(matrix) { var firstRow = matrix[0]; for (var i = 0; i < firstRow.length; i++) { if (firstRow[i] !== 0) { return true; }; } return false; }; /** Calculate the extra rewards add to the score */ var calcRewards = function(rows, tspinType) { if(tspinType == 2) rows*=2+1; if (rows && rows.length > 1) { return Math.pow(2, rows.length - 1) * 100; } return 0; }; /** Calculate game score */ var calcScore = function(rows) { if (rows && rows.length) { return rows.length * 100; } return 0; }; /** Calculate time interval by level, the higher the level,the faster shape moves */ var calcIntervalByLevel = function(level) { return consts.DEFAULT_INTERVAL - (level - 1) * 60; }; // Default max scene size var defaults = { maxHeight: 700, maxWidth: 560 }; /** Tetris main object definition */ function Tetris(id) { this.id = id; this.init(); } Tetris.prototype = { init: function(options) { var cfg = this.config = utils.extend(options, defaults); this.interval = consts.DEFAULT_INTERVAL; views.init(this.id, cfg.maxWidth, cfg.maxHeight); canvas.init(views.scene, views.preview, views.hold); inputs.init(); this.createSettings(); // if true no openers. just random tetrinos this.gameState = consts.DEFAULT_GAMESTATE; this.isTimerOn = false; this.currentOpener = 0; this.matrix = initMatrix(consts.ROW_COUNT, consts.COLUMN_COUNT); this.eventTimer = new Date(); this.debugTimer = new Date(); this.gamepadEnabled = false; this.reset(); this._initEvents(); //this._fireShape(); // ewww this._recurseGameState(); }, toggleTimer: function() { document.getElementById("Timer").value = (this.isTimerOn = !this.isTimerOn) ? "Seconds:" : "Timer Off"; }, toggleGamepad: function(){ document.getElementById("enablegamepad").value = ((this.gamepadEnabled = !this.gamepadEnabled) ? "Disable Gamepad" : "Enable Gamepad"); }, // Gamestate 1 setFreePlay: function() { this.gameState = consts.GAMESTATES[0]; document.getElementById("Timer").value = "Timer Off"; document.getElementById("Time").value = ""; document.getElementById("besttime").value = ""; this.isTimerOn = false; this.hintQueue = []; this.shapeQueue = []; this.hintMino = 0; this._restartHandler(); this.currentOpener = 0; }, // Gamestate 2 setCurrentOpener(opener) { document.getElementById("besttime").value = ""; this.gameState = consts.GAMESTATES[1]; this.currentOpener = opener; this._restartHandler(); }, // Gamestate 3 setDoTest: function() { if(this.gameState != consts.GAMESTATES[1]) return; // set game state to do test this.gameState = consts.GAMESTATES[2]; this._restartHandler(); }, // Gamestate 4 setGameStateSequenceEditor: function() { document.getElementById("side").display = "none"; // change to editor gamestate this.gameState = consts.GAMESTATES[3]; this.hintQueue = []; this.shapeQueue = []; this.hintMino = 0; this._restartHandler(); this.currentOpener = 0; this.pushHoldStack(); }, createSettings: function () { var list = document.getElementById("settings"); var settings = inputs.settingsList; settings.forEach(function(item) { var option = document.createElement('option'); option.text = item; option.id = item; list.add(option); }); }, updateSettingTextBox: function() { // var setting = inputs.settingsList[document.getElementById("settings").selectedIndex-1]; // var doKeyToAlpha = inputs.keyboardShiftEvents.included(setting) || inputs.keyboardKeyEvents.included(setting); // if(doKeyToAlpha) // document.getElementById("setting_value").value = inputs.settingsMap.get(setting).fromCharCode(); // else // document.getElementById("setting_value").value = inputs.settingsMap.get(setting); document.getElementById("setting_value").value = inputs.settingsMap.get(inputs.settingsList[document.getElementById("settings").selectedIndex-1]); }, addOpener: function() { var newOpener = document.createElement('li'); //
  • Mr. T-Spin's STD (reversed)
  • //newOpener.text = "New Sequence"; //newOpener.id = this.currentMinoInx; newOpener.style="color:powderblue;text-decoration:underline;font-size:12px;padding-left:1em"; newOpener.appendChild(document.createTextNode("New Sequence: " + this.currentMinoInx)); document.getElementById("Openers").appendChild(newOpener); // Print Sequence Data to console // console.log("this.hintQueue = new Array("); // this.shapeQueue.slice().reverse().forEach( function(shape, idx, arr) { console.log("shapes.getShape("+shape.nType()+ ((idx === arr.length-1) ? "));" : "),") ); } ); var shapes = []; this.shapeQueue.slice().reverse().forEach( function(shape, idx) { shapes.push(shape.x); shapes.push(shape.y); shapes.push(shape.state); } ); // console.log("var hintDataList = [" + shapes.join(",") + "];"); // console.log("this.createHintQueue(hintDataList);"); var sequenceCode = []; var shapeArrayStr = []; this.shapeQueue.slice().reverse().forEach( function(shape, idx, arr) { shapeArrayStr += "shapes.getShape("+shape.nType() + ((idx === arr.length-1) ? "));" : "), ") } ); sequenceCode += "case :\n\tthis.shapeQueue = new Array(" + shapeArrayStr + "\nbreak;" + "\n\n"; sequenceCode += "case :\n\tthis.hintQueue = new Array(" + shapeArrayStr; sequenceCode += "\n\nvar hintDataList = [" + shapes.join(",") + "];" + "\nthis.createHintQueue(hintDataList);" + "\nbreak;"; prompt("Generated Code:", sequenceCode); //openers.addSequence(this.shapeQueue); //this.setFreePlay(); //this.gameState = consts.GAMESTATES[1]; this.currentMinoInx = 0; //this.setCurrentOpener(99999);//this.currentMinoInx); clearMatrix(this.matrix); this.currentOpener = 9999; this.shapeQueue = []; this.hintQueue = []; //this._recurseGameState(); }, setSettings: function() { var newVal = document.getElementById("setting_value").value; var key = inputs.settingsList[document.getElementById("settings").selectedIndex-1]; utils.setCookie(key, newVal, 30); inputs.settingsMap.set(key, newVal); }, //Reset game reset: function() { this.numlefts = 0; this.running = false; this.isGameOver = false; this.level = 1; this.score = 0; this.lines = 0; // beginning of frame this.startTime = new Date().getTime(); this.currentTime = this.startTime; this.prevTime = this.startTime; this.sequencePrevTime = this.startTime; //todo:get rid of extra this.levelTime = this.startTime; this.prevInputTime = this.startTime; // current tetrino index gets set to 0 at the end of opener sequence this.currentMinoInx = 0; this.shapeQueue = []; this.hintQueue = []; this.holdStack = []; this.shape = shapes.getShape(0); // gets set to false after mino has been popped from hold stack; set back to true on mino dropped this.canPopFromHoldStack = false; // manipulation counter for srs extended piece lockdown this.manipulationCounter = 0; // timer for srs extened piece lockdown this.lockdownTimer = 0; this.landed = false; this.isSequenceCompleted = false; clearMatrix(this.matrix); views.setLevel(this.level); views.setScore(this.score); views.setGameOver(this.gameState == consts.GAMESTATES[0] && this.isGameOver); openers.reset(); shapes.resetMinoRNG(); this._draw(); }, //Start game start: function() { this.running = true; window.requestAnimationFrame(utils.proxy(this._refresh, this)); }, //Pause game pause: function() { this.running = false; this.currentTime = new Date().getTime(); this.prevTime = this.currentTime; }, pushHoldStack: function() { if(this.gameState == consts.GAMESTATES[3]) { while(this.holdStack.length < 7) this.holdStack.unshift(utils.deepClone(shapes.getShape(this.currentMinoInx++%7))); this.shape = this.holdStack.pop(); this._draw(); return; } // 1 shape hold queue if(this.holdStack.length > 0) { this.canPopFromHoldStack = false; this.shapeQueue.unshift(utils.deepClone(this.shape)); this.shape = utils.deepClone(this.holdStack.pop()); this.shape.resetOrigin(); this._draw(); }else if(this.holdStack.length < 4) { this.holdStack.push(utils.deepClone(this.shape)); this.shape = this.shapeQueue.shift(); this.canPopFromHoldStack = false; this.shape.resetOrigin(); this._draw(); } /* 4 shape hold queue if(this.holdStack.length < 4) { this.holdStack.push(utils.deepClone(this.shape)); this.shape = this.shapeQueue.shift(); this.canPopFromHoldStack = false; this.shape.resetOrigin(); this._draw(); }*/ }, popHoldStack: function() { if(this.gameState == consts.GAMESTATES[3]) { if(this.holdStack.length < 7) while(this.holdStack.length < 7) this.holdStack.unshift(utils.deepClone(shapes.getShape(this.currentMinoInx++%7))); // piece needs to be able to be placed if(this.shape.canDown(this.matrix)) return; this.shape.copyTo(this.matrix); this.shapeQueue.unshift(utils.deepClone(this.shape)); this.shape = utils.deepClone(this.holdStack.pop()); this._check(); this._draw(); return; } // todo: disable if 1 shape hold queue if(this.holdStack.length >= 1 && this.canPopFromHoldStack) { this.canPopFromHoldStack = false; this.shapeQueue.unshift(utils.deepClone(this.shape)); this.shape = this.holdStack.pop(); this.shape.resetOrigin(); this._draw(); } }, // Restart game _restartHandler: function() { this.reset(); this.start(); //this._fireShape(); this._recurseGameState(); }, // Bind game events _initEvents: function() { setInterval(() => {this._processTick();}, 1); setInterval(() => {this.lockDownTimer++;}, 100 ); views.btnRestart.addEventListener('click', utils.proxy(this._restartHandler, this), false); }, // Process freeplay queue _processFreeplayQueue: function() { while(this.shapeQueue.length <= 4) { this.preparedShape = shapes.randomShape(); this.shapeQueue.push(this.preparedShape); } this.shape = this.shapeQueue.shift();// || shapes.randomShape(); this.currentMinoInx++; }, // Process opener trainer queue _processOpenerTrainerQueue: function() { while(this.shapeQueue.length <= 4) { this.preparedShape = utils.deepClone(openers.getNextMino(this.currentOpener)); this.shapeQueue.push(this.preparedShape); } while(this.hintQueue.length <= 4) { this.preparedShape = utils.deepClone(openers.getNextHint(this.currentOpener)); this.hintQueue.push(this.preparedShape); } this.hintMino = this.hintQueue.shift(); this.shape = this.shapeQueue.shift(); this.currentMinoInx++; // Opener sequence completed if(this.currentMinoInx > openers.getLength()) { //new Audio("./dist/sound/Affirm2.ogg").play(); if(this.isTimerOn) { var besttime = document.getElementById("besttime").value; var deltaTime = new Date().getTime() - this.sequencePrevTime; if(besttime == "" || deltaTime/1000.0 < parseFloat(besttime)) { document.getElementById("besttime").value = (deltaTime/1000.0).toString(); } } this.hintQueue = []; this.shapeQueue = []; this.isSequenceCompleted = true; // Recursion warning if(this.currentOpener < 1000) // getting real hacky this._restartHandler(); else clearMatrix(this.matrix); // this.reset(); // this.start(); return; } }, // Process sequence editor _processSequenceEditor: function () { return; }, // Fill next queue and set next shape _fireShape: function() { //todo:should be in shapes.js this.landed = false; this.manipulationCounter = 0; this._draw(); }, _recurseGameState: function (){ switch(this.gameState) { case consts.GAMESTATES[0]: this._processFreeplayQueue(); this._fireShape(); break; case consts.GAMESTATES[1]: this._processOpenerTrainerQueue(); this._fireShape(); break; case consts.GAMESTATES[2]: this._processOpenerTrainerQueue(); this._fireShape(); case consts.GAMESTATES[3]: this._processSequenceEditor(); break; default: break; } }, // lockdown timer with centisecond resolution resetLockdown: function() { if(this.shape.canDown(this.matrix) == false) this.landed = true; this.lockDownTimer = 0; if(this.landed) this.manipulationCounter++; }, // Return if the piece can be shifted or rotated isPieceLocked: function() { if(this.manipulationCounter > 15) return true; if(this.lockDownTimer >= 5) return true; return false; }, // Draw game data _draw: function() { canvas.drawScene(); canvas.drawShape(this.shape); canvas.drawHoldShape(this.holdStack); canvas.drawPreviewShape(this.shapeQueue); if(this.gameState != consts.GAMESTATES[2]) canvas.drawHintShape(this.hintMino); if(this.shape != undefined) { let clone = Object.assign(Object.create(Object.getPrototypeOf(this.shape)), this.shape); var bottomY = clone.bottomAt(this.matrix); canvas.drawGhostShape(clone, bottomY); } canvas.drawMatrix(this.matrix); }, // tick input data -- wont have better than 4-15ms resolution since javascript is single theaded and any ARR or DAS below 15ms will likely be broken _processTick: async function() { if(this.isTimerOn) { var deltaPlayTime = new Date().getTime() - this.sequencePrevTime; document.getElementById("Time").value = (deltaPlayTime/1000).toString(); } // Don't process game related events if game over if(this.isGameOver) return; if(this.gamepadEnabled && inputs.gamepadEnabled()) { inputs.updateGamepad(); inputs.processGamepadDPad(); inputs.processGamepadInput(); while((inputs.gamepadQueue != undefined && inputs.gamepadQueue.length >= 1)){ var curkey = inputs.gamepadQueue.shift(); if(inputs.settingsMap.get("Gamepad Left").includes(curkey)) { this.shape.goLeft(this.matrix); this.resetLockdown(); this._draw(); } else if(inputs.settingsMap.get("Gamepad Right").includes(curkey)) { this.shape.goRight(this.matrix); this.resetLockdown(); this._draw(); } else if(inputs.settingsMap.get("Gamepad Rotateccw").includes(curkey)) { this.shape.rotate(this.matrix); this.resetLockdown(); this._draw(); } else if(inputs.settingsMap.get("Gamepad Rotate").includes(curkey)) { this.shape.rotateClockwise(this.matrix); this.resetLockdown(); this._draw(); } else if(inputs.settingsMap.get("Gamepad Down").includes(curkey)) { this.shape.goDown(this.matrix); this._draw(); } else if(inputs.settingsMap.get("Gamepad Harddrop").includes(curkey)) { // if editor if(this.gameState == consts.GAMESTATES[3]) { this.popHoldStack(); this._draw(); }else { this.shape.goBottom(this.matrix); this.lockDownTimer = 5000; this._update(); } } else if(inputs.settingsMap.get("Gamepad Hold").includes(curkey)) { this.pushHoldStack(); this._draw(); } else if(inputs.settingsMap.get("Gamepad Pophold").includes(curkey)) { this.popHoldStack(); this._draw(); } else if(inputs.settingsMap.get("Gamepad Reset").includes(curkey)) { this._restartHandler(); return; } } inputs.saveButtons(); inputs.gamepadClear(); } // Do keyboard inputs.processKeys(); inputs.processKeyShift(); // Keyboard inputs while((inputs.inputQueue != undefined && inputs.inputQueue.length >= 1)){ var curkey = inputs.inputQueue.shift(); if(inputs.settingsMap.get("Keyboard Left").includes(curkey)) { this.shape.goLeft(this.matrix); this.resetLockdown(); this._draw(); } else if(inputs.settingsMap.get("Keyboard Right").includes(curkey)) { this.shape.goRight(this.matrix); this.resetLockdown(); this._draw(); } else if(inputs.settingsMap.get("Keyboard Down").includes(curkey)) { this.shape.goDown(this.matrix); this._draw(); } else if(this.gameState == consts.GAMESTATES[3] && inputs.settingsMap.get("Keyboard Up").includes(curkey)) { this.shape.goUp(this.matrix); this._draw(); } else if(inputs.settingsMap.get("Keyboard Rotateccw").includes(curkey)) { this.shape.rotate(this.matrix); this.resetLockdown(); this._draw(); } else if(inputs.settingsMap.get("Keyboard Rotate").includes(curkey)) { this.shape.rotateClockwise(this.matrix); this.resetLockdown(); this._draw(); } else if(inputs.settingsMap.get("Keyboard Harddrop").includes(curkey)) { // if editor if(this.gameState == consts.GAMESTATES[3]) { this.popHoldStack(); this._draw(); }else { this.shape.goBottom(this.matrix); this.lockDownTimer = 5000; this._update(); } } else if(inputs.settingsMap.get("Keyboard Hold").includes(curkey)) { this.pushHoldStack(); this._draw(); } else if(inputs.settingsMap.get("Keyboard Pophold").includes(curkey)) { this.popHoldStack(); this._draw(); } else if(inputs.settingsMap.get("Keyboard Hold").includes(curkey)) { if(document.getElementById("divbg").style.display == "none") document.getElementById("divbg").style.display = "initial"; else document.getElementById("divbg").style.display="none"; } if(inputs.settingsMap.get("Keyboard Reset").includes(curkey)) { this._restartHandler(); return; } } inputs.inputQueue = []; inputs.saveKeyboardKeys(); inputs.saveButtons(); }, // Refresh game canvas _refresh: function() { if (!this.running) return; this.currentTime = new Date().getTime(); var deltaLevelTime = this.currentTime - this.prevTime; if (deltaLevelTime > this.interval) { // every .6 seconds? this._update(); this._checkLevel(this.prevTime = this.currentTime); } // Draw Frame if (!this.isGameOver) { window.requestAnimationFrame(utils.proxy(this._refresh, this)); } }, // check if the current piece is in the same location as the hint piece _checkHint: function() { if(this.gameState == consts.GAMESTATES[0]) return; if(!this.shape.isSameSRS(this.hintMino)) { //new Audio('./dist/Failed.ogg').play(); this._restartHandler(); // Restart return 1; } }, // Update game data _update: function() { switch(this.gameState) { case consts.GAMESTATES[0]: case consts.GAMESTATES[1]: case consts.GAMESTATES[2]: if(this.shape == undefined) break; if (this.shape.canDown(this.matrix)) { this.shape.goDown(this.matrix); } else if(this.isPieceLocked()){ this.canPopFromHoldStack = true; this.shape.copyTo(this.matrix); this._check(); if(this._checkHint()) return; //this._fireShape(); this._recurseGameState(); new Audio('./dist/sound/Blop2.ogg').play(); } this._draw(); this.isGameOver = checkGameOver(this.matrix); // if game over and gamestate is free play views.setGameOver(this.gameState == consts.GAMESTATES[0] && this.isGameOver); if (this.isGameOver) views.setFinalScore(this.score); break; case consts.GAMESTATES[3]: break; default: break; } }, // 0 - none, 1 - mini, 2 - tspin _tSpinType: function(tPiece, matrix) { var side1 = 0; var side2 = 0; var side3 = 0; var side4 = 0; side1X = tPiece.x; side1Y = tPiece.y; side2X = tPiece.x + 2; side2Y = tPiece.y; side3X = tPiece.x; side3Y = tPiece.y + 2; side4X = tPiece.x + 2; side4Y = tPiece.y + 2; if(matrix[side4Y] != undefined && matrix[side3Y] != undefined) { if(matrix[side1Y][side1X] != 0) side1 = 1; if(matrix[side2Y][side2X] != 0) side2 = 1; // TODO: figure out why this occasionally is undefined if(matrix[side3Y][side3X] != 0) side3 = 1; if(matrix[side4Y][side4X] != 0) side4 = 1; } console.log("sides: " + side1+side2+side3+side4); // if Sides A and B + (C or D) are touching a Surface //considered a T-Spin if((side1+side2+side3+side4) >= 3) return 2; //if Sides C and D + (A or B) are touching a Surface //considered a Mini T-Spin if((side1 || side2) && (side3 && side4)) return 1; return 0; }, // Check and update game data _check: function() { var rows = checkFullRows(this.matrix); if (rows.length) { var tspinType; if(this.shape.flag === 'T') tspinType = this._tSpinType(this.shape, this.matrix); removeRows(this.matrix, rows); console.log("type: " + tspinType); var score = calcScore(rows); var reward = calcRewards(rows, tspinType); this.score += score + reward; this.lines += rows.length; views.setScore(this.score); views.setReward(reward); views.setLines(this.lines); } }, // Check and update game level _checkLevel: function() { var currentTime = new Date().getTime(); if (currentTime - this.levelTime > consts.LEVEL_INTERVAL) { this.level += 1; this.interval = calcIntervalByLevel(this.level); views.setLevel(this.level); this.levelTime = currentTime; } }, } window.Tetris = Tetris; // export {Tetris}; },{"./canvas.js":1,"./consts.js":2,"./input.js":4,"./openers.js":6,"./shapes.js":7,"./utils.js":8,"./views.js":9}],6:[function(require,module,exports){ var shapes = require("./shapes.js"); var utils = require("./utils.js"); // import * as shapes from './shapes.js'; // https://harddrop.com/wiki/Opener // https://four.lol/ var openerGenerator = { shapeQueue: [], hintQueue: [], idx: 0, hintIdx: 0, isInit: 0, isHintInit: 0, customShapeQueue: [], customHintQueue: [], // O - 1, I - 6, L - 0, S - 5, J - 4, Z - 2, T - 3 // Current Tetriminos init(opener) { if(!this.isInit || this.shapeQueue == undefined) { switch(opener) { case 0: case 1: // Fonzie Variation this.shapeQueue = new Array( shapes.getShape(0), shapes.getShape(6), shapes.getShape(1), shapes.getShape(5), shapes.getShape(2), shapes.getShape(4), shapes.getShape(3)); break; case 2: // DTCannon this.shapeQueue = new Array( shapes.getShape(1), shapes.getShape(6), shapes.getShape(0), shapes.getShape(5), shapes.getShape(4), shapes.getShape(2), shapes.getShape(3), shapes.getShape(1), shapes.getShape(6), shapes.getShape(0), shapes.getShape(4), shapes.getShape(3), shapes.getShape(1), shapes.getShape(3)); break; case 3: this.shapeQueue = new Array( shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(0), shapes.getShape(2), shapes.getShape(1), shapes.getShape(5), shapes.getShape(3), shapes.getShape(1), shapes.getShape(2), shapes.getShape(6), shapes.getShape(0), shapes.getShape(4), shapes.getShape(3)); break; case 4: //Pokemino's STD this.shapeQueue = new Array( shapes.getShape(0), shapes.getShape(6), shapes.getShape(1), shapes.getShape(4), shapes.getShape(2), shapes.getShape(5), shapes.getShape(3), shapes.getShape(1), shapes.getShape(5), shapes.getShape(2), shapes.getShape(0), shapes.getShape(6), shapes.getShape(2), shapes.getShape(4), shapes.getShape(3), shapes.getShape(0), shapes.getShape(3)); break; case 5: // Mr TSpins STD reversed this.shapeQueue = new Array( shapes.getShape(1), shapes.getShape(2), shapes.getShape(5), shapes.getShape(0), shapes.getShape(4), shapes.getShape(6), shapes.getShape(3), shapes.getShape(1), shapes.getShape(6), shapes.getShape(2), shapes.getShape(4), shapes.getShape(5), shapes.getShape(0), shapes.getShape(0), shapes.getShape(3), shapes.getShape(3)); break; case 6: // Hachispin this.shapeQueue = new Array( shapes.getShape(1), shapes.getShape(2), shapes.getShape(6), shapes.getShape(5), shapes.getShape(4), shapes.getShape(0), shapes.getShape(3), shapes.getShape(6), shapes.getShape(1), shapes.getShape(5), shapes.getShape(4), shapes.getShape(2), shapes.getShape(0), shapes.getShape(3)); break; case 7: // Albatross this.shapeQueue = new Array(shapes.getShape(1), shapes.getShape(5), shapes.getShape(6), shapes.getShape(0), shapes.getShape(4), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(1), shapes.getShape(6), shapes.getShape(0), shapes.getShape(2), shapes.getShape(3)); break; case 8: // Number One this.shapeQueue = new Array( shapes.getShape(1), shapes.getShape(4), shapes.getShape(6), shapes.getShape(0), shapes.getShape(2), shapes.getShape(5), shapes.getShape(3)); break; case 9: // Pelican this.shapeQueue = new Array( shapes.getShape(5), shapes.getShape(2), shapes.getShape(4), shapes.getShape(0), shapes.getShape(6), shapes.getShape(1), shapes.getShape(3)); break; case 10: // DT Cannon TSZ base this.shapeQueue = new Array( shapes.getShape(3), shapes.getShape(1), shapes.getShape(2), shapes.getShape(6), shapes.getShape(5), shapes.getShape(0), shapes.getShape(4), shapes.getShape(4), shapes.getShape(0), shapes.getShape(3), shapes.getShape(3)); break; case 11: this.shapeQueue = new Array( shapes.getShape(0), shapes.getShape(1), shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(0), shapes.getShape(1), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(3), shapes.getShape(0), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(3), shapes.getShape(4), shapes.getShape(1), shapes.getShape(3), shapes.getShape(4), shapes.getShape(0), shapes.getShape(6)); break; case 12: this.shapeQueue = new Array( shapes.getShape(0), shapes.getShape(1), shapes.getShape(2), shapes.getShape(3)); break; case 13: this.shapeQueue = new Array(shapes.getShape(4), shapes.getShape(6), shapes.getShape(1), shapes.getShape(2), shapes.getShape(3), shapes.getShape(5), shapes.getShape(0), shapes.getShape(1), shapes.getShape(0), shapes.getShape(6), shapes.getShape(0), shapes.getShape(5), shapes.getShape(4), shapes.getShape(3), shapes.getShape(4), shapes.getShape(3), shapes.getShape(4)); break; case 14: this.shapeQueue = new Array(shapes.getShape(0), shapes.getShape(6), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(0), shapes.getShape(4), shapes.getShape(6), shapes.getShape(0), shapes.getShape(0), shapes.getShape(3), shapes.getShape(5)); break; case 15: this.shapeQueue = new Array(shapes.getShape(0), shapes.getShape(2), shapes.getShape(5), shapes.getShape(6), shapes.getShape(1), shapes.getShape(3), shapes.getShape(4), shapes.getShape(2), shapes.getShape(5), shapes.getShape(0), shapes.getShape(1), shapes.getShape(6), shapes.getShape(4), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(0), shapes.getShape(1), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(1), shapes.getShape(3), shapes.getShape(4), shapes.getShape(3)); break; default: this.shapeQueue.unshift(utils.deepClone(shapes.randomShape())); return; } } this.isInit = 1; return; }, getNextMino(opener) { if(this.customShapeQueue.length > 0) return this.customShapeQueue[this.idx++%this.customShapeQueue.length]; this.init(opener); var mino = this.shapeQueue[this.idx]; this.idx++; if(this.idx >= this.shapeQueue.length) { this.idx = 0; if(opener < 1000) this.isInit = 0; else this.isInit = 1; } return mino; }, createHintQueue(hintDataList) { for(var i = 0; i < this.hintQueue.length; i++) { this.hintQueue[i].x = hintDataList[i * 3]; this.hintQueue[i].y = hintDataList[i * 3 + 1]; this.hintQueue[i].state = this.hintQueue[i].nextState(hintDataList[i * 3 + 2]); } }, // Hint Tetrimions initHint(opener) { if(!this.isHintInit || this.hintQueue == undefined) { switch(opener) { case 0: this.hintQueue = []; break; case 1: // Fonzie Variation this.hintQueue = new Array( shapes.getShape(0), shapes.getShape(6), shapes.getShape(1), shapes.getShape(5), shapes.getShape(2), shapes.getShape(4), shapes.getShape(3)); // position x, position y, orientation, position x,... var hintDataList = [-1,17,1, 3,18,0, 6,18,0, 5,17,1, 3,17,0, 7,16,0, 1,17,2]; this.createHintQueue(hintDataList); break; case 2: // DT Cannon this.hintQueue = new Array( shapes.getShape(1), shapes.getShape(6), shapes.getShape(0), shapes.getShape(5), shapes.getShape(4), shapes.getShape(2), shapes.getShape(3), shapes.getShape(1), shapes.getShape(6), shapes.getShape(0), shapes.getShape(4), shapes.getShape(3), shapes.getShape(1), shapes.getShape(3)); // position x, position y, orientation, position x,... var hintDataList = [-2,18,0, 4,16,1, 6,17,1, 7,17,1, 4,17,-1, 3,17,3, 3,15,0, 5,15,0, 7,14,1, 2,13,-1, -1,15,1, 1,16,2, 3,16,1, 1,17,-1]; for(var i = 0; i < this.hintQueue.length; i++) { this.hintQueue[i].x = hintDataList[i * 3]; this.hintQueue[i].y = hintDataList[i * 3 + 1]; this.hintQueue[i].state = this.hintQueue[i].nextState(hintDataList[i * 3 + 2]); } break; case 3: //MKO Stacking this.hintQueue = new Array( shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(0), shapes.getShape(2), shapes.getShape(1), shapes.getShape(5), shapes.getShape(3), shapes.getShape(1), shapes.getShape(2), shapes.getShape(6), shapes.getShape(0), shapes.getShape(4), shapes.getShape(3)); // position x, position y, orientation, position x,... var hintDataList = [0,18,0, 0,16,-1, 8,16,-1, 4,18,0, 4,16,1, 5,18,0, 1,15,-1, 2,17,2, 5,18,0, 3,17,1, 6,16,0, 0,15,2, 0,14,0, 2,16,2]; for(var i = 0; i < this.hintQueue.length; i++) { this.hintQueue[i].x = hintDataList[i * 3]; this.hintQueue[i].y = hintDataList[i * 3 + 1]; this.hintQueue[i].state = this.hintQueue[i].nextState(hintDataList[i * 3 + 2]); } break; case 4: //Pokemino's STD this.hintQueue = new Array( shapes.getShape(0), shapes.getShape(6), shapes.getShape(1), shapes.getShape(4), shapes.getShape(2), shapes.getShape(5), shapes.getShape(3), shapes.getShape(1), shapes.getShape(5), shapes.getShape(2), shapes.getShape(0), shapes.getShape(6), shapes.getShape(2), shapes.getShape(4), shapes.getShape(3), shapes.getShape(0), shapes.getShape(3)); var hintDataList = [0,17,1, -2,16,1, 4,18,0, 4,17,-1, 3,15,1, 8,17,-1, 2,17,2, 0,17,0, 0,15,-1, 1,15,0, 8,16,-2, 5,15,-1, 3,14,1, 6,12,-1, 6,16,1, 2,16,-1, 7,17,2 ]; for(var i = 0; i < this.hintQueue.length; i++) { this.hintQueue[i].x = hintDataList[i * 3]; this.hintQueue[i].y = hintDataList[i * 3 + 1]; this.hintQueue[i].state = this.hintQueue[i].nextState(hintDataList[i * 3 + 2]); } break; case 5: // Mr TSpins STD reversed this.hintQueue = new Array( shapes.getShape(1), shapes.getShape(2), shapes.getShape(5), shapes.getShape(0), shapes.getShape(4), shapes.getShape(6), shapes.getShape(3), shapes.getShape(1), shapes.getShape(6), shapes.getShape(2), shapes.getShape(4), shapes.getShape(5), shapes.getShape(0), shapes.getShape(0), shapes.getShape(3), shapes.getShape(3)); var hintDataList = [4,18,0, 0,18,0, 7,17,1, 0,15,1, 4,17,-1, 5,14,-1, 2,17,2, 1,17,0, -1,16,-1, 2,15,-1, 0,14,0, 3,15,1, 8,16,-1, 5,13,2, 6,16,1, 7,17,2 ]; for(var i = 0; i < this.hintQueue.length; i++) { this.hintQueue[i].x = hintDataList[i * 3]; this.hintQueue[i].y = hintDataList[i * 3 + 1]; this.hintQueue[i].state = this.hintQueue[i].nextState(hintDataList[i * 3 + 2]); } break; case 6: // Hachispin this.hintQueue = new Array( shapes.getShape(1), shapes.getShape(2), shapes.getShape(6), shapes.getShape(5), shapes.getShape(4), shapes.getShape(0), shapes.getShape(3), shapes.getShape(6), shapes.getShape(1), shapes.getShape(5), shapes.getShape(4), shapes.getShape(2), shapes.getShape(0), shapes.getShape(3)); var hintDataList = [1,18,0, 0,18,0, 8,16,-1, 2,15,1, 6,17,2, 5,16,2, 1,16,2, -1,16,-1, -1,16,0, 5,16,0, 0,14,0, 3,15,0, 8,14,-1, 7,16,-1]; for(var i = 0; i < this.hintQueue.length; i++) { this.hintQueue[i].x = hintDataList[i * 3]; this.hintQueue[i].y = hintDataList[i * 3 + 1]; this.hintQueue[i].state = this.hintQueue[i].nextState(hintDataList[i * 3 + 2]); } break; case 7: // Albatross this.hintQueue = new Array(shapes.getShape(1), shapes.getShape(5), shapes.getShape(6), shapes.getShape(0), shapes.getShape(4), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(1), shapes.getShape(6), shapes.getShape(0), shapes.getShape(2), shapes.getShape(3)); var hintDataList = [1,18,0,0,17,3,8,16,3,5,17,2,6,16,2,3,16,0,1,16,2,-1,17,1,5,17,3,5,18,0,6,16,0,2,15,3,3,15,1,1,17,3]; this.createHintQueue(hintDataList); break; case 8: // Number One this.hintQueue = new Array( shapes.getShape(1), shapes.getShape(4), shapes.getShape(6), shapes.getShape(0), shapes.getShape(2), shapes.getShape(5), shapes.getShape(3)); var hintDataList = [3,18,0, 0,17,2, 0,16,0, 4,15,-1, 6,17,0, 8,16,-1, 3,17,-1]; for(var i = 0; i < this.hintQueue.length; i++) { this.hintQueue[i].x = hintDataList[i * 3]; this.hintQueue[i].y = hintDataList[i * 3 + 1]; this.hintQueue[i].state = this.hintQueue[i].nextState(hintDataList[i * 3 + 2]); } break; case 9: // Pelican this.hintQueue = new Array( shapes.getShape(5), shapes.getShape(2), shapes.getShape(4), shapes.getShape(0), shapes.getShape(6), shapes.getShape(1), shapes.getShape(3)); var hintDataList = [0,17,-1, 1,16,2, 5,18,0, 5,16,-1, 8,16,-1, 5,17,0, 3,16,2]; for(var i = 0; i < this.hintQueue.length; i++) { this.hintQueue[i].x = hintDataList[i * 3]; this.hintQueue[i].y = hintDataList[i * 3 + 1]; this.hintQueue[i].state = this.hintQueue[i].nextState(hintDataList[i * 3 + 2]); } break; case 10: // O - 1, I - 6, L - 0, S - 5, J - 4, Z - 2, T - 3 // DT Cannon TSZ base this.hintQueue = new Array( shapes.getShape(3), shapes.getShape(1), shapes.getShape(2), shapes.getShape(6), shapes.getShape(5), shapes.getShape(0), shapes.getShape(4), shapes.getShape(4), shapes.getShape(0), shapes.getShape(3), shapes.getShape(3)); var hintDataList = [4,18,0, -2,18,0, 2,17,1, 8,16,-1, 6,17,-1, 7,17,-1, 3,15,2, -1,15,1, 2,13,-1, 1,16,2, 1,17,3]; for(var i = 0; i < this.hintQueue.length; i++) { this.hintQueue[i].x = hintDataList[i * 3]; this.hintQueue[i].y = hintDataList[i * 3 + 1]; this.hintQueue[i].state = this.hintQueue[i].nextState(hintDataList[i * 3 + 2]); } break; case 11: this.hintQueue = new Array( shapes.getShape(0), shapes.getShape(1), shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(0), shapes.getShape(1), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(3), shapes.getShape(0), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(3), shapes.getShape(4), shapes.getShape(1), shapes.getShape(3), shapes.getShape(4), shapes.getShape(0), shapes.getShape(6)); var hintDataList = [3,17,1,6,18,0,1,17,3,5,17,3,2,16,3,-1,17,1,4,15,0,5,13,1,3,14,0,-1,14,3,8,15,3,-1,15,0,0,13,0,6,16,2,0,13,2,4,14,0,2,13,3,6,17,1,7,18,0,3,16,1,7,17,2,6,18,0,1,18,0,-1,17,1,2,16,2,5,17,0,0,15,2,3,15,2,6,15,2,8,16,3]; this.createHintQueue(hintDataList); break case 12: this.hintQueue = new Array( shapes.getShape(0), shapes.getShape(1), shapes.getShape(2), shapes.getShape(3)); var hintDataList = [3,17,1,6,18,0,5,17,2,1,18,0]; this.createHintQueue(hintDataList); break; case 13: this.hintQueue = new Array(shapes.getShape(4), shapes.getShape(6), shapes.getShape(1), shapes.getShape(2), shapes.getShape(3), shapes.getShape(5), shapes.getShape(0), shapes.getShape(1), shapes.getShape(0), shapes.getShape(6), shapes.getShape(0), shapes.getShape(5), shapes.getShape(4), shapes.getShape(3), shapes.getShape(4), shapes.getShape(3), shapes.getShape(4)); var hintDataList = [0,18,0,3,18,0,-1,17,0,7,18,0,3,17,0,8,16,3,0,15,2,-2,14,0,3,15,2,3,14,0,1,13,3,8,14,3,7,12,2,5,16,2,3,14,3,6,17,3,5,18,0]; this.createHintQueue(hintDataList); break; case 14: this.hintQueue = new Array(shapes.getShape(0), shapes.getShape(6), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(0), shapes.getShape(4), shapes.getShape(6), shapes.getShape(0), shapes.getShape(0), shapes.getShape(3), shapes.getShape(5)); var hintDataList = [-1,17,1,3,18,0,3,17,0,7,18,0,6,16,3,8,16,3,0,16,3,0,14,0,8,13,3,4,15,1,6,14,2,1,17,1,2,17,2]; this.createHintQueue(hintDataList); break; case 15: this.hintQueue = new Array(shapes.getShape(0), shapes.getShape(2), shapes.getShape(5), shapes.getShape(6), shapes.getShape(1), shapes.getShape(3), shapes.getShape(4), shapes.getShape(2), shapes.getShape(5), shapes.getShape(0), shapes.getShape(1), shapes.getShape(6), shapes.getShape(4), shapes.getShape(3), shapes.getShape(4), shapes.getShape(5), shapes.getShape(6), shapes.getShape(0), shapes.getShape(1), shapes.getShape(2), shapes.getShape(3), shapes.getShape(4), shapes.getShape(1), shapes.getShape(3), shapes.getShape(4), shapes.getShape(3)); var hintDataList = [-1,17,1,2,18,0,4,17,3,6,18,0,6,17,0,2,15,2,-1,14,1,5,17,0,4,14,3,5,14,3,6,15,0,6,14,3,8,12,3,0,16,1,6,15,0,0,15,0,-1,12,3,6,13,1,2,15,0,3,13,0,1,17,2,5,14,1,6,15,0,2,17,3,3,15,2,1,17,2]; this.createHintQueue(hintDataList); break; default: this.hintQueue.unshift(utils.deepClone(shapes.randomShape())); return; } } this.isHintInit = 1; return; }, // End initHint getNextHint(opener) { if(this.customHintQueue.length > 0) return this.customHintQueue[this.hintIdx++%this.customHintQueue.length]; this.initHint(opener); var mino = this.hintQueue[this.hintIdx]; this.hintIdx++; if(this.hintIdx >= this.hintQueue.length) { this.hintIdx = 0; if(opener < 1000) this.isHintInit = 0; else this.isHintInit = 1; } return mino; }, reset() { this.shapeQueue = []; this.hintQueue = []; this.idx = 0; this.hintIdx = 0; this.isInit = 0; this.isHintInit = 0; }, getLength() { return this.customHintQueue.length || this.hintQueue.length; }, addSequence(sequence) { //this.reset(); //this.shapeQueue = utils.deepClone(sequence); //this.hintQueue = utils.deepClone(sequence); for(var i in sequence) { var shape; shape = sequence[i]; shape.x = sequence[i].x; shape.y = sequence[i].y; shape.state = sequence[i].state; this.customHintQueue.unshift(utils.deepClone(shape)); shape.x = shape.originX; shape.y = shape.originY; this.customShapeQueue.unshift(utils.deepClone(shape)); this.isInit = 1; this.isHintInit = 1; this.idx = 0; this.hintIdx = 0; } } }; function reset() { openerGenerator.reset(); } function getNextMino(opener) { var mino = openerGenerator.getNextMino(opener); return mino; } function getNextHint(opener) { var mino = openerGenerator.getNextHint(opener); return mino; } function getLength() { return openerGenerator.getLength(); } function addSequence(sequence) { openerGenerator.addSequence(sequence); } module.exports.addSequence = addSequence; module.exports.getNextMino = getNextMino; module.exports.getNextHint = getNextHint; module.exports.getLength = getLength; module.exports.reset = reset; // export getNextMino; // export getNextHint; // export getLength; // export reset; },{"./shapes.js":7,"./utils.js":8}],7:[function(require,module,exports){ var consts = require('./consts.js'); var utils = require('./utils.js'); // import * as consts from './const.js'; var COLORS = consts.COLORS; var COLUMN_COUNT = consts.COLUMN_COUNT; /** Defined all shapes used in Tetris game. You can add more shapes if you wish. */ function ShapeL() { var state1 = [ [0, 0, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0] ]; var state2 = [ [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0] ]; var state3 = [ [0, 0, 0, 0], [1, 1, 1, 0], [1, 0, 0, 0], [0, 0, 0, 0] ]; var state4 = [ [1, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0] ]; // Rotation point offsets: clockwise, counterclockwise, // In guidline Tetris each piece has 5 possible rotation points with respect to each state/orientation. Iterate through all every rotation. var state1RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, -1, 0, 1, 1, -1, 1, 0, -2, 0, -2, 1, -2, -1, -2 ]; var state2RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, 1, 0, 1, -1, 1, -1, 0, 2, 0, 2, 1, 2, 1, 2 ]; var state3RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, 1, 0, -1, 1, 1, 1, 0, -2, 0, -2, -1, -2, 1, -2 ]; var state4RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, -1, 0, -1, -1, -1, -1, 0, 2, 0, 2, -1, 2, -1, 2 ]; this.rotationPoints = [state1RotationPointsOffset, state2RotationPointsOffset, state3RotationPointsOffset, state4RotationPointsOffset]; this.states = [state1, state2, state3, state4]; this.x = 3; this.y = -3; this.originX = 3; this.originY = -3; this.flag = 'L'; } function ShapeLR() { var state1 = [ [1, 0, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0] ]; var state2 = [ [0, 1, 1, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0] ]; var state3 = [ [0, 0, 0, 0], [1, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0] ]; var state4 = [ [0, 1, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0] ]; var state1RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, -1, 0, 1, 1, -1, 1, 0, -2, 0, -2, 1, -2, -1, -2 ]; var state2RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, 1, 0, 1, -1, 1, -1, 0, 2, 0, 2, 1, 2, 1, 2 ]; var state3RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, 1, 0, -1, 1, 1, 1, 0, -2, 0, -2, -1, -2, 1, -2 ]; var state4RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, -1, 0, -1, -1, -1, -1, 0, 2, 0, 2, -1, 2, -1, 2 ]; this.rotationPoints = [state1RotationPointsOffset, state2RotationPointsOffset, state3RotationPointsOffset, state4RotationPointsOffset]; this.states = [state1, state2, state3, state4]; this.x = 3; this.y = -3; this.originX = 3; this.originY = -3; this.flag = 'LR'; } function ShapeO() { var state1 = [ [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0] ]; var state2 = [ [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0] ]; var state3 = [ [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0] ]; var state4 = [ [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0] ]; var state1RotationPointsOffset = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; var state2RotationPointsOffset = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; var state3RotationPointsOffset = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; var state4RotationPointsOffset = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; this.rotationPoints = [state1RotationPointsOffset, state2RotationPointsOffset, state3RotationPointsOffset, state4RotationPointsOffset]; this.states = [state1, state2, state3, state4]; this.x = 2; this.y = -2; this.originX = 2; this.originY = -2; this.flag = 'O'; } function ShapeI() { // North var state1 = [ [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0] ]; // East var state2 = [ [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0] ]; // South var state3 = [ [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0] ]; // West var state4 = [ [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0] ]; var state1RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, -2, 0, 2, 0, 1, 0, -1, 2, -2, -1, 2, -1, 1, 2 ]; var state2RotationPointsOffset = [ 0, 0, 0, 0, 2, 0, -1, 0, -1, 0, 2, 0, 2, 1, -1, 2, -1, -2, 2, -1 ]; var state3RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, 2, 0, -2, 0, -1, 0, 1, -2, 2, 1, -2, 1, -1, -2 ]; var state4RotationPointsOffset = [ 0, 0, 0, 0, -2, 0, 1, 0, 1, 0, -2, 0, -2, -1, 1, -2, 1, 2, -2, 1 ]; this.rotationPoints = [state1RotationPointsOffset, state2RotationPointsOffset, state3RotationPointsOffset, state4RotationPointsOffset]; this.states = [state1, state2, state3, state4]; this.x = 3; this.y = -4; this.originX = 3; this.originY = -4; this.flag = 'I'; } function ShapeT() { var state1 = [ [0, 1, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0] ]; var state2 = [ [0, 1, 0, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0] ]; var state3 = [ [0, 0, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0] ]; var state4 = [ [0, 1, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0] ]; // rotation points clockwise, counterclockwise var state1RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, -1, 0, 1, 1, -1, 1, NaN, NaN, NaN, NaN, 1, -2, -1, -2 ]; var state2RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, 1, 0, 1, -1, 1, -1, 0, 2, 0, 2, 1, 2, 1, 2 ]; var state3RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, 1, 0, NaN, NaN, NaN, NaN, 0, -2, 0, -2, -1, -2, 1, -2 ]; var state4RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, -1, 0, -1, -1, -1, -1, 0, 2, 0, 2, -1, 2, -1, 2 ]; this.rotationPoints = [state1RotationPointsOffset, state2RotationPointsOffset, state3RotationPointsOffset, state4RotationPointsOffset]; this.states = [state1, state2, state3, state4]; this.x = 3; this.y = -2; this.originX = 3; this.originY = -2; this.flag = 'T'; } function ShapeZ() { var state1 = [ [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0] ]; var state2 = [ [0, 0, 1, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0] ]; var state3 = [ [0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0] ]; var state4 = [ [0, 1, 0, 0], [1, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 0] ]; // Rotation point offsets: clockwise, counterclockwise, // In guidline Tetris each piece has 5 possible rotation points with respect to each state/orientation. Iterate through all every rotation. var state1RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, -1, 0, 1, 1, -1, 1, 0, -2, 0, -2, 1, -2, -1, -2 ]; var state2RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, 1, 0, 1, -1, 1, -1, 0, 2, 0, 2, 1, 2, 1, 2 ]; var state3RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, 1, 0, -1, 1, 1, 1, 0, -2, 0, -2, -1, -2, 1, -2 ]; var state4RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, -1, 0, -1, -1, -1, -1, 0, 2, 0, 2, -1, 2, -1, 2 ]; this.rotationPoints = [state1RotationPointsOffset, state2RotationPointsOffset, state3RotationPointsOffset, state4RotationPointsOffset]; this.states = [state1, state2, state3, state4]; this.x = 3; this.y = -2; this.originX = 3; this.originY = -2; this.flag = 'Z'; } function ShapeZR() { var state1 = [ [0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ]; var state2 = [ [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0] ]; var state3 = [ [0, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0] ]; var state4 = [ [1, 0, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0] ]; // Rotation point offsets: clockwise, counterclockwise, // In guidline Tetris each piece has 5 possible rotation points with respect to each state/orientation. Iterate through all every rotation. var state1RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, -1, 0, 1, 1, -1, 1, 0, -2, 0, -2, 1, -2, -1, -2 ]; var state2RotationPointsOffset = [ 0, 0, 0, 0, 1, 0, 1, 0, 1, -1, 1, -1, 0, 2, 0, 2, 1, 2, 1, 2 ]; var state3RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, 1, 0, -1, 1, 1, 1, 0, -2, 0, -2, -1, -2, 1, -2 ]; var state4RotationPointsOffset = [ 0, 0, 0, 0, -1, 0, -1, 0, -1, -1, -1, -1, 0, 2, 0, 2, -1, 2, -1, 2 ]; this.rotationPoints = [state1RotationPointsOffset, state2RotationPointsOffset, state3RotationPointsOffset, state4RotationPointsOffset]; this.states = [state1, state2, state3, state4]; this.x = 3; this.y = -2 this.originX = 3; this.originY = -2; this.flag = 'ZR'; } /** doesShapeOverlap @param shape: tetris shape @param matrix: game matrix */ var doesShapeOverlap = function(shape, matrix) { var rows = matrix.length; var cols = matrix[0].length; var rotationDirection = 0; var isBoxInMatrix = function(box) { var x = shape.x + box.x; var y = shape.y + box.y; if(isNaN(x))return true; if(isNaN(y))return true; if(x < 0) return true; if(x > matrix.cols)return true; if(y > rows) return true; // todo: why is matrix not defined when piece popped from hold stack if(matrix[y] == undefined) return true; //console.log("matrix X Y: " + " " + x + " "+ y); return (matrix[y][x] != 0) }; boxes = shape.getBoxes(shape.state); for (var i in boxes) if (isBoxInMatrix(boxes[i])) return true; return false; }; /** Is same on matrix @param shape: tetris shape @param hintPiece: hintPiece shape @param matrix: game matrix @param action: 'left','right','down','rotate' */ var isBoxesSame = function(shape, hintPiece) { var isBoxSame = function(shapeBox, hintPieceBox) { var shapeX = shape.x + shapeBox.x; var shapeY = shape.y + shapeBox.y; var hintPieceX = hintPiece.x + hintPieceBox.x; var hintPieceY = hintPiece.y + hintPieceBox.y; if(shapeX == hintPieceX && shapeY == hintPieceY) return true; return false; }; //var boxes = action === 'rotate'?shape.getBoxes(shape.nextState()) : shape.getBoxes(shape.state); var boxes; var hintPieceBoxes; boxes = shape.getBoxes(shape.state); hintPieceBoxes = hintPiece.getBoxes(hintPiece.state); for (var i in boxes) { if (!isBoxSame(boxes[i], hintPieceBoxes[i])) { return false; } } return true; }; /** Is shape can move @param shape: tetris shape @param matrix: game matrix @param action: 'left','right','down','rotate' */ var isShapeCanMove = function(shape, matrix, action) { var rows = matrix.length; var cols = matrix[0].length; var rotationDirection = 0; var isBoxCanMove = function(box) { var x = shape.x + box.x; var y = shape.y + box.y; if (y < 0) { return true; } if (action === 'left') { x -= 1; return x >= 0 && x < cols && matrix[y][x] == 0; } else if (action === 'right') { x += 1; return x >= 0 && x < cols && matrix[y][x] == 0; } else if (action === 'up') { y -= 1; return y >= 0 && matrix[y][x] == 0; } else if (action === 'down') { y += 1; return y < rows && matrix[y][x] == 0; } else if (action === 'rotate') { rotationDirection = 1; return y < rows && !matrix[y][x]; } else if (action === 'rotateclockwise') { rotationDirection = -1; return y < rows && !matrix[y][x]; } }; //var boxes = action === 'rotate'?shape.getBoxes(shape.nextState()) : shape.getBoxes(shape.state); var boxes; if(rotationDirection != 0) boxes = shape.getBoxes(shape.nextState(rotationDirection)); else boxes = shape.getBoxes(shape.state); for (var i in boxes) { if (!isBoxCanMove(boxes[i])) { return false; } } return true; }; /** All shapes shares the same method, use prototype for memory optimized */ ShapeL.prototype = ShapeLR.prototype = ShapeO.prototype = ShapeI.prototype = ShapeT.prototype = ShapeZ.prototype = ShapeZR.prototype = { init: function(result) { this.color = COLORS[result]; this.state = 0; this.allBoxes = {}; this.y = 0; }, // Get boxes matrix which composite the shape getBoxes: function(state) { var boxes = this.allBoxes[state] || []; if (boxes.length) { return boxes; } var matrix = this.matrix(state); for (var i = 0; i < matrix.length; i++) { var row = matrix[i]; for (var j = 0; j < row.length; j++) { if (row[j] === 1) { boxes.push({ x: j, y: i }); } } } this.allBoxes[state] = boxes; return boxes; }, //Get matrix for specified state matrix: function(state) { var st = state !== undefined ? state : this.state; return this.states[st]; }, canMoveTo: function(shape, matrix) { if(!doesShapeOverlap(shape, matrix)) return true; return false; }, // 0 - no, 1 - up,left, 2 - up,right, 3 - down,left, 4 - down, right kickShape: function(matrix, rotationDirection) { let clone = utils.deepClone(this); for(var j = 0; j < 4; j++) { if(this.state == j) { clone.state = this.nextState(rotationDirection); var i = 0; if(rotationDirection == 1) i = 2; for(; i < 5*4; i+=4) { var shiftX = this.rotationPoints[j][i]; var shiftY = this.rotationPoints[j][i+1]; if(!isNaN(shiftY) && !isNaN(shiftX)) { clone.x = this.x + shiftX; clone.y = this.y - shiftY; if(this.canMoveTo(clone, matrix) == true) { this.state = clone.state; this.x = clone.x; this.y = clone.y; return; } } } } } }, //Rotate shape rotate: function(matrix) { this.kickShape(matrix, -1); }, //Rotate shape clockwise rotateClockwise: function(matrix) { this.kickShape(matrix, 1); }, //Caculate the max column of the shape getColumnCount: function() { var mtx = this.matrix(); var colCount = 0; for (var i = 0; i < mtx.length; i++) { colCount = Math.max(colCount, mtx[i].length); } return colCount; }, //Caculate the max row of the shape getRowCount: function() { return this.matrix().length; }, //Get the right pos of the shape getRight: function() { var boxes = this.getBoxes(this.state); var right = 0; for (var i in boxes) { right = Math.max(boxes[i].x, right); } return this.x + right; }, //Return the next state of the shape nextState: function(direction) { if(direction == 0) return this.state; var rotate = this.state; rotate += direction; if(rotate < 0) return this.states.length - 1; return rotate % this.states.length; }, //Check if the shape can move down canDown: function(matrix) { return isShapeCanMove(this, matrix, 'down'); }, //Move the shape down goDown: function(matrix) { if (isShapeCanMove(this, matrix, 'down')) { this.y += 1; } }, //Move the shape up goUp: function(matrix) { if (isShapeCanMove(this, matrix, 'up')) { this.y -= 1; } }, //Move the shape to the Bottommost bottomAt: function(matrix) { var save = this.y; var ret; while (isShapeCanMove(this, matrix, 'down')) { this.y += 1; } ret = this.y; this.y = save; return ret; }, //Move the shape to the Bottommost goBottom: function(matrix) { while (isShapeCanMove(this, matrix, 'down')) { this.y += 1; } }, //Move the shape to the left goLeft: function(matrix) { if (isShapeCanMove(this, matrix, 'left')) { new Audio('./dist/sound/Click.ogg').play(); this.x -= 1; } }, //Move the shape to the right goRight: function(matrix) { if (isShapeCanMove(this, matrix, 'right')) { new Audio('./dist/sound/Click.ogg').play(); this.x += 1; } }, //Copy the shape data to the game data copyTo: function(matrix) { var smatrix = this.matrix(); for (var i = 0; i < smatrix.length; i++) { var row = smatrix[i]; for (var j = 0; j < row.length; j++) { if (row[j] === 1) { var x = this.x + j; var y = this.y + i; if (x >= 0 && x < matrix[0].length && y >= 0 && y < matrix.length) { matrix[y][x] = this.color; } } } } }, // check if piece is same on matrix isSameSRS: function(shape) { return isBoxesSame(this, shape) }, resetOrigin: function() { this.y = this.originY + 1; }, nType: function() { switch (this.flag) { case 'L': // shape = new ShapeL(); return 0; break; case 'O': //shape = new ShapeO(); return 1; break; case 'Z': // shape = new ShapeZ(); return 2; break; case 'T': // shape = new ShapeT(); return 3; break; case 'LR': // shape = new ShapeLR(); return 4; break; case 'ZR': // shape = new ShapeZR(); return 5; break; case 'I': // shape = new ShapeI(); return 6; break; } } } /** Create a random shape for game */ function getRandomInt(max) { return Math.floor(Math.random() * Math.floor(max)); } // Handles randomly generating and returning a tetromino var RandomGenerator = { returnBag: [], getTetrimino() { if(this.returnBag.length < 7) this.returnBag.push.apply(this.returnBag, this.generateNewBag()); return parseInt(this.returnBag.shift()); }, onlyUnique(value, index, self) { return self.indexOf(value) === index; }, generateNewBag() { var minoes = ['0','1','2','3','4','5','6']; var newBag = []; var bagLength = 7; while(newBag.length < bagLength) { mino = getRandomInt(bagLength); newBag.push(minoes[mino]); newBag = newBag.filter(this.onlyUnique); } return newBag; }, reset() { if(this.returnBag != undefined) this.returnBag.splice(0, returnBag.length); } }; function randomShape() { var result = RandomGenerator.getTetrimino(); var shape; switch (result) { case 0: shape = new ShapeL(); break; case 1: shape = new ShapeO(); break; case 2: shape = new ShapeZ(); break; case 3: shape = new ShapeT(); break; case 4: shape = new ShapeLR(); break; case 5: shape = new ShapeZR(); break; case 6: shape = new ShapeI(); break; } shape.init(result); return shape; } function getShape(shapei) { var result = shapei var shape; switch (result) { case 0: shape = new ShapeL(); break; case 1: shape = new ShapeO(); break; case 2: shape = new ShapeZ(); break; case 3: shape = new ShapeT(); break; case 4: shape = new ShapeLR(); break; case 5: shape = new ShapeZR(); break; case 6: shape = new ShapeI(); break; } shape.init(result); return shape; } module.exports.resetMinoRNG = RandomGenerator.reset; module.exports.randomShape = randomShape; module.exports.getShape = getShape; // export randomShape; // export getShape; },{"./consts.js":2,"./utils.js":8}],8:[function(require,module,exports){ var exports = module.exports = {}; var setCookie = function(cname, cvalue, exdays) { var d = new Date(); d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); var expires = "expires="+d.toUTCString(); document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; }; var getCookie = function(cname) { var name = cname + "="; var ca = document.cookie.split(';'); for(var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') { c = c.substring(1); } if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); } } return ""; }; var $ = function(id){ return document.getElementById(id); }; //if object is plain object var _isPlainObject = function(obj) { if (typeof obj !== 'object') { return false; } if (obj.constructor && !hasOwnProperty.call(obj.constructor.prototype, 'isPrototypeOf')) { return false; } // If the function hasn't returned already, we're confident that // |obj| is a plain object, created by {} or constructed with new Object return true; }; // Deeper clone var deepClone = function(copyObject) { return Object.assign(Object.create(Object.getPrototypeOf(copyObject)), copyObject); }; // this method source code is from jquery 2.0.x // merge object's value and return var extend = function() { var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = true; // Handle a deep copy situation if (typeof target === 'boolean') { deep = target; // skip the boolean and the target target = arguments[i] || {}; i++; } // Handle case when target is a string or something (possible in deep copy) if (typeof target !== 'object' && typeof obj !== 'function') { target = {}; } if (i === length) { target = this; i--; } for (; i < length; i++) { // Only deal with non-null/undefined values if ((options = arguments[i]) != null) { // Extend the base object for (name in options) { src = target[name]; copy = options[name]; // Prevent never-ending loop if (target === copy) { continue; } // Recurse if we're merging plain objects or arrays if (deep && copy && (_isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { if (copyIsArray) { copyIsArray = false; clone = src && Array.isArray(src) ? src : []; } else { clone = src && _isPlainObject(src) ? src : {}; } // Never move original objects, clone them //console.log('abc'); target[name] = extend(deep, clone, copy); // Don't bring in undefined values } else if (copy !== undefined) { target[name] = copy; } } } } // Return the modified object return target; }; var proxy = function(fn,context){ var args = [].slice.call( arguments, 2 ); proxy = function() { return fn.apply( context || this, args.concat( [].slice.call( arguments ) ) ); }; return proxy; }; var aniFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; window.requestAnimationFrame = aniFrame; exports.$ = $; exports.extend = extend; exports.proxy = proxy; exports.deepClone = deepClone; exports.setCookie = setCookie; exports.getCookie = getCookie; // export $; // export extend; // export proxy; },{}],9:[function(require,module,exports){ /** All dom definitions and actions */ var utils = require('./utils.js'); var consts = require('./consts.js'); // import * as utils from './utils.js'; // import * as consts from './const.js'; var $ = utils.$; //doms var scene = $('scene'); var side = $('side'); var info = $('info'); var preview = $('preview'); var hold = $('hold'); var leftSide = $('leftSide'); var level = $('level'); var score = $('score'); var lines = $('lines'); var rewardInfo = $('rewardInfo'); var reward = $('reward'); var gameOver = $('gameOver'); var btnRestart = $('restart'); var finalScore = $('finalScore'); //defaults var SIDE_WIDTH = consts.SIDE_WIDTH; /** Caculate the game container size */ var getContainerSize = function(maxW,maxH){ var dw = document.documentElement.clientWidth; var dh = document.documentElement.clientHeight; var size = {}; if (dw>dh){ size.height = Math.min(maxH,dh); size.width = Math.min(size.height /*/ 2*/ + SIDE_WIDTH,maxW); }else{ size.width = Math.min(maxW,dw); size.height = Math.min(maxH,dh); } return size; }; /** Layout game elements */ var layoutView = function(container,maxW,maxH){ var size = getContainerSize(maxW,maxH); var st = container.style; st.height = size.height + 'px'; st.width = size.width + 'px'; st.marginTop = (-(size.height/2)) + 'px'; st.marginLeft = (-(size.width/2)) + 'px'; //layout scene //hold.width = 80; //hold.height = 380; scene.height = size.height; scene.width = scene.height / 2; var sideW = size.width - scene.width + leftSide.width; side.style.width = sideW + 'px'; if (sideW < SIDE_WIDTH ){ info.style.width = side.style.width; } side.style.height = 500 + 'px'; hold.style.top = 10+'px';//preview.top + 10px pad preview.width = 80; preview.height = 380; hold.width = 80; hold.height = 380; gameOver.style.width = scene.width +'px'; } /** Main tetris game view */ var tetrisView = { init:function(id, maxW,maxH){ this.container = $(id); this.scene = scene; this.preview = preview; this.hold = hold; this.btnRestart = btnRestart; layoutView(this.container,maxW,maxH); this.scene.focus(); rewardInfo.addEventListener('animationEnd',function(e){ rewardInfo.className = 'invisible'; }); }, // Update the score setScore:function(scoreNumber){ score.innerHTML = scoreNumber; }, // Update the finnal score setFinalScore:function(scoreNumber){ finalScore.innerHTML = scoreNumber; }, // Update the level setLevel:function(levelNumber){ level.innerHTML = levelNumber; }, // Update the extra reward score setLines:function(setlines){ //lines.innerHTML = setlines; }, setReward:function(rewardScore){ if (rewardScore>0){ reward.innerHTML = rewardScore; rewardInfo.className = 'fadeOutUp animated'; }else{ rewardInfo.className = 'invisible'; } }, // Set game over view setGameOver:function(isGameOver){ gameOver.style.display = isGameOver?'block':'none'; } }; module.exports = tetrisView; // export tetrisView; },{"./consts.js":2,"./utils.js":8}]},{},[5]);