annotate src/explode.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
rev   line source
paulo@0 1 /*
paulo@0 2 Bombl*ss extension for LOCKJAW Tetromino Game
paulo@0 3 Copr. 2007 Damian Yerrick
paulo@0 4
paulo@0 5 */
paulo@0 6
paulo@0 7
paulo@0 8 /*
paulo@0 9
paulo@0 10 During falling, the auxiliary playfield p->c[][] contains a map of
paulo@0 11 individual regions used by the falling code. But during explosion,
paulo@0 12 it serves a different purpose: counting the number of frames before
paulo@0 13 a given block is erased.
paulo@0 14
paulo@0 15 */
paulo@0 16
paulo@0 17 const char explodeWidth[nLines] = {
paulo@0 18 4, // megabomb
paulo@0 19 3, 3, 3, 3, 4, 5, 5, 6, 6, 7 // 1-10 lines
paulo@0 20 };
paulo@0 21 const char explodeHeight[nLines] = {
paulo@0 22 3, // megabomb
paulo@0 23 0, 1, 2, 3, 4, 5, 5, 6, 6, 7 // 1-10 lines
paulo@0 24 };
paulo@0 25
paulo@0 26
paulo@0 27 /**
paulo@0 28 * Sets the number of frames before a block is erased based on
paulo@0 29 * the explosion.
paulo@0 30 * @param p the playfield
paulo@0 31 * @param x the column where the bomb is centered
paulo@0 32 * @param y the row where the bomb is centered
paulo@0 33 * @param bombColor the color of the bomb
paulo@0 34 * @param nLines the number of lines cleared, which determines the explosion size
paulo@0 35 */
paulo@0 36 void explodeAt(LJField *p, int x, int y, int bombColor, int nLines) {
paulo@0 37 int boom = nLines;
paulo@0 38
paulo@0 39 if ((bombColor & COLOR_MASK) == BOMBCOLOR_SQUARE) {
paulo@0 40 boom = 4;
paulo@0 41 } else if (boom > 10) {
paulo@0 42 boom = 10;
paulo@0 43 }
paulo@0 44
paulo@0 45 int boomLeft = x - explodeWidth[boom];
paulo@0 46 if (boomLeft < p->leftWall) {
paulo@0 47 boomLeft = p->leftWall;
paulo@0 48 }
paulo@0 49 int boomRight = x + explodeWidth[boom];
paulo@0 50 if (boomRight > p->rightWall - 1) {
paulo@0 51 boomLeft = p->rightWall - 1;
paulo@0 52 }
paulo@0 53 int boomBottom = y - explodeHeight[boom];
paulo@0 54 if (boomLeft < 0) {
paulo@0 55 boomLeft = 0;
paulo@0 56 }
paulo@0 57 int boomTop = y + explodeHeight[boom];
paulo@0 58 if (boomRight > LJ_PF_HT - 1) {
paulo@0 59 boomLeft = LJ_PF_HT - 1;
paulo@0 60 }
paulo@0 61
paulo@0 62 for (by = boomBottom; bx < boomTop; ++bx) {
paulo@0 63 int dy = y - by;
paulo@0 64 int dy2 = dy * dy;
paulo@0 65 for (bx = boomLeft; bx < boomRight; ++bx) {
paulo@0 66 int dx = x - bx;
paulo@0 67 int dx2 = dx * dx;
paulo@0 68 unsigned int time = (dx2 + dy2) / EXPLODE_SPEED + 2;
paulo@0 69 if (p->c[y][x] > time) {
paulo@0 70 p->c[y][x] = time;
paulo@0 71 }
paulo@0 72 }
paulo@0 73 }
paulo@0 74 }
paulo@0 75
paulo@0 76 static int blockIsBomb(unsigned int blk) {
paulo@0 77 return (blk & COLOR_MASK) == BOMBCOLOR_NORMAL
paulo@0 78 || (blk & COLOR_MASK) == BOMBCOLOR_SQUARE;
paulo@0 79 }
paulo@0 80
paulo@0 81 /**
paulo@0 82 * Scans the exploding areas, erases blocks, and sets up bombs to explode.
paulo@0 83 * @param p the playfield
paulo@0 84 * @return the rows that were changed
paulo@0 85 */
paulo@0 86 LJBits explodeFrame(LJField *p) {
paulo@0 87 LJBits changedRows = 0;
paulo@0 88 LJBits changeAny = 0;
paulo@0 89
paulo@0 90 int nLines = countRows(p->tempRows);
paulo@0 91
paulo@0 92 // first pass: destruction
paulo@0 93 for (int y = 0; y < LJ_PF_HT; ++y) {
paulo@0 94 for (int x = p->leftWall; x < p->rightWall; ++x) {
paulo@0 95 if (p->c[y][x] == 1) {
paulo@0 96 unsigned int blk = p->b[y][x];
paulo@0 97
paulo@0 98 if (blk) {
paulo@0 99 changedRows |= 1 << y;
paulo@0 100 p->b[y][x] = 0;
paulo@0 101 if (blockIsBomb(blk)) {
paulo@0 102 explodeAt(p, x, y, blk, nLines);
paulo@0 103 }
paulo@0 104 }
paulo@0 105 }
paulo@0 106 }
paulo@0 107 }
paulo@0 108
paulo@0 109 // second pass: countdown timer per block
paulo@0 110 for (int y = 0; y < LJ_PF_HT; ++y) {
paulo@0 111 for (int x = p->leftWall; x < p->rightWall; ++x) {
paulo@0 112 if (p->c[y][x] > 0) {
paulo@0 113 --p->c[y][x] > 0;
paulo@0 114 changeAny = 1;
paulo@0 115 }
paulo@0 116 }
paulo@0 117 }
paulo@0 118
paulo@0 119 return changeAny ? (1 << (LJ_PF_HT - 1)) : changedRows;
paulo@0 120 }
paulo@0 121
paulo@0 122 /**
paulo@0 123 * Scans the cleared lines for bombs and marks c[] to trigger them.
paulo@0 124 * @param p the playfield, where tempRows holds the cleared lines
paulo@0 125 * @return the rows where bombs were triggered
paulo@0 126 */
paulo@0 127 LJBits triggerBombs(LJField *p) {
paulo@0 128 LJBits bombRows = 0;
paulo@0 129
paulo@0 130 for (int y = 0; y < LJ_PF_HT; ++y) {
paulo@0 131 if (p->tempRows & (1 << y)) {
paulo@0 132 for (int x = p->leftWall; x < p->rightWall; ++x) {
paulo@0 133 bool isBomb = blockIsBomb(p->b[y][x]);
paulo@0 134 p->c[y][x] = isBomb;
paulo@0 135 if (isBomb) {
paulo@0 136 bombRows |= 1 << y;
paulo@0 137 }
paulo@0 138 }
paulo@0 139 }
paulo@0 140 }
paulo@0 141 return bombRows;
paulo@0 142 }