diff --git a/index.html b/index.html index 8f632ee..5cca42e 100755 --- a/index.html +++ b/index.html @@ -51,7 +51,7 @@

Hold

Piece 块 - 00:00.00 + @@ -66,7 +66,7 @@

Hold

diff --git a/piece.js b/piece.js index 4e127d2..b0d93fd 100644 --- a/piece.js +++ b/piece.js @@ -7,6 +7,10 @@ function Piece() { this.gravity = gravityUnit; this.lockDelay = 0; this.lockDelayLimit = 30; + this.are = 0; + this.areLimit = 0; + this.irsDir = 0; + this.ihs = false; this.shiftDelay = 0; this.shiftDir; this.shiftReleased; @@ -21,9 +25,14 @@ function Piece() { */ Piece.prototype.new = function(index) { // TODO if no arguments, get next grabbag piece + console.log("new irs"+this.irsDir+", ihs"+this.ihs); this.pos = RotSys[settings.RotSys].initinfo[index][2]; + this.x = ~~((stack.width - 4) / 2) + RotSys[settings.RotSys].initinfo[index][0]; + this.y = stack.hiddenHeight - 2 + RotSys[settings.RotSys].initinfo[index][1]; + this.index = index; this.tetro = []; this.held = false; + this.ihs = false; this.finesse = 0; this.dirty = true; this.dead = false; @@ -32,11 +41,28 @@ Piece.prototype.new = function(index) { // TODO Do this better. Make clone object func maybe. //for property in pieces, this.prop = piece.prop - this.tetro = pieces[index].tetro[this.pos]; - this.x = ~~((stack.width - 4) / 2) + RotSys[settings.RotSys].initinfo[index][0]; - this.y = stack.hiddenHeight - 2 + RotSys[settings.RotSys].initinfo[index][1]; - this.index = index; - + if (this.irsDir !== 0) { + var curPos = this.pos; + var newPos = (this.pos+this.irsDir).mod(4); + var offsetX = + RotSys[settings.RotSys].offset[this.index][newPos][0] - + RotSys[settings.RotSys].offset[this.index][curPos][0]; + var offsetY = + RotSys[settings.RotSys].offset[this.index][newPos][1] - + RotSys[settings.RotSys].offset[this.index][curPos][1]; + this.tetro = pieces[index].tetro[newPos]; + if (!this.moveValid(offsetX, offsetY, this.tetro)) { + this.tetro = pieces[index].tetro[curPos]; + } else { + this.x += offsetX; + this.y += offsetY; + this.pos = newPos; + } + this.irsDir = 0; + } else { + this.tetro = pieces[index].tetro[this.pos]; + } + // TODO ---------------- snip //TODO Do this better. (make grabbag object) @@ -46,8 +72,10 @@ Piece.prototype.new = function(index) { this.lockDelayLimit = setting['Lock Delay'][settings['Lock Delay']]; if (settings.Gravity !== 0) { + this.areLimit = 0; this.gravity = gravityArr[settings.Gravity - 1]; } else if (gametype === 1) { //Marathon + this.areLimit = 0; if (level < 20) { this.gravity = [ 1/60, 1/30, 1/25, 1/20, 1/15, 1/12, 1/10, 1/8, 1/6, 1/6, @@ -58,13 +86,29 @@ Piece.prototype.new = function(index) { this.gravity = 20; this.lockDelayLimit = ~~(30 * Math.pow(0.93, (Math.pow(level-20, 0.8)))); // magic! } + } else if (gametype === 6) { //Death + this.gravity = 20; + if (level < 20) { + this.lockDelayLimit = [ + 30, 25, 22, 20, 20, 18, 17, 17, 15, 15, + 13, 13, 13, 13, 13, 12, 12, 12, 11, 11 + ][level]; + this.areLimit = [ + 18, 18, 18, 15, 15, 12, 12, 12, 12, 12, + 12, 12, 10, 10, 10, 8, 8, 8, 8, 8 + ][level]; + } else { + this.lockDelayLimit = 11; + this.areLimit = 6; + } } else { + this.areLimit = 0; this.gravity = gravityUnit; } // Check for blockout. if (!this.moveValid(0, 0, this.tetro)) { - this.dead = true; + //this.dead = true; //show it? gameState = 9; msg.innerHTML = 'BLOCK OUT!'; menu(3); @@ -332,7 +376,14 @@ Piece.prototype.update = function() { stack.addPiece(this.tetro); sound.playse("lock"); this.dead = true; - this.new(preview.next()); // consider move to main update + this.dirty = true; + this.held = false; + if (this.areLimit === 0) { + this.new(preview.next()); // consider move to main update + } else { + gameState = 4; + this.are = 0; + } /* farter */ } else { this.lockDelay++; @@ -340,7 +391,9 @@ Piece.prototype.update = function() { } } Piece.prototype.draw = function() { + clear(activeCtx); if (!this.dead) { + this.drawGhost(); if (settings.Ghost !== 3) { var a = void 0; if (landed) { @@ -352,17 +405,15 @@ Piece.prototype.draw = function() { } } Piece.prototype.drawGhost = function() { - if (!this.dead) { - activeCtx.globalAlpha = 0.4; - if (settings.Ghost === 0 && !landed) { - draw(this.tetro, this.x, - Math.floor(this.y + this.getDrop(2147483647)) - stack.hiddenHeight, activeCtx, 0); - } else if (settings.Ghost === 1 && !landed) { - draw(this.tetro, this.x, - Math.floor(this.y + this.getDrop(2147483647)) - stack.hiddenHeight, activeCtx); - } - activeCtx.globalAlpha = 1; + activeCtx.globalAlpha = 0.4; + if (settings.Ghost === 0 && !landed) { + draw(this.tetro, this.x, + Math.floor(this.y + this.getDrop(2147483647)) - stack.hiddenHeight, activeCtx, 0); + } else if (settings.Ghost === 1 && !landed) { + draw(this.tetro, this.x, + Math.floor(this.y + this.getDrop(2147483647)) - stack.hiddenHeight, activeCtx); } + activeCtx.globalAlpha = 1; } var piece = new Piece(); diff --git a/stack.js b/stack.js index 4f09a84..09ffc60 100644 --- a/stack.js +++ b/stack.js @@ -131,7 +131,7 @@ Stack.prototype.addPiece = function(tetro) { combo = 0; } lines += lineClear; - if (gametype === 1) + if (gametype === 1 || gametype === 6) level = ~~(lines / 10); score = score.add(scoreAdd.mul(bigInt(16).pow(allclear))); diff --git a/style.css b/style.css index 7552358..5b9b403 100755 --- a/style.css +++ b/style.css @@ -148,6 +148,7 @@ nav li { #stats { display: block; position: absolute; + padding: 0; } #stats tbody { display: block; @@ -155,7 +156,6 @@ nav li { #stats tr { display: block; width: 100%; - padding: 0 0.5rem; } #stats th { text-transform: uppercase; @@ -173,10 +173,12 @@ nav li { } #time { text-align: center; - font-weight: 900; - font-size: 1.125em; display: block; } +#time > canvas { + width: 100%; + height: 1.125em; +} #score { text-align: center; font-weight: 900; diff --git a/tetris.js b/tetris.js index 89bd2a3..2a8ab02 100644 --- a/tetris.js +++ b/tetris.js @@ -47,6 +47,8 @@ var activeCanvas = document.getElementById('active'); var previewCanvas = document.getElementById('preview'); var spriteCanvas = document.getElementById('sprite'); +var timeCanvas = document.getElementById('time').childNodes[0]; + var holdCtx = holdCanvas.getContext('2d'); var bgStackCtx = bgStackCanvas.getContext('2d'); var stackCtx = stackCanvas.getContext('2d'); @@ -54,6 +56,7 @@ var activeCtx = activeCanvas.getContext('2d'); var previewCtx = previewCanvas.getContext('2d'); var spriteCtx = spriteCanvas.getContext('2d'); +var timeCtx = timeCanvas.getContext('2d'); var touchLeft = document.getElementById('touchLeft'); var touchRight = document.getElementById('touchRight'); @@ -79,7 +82,7 @@ touchRotRight.bindsMemberName = "rotRight"; touchRotLeft.bindsMemberName = "rotLeft"; touchRot180.bindsMemberName = "rot180"; -var nLayouts = 7, currLayout = -1 /* auto */; +var nLayouts = 8, currLayout = -1 /* auto */; /** * Piece data @@ -505,6 +508,8 @@ var arrStages = [ ]; var frame; var frameLastRise; +var frameLastHarddropDown; +var frameSkipped; /** *Pausing variables @@ -547,6 +552,7 @@ var statsFinesse; var piecesSet; var startTime; var scoreTime; +var scoreStartTime; var digLines = []; // Keys @@ -640,11 +646,19 @@ function resize() { stats.style.fontSize = ~~(stackCanvas.width / 11) + 'px'; document.documentElement.style.fontSize = ~~(stackCanvas.width / 16) + 'px'; - stats.style.width = a.style.width; for (var i = 0, len = h3.length; i < len; i++) { h3[i].style.lineHeight = (cellSize * 2) + 'px'; h3[i].style.fontSize = stats.style.fontSize; } + stats.style.width = h3[0].clientWidth + 'px'; + + timeCanvas.width = h3[0].clientWidth; + timeCanvas.height = timeCanvas.clientHeight || timeCanvas.offsetHeight || timeCanvas.getBoundingClientRect().height; + timeCtx.fillStyle = "#fff"; + timeCtx.font = 'bold 1.125em "Trebuchet MS"'; + timeCtx.textAlign = "center"; + timeCtx.textBaseline = "middle"; + // position of touch buttons { @@ -652,7 +666,7 @@ function resize() { var dpiY = 96; var winW = window.innerWidth / dpiX; var winH = window.innerHeight / dpiY; - var buttonH = 0.7, buttonW = 1, fontSize=0.55, unit="in"; + var buttonH = 0.7, buttonW = 1, fontSize=0.55, margin=0.1, unit="in"; var setPos = function(elem, posX, posY, sizeW, sizeH, alignX, alignY, offsetX, offsetY, clientW, clientH) @@ -660,8 +674,8 @@ function resize() { elem.style.width = "" + sizeW + unit; elem.style.height = "" + sizeH + unit; // border ignored, for now - elem.style.left = "" + (offsetX + alignX * 0.5 * (clientW - sizeW) + posX * sizeW - ( (alignX-1) * 0.05)) + unit; - elem.style.top = "" + (offsetY + alignY * 0.5 * (clientH - sizeH) + posY * sizeH - ( (alignY-1) * 0.05)) + unit; + elem.style.left = "" + (offsetX + alignX * 0.5 * (clientW - sizeW) + posX * sizeW - ( (alignX-1) * margin/2 )) + unit; + elem.style.top = "" + (offsetY + alignY * 0.5 * (clientH - sizeH) + posY * sizeH - ( (alignY-1) * margin/2 )) + unit; elem.style.display = "block"; elem.style.fontSize = "" + fontSize + unit; } @@ -696,14 +710,25 @@ function resize() { }, "JOY": function() { - setPos(touchRotLeft, -0.5, 1, buttonW, buttonH, 2, 1, 0, 0, winW, winH); - setPos(touchRot180, -0.5, -1, buttonW, buttonH, 2, 1, 0, 0, winW, winH); - setPos(touchRotRight, 0, 0, buttonW, buttonH, 2, 1, 0, 0, winW, winH); - setPos(touchHold, -1, 0, buttonW, buttonH, 2, 1, 0, 0, winW, winH); - setPos(touchRight, 1, 0, buttonW, buttonH, 0, 1, 0, 0, winW, winH); - setPos(touchLeft, 0, 0, buttonW, buttonH, 0, 1, 0, 0, winW, winH); - setPos(touchDown, 0.5, 1, buttonW, buttonH, 0, 1, 0, 0, winW, winH); - setPos(touchDrop, 0.5, -1, buttonW, buttonH, 0, 1, 0, 0, winW, winH); + var oy/*offset Y by block*/,ay/*align Y*/; + if (winH-winW>buttonH*1.5) { + oy=-1; ay=2; + } else { + oy=0; ay=1; + } + /* single finger */ + buttonW = 0.8; + if ((winW-0.1)/4fsbl)?fsbl:skipR; + skipL = skipL/fsbl*timeCanvas.width; + skipR = skipR/fsbl*timeCanvas.width; + + timeCtx.clearRect(0, 0, timeCanvas.width, timeCanvas.height); + timeCtx.fillText(displayTime, timeCanvas.width/2, timeCanvas.height/2); + timeCtx.fillRect(skipL,timeCanvas.height-0.2,skipR,timeCanvas.height); } /** @@ -1386,19 +1427,6 @@ function touch(e) preventDefault: function(){} }); for (var i = 0, l = e.touches.length; i < l; i++) { - /* - //fails when dragged - if (e.touches[i].target) { - if (e.touches[i].target.hasOwnProperty("bindsMemberName")) { - keyUpDown({ - type: "keydown", - keyCode: binds[e.touches[i].target.bindsMemberName], - preventDefault: function(){} - }); - e.preventDefault(); - } - } - */ var tX = e.touches[i].pageX, tY = e.touches[i].pageY; for (var j in touchButtons) { var oRef = touchButtons[j]; @@ -1469,6 +1497,7 @@ function update() { //piece.finesse++; } if (!(lastKeys & flags.hardDrop) && flags.hardDrop & keysDown) { + frameLastHarddropDown = frame; piece.hardDrop(); } @@ -1476,40 +1505,41 @@ function update() { if(gametype === 3) { //Dig var fromLastRise = frame-frameLastRise; + var fromLastHD = (flags.hardDrop & keysDown)?(frame-frameLastHarddropDown):0; + var arrRow = [8,8,8,8,8,8,8,8,8,8]; - { - var curStage = 0, objCurStage; - while(curStage= objCurStage.delay || (fromLastHD >= 20 && fromLastRise >= 15)) { + //IJLOSTZ + var arrRainbow=[ + 2,-1,1,5,4,3,7,6,-1,8, + 8,8,8,6,6,2,1,5,8,-1, + 7,7,-1,8,8]; + var idxRainbow,flagAll,colorUsed; + idxRainbow = ~~(objCurStage.begin/100); + flagAll = (~~(objCurStage.begin/50))%2; + if(idxRainbow >= arrRainbow.length) { + idxRainbow = arrRainbow.length - 1; } - curStage--; - objCurStage = arrStages[curStage]; - if(fromLastRise >= objCurStage.delay) { - //IJLOSTZ - var arrRainbow=[ - 2,-1,1,5,4,3,7,6,-1,8, - 8,8,8,6,6,2,1,5,8,-1, - 7,7,-1,8,8]; - var idxRainbow,flagAll,colorUsed; - idxRainbow = ~~(objCurStage.begin/100); - flagAll = (~~(objCurStage.begin/50))%2; - if(idxRainbow >= arrRainbow.length) { - idxRainbow = arrRainbow.length - 1; - } - colorUsed = arrRainbow[idxRainbow]; - for(var x=0; x=300) { // exp + gameState = 1; + msg.innerHTML = 'GREAT!'; + piece.dead = true; + menu(3); + sound.playse("endingstart"); + } } /* farter */ + scoreTime = Date.now() - scoreStartTime - pauseTime; statistics(); if (lastKeys !== keysDown) { @@ -1617,90 +1656,129 @@ function gameLoop() { if (!paused && gameState !== 3) { requestAnimFrame(gameLoop); - //setTimeout(gameLoop, 33); - - //TODO check to see how pause works in replays. - frame++; - - if (gameState === 0) { - // Playing - - update(); + var repeat = ~~((Date.now() - startTime - pauseTime)/1000*60) - frame; + if (repeat>1) { + frameSkipped += repeat-1; + } - // TODO improve this with 'dirty' flags. - /* farter */ // as you draw for lock delay brightness gradient... give this up.. + for (var repf=0;repf= stack.hiddenHeight) { - /** - * Fade to grey animation played when player loses. - */ - if (toGreyRow === stack.height - 1) - clear(activeCtx); - if (frame % 2) { - for (var x = 0; x < stack.width; x++) { - /* farter */ //WTF gamestate-1 - if (stack.grid[x][toGreyRow]) - stack.grid[x][toGreyRow] = - (gameState === 9 ? 8 : 0); + if (piece.x !== lastX || + Math.floor(piece.y) !== lastY || + piece.pos !== lastPos || + piece.lockDelay !== lastLockDelay || + piece.dirty) { + piece.draw(); + } + lastX = piece.x; + lastY = Math.floor(piece.y); + lastPos = piece.pos; + lastLockDelay = piece.lockDelay; + piece.dirty = false; + + } else if (gameState === 2 || gameState === 4) { + + if (lastKeys !== keysDown && !watchingReplay) { + replay.keys[frame] = keysDown; + } else if (frame in replay.keys) { + keysDown = replay.keys[frame]; + } + // DAS Preload + if (keysDown & flags.moveLeft) { + piece.shiftDelay = settings.DAS; + piece.shiftReleased = false; + piece.shiftDir = -1; + } else if (keysDown & flags.moveRight) { + piece.shiftDelay = settings.DAS; + piece.shiftReleased = false; + piece.shiftDir = 1; + } else { + piece.shiftDelay = 0; + piece.shiftReleased = true; + piece.shiftDir = 0; + } + if (flags.rotLeft & keysDown && !(lastKeys & flags.rotLeft)) { + piece.irsDir = -1; + piece.finesse++; + console.log("IRS"); + } else if (flags.rotRight & keysDown && !(lastKeys & flags.rotRight)) { + piece.irsDir = 1; + piece.finesse++; + console.log("IRS"); + } else if (flags.rot180 & keysDown && !(lastKeys & flags.rot180)) { + piece.irsDir = 2; + piece.finesse++; + console.log("IRS"); + } + if (!(lastKeys & flags.holdPiece) && flags.holdPiece & keysDown) { + piece.ihs = true; + console.log("IHS"); + } + if (lastKeys !== keysDown) { + lastKeys = keysDown; + } + if (gameState === 2) { + // Count Down + if (frame < 50) { + if (msg.innerHTML !== 'READY') msg.innerHTML = 'READY'; + } else if (frame < 100) { + if (msg.innerHTML !== 'GO!') msg.innerHTML = 'GO!'; + } else { + msg.innerHTML = ''; + scoreStartTime = Date.now(); + scoreTime = 0; } - stack.draw(); - toGreyRow--; + } else { + piece.are++; + scoreTime = Date.now() - scoreStartTime - pauseTime; + } + if ( + (gameState === 2 && frame >= 100) || + (gameState === 4 && piece.are >= piece.areLimit) + ) { + gameState = 0; + if (piece.ihs) { + piece.index = preview.next(); + piece.hold(); + } else { + piece.new(preview.next()); + } + piece.draw(); + } + + statistics(); + + } else if (gameState === 9 || gameState === 1) { + if (toGreyRow >= stack.hiddenHeight) { + /** + * Fade to grey animation played when player loses. + */ + if (frame % 2) { + for (var x = 0; x < stack.width; x++) { + /* farter */ //WTF gamestate-1 + if (stack.grid[x][toGreyRow]) + stack.grid[x][toGreyRow] = + (gameState === 9 ? 8 : 0); + } + stack.draw(); + toGreyRow--; + } + } else { + //clear(activeCtx); + //piece.dead = true; + trysubmitscore(); + gameState = 3; } - } else { - trysubmitscore(); - gameState = 3; } } }