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 }
|