|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function ControlGroup(blocks, shape, isLegalCallback) { |
|
var i, |
|
newX, newY, |
|
shapeConf; |
|
|
|
|
|
shapeConf = SHAPES[shape]; |
|
this.pos = shapeConf.pos; |
|
this.spin = shapeConf.spin; |
|
this.bottomed = false; |
|
|
|
this.blocks = blocks; |
|
this.baseX = shapeConf.startX; |
|
this.baseY = shapeConf.startY; |
|
|
|
this.shape = shape; |
|
this.kickOffsets = WALL_KICK_OFFSETS[shapeConf.kickType]; |
|
this.dir = 0; |
|
|
|
this.isIllegalStart = false; |
|
|
|
this.isLegalCallback = isLegalCallback || function() {return true;}; |
|
|
|
this.lastWasSpin = false; |
|
|
|
for (i = 0; i < blocks.length; i += 1) { |
|
newX = this.baseX + this.pos[i].x; |
|
newY = this.baseY + this.pos[i].y; |
|
|
|
if (!this.isLegalCallback(newX, newY)) { |
|
this.isIllegalStart = true; |
|
} |
|
this.blocks[i].setPosition(newX, newY); |
|
} |
|
|
|
this.updateBottomedState(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.isLegalPosition = function (x, y) { |
|
var i, |
|
blocks = this.blocks; |
|
|
|
|
|
for (i = 0; i < 4; i += 1) { |
|
if (blocks[i].isPosition(x, y)) { |
|
return true; |
|
} |
|
} |
|
|
|
|
|
return this.isLegalCallback(x, y); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.shift = function(left) { |
|
var dx = (left ? -1 : 1), |
|
i; |
|
|
|
for (i = 0; i < 4; i += 1) { |
|
if (!this.isLegalPosition(this.blocks[i].getX()+dx, this.blocks[i].getY())) { |
|
return false; |
|
} |
|
} |
|
|
|
this.lastWasSpin = false; |
|
this.baseX += dx; |
|
|
|
for (i = 0; i < this.blocks.length; i += 1) { |
|
this.blocks[i].moveBlock(dx, 0); |
|
} |
|
this.updateBottomedState(); |
|
|
|
return true; |
|
}; |
|
|
|
ControlGroup.prototype.updateBottomedState = function() { |
|
var i; |
|
|
|
for (i = 0; i < this.blocks.length; i += 1) { |
|
if (!this.isLegalPosition(this.blocks[i].getX(), this.blocks[i].getY() + 1)) { |
|
this.bottomed = true; |
|
return; |
|
} |
|
} |
|
|
|
this.bottomed = false; |
|
}; |
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.drop = function() { |
|
var i; |
|
|
|
|
|
if (this.bottomed) { |
|
return; |
|
} |
|
|
|
this.lastWasSpin = false; |
|
this.baseY += 1; |
|
|
|
for (i = 0; i < this.blocks.length; i += 1) { |
|
this.blocks[i].moveBlock(0, 1); |
|
} |
|
this.updateBottomedState(); |
|
}; |
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.isBottomed = function() { |
|
return this.bottomed; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.turn = function(cw) { |
|
var kick, |
|
newPos = null, |
|
direction = cw ? 'cw' : 'ccw', |
|
availableKicks = this.kickOffsets[this.dir][direction], |
|
i; |
|
|
|
|
|
for (i = 0; i < availableKicks.length; i += 1) { |
|
kick = availableKicks[i]; |
|
newPos = this.tryTurn(cw, kick); |
|
if (newPos) { |
|
break; |
|
} |
|
} |
|
|
|
|
|
if (!newPos) { |
|
return false; |
|
} |
|
|
|
this.lastWasSpin = true; |
|
|
|
|
|
for (i = 0; i < 4; i += 1) { |
|
this.blocks[i].setPosition(newPos[i].x, newPos[i].y); |
|
} |
|
this.baseX += kick.x; |
|
this.baseY += kick.y; |
|
|
|
|
|
if (cw) { |
|
this.dir += 1; |
|
if (this.dir === 4) { |
|
this.dir = 0; |
|
} |
|
} else { |
|
this.dir -= 1; |
|
if (this.dir === -1) { |
|
this.dir = 3; |
|
} |
|
} |
|
|
|
this.updateBottomedState(); |
|
|
|
return true; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.tryTurn = function (cw, kick) { |
|
var newX, newY, |
|
oldX, oldY, |
|
i, |
|
newPos = [], |
|
curPos; |
|
|
|
if (this.spin === 'block') { |
|
for (i = 0; i < this.blocks.length; i += 1) { |
|
newX = (cw ? -1 : 1) * (this.blocks[i].blockY - this.baseY) + this.baseX + kick.x; |
|
newY = (cw ? 1 : -1) * (this.blocks[i].blockX - this.baseX) + this.baseY + kick.y; |
|
|
|
newPos[i] = {x: newX, y: newY}; |
|
} |
|
} else { |
|
|
|
for (i = 0; i < this.blocks.length; i += 1) { |
|
oldX = this.blocks[i].blockX - this.baseX; |
|
oldY = this.blocks[i].blockY - this.baseY; |
|
|
|
if (oldX >= 0) { oldX += 1; } |
|
if (oldY >= 0) { oldY += 1; } |
|
|
|
newX = (cw ? -1 : 1) * oldY; |
|
newY = (cw ? 1 : -1) * oldX; |
|
|
|
if (newX > 0) { newX -= 1; } |
|
if (newY > 0) { newY -= 1; } |
|
|
|
newPos[i] = {x: newX + this.baseX + kick.x, y: newY + this.baseY + kick.y}; |
|
} |
|
} |
|
|
|
|
|
|
|
for (i = 0; i < 4; i += 1) { |
|
curPos = newPos[i]; |
|
if (!this.isLegalPosition(curPos.x, curPos.y)) { |
|
return null; |
|
} |
|
} |
|
|
|
return newPos; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.getFallPositions = function () { |
|
var res = [], |
|
dist = 0, |
|
i, |
|
curBlock, |
|
notDone = true; |
|
|
|
while (notDone) { |
|
dist += 1; |
|
|
|
|
|
for (i = 0; i < 4 && notDone; i += 1) { |
|
curBlock = this.blocks[i]; |
|
|
|
if (!this.isLegalPosition(curBlock.getX(), curBlock.getY() + dist)) { |
|
|
|
dist -= 1; |
|
notDone = false; |
|
} |
|
} |
|
} |
|
|
|
|
|
for (i = 0; i < 4; i += 1) { |
|
curBlock = this.blocks[i]; |
|
res.push({x: curBlock.getX(), y: curBlock.getY() + dist}); |
|
} |
|
|
|
return {dist: dist, positions: res}; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.fall = function() { |
|
var fall = this.getFallPositions(), |
|
positions = fall.positions, |
|
dist = fall.dist, |
|
i, curPos; |
|
|
|
if (dist !== 0) { |
|
this.lastWasSpin = false; |
|
} |
|
|
|
|
|
for (i = 0; i < 4; i += 1) { |
|
curPos = positions[i]; |
|
this.blocks[i].setPosition(curPos.x, curPos.y); |
|
} |
|
|
|
this.bottomed = true; |
|
return dist; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.configurePreviewBlocks = function(previews) { |
|
var positions = this.getFallPositions().positions, |
|
i; |
|
|
|
for (i = 0; i < 4; i += 1) { |
|
previews[i].setPosition(positions[i].x, positions[i].y); |
|
} |
|
}; |
|
|
|
ControlGroup.prototype.getShape = function () { |
|
return this.shape; |
|
}; |
|
|
|
ControlGroup.prototype.getBlocks = function () { |
|
return this.blocks; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
ControlGroup.prototype.getTSpin = function() { |
|
var i, |
|
testPoints = [{x:-1,y:-1},{x:1,y:-1},{x:1,y:1},{x:-1,y:1}], |
|
count = 0, |
|
mini = false, |
|
curPoint; |
|
|
|
if (!this.lastWasSpin) { |
|
return null; |
|
} |
|
|
|
|
|
if (this.shape !== 't') { |
|
return null; |
|
} |
|
|
|
|
|
if (this.dir === 0) { |
|
testPoints[0].miniCheck = true; |
|
testPoints[1].miniCheck = true; |
|
} else if (this.dir === 1) { |
|
testPoints[1].miniCheck = true; |
|
testPoints[2].miniCheck = true; |
|
} else if (this.dir === 2) { |
|
testPoints[2].miniCheck = true; |
|
testPoints[3].miniCheck = true; |
|
} else if (this.dir === 3) { |
|
testPoints[3].miniCheck = true; |
|
testPoints[0].miniCheck = true; |
|
} |
|
|
|
|
|
for (i = 0; i < 4; i += 1) { |
|
curPoint = testPoints[i] |
|
if (!this.isLegalPosition(this.baseX + curPoint.x, this.baseY + curPoint.y)) { |
|
count += 1; |
|
} else if (curPoint.miniCheck) { |
|
mini = true; |
|
} |
|
} |
|
|
|
if (count >= 3) { |
|
if (mini) { |
|
return 'mini'; |
|
} |
|
return 'normal'; |
|
} |
|
return null; |
|
}; |
|
|