Diffstat (limited to 'noncore/games/tetrix/gtetrix.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/games/tetrix/gtetrix.cpp | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/noncore/games/tetrix/gtetrix.cpp b/noncore/games/tetrix/gtetrix.cpp new file mode 100644 index 0000000..d1f38b1 --- a/dev/null +++ b/noncore/games/tetrix/gtetrix.cpp | |||
@@ -0,0 +1,514 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | |||
21 | |||
22 | #include "gtetrix.h" | ||
23 | |||
24 | #include <string.h> | ||
25 | |||
26 | GenericTetrix::GenericTetrix(int boardWidth,int boardHeight) | ||
27 | { | ||
28 | int i,j; | ||
29 | |||
30 | width = boardWidth; | ||
31 | height = boardHeight; | ||
32 | boardPtr = new int[height*width]; // Note the order, this makes it easier | ||
33 | // to remove full lines. | ||
34 | for(i = 0 ; i < height ; i++) | ||
35 | for(j = 0 ; j < width ; j++) | ||
36 | board(j,i) = 0; | ||
37 | currentLine = -1; // -1 if no falling piece. | ||
38 | currentPos = 0; | ||
39 | showNext = 0; // FALSE | ||
40 | nLinesRemoved = 0; | ||
41 | nPiecesDropped = 0; | ||
42 | score = 0; | ||
43 | level = 1; | ||
44 | gameID = 0; | ||
45 | nClearLines = height; | ||
46 | } | ||
47 | |||
48 | GenericTetrix::~GenericTetrix() | ||
49 | { | ||
50 | delete[] boardPtr; | ||
51 | } | ||
52 | |||
53 | |||
54 | void GenericTetrix::clearBoard(int fillRandomLines) | ||
55 | { | ||
56 | int i,j; | ||
57 | |||
58 | if (fillRandomLines >= height) | ||
59 | fillRandomLines = height - 1; | ||
60 | |||
61 | erasePiece(); | ||
62 | for(i = height - nClearLines - 1 ; i >= fillRandomLines ; i--) | ||
63 | for(j = 0 ; j < width ; j++) | ||
64 | if (board(j,i) != 0) { | ||
65 | draw(j,i,0); | ||
66 | board(j,i) = 0; | ||
67 | } | ||
68 | if (fillRandomLines != 0) | ||
69 | for (i = 0 ; i < fillRandomLines ; i++) { | ||
70 | fillRandom(i); | ||
71 | } | ||
72 | nClearLines = height - fillRandomLines; | ||
73 | } | ||
74 | |||
75 | void GenericTetrix::showBoard() | ||
76 | { | ||
77 | int i,j; | ||
78 | |||
79 | showPiece(); | ||
80 | for(i = height - nClearLines - 1 ; i >= 0 ; i--) | ||
81 | for(j = 0 ; j < width ; j++) | ||
82 | if (board(j,i) != 0) | ||
83 | draw(j,i,board(j,i)); | ||
84 | } | ||
85 | |||
86 | void GenericTetrix::hideBoard() | ||
87 | { | ||
88 | int i,j; | ||
89 | |||
90 | erasePiece(); | ||
91 | for(i = height - nClearLines - 1 ; i >= 0 ; i--) | ||
92 | for(j = 0 ; j < width ; j++) | ||
93 | if (board(j,i) != 0) | ||
94 | draw(j,i,0); | ||
95 | } | ||
96 | |||
97 | void GenericTetrix::startGame(int gameType,int fillRandomLines) | ||
98 | { | ||
99 | gameID = gameType; | ||
100 | clearBoard(fillRandomLines); | ||
101 | nLinesRemoved = 0; | ||
102 | updateRemoved(nLinesRemoved); | ||
103 | nClearLines = height; | ||
104 | nPiecesDropped = 0; | ||
105 | score = 0; | ||
106 | updateScore(score); | ||
107 | level = 1; | ||
108 | updateLevel(level); | ||
109 | newPiece(); | ||
110 | } | ||
111 | |||
112 | void GenericTetrix::revealNextPiece(int revealIt) | ||
113 | { | ||
114 | if (showNext == revealIt) | ||
115 | return; | ||
116 | showNext = revealIt; | ||
117 | if (!showNext) | ||
118 | eraseNextPiece(); | ||
119 | else | ||
120 | showNextPiece(); | ||
121 | } | ||
122 | |||
123 | void GenericTetrix::updateBoard(int x1,int y1,int x2, int y2, | ||
124 | int dontUpdateBlanks) | ||
125 | { | ||
126 | int i,j; | ||
127 | int tmp; | ||
128 | |||
129 | if (x1 > x2) { | ||
130 | tmp = x2; | ||
131 | x2 = x1; | ||
132 | x1 = tmp; | ||
133 | } | ||
134 | if (y1 > y2) { | ||
135 | tmp = y2; | ||
136 | y2 = y1; | ||
137 | y1 = tmp; | ||
138 | } | ||
139 | if (x1 < 0) | ||
140 | x1 = 0; | ||
141 | if (x2 >= width) | ||
142 | x2 = width - 1; | ||
143 | if (y1 < 0) | ||
144 | y1 = 0; | ||
145 | if (y2 >= height) | ||
146 | y2 = height - 1; | ||
147 | for(i = y1 ; i <= y2 ; i++) | ||
148 | for(j = x1 ; j <= x2 ; j++) | ||
149 | if (!dontUpdateBlanks || board(j,height - i - 1) != 0) | ||
150 | draw(j,height - i - 1,board(j,height - i - 1)); | ||
151 | showPiece(); // Remember to update piece correctly!!!! | ||
152 | } | ||
153 | |||
154 | |||
155 | void GenericTetrix::fillRandom(int line) | ||
156 | { | ||
157 | int i,j; | ||
158 | int holes; | ||
159 | |||
160 | for(i = 0 ; i < width ; i++) | ||
161 | board(i,line) = TetrixPiece::randomValue(7); | ||
162 | holes = 0; | ||
163 | for(i = 0 ; i < width ; i++) | ||
164 | if (board(i,line) == 0) // Count holes in the line. | ||
165 | holes++; | ||
166 | if (holes == 0) // Full line, make a random hole: | ||
167 | board(TetrixPiece::randomValue(width),line) = 0; | ||
168 | if (holes == width) // Empty line, make a random square: | ||
169 | board(TetrixPiece::randomValue(width),line) = | ||
170 | TetrixPiece::randomValue(6) + 1; | ||
171 | for(j = 0 ; j < width ; j++) | ||
172 | draw(j,i,board(j,i)); | ||
173 | } | ||
174 | |||
175 | void GenericTetrix::moveLeft(int steps) | ||
176 | { | ||
177 | while(steps) { | ||
178 | if (!canMoveTo(currentPos - 1,currentLine)) | ||
179 | return; | ||
180 | moveTo(currentPos - 1,currentLine); | ||
181 | steps--; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | void GenericTetrix::moveRight(int steps) | ||
186 | { | ||
187 | while(steps) { | ||
188 | if (!canMoveTo(currentPos + 1,currentLine)) | ||
189 | return; | ||
190 | moveTo(currentPos + 1,currentLine); | ||
191 | steps--; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | void GenericTetrix::rotateLeft() | ||
196 | { | ||
197 | TetrixPiece tmp(currentPiece); | ||
198 | |||
199 | tmp.rotateLeft(); | ||
200 | if (!canPosition(tmp)) | ||
201 | return; | ||
202 | position(tmp); | ||
203 | currentPiece = tmp; | ||
204 | } | ||
205 | |||
206 | void GenericTetrix::rotateRight() | ||
207 | { | ||
208 | TetrixPiece tmp(currentPiece); | ||
209 | |||
210 | tmp.rotateRight(); | ||
211 | if (!canPosition(tmp)) | ||
212 | return; | ||
213 | position(tmp); | ||
214 | currentPiece = tmp; | ||
215 | } | ||
216 | |||
217 | void GenericTetrix::dropDown() | ||
218 | { | ||
219 | if (currentLine == -1) | ||
220 | return; | ||
221 | |||
222 | int dropHeight = 0; | ||
223 | int newLine = currentLine; | ||
224 | while(newLine) { | ||
225 | if (!canMoveTo(currentPos,newLine - 1)) | ||
226 | break; | ||
227 | newLine--; | ||
228 | dropHeight++; | ||
229 | } | ||
230 | if (dropHeight != 0) | ||
231 | moveTo(currentPos,newLine); | ||
232 | internalPieceDropped(dropHeight); | ||
233 | } | ||
234 | |||
235 | void GenericTetrix::oneLineDown() | ||
236 | { | ||
237 | if (currentLine == -1) | ||
238 | return; | ||
239 | if (canMoveTo(currentPos,currentLine - 1)) { | ||
240 | moveTo(currentPos,currentLine - 1); | ||
241 | } else { | ||
242 | internalPieceDropped(0); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | void GenericTetrix::newPiece() | ||
247 | { | ||
248 | currentPiece = nextPiece; | ||
249 | if (showNext) | ||
250 | eraseNextPiece(); | ||
251 | nextPiece.setRandomType(); | ||
252 | if (showNext) | ||
253 | showNextPiece(); | ||
254 | currentLine = height - 1 + currentPiece.getMinY(); | ||
255 | currentPos = width/2 + 1; | ||
256 | if (!canMoveTo(currentPos,currentLine)) { | ||
257 | currentLine = -1; | ||
258 | gameOver(); | ||
259 | } else { | ||
260 | showPiece(); | ||
261 | } | ||
262 | } | ||
263 | |||
264 | void GenericTetrix::removePiece() | ||
265 | { | ||
266 | erasePiece(); | ||
267 | currentLine = -1; | ||
268 | } | ||
269 | |||
270 | void GenericTetrix::drawNextSquare(int,int,int) | ||
271 | { | ||
272 | |||
273 | } | ||
274 | |||
275 | void GenericTetrix::pieceDropped(int) | ||
276 | { | ||
277 | newPiece(); | ||
278 | } | ||
279 | |||
280 | void GenericTetrix::updateRemoved(int) | ||
281 | { | ||
282 | } | ||
283 | |||
284 | void GenericTetrix::updateScore(int) | ||
285 | { | ||
286 | } | ||
287 | |||
288 | void GenericTetrix::updateLevel(int) | ||
289 | { | ||
290 | } | ||
291 | |||
292 | void GenericTetrix::removeFullLines() | ||
293 | { | ||
294 | int i,j,k; | ||
295 | int nFullLines; | ||
296 | |||
297 | for(i = 0 ; i < height - nClearLines ; i++) { | ||
298 | for(j = 0 ; j < width ; j++) | ||
299 | if (board(j,i) == 0) | ||
300 | break; | ||
301 | if (j == width) { | ||
302 | nFullLines = 1; | ||
303 | for(k = i + 1 ; k < height - nClearLines ; k++) { | ||
304 | for(j = 0 ; j < width ; j++) | ||
305 | if (board(j,k) == 0) | ||
306 | break; | ||
307 | if (j == width) { | ||
308 | nFullLines++; | ||
309 | } else { | ||
310 | for(j = 0 ; j < width ; j++) { | ||
311 | if (board(j,k - nFullLines) != board(j,k)) { | ||
312 | board(j,k - nFullLines) = board(j,k); | ||
313 | draw( j,k - nFullLines, | ||
314 | board(j,k - nFullLines)); | ||
315 | } | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | nClearLines = nClearLines + nFullLines; | ||
320 | nLinesRemoved = nLinesRemoved + nFullLines; | ||
321 | updateRemoved(nLinesRemoved); | ||
322 | score = score + 10*nFullLines; // updateScore must be | ||
323 | // called by caller! | ||
324 | for (i = height - nClearLines ; | ||
325 | i < height - nClearLines + nFullLines ; | ||
326 | i++) | ||
327 | for(j = 0 ; j < width ; j++) | ||
328 | if (board(j,i) != 0) { | ||
329 | draw(j,i,0); | ||
330 | board(j,i) = 0; | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | void GenericTetrix::showPiece() | ||
337 | { | ||
338 | int x,y; | ||
339 | |||
340 | if (currentLine == -1) | ||
341 | return; | ||
342 | |||
343 | for(int i = 0 ; i < 4 ; i++) { | ||
344 | currentPiece.getCoord(i,x,y); | ||
345 | draw(currentPos + x,currentLine - y,currentPiece.getType()); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | void GenericTetrix::erasePiece() | ||
350 | { | ||
351 | int x,y; | ||
352 | |||
353 | if (currentLine == -1) | ||
354 | return; | ||
355 | |||
356 | for(int i = 0 ; i < 4 ; i++) { | ||
357 | currentPiece.getCoord(i,x,y); | ||
358 | draw(currentPos + x,currentLine - y,0); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | void GenericTetrix::internalPieceDropped(int dropHeight) | ||
363 | { | ||
364 | gluePiece(); | ||
365 | nPiecesDropped++; | ||
366 | if (nPiecesDropped % 25 == 0) { | ||
367 | level++; | ||
368 | updateLevel(level); | ||
369 | } | ||
370 | score = score + 7 + dropHeight; | ||
371 | removeFullLines(); | ||
372 | updateScore(score); | ||
373 | pieceDropped(dropHeight); | ||
374 | } | ||
375 | |||
376 | void GenericTetrix::gluePiece() | ||
377 | { | ||
378 | int x,y; | ||
379 | int min; | ||
380 | |||
381 | if (currentLine == -1) | ||
382 | return; | ||
383 | |||
384 | for(int i = 0 ; i < 4 ; i++) { | ||
385 | currentPiece.getCoord(i,x,y); | ||
386 | board(currentPos + x,currentLine - y) = currentPiece.getType(); | ||
387 | } | ||
388 | min = currentPiece.getMinY(); | ||
389 | if (currentLine - min >= height - nClearLines) | ||
390 | nClearLines = height - currentLine + min - 1; | ||
391 | } | ||
392 | |||
393 | void GenericTetrix::showNextPiece(int erase) | ||
394 | { | ||
395 | int x,y; | ||
396 | int minX = nextPiece.getMinX(); | ||
397 | int minY = nextPiece.getMinY(); | ||
398 | int maxX = nextPiece.getMaxX(); | ||
399 | int maxY = nextPiece.getMaxY(); | ||
400 | |||
401 | int xOffset = (3 - (maxX - minX))/2; | ||
402 | int yOffset = (3 - (maxY - minY))/2; | ||
403 | |||
404 | for(int i = 0 ; i < 4 ; i++) { | ||
405 | nextPiece.getCoord(i,x,y); | ||
406 | if (erase) | ||
407 | drawNextSquare(x + xOffset - minX, | ||
408 | y + yOffset - minY,0); | ||
409 | else | ||
410 | drawNextSquare(x + xOffset - minX, | ||
411 | y + yOffset - minY,nextPiece.getType()); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | int GenericTetrix::canPosition(TetrixPiece &piece) | ||
416 | { | ||
417 | if (currentLine == -1) | ||
418 | return 0; | ||
419 | |||
420 | int x,y; | ||
421 | |||
422 | for(int i = 0 ; i < 4 ; i++) { | ||
423 | piece.getCoord(i,x,y); | ||
424 | x = currentPos + x; | ||
425 | y = currentLine - y; // Board and pieces have inverted y-coord. systems. | ||
426 | if (x < 0 || x >= width || y < 0 || y >= height) | ||
427 | return 0; // Outside board, cannot put piece here. | ||
428 | if (board(x,y) != 0) | ||
429 | return 0; // Over a non-zero square, cannot put piece here. | ||
430 | } | ||
431 | return 1; // Inside board and no non-zero squares underneath. | ||
432 | |||
433 | } | ||
434 | |||
435 | int GenericTetrix::canMoveTo(int xPosition,int line) | ||
436 | { | ||
437 | if (currentLine == -1) | ||
438 | return 0; | ||
439 | |||
440 | int x,y; | ||
441 | |||
442 | for(int i = 0 ; i < 4 ; i++) { | ||
443 | currentPiece.getCoord(i,x,y); | ||
444 | x = xPosition + x; | ||
445 | y = line - y; // Board and pieces have inverted y-coord. systems. | ||
446 | if (x < 0 || x >= width || y < 0 || y >= height) | ||
447 | return 0; // Outside board, cannot put piece here. | ||
448 | if (board(x,y) != 0) | ||
449 | return 0; // Over a non-zero square, cannot put piece here. | ||
450 | } | ||
451 | return 1; // Inside board and no non-zero squares underneath. | ||
452 | } | ||
453 | |||
454 | void GenericTetrix::moveTo(int xPosition,int line) | ||
455 | { | ||
456 | if (currentLine == -1) | ||
457 | return; | ||
458 | optimizedMove(xPosition,line,currentPiece); | ||
459 | currentPos = xPosition; | ||
460 | currentLine = line; | ||
461 | } | ||
462 | |||
463 | void GenericTetrix::position(TetrixPiece &piece) | ||
464 | { | ||
465 | if (currentLine == -1) | ||
466 | return; | ||
467 | |||
468 | optimizedMove(currentPos,currentLine,piece); | ||
469 | } | ||
470 | |||
471 | void GenericTetrix::optimizedMove(int newPos, int newLine, | ||
472 | TetrixPiece &newPiece) | ||
473 | { | ||
474 | int updates [8][3]; | ||
475 | int nUpdates; | ||
476 | int value; | ||
477 | int x,y; | ||
478 | int i,j; | ||
479 | |||
480 | for(i = 0 ; i < 4 ; i++) { // Put the erasing coords into updates | ||
481 | currentPiece.getCoord(i,x,y); | ||
482 | updates[i][0] = currentPos + x; | ||
483 | updates[i][1] = currentLine - y; | ||
484 | updates[i][2] = 0; | ||
485 | } | ||
486 | nUpdates = 4; | ||
487 | for(i = 0 ; i < 4 ; i++) { // Any drawing coord same as an erasing one? | ||
488 | newPiece.getCoord(i,x,y); | ||
489 | x = newPos + x; | ||
490 | y = newLine - y; | ||
491 | for (j = 0 ; j < 4 ; j++) | ||
492 | if (updates[j][0] == x && updates[j][1] == y) { // Same coord, | ||
493 | // don't have to erase | ||
494 | if (currentPiece.getType() == newPiece.getType()) | ||
495 | updates[j][2] = -1; // Correct on screen, no update! | ||
496 | else | ||
497 | updates[j][2] = newPiece.getType(); | ||
498 | break; | ||
499 | } | ||
500 | if (j == 4) { // This coord does not overlap an erasing one | ||
501 | updates[nUpdates][0] = x; | ||
502 | updates[nUpdates][1] = y; | ||
503 | updates[nUpdates][2] = newPiece.getType(); | ||
504 | nUpdates++; | ||
505 | } | ||
506 | } | ||
507 | for (i = 0 ; i < nUpdates ; i++) { // Do the updating | ||
508 | x = updates[i][0]; | ||
509 | y = updates[i][1]; | ||
510 | value = updates[i][2]; | ||
511 | if (value != -1) // Only update if new value != current | ||
512 | draw(x,y,value); | ||
513 | } | ||
514 | } | ||