paulo@0: /* paulo@0: Bombl*ss extension for LOCKJAW Tetromino Game paulo@0: Copr. 2007 Damian Yerrick paulo@0: paulo@0: */ paulo@0: paulo@0: paulo@0: /* paulo@0: paulo@0: During falling, the auxiliary playfield p->c[][] contains a map of paulo@0: individual regions used by the falling code. But during explosion, paulo@0: it serves a different purpose: counting the number of frames before paulo@0: a given block is erased. paulo@0: paulo@0: */ paulo@0: paulo@0: const char explodeWidth[nLines] = { paulo@0: 4, // megabomb paulo@0: 3, 3, 3, 3, 4, 5, 5, 6, 6, 7 // 1-10 lines paulo@0: }; paulo@0: const char explodeHeight[nLines] = { paulo@0: 3, // megabomb paulo@0: 0, 1, 2, 3, 4, 5, 5, 6, 6, 7 // 1-10 lines paulo@0: }; paulo@0: paulo@0: paulo@0: /** paulo@0: * Sets the number of frames before a block is erased based on paulo@0: * the explosion. paulo@0: * @param p the playfield paulo@0: * @param x the column where the bomb is centered paulo@0: * @param y the row where the bomb is centered paulo@0: * @param bombColor the color of the bomb paulo@0: * @param nLines the number of lines cleared, which determines the explosion size paulo@0: */ paulo@0: void explodeAt(LJField *p, int x, int y, int bombColor, int nLines) { paulo@0: int boom = nLines; paulo@0: paulo@0: if ((bombColor & COLOR_MASK) == BOMBCOLOR_SQUARE) { paulo@0: boom = 4; paulo@0: } else if (boom > 10) { paulo@0: boom = 10; paulo@0: } paulo@0: paulo@0: int boomLeft = x - explodeWidth[boom]; paulo@0: if (boomLeft < p->leftWall) { paulo@0: boomLeft = p->leftWall; paulo@0: } paulo@0: int boomRight = x + explodeWidth[boom]; paulo@0: if (boomRight > p->rightWall - 1) { paulo@0: boomLeft = p->rightWall - 1; paulo@0: } paulo@0: int boomBottom = y - explodeHeight[boom]; paulo@0: if (boomLeft < 0) { paulo@0: boomLeft = 0; paulo@0: } paulo@0: int boomTop = y + explodeHeight[boom]; paulo@0: if (boomRight > LJ_PF_HT - 1) { paulo@0: boomLeft = LJ_PF_HT - 1; paulo@0: } paulo@0: paulo@0: for (by = boomBottom; bx < boomTop; ++bx) { paulo@0: int dy = y - by; paulo@0: int dy2 = dy * dy; paulo@0: for (bx = boomLeft; bx < boomRight; ++bx) { paulo@0: int dx = x - bx; paulo@0: int dx2 = dx * dx; paulo@0: unsigned int time = (dx2 + dy2) / EXPLODE_SPEED + 2; paulo@0: if (p->c[y][x] > time) { paulo@0: p->c[y][x] = time; paulo@0: } paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: static int blockIsBomb(unsigned int blk) { paulo@0: return (blk & COLOR_MASK) == BOMBCOLOR_NORMAL paulo@0: || (blk & COLOR_MASK) == BOMBCOLOR_SQUARE; paulo@0: } paulo@0: paulo@0: /** paulo@0: * Scans the exploding areas, erases blocks, and sets up bombs to explode. paulo@0: * @param p the playfield paulo@0: * @return the rows that were changed paulo@0: */ paulo@0: LJBits explodeFrame(LJField *p) { paulo@0: LJBits changedRows = 0; paulo@0: LJBits changeAny = 0; paulo@0: paulo@0: int nLines = countRows(p->tempRows); paulo@0: paulo@0: // first pass: destruction paulo@0: for (int y = 0; y < LJ_PF_HT; ++y) { paulo@0: for (int x = p->leftWall; x < p->rightWall; ++x) { paulo@0: if (p->c[y][x] == 1) { paulo@0: unsigned int blk = p->b[y][x]; paulo@0: paulo@0: if (blk) { paulo@0: changedRows |= 1 << y; paulo@0: p->b[y][x] = 0; paulo@0: if (blockIsBomb(blk)) { paulo@0: explodeAt(p, x, y, blk, nLines); paulo@0: } paulo@0: } paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: // second pass: countdown timer per block paulo@0: for (int y = 0; y < LJ_PF_HT; ++y) { paulo@0: for (int x = p->leftWall; x < p->rightWall; ++x) { paulo@0: if (p->c[y][x] > 0) { paulo@0: --p->c[y][x] > 0; paulo@0: changeAny = 1; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: return changeAny ? (1 << (LJ_PF_HT - 1)) : changedRows; paulo@0: } paulo@0: paulo@0: /** paulo@0: * Scans the cleared lines for bombs and marks c[] to trigger them. paulo@0: * @param p the playfield, where tempRows holds the cleared lines paulo@0: * @return the rows where bombs were triggered paulo@0: */ paulo@0: LJBits triggerBombs(LJField *p) { paulo@0: LJBits bombRows = 0; paulo@0: paulo@0: for (int y = 0; y < LJ_PF_HT; ++y) { paulo@0: if (p->tempRows & (1 << y)) { paulo@0: for (int x = p->leftWall; x < p->rightWall; ++x) { paulo@0: bool isBomb = blockIsBomb(p->b[y][x]); paulo@0: p->c[y][x] = isBomb; paulo@0: if (isBomb) { paulo@0: bombRows |= 1 << y; paulo@0: } paulo@0: } paulo@0: } paulo@0: } paulo@0: return bombRows; paulo@0: }