#include <qpixmap.h>
#include <qwidget.h>
#include <qapp.h>
#include <stdlib.h>
#include "controller.h"
CtrlBoard::CtrlBoard(QWidget *parent)
: QFrame(parent)
{
setFrameStyle(QFrame::Panel | QFrame::Sunken);
setFocusPolicy(QWidget::StrongFocus);
isStarted = false;
isPaused = false;
clearBoard();
nextBlock.setRandomShape();
timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));
}
void CtrlBoard::setNextBlock(QLabel *label)
{
nextBlockLabel = label;
}
QSize CtrlBoard::sizeHint() const
{
return QSize(BoardWidth * 15 + frameWidth() * 2,
BoardHeight * 15 + frameWidth() * 2);
}
QSize CtrlBoard::minimumSizeHint() const
{
return QSize(BoardWidth * 5 + frameWidth() * 2,
BoardHeight * 5 + frameWidth() * 2);
}
void CtrlBoard::start()
{
if(isPaused || isStarted)
return;
isStarted = true;
isWaitingAfterLine = false;
score = 0;
level = 1;
clearBoard();
emit scoreChanged(score);
emit levelChanged(level);
newBlock();
timer->start(timeoutTime());
}
void CtrlBoard::restart()
{
if(isStarted && !isPaused)
timer->stop();
isStarted = true;
isPaused = false;
isWaitingAfterLine = false;
score = 0;
level = 1;
emit scoreChanged(score);
emit levelChanged(level);
clearBoard();
nextBlock.setRandomShape();
newBlock();
timer->start(timeoutTime());
}
void CtrlBoard::pause()
{
if(!isStarted)
return;
isPaused = !isPaused;
if(isPaused){
timer->stop();
}
else{
timer->start(timeoutTime());
}
update();
}
void CtrlBoard::paintEvent(QPaintEvent *event)
{
QFrame::paintEvent(event);
QPainter painter(this);
QRect rect = contentsRect();
int boardTop = rect.bottom() - BoardHeight*squareHeight();
for(int i = 0;i < BoardHeight;++i){
for(int j = 0;j < BoardWidth;++j){
BlockShape shape = shapeAt(j,BoardHeight - i - 1);
if(shape != NoShape)
drawSquare(painter,rect.left() + j * squareWidth(),boardTop + i * squareHeight(),shape);
}
}
if(curBlock.shape() != NoShape){
for(int i = 0;i < 4;++i){
int x = curX + curBlock.x(i);
int y = curY - curBlock.y(i);
drawSquare(painter, rect.left() + x * squareWidth(),
boardTop + (BoardHeight - y - 1) * squareHeight(),
curBlock.shape());
}
}
}
void CtrlBoard::keyPressEvent(QKeyEvent *event)
{
if(!isStarted || curBlock.shape() == NoShape){
QFrame::keyPressEvent(event);
return;
}
if(!isPaused){
switch(event->key()){
case Qt::Key_1:
pause();
break;
case Qt::Key_2:
dropBottom();
break;
case Qt::Key_4:
tryMove(curBlock,curX - 1,curY);
break;
case Qt::Key_5:
droponeLine();
break;
case Qt::Key_6:
tryMove(curBlock,curX + 1,curY);
break;
case Qt::Key_7:
tryMove(curBlock.turnToLeft(),curX,curY);
break;
case Qt::Key_9:
tryMove(curBlock.turnToRight(),curX,curY);
break;
default:
QFrame::keyPressEvent(event);
}
}
else
if(event->key() == Qt::Key_1)
pause();
}
void CtrlBoard::timeout()
{
if(isWaitingAfterLine){
timer->stop();
isWaitingAfterLine = false;
newBlock();
timer->start(timeoutTime());
}
else{
droponeLine();
}
}
int CtrlBoard::timeoutTime()
{
int time = 500;
if(level <= 2)
time = 400;
else if(level <= 5)
time = 300;
else if(level <= 10)
time = 200;
else if(level <= 15)
time = 100;
else
time = 80;
return time;
}
void CtrlBoard::clearBoard()
{
for(int i = 0;i < BoardHeight * BoardWidth;++i)
board[i] = NoShape;
}
void CtrlBoard::dropBottom()
{
int newY = curY;
while(newY > 0){
if(!tryMove(curBlock,curX,newY - 1))
break;
--newY;
}
blockDropped();
}
void CtrlBoard::droponeLine()
{
if(!tryMove(curBlock,curX,curY - 1))
blockDropped();
}
void CtrlBoard::blockDropped()
{
for(int i = 0;i < 4;++i){
int x = curX + curBlock.x(i);
int y = curY - curBlock.y(i);
shapeAt(x,y) = curBlock.shape();
}
score += 1;
emit scoreChanged(score);
if(score - 100 * (level - 1) >= 100){
++level;
timer->stop();
timer->start(timeoutTime());
emit levelChanged(level);
}
clearFullLines();
if(!isWaitingAfterLine)
newBlock();
}
void CtrlBoard::clearFullLines()
{
int numFullLines = 0;
for(int i = BoardHeight - 1;i >= 0;--i){
bool lineIsFull = true;
for(int j = 0;j < BoardWidth;++j){
if(shapeAt(j,i) == NoShape){
lineIsFull = false;
break;
}
}
if(lineIsFull){
++numFullLines;
for(int k = i;k < BoardHeight - 1;++k){
for(int j = 0;j < BoardWidth;++j)
shapeAt(j, k) = shapeAt(j,k + 1);
}
for(int j = 0;j < BoardWidth;++j)
shapeAt(j,BoardHeight - 1) = NoShape;
}
}
if(numFullLines > 0){
score += 10 * (2 * numFullLines + 1);
emit scoreChanged(score);
timer->start(500);
isWaitingAfterLine = true;
curBlock.setShape(NoShape);
update();
}
}
void CtrlBoard::newBlock()
{
curBlock = nextBlock;
nextBlock.setRandomShape();
showNextBlock();
curX = BoardWidth / 2 + 1;
curY = BoardHeight - 1 + curBlock.minY();
if(!tryMove(curBlock,curX,curY)){
curBlock.setShape(NoShape);
timer->stop();
isStarted = false;
}
}
void CtrlBoard::showNextBlock()
{
if (!nextBlockLabel)
return;
int dx = nextBlock.maxX() - nextBlock.minX() + 1;
int dy = nextBlock.maxY() - nextBlock.minY() + 1;
QPixmap pixmap(dx * squareWidth(), dy * squareHeight());
QPainter painter(&pixmap);
painter.fillRect(pixmap.rect(),nextBlockLabel->palette().brush(QPalette::Active,QColorGroup::Background));
for(int i = 0;i < 4;++i){
int x = nextBlock.x(i) - nextBlock.minX();
int y = nextBlock.y(i) - nextBlock.minY();
drawSquare(painter, x * squareWidth(), y * squareHeight(),
nextBlock.shape());
}
nextBlockLabel->setPixmap(pixmap);
}
bool CtrlBoard::tryMove(const Block &newBlock,int newX,int newY)
{
for(int i = 0;i < 4;++i){
int x = newX + newBlock.x(i);
int y = newY - newBlock.y(i);
if(x < 0 || x >= BoardWidth || y < 0 || y >= BoardHeight)
return false;
if(shapeAt(x, y) != NoShape)
return false;
}
curBlock = newBlock;
curX = newX;
curY = newY;
update();
return true;
}
void CtrlBoard::drawSquare(QPainter &painter,int x,int y,BlockShape shape)
{
static const QRgb colorTable[8] = {
0x000000, 0xCC6666, 0x66CC66, 0x6666CC,
0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00
};
QColor color = colorTable[int(shape)];
painter.fillRect(x + 1,y + 1,squareWidth() - 2,squareHeight() - 2,color);
painter.setPen(color.light());
painter.drawLine(x,y + squareHeight() - 1,x,y);
painter.drawLine(x,y,x + squareWidth() - 1,y);
painter.setPen(color.dark());
painter.drawLine(x + 1,y + squareHeight() - 1,
x + squareWidth() - 1,y + squareHeight() - 1);
painter.drawLine(x + squareWidth() - 1,y + squareHeight() - 1,
x + squareWidth() - 1,y + 1);
}