summaryrefslogtreecommitdiff
path: root/noncore/games/zlines/linesboard.cpp
Unidiff
Diffstat (limited to 'noncore/games/zlines/linesboard.cpp') (more/less context) (show whitespace changes)
-rw-r--r--noncore/games/zlines/linesboard.cpp591
1 files changed, 591 insertions, 0 deletions
diff --git a/noncore/games/zlines/linesboard.cpp b/noncore/games/zlines/linesboard.cpp
new file mode 100644
index 0000000..0965b2c
--- a/dev/null
+++ b/noncore/games/zlines/linesboard.cpp
@@ -0,0 +1,591 @@
1/***************************************************************************
2 linesboard.cpp - description
3 -------------------
4 begin : Fri May 19 2000
5 copyright : (C) 2000 by Roman Merzlyakov
6 email : roman@sbrf.barrt.ru
7 copyright : (C) 2000 by Roman Razilov
8 email : Roman.Razilov@gmx.de
9 ***************************************************************************/
10
11/***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 ***************************************************************************/
19#include <qpainter.h>
20#include <qpixmap.h>
21#include <qcolor.h>
22#include <qkeycode.h>
23#include <stdlib.h>
24
25#include "linesboard.h"
26
27/*
28 Constructs a LinesBoard widget.
29*/
30
31LinesBoard::LinesBoard( BallPainter * abPainter, QWidget* parent, const char* name )
32 : Field( parent, name )
33{
34 anim = ANIM_NO;
35// waypos = 0;
36// waylen = 0;
37// jumpingRow = -1;
38// jumpingCol = -1;
39 painting = 0;
40 way = new Waypoints[NUMCELLSW*NUMCELLSH];
41
42 bPainter = abPainter;
43
44 setFocusPolicy( NoFocus );
45 setBackgroundColor( gray );
46
47 setMouseTracking( FALSE );
48 setFixedSize(wHint(), hHint());
49
50 timer = new QTimer(this);
51 connect( timer, SIGNAL(timeout()), SLOT(timerSlot()) );
52 timer->start( TIMERCLOCK, FALSE );
53
54}
55
56/*
57 Destructor: deallocates memory for contents
58*/
59
60LinesBoard::~LinesBoard()
61{
62 // debug("stop");
63 timer->stop();
64 delete timer;
65 delete []way;
66}
67
68
69void LinesBoard::placeBalls(int pnextBalls[BALLSDROP])
70{
71 debug("LinesBoard::placeBalls( )");
72 for(int i=0; i < BALLSDROP; i++){
73 nextBalls[i] = pnextBalls[i];
74 }
75 nextBallToPlace = 0;
76 placeBall();
77 debug("LinesBoard::placeBalls End ");
78}
79void LinesBoard::placeBall( )
80{
81 int color = nextBalls[nextBallToPlace];
82 debug("LinesBoard::placeBall( ) color=%i, nextBallToPlace = %i", color, nextBallToPlace);
83 char* xx = (char*)malloc( sizeof(char)*NUMCELLSW*NUMCELLSH );
84 char* yy = (char*)malloc( sizeof(char)*NUMCELLSW*NUMCELLSH );
85// int nb=3;
86// if( freeSpace() < 3) nb = freeSpace();
87 int empty=0;
88 for(int y=0; y<NUMCELLSH; y++)
89 for(int x=0; x<NUMCELLSW; x++)
90 if( getBall(x,y) == NOBALL )
91 {
92 xx[empty] = x;
93 yy[empty] = y;
94 empty++;
95 };
96// debug("empty = %i",empty);
97 if ( empty > 0)
98 {
99 int pos = rand()%empty;
100 putBall( xx[pos], yy[pos], color );
101 clearAnim();
102 setAnim( xx[pos], yy[pos], ANIM_BORN );
103 nextBallToPlace++;
104 AnimStart(ANIM_BORN);
105 free(xx);
106 free(yy);
107 }
108 else
109 {
110 free(xx);
111 free(yy);
112 emit endGame();
113 }
114 debug("LinesBoard::placeBall END");
115}
116
117
118/*id LinesBoard::doAfterBalls() {
119 erase5Balls();
120 repaint(FALSE);
121}
122*/
123/*
124 Sets the size of the table
125*/
126
127int LinesBoard::width() { return CELLSIZE * NUMCELLSW; }
128int LinesBoard::height() { return CELLSIZE * NUMCELLSH; }
129int LinesBoard::wHint() { return width(); }
130int LinesBoard::hHint() { return height(); }
131
132
133
134void LinesBoard::paintEvent( QPaintEvent* )
135{
136// debug("LinesBoard::paintEvent ");
137 QPixmap pixmap(width(), height());
138 QPainter paint(&pixmap, this);
139
140 for( int y=0; y < NUMCELLSH; y++ ){
141 for( int x=0; x < NUMCELLSW; x++ ){
142 if( getBall(x,y) == NOBALL )
143 {
144// debug("draw empty %i %i", x, y );
145 paint.drawPixmap(x*CELLSIZE, y*CELLSIZE, *(bPainter->GetBackgroundPix()) );
146 }
147 else
148 {
149// debug("draw empty %i %i %c", x, y, getBall(x,y) );
150 paint.drawPixmap(x*CELLSIZE, y*CELLSIZE,
151 *(bPainter->GetBall(getBall(x,y),animstep,getAnim(x,y))));
152 }
153 }
154 }
155
156 bitBlt(this, 0,0, &pixmap, 0,0, width(), height(), CopyROP);
157}
158
159/*
160 Handles mouse press events for the LinesBoard widget.
161*/
162void LinesBoard::mousePressEvent( QMouseEvent* e )
163{
164 debug("LinesBoard::mousePressEvent START");
165 int curRow = e->y() / CELLSIZE;
166 int curCol = e->x() / CELLSIZE;
167 //debug
168 debug("Mouse pressed: curRow=%i, curCol=%i", curRow, curCol);
169
170 //check range
171 if (!checkBounds( curCol, curRow ) )
172 return;
173// if( running || anim != ANIM_NO ) return;
174 if(anim != ANIM_JUMP && anim != ANIM_NO) return;
175 if ( anim == ANIM_JUMP )
176 {
177 if ( getBall(curCol,curRow) == NOBALL )
178 {
179 if(existPath(jumpingCol, jumpingRow, curCol, curRow))
180 {
181 saveUndo();
182 AnimStart(ANIM_RUN);
183 }
184 }
185 else
186 AnimJump(curCol,curRow);
187 }
188 else
189 AnimJump(curCol,curRow);
190 debug("LinesBoard::mousePressEvent END");
191}
192void LinesBoard::AnimJump(int x, int y ) {
193 debug("LinesBoard::AnimJump( %i,%i)", x,y );
194 if ( getBall(x,y) != NOBALL )
195 if (!( anim == ANIM_JUMP && jumpingCol == x && jumpingRow == y ))
196 if ( AnimEnd() )
197 {
198 clearAnim();
199 setAnim(x,y,ANIM_JUMP);
200 jumpingCol = x;
201 jumpingRow = y;
202 AnimStart(ANIM_JUMP);
203 }
204 debug("LinesBoard::AnimJump END");
205}
206void LinesBoard::AnimStart(int panim) {
207 debug("LinesBoard::AnimStart( %i )", panim);
208 if (anim != ANIM_NO)
209 AnimEnd();
210 animstep = 0;
211 animdelaystart = 1;
212 switch(panim) {
213 case ANIM_NO:
214 break;
215 case ANIM_BORN:
216 debug("LinesBoard::AnimStart( ANIM_BORN )");
217 animdelaystart=1;
218 animmax = BOOMBALLS;
219 break;
220 case ANIM_JUMP:
221 direction = -1;
222 animstep = 4;
223 animmax = PIXTIME -1;
224 break;
225 case ANIM_RUN:
226 animdelaystart=3;
227 // do first step on next timer;
228 animdelaycount = 0;
229 // animmax already set
230 break;
231 case ANIM_BURN:
232 animdelaystart=1;
233 animmax = FIREBALLS + FIREPIX - 1;
234 break;
235 default:
236 ;
237 }
238 anim = panim;
239 animdelaycount = animdelaystart;
240 debug("LinesBoard::AnimStart END");
241}
242int LinesBoard::AnimEnd( )
243{
244 debug("LinesBoard::AnimEnd( %i )",anim );
245 if (anim == ANIM_NO ) return true;
246 int oldanim = anim;
247 anim = ANIM_NO;
248 if (oldanim == ANIM_RUN) {
249 if (animstep != animmax) {
250 moveBall(way[animstep].x,way[animstep].y,way[animmax].x,way[animmax].y);
251 }
252 if ( erase5Balls() == 0 ) {
253 // debug("end turn");
254 emit endTurn();
255 debug("LinesBoard::AnimEnd END true 1");
256 return true;
257 }
258 else
259 debug("LinesBoard::AnimEnd END false 2");
260 return false;
261 } else if ( oldanim == ANIM_BURN )
262 {
263 emit eraseLine( deleteAnimatedBalls() );
264 repaint(FALSE);
265 if ( nextBallToPlace < BALLSDROP )
266 {
267 placeBall();
268 // continue with born
269 debug("LinesBoard::AnimEnd END false 3");
270 return false;
271 }
272 else
273 {
274 // emit endTurn();
275 debug("LinesBoard::AnimEnd END true 4");
276 return true;
277 }
278 } else if ( oldanim == ANIM_BORN )
279 {
280 if ( erase5Balls() == 0 )
281 {
282 if ( freeSpace() > 0)
283 {
284 if ( nextBallToPlace < BALLSDROP )
285 {
286 placeBall();
287 debug("LinesBoard::AnimEnd END false 5");
288 return false;
289 }
290 else
291 {
292 debug("LinesBoard::AnimEnd END true 6");
293 return true;
294 }
295 }
296 else
297 {
298 debug("emit endGame");
299 emit endGame();
300 debug("LinesBoard::AnimEnd END false 7");
301 return false;
302 }
303 }
304 else
305 {
306 // wait for user input
307 debug("LinesBoard::AnimEnd END true 8");
308 return true;
309 }
310 }
311 else
312 {
313 debug("LinesBoard::AnimEnd END true");
314 return true;
315 }
316 return true;
317}
318void LinesBoard::AnimNext() {
319 if ( anim != ANIM_NO )
320 {
321 debug("LinesBoard::AnimNext( ) anim %i animstep %i",anim,animstep);
322 if ( anim == ANIM_JUMP ) {
323 if ( (direction > 0 && animstep == animmax) || ( direction < 0 && animstep == 0))
324 direction = -direction;
325 animstep += direction;
326 repaint(FALSE);
327 } else {
328 if ( animstep >= animmax )
329 AnimEnd();
330 else {
331 animdelaycount--;
332 if (animdelaycount <= 0) {
333 debug("LinesBoard::AnimNext step %i", animstep);
334 if ( anim == ANIM_RUN )
335 moveBall(way[animstep].x,way[animstep].y,way[animstep+1].x,way[animstep+1].y);
336 animstep++;
337 animdelaycount = animdelaystart;
338 repaint( FALSE );
339 }
340 }
341 }
342 debug("LinesBoard::AnimNext END");
343 }
344}
345int LinesBoard::getAnim( int x, int y )
346{
347// debug("LinesBoard::getAnim( %i,%i )",x,y);
348 return (( Field::getAnim(x,y) != ANIM_NO )? anim : ANIM_NO);
349}
350
351void LinesBoard::timerSlot()
352{
353// debug("LinesBoard::Timer() anim = %i",anim );
354 AnimNext();
355}
356
357int LinesBoard::erase5Balls()
358{
359 //debug
360 debug("LinesBoard::erase5Balls()");
361
362 int nb=5; // minimum balls for erasure
363
364 bool bit_erase[NUMCELLSH][NUMCELLSW]; //bool array for balls, that must be erased
365 for(int y=0; y<NUMCELLSH; y++)
366 for(int x=0; x<NUMCELLSW; x++)
367 bit_erase[y][x] = false;
368
369 int color,newcolor;
370 int count;
371 //for horisontal
372 //debug("entering to horiz");
373
374 for(int y=0; y<NUMCELLSH; y++) {
375 count = 1;
376 color = NOBALL;
377 for(int x=0; x<NUMCELLSW; x++){
378 if ( (newcolor = getBall(x,y)) == color) {
379 if ( color != NOBALL) {
380 count++;
381 if ( count >= nb )
382 if ( count == nb )
383 for (int i = 0; i < nb; i++)
384 bit_erase[y][x-i] = true;
385 else bit_erase[y][x] = true;
386 }
387 } else {
388 color = newcolor;
389 count = 1;
390 }
391 }
392 }
393
394 //for vertical
395 //debug("entering to vert");
396 for(int x=0; x<NUMCELLSW; x++) {
397 count = 0;
398 color = NOBALL;
399 for(int y=0; y<NUMCELLSH; y++){
400 if ( (newcolor = getBall(x,y)) == color) {
401 if ( color != NOBALL) {
402 count++;
403 if ( count >= nb )
404 if ( count == nb )
405 for (int i = 0; i < nb; i++)
406 bit_erase[y-i][x] = true;
407 else bit_erase[y][x] = true;
408 }
409 } else {
410 color = newcolor;
411 count = 1;
412 }
413 }
414 }
415
416
417 // debug("entering to diag1");
418 //for left-down to rigth-up diagonal
419 for ( int xs = NUMCELLSW-1,ys = NUMCELLSH-nb; xs >= nb-1; ) {
420 count = 0;
421 color = NOBALL;
422 for ( int x = xs, y = ys; x >= 0 && y < NUMCELLSH; x--, y++ ) {
423 if ( (newcolor = getBall(x,y)) == color) {
424 if ( color != NOBALL) {
425 count++;
426 if ( count >= nb )
427 if ( count == nb )
428 for (int i = 0; i < nb; i++)
429 bit_erase[y-i][x+i] = true;
430 else bit_erase[y][x] = true;
431 }
432 } else {
433 color = newcolor;
434 count = 1;
435 }
436 }
437 if ( ys > 0 ) ys--; else xs--;
438 }
439
440 //debug("entering to diag2");
441
442 //for left-up to rigth-down diagonal
443 for ( int xs = 0,ys = NUMCELLSH-nb; xs <= NUMCELLSW-nb; )
444 {
445 count = 0;
446 color = NOBALL;
447 for ( int x = xs, y = ys; x < NUMCELLSW && y < NUMCELLSH; x++, y++ )
448 {
449 if ( (newcolor = getBall(x,y)) == color)
450 {
451 if ( color != NOBALL)
452 {
453 count++;
454 if ( count >= nb )
455 if ( count == nb )
456 for (int i = 0; i < nb; i++)
457 bit_erase[y-i][x-i] = true;
458 else
459 bit_erase[y][x] = true;
460 }
461 }
462 else
463 {
464 color = newcolor;
465 count = 1;
466 }
467 }
468 if ( ys > 0 ) ys--; else xs++;
469 }
470
471 //remove all lines balls, that more than nb
472 int cb=0;
473 for(int y=0; y < NUMCELLSH; y++)
474 for(int x=0; x < NUMCELLSW; x++)
475 {
476 if (bit_erase[y][x])
477 {
478 setAnim(x,y,ANIM_YES);
479 cb++;
480 }
481 else
482 {
483 setAnim(x,y,ANIM_NO);
484 }
485 }
486 //debug
487 debug("LinesBoard::erase5Balls marked %i balls", cb);
488 if ( cb > 0 )
489 {
490 AnimStart(ANIM_BURN);
491 //emit eraseLine(cb);
492 }
493
494 //debug
495 debug("LinesBoard::erase5Balls END");
496 return cb;
497}
498
499
500#define GO_EMPTY 4
501#define GO_A 5
502#define GO_B 6
503#define GO_BALL 7
504
505bool LinesBoard::existPath(int bx, int by, int ax, int ay)
506{
507 debug("LinesBoard::existPath( %i, %i, %i, %i )", bx, by, ax, ay);
508 int dx[4]={1,-1, 0, 0};
509 int dy[4]={0, 0, 1,-1};
510
511 // debug("path %i %i %i %i",bx,by,ax,ay);
512 if (getBall(ax,ay) != NOBALL)
513 return false;
514
515 char pf[NUMCELLSH][NUMCELLSW];
516 for(int y=0; y<NUMCELLSH; y++)
517 for(int x=0; x<NUMCELLSW; x++)
518 pf[y][x] = (getBall(x,y) == NOBALL) ? GO_EMPTY:GO_BALL;
519
520 Waypoints lastchanged[2][NUMCELLSH*NUMCELLSW];
521
522 int lastChangedCount[2];
523 int currentchanged = 0;
524 int nextchanged = 1;
525 lastchanged[currentchanged][0].x = ax;
526 lastchanged[currentchanged][0].y = ay;
527 lastChangedCount[currentchanged] = 1;
528 pf[ay][ax]=GO_A;
529 pf[by][bx]=GO_B;
530
531 // int expanded;
532 bool B_reached = false;
533
534 do
535 {
536 lastChangedCount[nextchanged] = 0;
537 for(int dir=0; dir<4; dir++)
538 {
539 for ( int i = 0 ; i < lastChangedCount[currentchanged]; i++ )
540 {
541 int nx = lastchanged[currentchanged][i].x + dx[dir];
542 int ny = lastchanged[currentchanged][i].y + dy[dir];
543 if( (nx>=0) && (nx<NUMCELLSW) && (ny>=0) && (ny<NUMCELLSH) )
544 {
545 if( pf[ny][nx]==GO_EMPTY ||( nx==bx && ny==by ))
546 {
547 pf[ny][nx] = dir;
548 lastchanged[nextchanged][lastChangedCount[nextchanged]].x = nx;
549 lastchanged[nextchanged][lastChangedCount[nextchanged]].y = ny;
550 lastChangedCount[nextchanged]++;
551 };
552 if( (nx==bx) && (ny==by) )
553 {
554 B_reached = true;
555 break;
556 }
557 }
558 }
559 }
560 nextchanged = nextchanged ^ 1;
561 currentchanged = nextchanged ^ 1;
562 // debug("currentchanged %i lastChangedCount[currentchanged] %i",
563 // currentchanged,lastChangedCount[currentchanged]);
564 } while(!B_reached && lastChangedCount[currentchanged] != 0);
565 //debug("B_reached %i ", B_reached );
566
567 if (B_reached) {
568 AnimStart( ANIM_BLOCK);
569 animmax = 0;
570// waypos = 0;
571 int x, y,dir;
572 for( x = bx, y = by,dir; (dir = pf[y][x]) != GO_A;x -=dx[dir],y -= dy[dir]) {
573 way[animmax].x = x;
574 way[animmax].y = y;
575 //debug("%i %i %i %i",dir,waylen,x,y);
576 animmax++;
577 }
578 way[animmax].x = x;
579 way[animmax].y = y;
580 }
581 debug("LinesBoard::existPath END %s", B_reached?"true":"false" );
582 return B_reached;
583}
584
585void LinesBoard::undo()
586{
587 AnimEnd();
588 restoreUndo();
589 repaint( FALSE );
590}
591