2 /****************************************************************************
3 * Copyright (C) 2002 by Leo Khramov
4 * email: leo@xnc.dubna.su
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 ****************************************************************************/
17 # Original algorithm with polyominoes by
19 # David A. Bagley, bagleyd@bigfoot.com
21 # Q. Alex Zhao, azhao@cc.gatech.edu
23 $Id: wellclass.cxx,v 1.3 2003/02/21 11:40:33 leo Exp $
27 /// module description
28 /// Main class that is the game itself - contains game board, generate figures
29 /// drop it to the field, and interacts with the user.
31 #include "wellclass.h"
32 #include "wellengine.h"
33 #include "welldrawing.h"
34 #include "commonfuncs.h"
36 static int speeds
[NUM_LEVELS
] = {
37 100, 92, 84, 76, 68, 60, 53, 46, 39, 32, 26, 20, 15, 11, 8, 5, 3, 1, 0};
39 //===========================================================================
41 /// Constructor of base class - loads polyominoes and init structs
43 WellBase::WellBase() : WellObject()
45 int turn_style
, number_polyominoes
;
51 pause
=steps_to_rotate
=0;
54 set_default_options();
59 turn_style
= tris
[squares
- MIN_SQUARES
].mode
[diagonal
].turn_style
;
60 if (turn_style
< 0 || turn_style
>= MAX_TYPES
)
62 fprintf(stderr
, "Welltris: corrupted input file %s\n",
64 fprintf(stderr
, "\tturn_style = %d.\n", turn_style
);
68 tris
[squares
- MIN_SQUARES
].mode
[diagonal
].number
[mixed
][turn_style
];
69 if (number_polyominoes
<= 0 || number_polyominoes
> MAX_START_POLYOMINOES
)
71 fprintf(stderr
, "Welltris: corrupted input file %s\n",
73 fprintf(stderr
, "\tnumber_polyominoes = %d.\n",
77 geo
=get_geo_by_name("the_game");
80 //===========================================================================
82 /// set params for new game
84 void WellBase::new_game()
87 for (j
= 0; j
< MAX_DEPTH
; j
++)
88 for (i
= 0; i
< MAX_PERIMETER
; i
++)
90 wall
[j
][i
].pmid
= EMPTY
;
93 for (j
= 0; j
< MAX_WIDTH
; j
++)
94 for (i
= 0; i
< MAX_WIDTH
; i
++)
96 base
[j
][i
].pmid
= EMPTY
;
99 for (i
= 0; i
< MAX_SIDES
; i
++)
102 dre
->set_inner_alpha(30);
103 dre
->set_outer_alpha(0);
104 dre
->set_field_sizes(20,20,14,18);
105 dre
->calc_grid_points();
106 dre
->set_field_id(0);
111 steps_to_rotate
=level
;
121 player_score
=new Score
;
122 player_score
->set_player(player_name
);
123 player_score
->squares
=squares
;
124 player_score
->set_params(score
,rows
,level
);
125 player_score
->next_piece
=showNext
;
126 player_score
->rotation
=rotation
;
127 player_score
->mixed
=mixed
;
130 //===========================================================================
131 /// global init(WellEngine*)
132 /// init class and other related stuff
134 void WellBase::init(WellEngine
* we
)
136 //Additional init's such as read defaults....
137 dbgprintf(("WellBase: game board size: %dx%d\n",VIEW_L
,VIEW_H
));
138 //And Draw Engine inits
140 dre
=we
->new_well_drawing_engine();
141 dre
->init(NUM_ROT_STEPS
,VIEW_X
,VIEW_Y
,VIEW_L
,VIEW_H
);
143 txt_score
=we
->new_well_image_font(imFont1
,FONT2_L
,FONT2_H
,FONT2_DX
,FONT2_DY
);
144 txt_score
->set_screen_region(SCORE_REG_X
,SCORE_REG_Y
,
145 SCORE_REG_L
,SCORE_REG_H
);
147 txt_lines
=we
->new_well_image_font(imFont1
,FONT1_L
,FONT1_H
,FONT1_DX
,FONT1_DY
);
148 txt_lines
->set_screen_region(LINES_REG_X
,LINES_REG_Y
,
149 LINES_REG_L
,LINES_REG_H
);
151 txt_levelup
=we
->new_well_image_font(imFont1
,FONT1_L
,FONT1_H
,FONT1_DX
,FONT1_DY
);
152 txt_levelup
->set_screen_region(LEVUP_REG_X
,LEVUP_REG_Y
,
153 LEVUP_REG_L
,LEVUP_REG_H
);
155 txt_level
=we
->new_well_image_font(imFont1
,FONT1_L
,FONT1_H
,FONT1_DX
,FONT1_DY
);
156 txt_level
->set_screen_region(LEVEL_REG_X
,LEVEL_REG_Y
,
157 LEVEL_REG_L
,LEVEL_REG_H
);
159 txt_first
=we
->new_well_image_font(imFont1
,FONT1_L
,FONT1_H
,FONT1_DX
,FONT1_DY
);
160 txt_first
->set_screen_region(CHAL1_REG_X
,CHAL1_REG_Y
,
161 CHAL_REG_L
,CHAL_REG_H
);
163 txt_second
=we
->new_well_image_font(imFont1
,FONT1_L
,FONT1_H
,FONT1_DX
,FONT1_DY
);
164 txt_second
->set_screen_region(CHAL2_REG_X
,CHAL2_REG_Y
,
165 CHAL_REG_L
,CHAL_REG_H
);
167 txt_third
=we
->new_well_image_font(imFont1
,FONT1_L
,FONT1_H
,FONT1_DX
,FONT1_DY
);
168 txt_third
->set_screen_region(CHAL3_REG_X
,CHAL3_REG_Y
,
169 CHAL_REG_L
,CHAL_REG_H
);
174 //===========================================================================
175 /// global new_level_calc()
176 /// calculate params for new level
178 void WellBase::new_level_calc()
180 rows_levelup
=THRESHOLD(level
);
185 default_well_engine
->del_timer(this);
186 default_well_engine
->add_timer(this,speeds
[level
]);
190 //==========================================================================
191 /// global set_default_option()
192 /// set options needed by the game to its default values
194 void WellBase::set_default_options()
209 //===========================================================================
210 /// global read_polyominoes()
211 /// reading polyominoes (our game figures) info from file
213 void WellBase::read_polyominoes()
215 char fname
[L_MAXPATH
];
216 int c
, i
, j
, k
, sq
, polyomino
, sum
, start
, n
, size
, height
, diag
,
218 int counter
[MAX_SQUARES
- MIN_SQUARES
+ 1];
219 int start_counter
[MAX_SQUARES
- MIN_SQUARES
+ 1][MAX_MODES
][MAX_TYPES
];
222 find_full_path_for_file(POLYOMINOFILE
,fname
,ReadOnly
);
224 for (sq
= 0; sq
<= MAX_SQUARES
- MIN_SQUARES
; sq
++)
227 for (polyomino
= 0; polyomino
< MAX_POLYOMINOES
; polyomino
++)
228 for (j
= 0; j
< MAX_SQUARES
; j
++)
229 for (i
= 0; i
< MAX_SQUARES
; i
++)
230 tris
[sq
].polyomino
[polyomino
].shape
[j
][i
] = 0;
231 for (j
= 0; j
< MAX_TYPES
; j
++)
233 for (polyomino
= 0; polyomino
< MAX_START_POLYOMINOES
; polyomino
++)
235 tris
[sq
].mode
[NODIAG
].start
[polyomino
][j
] = 0;
236 tris
[sq
].mode
[DIAGONAL
].start
[polyomino
][j
] = 0;
238 start_counter
[sq
][NODIAG
][j
] = 0;
239 start_counter
[sq
][DIAGONAL
][j
] = 0;
240 tris
[sq
].mode
[NODIAG
].number
[NOMIX
][j
] = 0;
241 tris
[sq
].mode
[DIAGONAL
].number
[NOMIX
][j
] = 0;
242 tris
[sq
].mode
[NODIAG
].number
[MIXED
][j
] = 0;
243 tris
[sq
].mode
[DIAGONAL
].number
[MIXED
][j
] = 0;
245 tris
[sq
].mode
[NODIAG
].turn_style
= NONE
;
246 tris
[sq
].mode
[DIAGONAL
].turn_style
= NONE
;
248 if ((fp
= fopen(fname
, "r")) == (FILE *)NULL
)
250 (void) fprintf(stderr
, "Can not open input file, %s\n.", POLYOMINOFILE
);
255 while ((c
= getc(fp
)) != EOF
)
259 while ((c
= getc(fp
)) != '/') {}
264 (void) fscanf(fp
, "%d", &k
);
265 sq
= k
- MIN_SQUARES
;
266 for (i
= 0; i
< MAX_TYPES
; i
++)
268 (void) fscanf(fp
, "%d", &k
);
269 tris
[sq
].mode
[NODIAG
].number
[NOMIX
][i
] = k
;
271 (void) fscanf(fp
, "%d", &k
);
272 tris
[sq
].mode
[NODIAG
].turn_style
= k
;
273 (void) fscanf(fp
, "%d", &k
);
274 tris
[sq
].diagonal_switch
= k
;
275 if (tris
[sq
].diagonal_switch
== true)
277 for (i
= 0; i
< MAX_TYPES
; i
++)
279 (void) fscanf(fp
, "%d", &k
);
280 tris
[sq
].mode
[DIAGONAL
].number
[NOMIX
][i
] = k
;
282 (void) fscanf(fp
, "%d", &k
);
283 tris
[sq
].mode
[DIAGONAL
].turn_style
= k
;
289 (void) fscanf (fp
, "%d", &size
);
292 if (c
== '~') /* Useful for debugging Things */
294 (void) fscanf (fp
, "%d", &toss
);
299 (void) fscanf(fp
, "%d", &k
);
300 sq
= k
- MIN_SQUARES
;
301 (void) fscanf(fp
, "%d", &n
);
302 if (tris
[sq
].diagonal_switch
== true)
303 (void) fscanf(fp
, "%d", &n
);
304 for (polyomino
= 0; polyomino
<= toss
; polyomino
++)
305 while ((c
= getc(fp
)) != EOF
&& c
!= '\n');
306 for (polyomino
= 0; polyomino
< n
- toss
; polyomino
++)
308 sum
= polyomino
+ counter
[sq
];
309 /* This is only there to "read" input file */
310 (void) fscanf(fp
, "%d", &k
);
311 (void) fscanf(fp
, "%d", &k
);
312 tris
[sq
].polyomino
[sum
].rotation
=
313 k
+ counter
[sq
] - toss
;
314 (void) fscanf(fp
, "%d", &k
);
315 tris
[sq
].polyomino
[sum
].reflection
=
316 k
+ counter
[sq
] - toss
;
317 for (game
= JUMPIN
; game
<= GRADUAL
; game
++)
319 (void) fscanf(fp
, "%d", &height
);
320 if (!gradualAppear
&& game
== JUMPIN
)
321 tris
[sq
].polyomino
[sum
].start_height
= height
;
322 else if (gradualAppear
&& game
== GRADUAL
)
323 tris
[sq
].polyomino
[sum
].start_height
= height
;
324 for (diag
= NODIAG
; diag
<= tris
[sq
].diagonal_switch
; diag
++)
326 (void) fscanf(fp
, "%d", &start
);
330 tris
[sq
- 1].mode
[diag
].turn_style
== NONE
)
332 i
= start_counter
[sq
][diag
][NONE
];
333 tris
[sq
].mode
[diag
].start
[i
][NONE
] = sum
;
334 start_counter
[sq
][diag
][NONE
]++;
337 tris
[sq
- 1].mode
[diag
].turn_style
< ALL
) &&
340 i
= start_counter
[sq
][diag
][NOREFL
];
341 tris
[sq
].mode
[diag
].start
[i
][NOREFL
] = sum
;
342 start_counter
[sq
][diag
][NOREFL
]++;
346 i
= start_counter
[sq
][diag
][ALL
];
347 tris
[sq
].mode
[diag
].start
[i
][ALL
] = sum
;
348 start_counter
[sq
][diag
][ALL
]++;
353 tris
[sq
].polyomino
[sum
].size
= size
;
354 for (j
= 0; j
< size
; j
++)
355 for (i
= 0; i
< size
; i
++)
357 (void) fscanf(fp
, "%d", &k
);
358 tris
[sq
].polyomino
[sum
].shape
[j
][i
] = k
;
361 counter
[sq
] += n
- toss
;
366 for (i
= 0; i
<= MAX_SQUARES
- MIN_SQUARES
; i
++)
367 for (j
= 0; j
< MAX_TYPES
; j
++)
368 for (k
= 0; k
<= i
; k
++)
370 tris
[i
].mode
[NODIAG
].number
[MIXED
][j
] +=
371 tris
[k
].mode
[NODIAG
].number
[NOMIX
][j
];
372 if (tris
[i
].diagonal_switch
== true)
373 /*since k & i are not independent*/
374 tris
[i
].mode
[DIAGONAL
].number
[MIXED
][j
] +=
375 tris
[k
].mode
[DIAGONAL
].number
[NOMIX
][j
];
381 //===========================================================================
383 /// install itself in lists for proper processing events, draw itself.
385 void WellBase::show()
387 default_well_engine
->set_main_background_image(imBoardBG
);
388 dbgprintf(("WellBase registering event handlers\n"));
390 default_well_engine
->add_timer(this,speeds
[level
]);
391 default_well_engine
->add_object(this);
399 //===========================================================================
401 /// unregister itself from any events
403 void WellBase::hide()
406 dbgprintf(("WellBase unregistering from engine\n"));
407 default_well_engine
->del_timer(this);
408 default_well_engine
->del_object(this);
411 //===========================================================================
412 /// global new_thing()
413 /// Generate new figure random gen for field
415 void WellBase::new_thing()
417 curThing
= nextThing
;
418 nextThing
.random_number
= LRAND();
419 nextThing
.random_rotation
= NRAND(MAX_SIDES
);
420 nextThing
.random_reflection
= NRAND(2);
421 nextThing
.bonus
= bonusNow
;
426 //===========================================================================
427 /// global redo_next()
428 /// fill nextThing vars with data from polyomino
430 void WellBase::redo_next()
432 int turn_style
= tris
[squares
- MIN_SQUARES
].mode
[diagonal
].turn_style
;
435 nextThing
.squares
= squares
- MIN_SQUARES
+ nextThing
.bonus
;
436 nextThing
.squares
= nextThing
.squares
> MAX_SQUARES
- MIN_SQUARES
?
437 MAX_SQUARES
- MIN_SQUARES
: nextThing
.squares
;
438 next_start
= nextThing
.random_number
% tris
[nextThing
.squares
].
439 mode
[diagonal
].number
[(nextThing
.bonus
) ? NOMIX
: mixed
][turn_style
];
440 nextThing
.color_number
= next_start
;
441 dbgprintf(("NEXT COLOR number is %d\n",next_start
));
442 if (mixed
&& !nextThing
.bonus
)
444 nextThing
.squares
= 0;
446 tris
[nextThing
.squares
].mode
[diagonal
].number
[NOMIX
][turn_style
])
449 tris
[nextThing
.squares
].mode
[diagonal
].number
[NOMIX
][turn_style
];
453 nextThing
.polyomino_number
=
454 tris
[nextThing
.squares
].mode
[diagonal
].start
[next_start
][turn_style
];
455 if (tris
[nextThing
.squares
].mode
[diagonal
].turn_style
> NONE
)
456 for (i
= 0; i
< nextThing
.random_rotation
; i
++)
457 nextThing
.polyomino_number
= tris
[nextThing
.squares
].polyomino
458 [nextThing
.polyomino_number
].rotation
;
459 if (tris
[nextThing
.squares
].mode
[diagonal
].turn_style
== ALL
)
460 for (i
= 0; i
< nextThing
.random_reflection
; i
++)
461 nextThing
.polyomino_number
= tris
[nextThing
.squares
].polyomino
462 [nextThing
.polyomino_number
].reflection
;
464 tris
[nextThing
.squares
].polyomino
[nextThing
.polyomino_number
].size
;
465 nextThing
.ypos
= -tris
[nextThing
.squares
].polyomino
466 [nextThing
.polyomino_number
].start_height
;
470 //===========================================================================
472 /// Putting figure into game field
474 void WellBase::put_box()
477 int x
= curThing
.xpos
, y
= curThing
.ypos
;
479 for (i
= 0; i
< curThing
.size
; i
++)
480 for (j
= 0; j
< curThing
.size
; j
++)
481 if ((y
+ j
>= 0) && tris
[curThing
.squares
].polyomino
482 [curThing
.polyomino_number
].shape
[j
][i
]) {
483 xi
= (x
+ i
) % MAX_PERIMETER
;
485 if (yj
< MAX_DEPTH
) { // Draw on the wall of glass
486 wall
[yj
][xi
].pmid
= tris
[curThing
.squares
].polyomino
487 [curThing
.polyomino_number
].shape
[j
][i
];
488 wall
[yj
][xi
].cid
= curThing
.color_number
;
489 frozen_wall
[xi
/ MAX_WIDTH
] = MAX_SIDES
;
490 } else { // Draw on the floor (base)
492 wall_to_base(&base_i
, &base_j
, xi
, yj
);
493 base
[base_j
][base_i
].pmid
= tris
[curThing
.squares
].polyomino
494 [curThing
.polyomino_number
].shape
[j
][i
];
495 base
[base_j
][base_i
].cid
= curThing
.color_number
;
501 //===========================================================================
502 /// global overlapping()
503 /// check overlapping our figure in current position with another ones
506 bool WellBase::overlapping()
509 int x
= curThing
.xpos
, y
= curThing
.ypos
;
511 for (i
= 0; i
< curThing
.size
; i
++)
512 for (j
= 0; j
< curThing
.size
; j
++)
513 if (tris
[curThing
.squares
].polyomino
514 [curThing
.polyomino_number
].shape
[j
][i
]) {
515 xi
= (x
+ i
) % MAX_PERIMETER
;
517 if (yj
< MAX_DEPTH
) {
518 if (frozen_wall
[xi
/ MAX_WIDTH
])
521 /* This method one can turn polyomino to an area above of screen, also
522 part of the polyomino may not be visible initially */
523 if ((yj
>= 0) && (wall
[yj
][xi
].pmid
>= 0))
526 /* This method does not allow turning polyomino to an area above screen */
527 if ((yj
< 0) || (wall
[yj
][xi
].pmid
>= 0))
531 else if (yj
< MAX_DEPTH
+ MAX_WIDTH
) {
533 wall_to_base(&base_i
, &base_j
, xi
, yj
);
534 if (base
[base_j
][base_i
].pmid
>= 0)
544 //===========================================================================
545 /// global wall_to_base(int* base_x,int* base_y,int wall_x,int wall_y)
546 /// Translate wall coordinates to floor (base) one.
548 void WellBase::wall_to_base(int* base_x
,int* base_y
,int wall_x
,int wall_y
)
550 switch (wall_x
/ MAX_WIDTH
)
554 *base_y
= wall_y
- MAX_DEPTH
;
557 *base_x
= MAX_WIDTH
- 1 + MAX_DEPTH
- wall_y
;
558 *base_y
= wall_x
- MAX_WIDTH
;
561 *base_x
= MAX_PERIMETER
- 1 - MAX_WIDTH
- wall_x
;
562 *base_y
= MAX_WIDTH
- 1 + MAX_DEPTH
- wall_y
;
565 *base_x
= wall_y
- MAX_DEPTH
;
566 *base_y
= MAX_PERIMETER
- 1 - wall_x
;
569 (void) fprintf (stderr
, "wall_to_base kinds range 0-3, got %d.\n",
575 //===========================================================================
576 /// global at_bottom()
577 /// Do we at bottom of the glass? (any piece of our figure)
579 bool WellBase::at_bottom()
582 int x
= curThing
.xpos
, y
= curThing
.ypos
;
584 for (i
= 0; i
< curThing
.size
; i
++)
585 for (j
= 0; j
< curThing
.size
; j
++)
586 if (tris
[curThing
.squares
].polyomino
587 [curThing
.polyomino_number
].shape
[j
][i
]) {
588 xi
= (x
+ i
) % MAX_PERIMETER
;
592 if (yj
< MAX_DEPTH
- 1) {
593 if (frozen_wall
[xi
/ MAX_WIDTH
])
595 if (wall
[yj
+ 1][xi
].pmid
>= 0)
598 else if (yj
< MAX_DEPTH
+ MAX_WIDTH
- 1) {
600 wall_to_base(&base_i
, &base_j
, xi
, yj
+ 1);
601 if (base
[base_j
][base_i
].pmid
>= 0)
611 //===========================================================================
612 /// global at_base_fully()
613 /// Do we fully on the floor? (all pieces of our figure)
615 bool WellBase::at_base_fully()
619 for (i
= 0; i
< curThing
.size
; i
++)
620 for (j
= 0; j
< curThing
.size
; j
++)
621 if (curThing
.ypos
+ j
< MAX_DEPTH
&& tris
[curThing
.squares
].polyomino
622 [curThing
.polyomino_number
].shape
[j
][i
])
627 //===========================================================================
628 /// global at_base_partially()
629 /// Do we on the floor? (at least one of our piece)
631 bool WellBase::at_base_partially()
635 for (i
= 0; i
< curThing
.size
; i
++)
636 for (j
= 0; j
< curThing
.size
; j
++)
637 if (curThing
.ypos
+ j
>= MAX_DEPTH
&& tris
[curThing
.squares
].polyomino
638 [curThing
.polyomino_number
].shape
[j
][i
])
643 //===========================================================================
644 /// global wall_change(thing_t old,thing_t new_t)
645 /// Do we change the wall from last position?
647 bool WellBase::wall_change(thing_t old
,thing_t new_t
)
650 int x
= curThing
.xpos
;
652 for (i
= 0; i
< old
.size
; i
++)
653 for (j
= 0; j
< old
.size
; j
++)
654 if (tris
[old
.squares
].polyomino
[old
.polyomino_number
].shape
[j
][i
]) {
656 w
= ((x
+ i
) % MAX_PERIMETER
) / MAX_WIDTH
;
657 else if (w
!= ((x
+ i
) % MAX_PERIMETER
) / MAX_WIDTH
)
660 for (i
= 0; i
< new_t
.size
; i
++)
661 for (j
= 0; j
< new_t
.size
; j
++)
662 if (tris
[new_t
.squares
].polyomino
[new_t
.polyomino_number
].shape
[j
][i
])
663 if (w
!= ((x
+ i
) % MAX_PERIMETER
) / MAX_WIDTH
)
669 //===========================================================================
670 /// global try_move(Actions move)
671 /// Trying to move/rotate/fall our figure according to the given move action
673 void WellBase::try_move(Actions move
)
690 } while (!overlapping());
695 curThing
.xpos
= (curThing
.xpos
+ MAX_PERIMETER
- 1) % MAX_PERIMETER
;
696 if (at_base_fully() || (at_base_partially() && wall_change(old
, curThing
)))
701 curThing
.xpos
= (curThing
.xpos
+ 1) % MAX_PERIMETER
;
702 if (at_base_fully() || (at_base_partially() && wall_change(old
, curThing
)))
707 if (tris
[squares
- MIN_SQUARES
].mode
[diagonal
].turn_style
> NONE
)
710 for (i
= 0; i
< MAX_SIDES
- 1; i
++)
711 curThing
.polyomino_number
= tris
[curThing
.squares
].polyomino
712 [curThing
.polyomino_number
].rotation
;
714 curThing
.polyomino_number
= tris
[curThing
.squares
].polyomino
715 [curThing
.polyomino_number
].rotation
;
716 curThing
.xpos
= old
.xpos
;
717 curThing
.ypos
= old
.ypos
;
718 if (at_base_partially() && wall_change(old
, curThing
))
723 case REFLECT
: /* reflect on y axis */
724 if (tris
[squares
- MIN_SQUARES
].mode
[diagonal
].turn_style
== ALL
)
726 curThing
.polyomino_number
= tris
[curThing
.squares
].polyomino
727 [curThing
.polyomino_number
].reflection
;
728 curThing
.xpos
= old
.xpos
;
729 curThing
.ypos
= old
.ypos
;
730 if (at_base_partially() && wall_change(old
, curThing
))
739 if (!skip
&& !overlapping())
740 draw_thing_diff(&old
);
745 //===========================================================================
746 /// global draw_box(int color,int i,int j)
747 /// Draw our box (piece of figure) on our virtual square (walls + floor)
749 void WellBase::draw_box(int color
,int i
,int j
)
751 if (j
< MAX_DEPTH
) { //Draw trapazoid on the wall
752 dre
->draw_trapazoid(color
, i
, j
);
754 else { // Draw square on the floor
756 wall_to_base(&base_i
, &base_j
, i
, j
);
757 dre
->draw_square(color
, base_i
, base_j
);
761 //===========================================================================
762 /// global draw_thing()
763 /// for all squares in figure do draw_box -> draw whole figure on the field
765 void WellBase::draw_thing()
769 for (i
= 0; i
< curThing
.size
; i
++)
770 for (j
= 0; j
< curThing
.size
; j
++)
771 if (tris
[curThing
.squares
].polyomino
772 [curThing
.polyomino_number
].shape
[j
][i
]) {
773 xi
= (curThing
.xpos
+ i
) % MAX_PERIMETER
;
774 draw_box(curThing
.color_number
,xi
, curThing
.ypos
+ j
);
778 //===========================================================================
779 /// global draw_thing_diff(thing_t* old)
780 /// Make diff between old and new position on figure and Draw its
781 /// actually Draw new one and clear empty old pieces :)
783 void WellBase::draw_thing_diff(thing_t
* old
)
787 for (i
= 0; i
< curThing
.size
; i
++)
788 for (j
= 0; j
< curThing
.size
; j
++)
789 if ((curThing
.ypos
+ j
>= 0) && tris
[curThing
.squares
].polyomino
790 [curThing
.polyomino_number
].shape
[j
][i
])
792 draw_box(curThing
.color_number
,
793 (curThing
.xpos
+ i
) % MAX_PERIMETER
, curThing
.ypos
+ j
);
796 for (i
= 0; i
< curThing
.size
; i
++)
797 for (j
= 0; j
< curThing
.size
; j
++)
799 ox
= (old
->xpos
+ i
- curThing
.xpos
+ MAX_PERIMETER
) % MAX_PERIMETER
;
800 oy
= old
->ypos
+ j
- curThing
.ypos
;
801 if (tris
[old
->squares
].polyomino
[old
->polyomino_number
].shape
[j
][i
] &&
802 ((ox
>= curThing
.size
) || (oy
< 0) || (oy
>= curThing
.size
) ||
803 !tris
[curThing
.squares
].polyomino
804 [curThing
.polyomino_number
].shape
[oy
][ox
]))
806 draw_box(BackColor
,(old
->xpos
+ i
) % MAX_PERIMETER
, old
->ypos
+ j
);
811 //===========================================================================
812 /// global fill_lines()
813 /// Fill all glass with random squares. Just for test only
815 void WellBase::fill_lines()
818 int turn_style
= tris
[squares
- MIN_SQUARES
].mode
[diagonal
].turn_style
;
820 for (j
= 0; j
< MAX_DEPTH
+ MAX_WIDTH
; j
++)
821 for (i
= 0; i
< MAX_PERIMETER
; i
++)
823 draw_box(NRAND(tris
[squares
- MIN_SQUARES
].mode
824 [diagonal
].number
[mixed
][turn_style
]),
829 //===========================================================================
830 /// global freeze_wall(int w)
831 /// Freeze wall - make some blinks while freezing :)
833 void WellBase::freeze_wall(int w
)
837 for (j
= 0; j
< MAX_DEPTH
; j
++)
838 for (i
= 0; i
< MAX_WIDTH
; i
++)
840 if (wall
[j
][i
+w
*MAX_WIDTH
].pmid
< 0)
841 dre
->draw_trapazoid(FreezeColor
, w
* MAX_WIDTH
+ i
, j
);
845 for (j
= 0; j
< MAX_DEPTH
; j
++)
846 for (i
= 0; i
< MAX_WIDTH
; i
++)
848 if (wall
[j
][i
+w
*MAX_WIDTH
].pmid
< 0)
849 dre
->draw_trapazoid (BackColor
, w
* MAX_WIDTH
+ i
, j
);
853 for (j
= 0; j
< MAX_DEPTH
; j
++)
854 for (i
= 0; i
< MAX_WIDTH
; i
++)
856 if (wall
[j
][i
+w
*MAX_WIDTH
].pmid
< 0)
857 dre
->draw_trapazoid (FreezeColor
, w
* MAX_WIDTH
+ i
, j
);
864 //===========================================================================
865 /// global defreeze_wall(int w)
866 /// Return wall to normal state
868 void WellBase::defreeze_wall(int w
)
872 for (j
= 0; j
< MAX_DEPTH
; j
++)
873 for (i
= 0; i
< MAX_WIDTH
; i
++)
875 if (wall
[j
][i
+w
*MAX_WIDTH
].pmid
< 0)
876 dre
->draw_trapazoid (BackColor
, w
* MAX_WIDTH
+ i
, j
);
883 void WellBase::udelay(int msec
)
885 default_well_engine
->udelay(msec
);
888 //===========================================================================
889 /// global draw_field()
890 /// Draw field with squares and frozen walls
892 void WellBase::draw_field()
896 for (i
= 0; i
< MAX_PERIMETER
; i
++)
897 for (j
= 0; j
< MAX_DEPTH
; j
++)
899 if (wall
[j
][i
].pmid
>= 0)
900 dre
->draw_trapazoid(wall
[j
][i
].cid
, i
, j
);
903 if (frozen_wall
[i
/ MAX_WIDTH
])
904 dre
->draw_trapazoid(FreezeColor
, i
, j
);
906 dre
->draw_trapazoid(BackColor
, i
, j
);
909 for (i
= 0; i
< MAX_WIDTH
; i
++)
910 for (j
= 0; j
< MAX_WIDTH
; j
++)
911 if (base
[j
][i
].pmid
>= 0)
912 dre
->draw_square(base
[j
][i
].cid
, i
, j
);
914 dre
->draw_square(BackColor
, i
, j
);
915 dre
->clear_dirty_list();
919 //===========================================================================
920 /// global draw_next()
921 /// Draw next figure (cheating?)
922 /// Currently not implemented
924 void WellBase::draw_next()
929 Colors color
= nextThing
.bonus
? BonusColor
: GridColor
;
930 Colors color2
= nextThing
.bonus
? BonusColor2
: GridColor2
;
932 dbgprintf(("Next color: %d, size: %d\n",nextThing
.color_number
,
934 x
=NEXT_CENTER_X
- nextThing
.size
*(NEXT_BOX_SIZE
+2)/2;
935 y
=NEXT_CENTER_Y
- nextThing
.size
*(NEXT_BOX_SIZE
+2)/2;
937 for (i
= 0; i
< nextThing
.size
; i
++)
938 for (j
= 0; j
< nextThing
.size
; j
++)
939 if (tris
[nextThing
.squares
].polyomino
940 [nextThing
.polyomino_number
].shape
[j
][i
])
942 dre
->draw_rect(x
+ (NEXT_BOX_SIZE
+2)*i
, y
+ (NEXT_BOX_SIZE
+2)*j
,
943 NEXT_BOX_SIZE
, NEXT_BOX_SIZE
, color
);
944 dre
->draw_rect(x
+ (NEXT_BOX_SIZE
+2)*i
+1, y
+ (NEXT_BOX_SIZE
+2)*j
+1,
945 NEXT_BOX_SIZE
-2, NEXT_BOX_SIZE
-2, color2
);
950 //===========================================================================
951 /// global clear_next()
952 /// Clear next figure
953 /// Currently not implemented
955 void WellBase::clear_next()
957 dre
->fill_rect(NEXT_CENTER_X
-NEXT_X_SIZE
/2+1,NEXT_CENTER_Y
-NEXT_Y_SIZE
/2+1,
958 NEXT_X_SIZE
-1,NEXT_Y_SIZE
-1,BackColor
);
961 //===========================================================================
962 /// global draw_status()
963 /// draw status of the game, i.e. scores, lines...
964 /// Currently not implemented
966 void WellBase::draw_status()
969 Score
*pscore2
=0,*pscore1
=0;
971 char buf2
[PLAYER_NAME_LEN
];
976 dbgprintf(("score: %d, lines: %d, level %d, levelup at: +%d\n",
977 score
, rows
, level
, rows_levelup
- rows
));
978 sprintf(buf
,"%d",score
);
979 txt_score
->set_text(buf
);
980 txt_score
->draw_text(RightJust
);
981 sprintf(buf
,"%d",rows
);
982 txt_lines
->set_text(buf
);
983 txt_lines
->draw_text(RightJust
);
984 sprintf(buf
,"+%d",rows_levelup
- rows
+ 1);
985 txt_levelup
->set_text(buf
);
986 txt_levelup
->draw_text(RightJust
);
987 sprintf(buf
,"%d",level
);
988 txt_level
->set_text(buf
);
989 txt_level
->draw_text(RightJust
);
990 dbgprintf(("score done\n"));
991 pscore2
=default_top_nine
->find_challenger(player_score
);
993 pscore1
=default_top_nine
->find_challenger(pscore2
);
998 delta_score
=pscore1
->score
- player_score
->score
;
999 delta_score
= delta_score
>=100000 ? 99999 : delta_score
;
1000 strncpy(buf2
,pscore1
->player
,CHAL_NAME_LEN
);
1001 buf2
[CHAL_NAME_LEN
]=0;
1002 sprintf(buf
,"%d.%-9s+%05d",pscore1
->place
,buf2
,
1004 dbgprintf(("draw_status: %s\n",buf
));
1005 txt_first
->set_text(buf
);
1006 txt_first
->draw_text();
1008 strncpy(buf2
,pscore2
->player
,CHAL_NAME_LEN
);
1009 buf2
[CHAL_NAME_LEN
]=0;
1010 delta_score
=pscore2
->score
- player_score
->score
;
1011 delta_score
= delta_score
>=100000 ? 99999 : delta_score
;
1012 sprintf(buf
,"%d.%-9s+%05d",pscore2
->place
,buf2
,
1014 txt_second
->set_text(buf
);
1015 txt_second
->draw_text();
1017 sprintf(buf
,"%d.You are here",pscore2
->place
+1);
1018 txt_third
->set_text(buf
);
1019 txt_third
->draw_text();
1024 strncpy(buf2
,pscore2
->player
,CHAL_NAME_LEN
);
1025 buf2
[CHAL_NAME_LEN
]=0;
1026 delta_score
=pscore2
->score
- player_score
->score
;
1027 delta_score
= delta_score
>=100000 ? 99999 : delta_score
;
1028 sprintf(buf
,"%d.%-9s+%05d",pscore2
->place
,buf2
,
1030 txt_first
->set_text(buf
);
1031 txt_first
->draw_text();
1033 sprintf(buf
,"%d.You are here",pscore2
->place
+1);
1034 txt_second
->set_text(buf
);
1035 txt_second
->draw_text();
1037 txt_third
->clear_region();
1040 sprintf(buf
,"%d.You are here",1);
1041 txt_first
->set_text(buf
);
1042 txt_first
->draw_text();
1044 txt_second
->clear_region();
1046 txt_third
->clear_region();
1050 default_well_engine
->screen_copy(&geo
[GEO_ROT_IDX
]);
1052 default_well_engine
->screen_copy(&geo
[GEO_NEXT_IDX
]);
1054 default_well_engine
->screen_copy(&geo
[GEO_MIXED_IDX
]);
1058 //===========================================================================
1059 /// global draw_grid()
1060 /// draw grid of the field
1062 void WellBase::draw_grid()
1067 //===========================================================================
1068 /// global drop_wall(int wall_num)
1069 /// Drop all squres on the wall to the floor after row is cleared
1071 void WellBase::drop_wall(int w
)
1073 int i
, j
, k
, l
, fits
, lines
, base_x
, base_y
;
1075 for (j
= MAX_DEPTH
- 1; j
>= 0 && lines
== 0; j
--)
1076 for (i
= 0; i
< MAX_WIDTH
; i
++)
1077 if (wall
[j
][w
* MAX_WIDTH
+ i
].pmid
!= EMPTY
)
1078 lines
= MAX_DEPTH
- j
;
1082 while (j
< (MAX_WIDTH
/ 2 + lines
- 1) && fits
) {
1084 for (l
= MAX_DEPTH
- j
; l
< MAX_DEPTH
; l
++)
1085 for (i
= 0; i
< MAX_WIDTH
; i
++)
1086 if (wall
[l
][w
* MAX_WIDTH
+ i
].pmid
!= EMPTY
) {
1087 wall_to_base(&base_x
, &base_y
,
1088 w
* MAX_WIDTH
+ i
, l
+ j
);
1089 if (base
[base_y
][base_x
].pmid
!= EMPTY
)
1097 for (l
= MAX_DEPTH
- 1; l
>= 0; l
--)
1098 for (i
= 0; i
< MAX_WIDTH
; i
++)
1099 if (wall
[l
][w
* MAX_WIDTH
+ i
].pmid
!= EMPTY
) {
1100 k
= w
* MAX_WIDTH
+ i
;
1101 if (l
+ j
>= MAX_DEPTH
) {
1102 wall_to_base(&base_x
, &base_y
, k
, l
+ j
);
1103 base
[base_y
][base_x
] = wall
[l
][k
];
1104 wall
[l
][k
].pmid
= EMPTY
;
1105 dre
->draw_trapazoid(BackColor
, k
, l
);
1106 dre
->draw_square(wall
[l
][k
].cid
, base_x
, base_y
);
1108 wall
[l
+ j
][k
] = wall
[l
][k
];
1109 wall
[l
][k
].pmid
= EMPTY
;
1110 dre
->draw_trapazoid(BackColor
, k
, l
);
1111 dre
->draw_trapazoid(wall
[l
][k
].cid
, k
, l
+ j
);
1122 //===========================================================================
1123 /// global all_frozen()
1124 /// True if all walls are frozen -> end of the game
1126 bool WellBase::all_frozen()
1130 for (w
= 0; w
< MAX_SIDES
; w
++)
1131 if (frozen_wall
[w
] == MAX_SIDES
) {
1134 for (w
= 0; w
< MAX_SIDES
; w
++)
1135 if (frozen_wall
[w
] == 0)
1140 //===========================================================================
1141 /// global check_freeze()
1142 /// Check frozen walls - decrease frozen counter and do defreeze
1145 void WellBase::check_freeze()
1148 bool all_frozen
=true;
1150 for (w
= 0; w
< MAX_SIDES
; w
++) {
1151 if (frozen_wall
[w
] == 0)
1159 if (frozen_wall
[w
] == 0)
1170 dbgprintf(("check_freeze - all frozen - doing game_over\n"));
1174 /* not all frozen else this is an infinite loop */
1175 /* curThing.xpos = (MAX_WIDTH - curThing.size) / 2; */
1176 curThing
.xpos
= NRAND(MAX_WIDTH
- curThing
.size
+ 1);
1178 w
= NRAND(MAX_SIDES
);
1179 } while (frozen_wall
[w
]); //Hmm, very strange method of choosing the wall???
1180 curThing
.xpos
+= w
* MAX_WIDTH
;
1183 //===========================================================================
1184 /// global check_lines()
1185 /// Checking for full lines on the floor and deleting it - make free space
1187 int WellBase::check_lines()
1189 int lSet
[2][MAX_WIDTH
], nset
[2];
1192 nset
[0] = nset
[1] = 0;
1194 //First check horizontal lines, increase nset[0] and lSet[0][line]
1195 for (j
= 0; j
< MAX_WIDTH
; j
++)
1198 for (i
= 0; i
< MAX_WIDTH
; i
++)
1199 if (base
[j
][i
].pmid
>= 0)
1201 if (lSet
[0][j
] == MAX_WIDTH
)
1204 //Then the same for vertical ones
1205 for (i
= 0; i
< MAX_WIDTH
; i
++)
1208 for (j
= 0; j
< MAX_WIDTH
; j
++)
1209 if (base
[j
][i
].pmid
>= 0)
1211 if (lSet
[1][i
] == MAX_WIDTH
)
1214 if (nset
[0] || nset
[1]) //If we have full lines
1216 // Now flashing full lines awhile
1217 for (k
= 0; k
< NUM_FLASHES
; k
++)
1220 color
=(k
%2) ? BackColor
: FlashColor
;
1221 for (j
= 0; j
< MAX_WIDTH
; j
++)
1223 if (lSet
[0][j
] == MAX_WIDTH
)
1225 for (i
= 0; i
< MAX_WIDTH
; i
++)
1226 dre
->draw_square(color
, i
, j
);
1228 if (lSet
[1][j
] == MAX_WIDTH
)
1230 for (i
= 0; i
< MAX_WIDTH
; i
++)
1231 dre
->draw_square(color
, j
, i
);
1236 udelay(FLUSH_DELAY
/2);
1239 if (nset
[0] > 0) //Now delete full horizontal lines
1240 for (j
= 0; j
< MAX_WIDTH
; j
++)
1241 if (lSet
[0][j
] == MAX_WIDTH
)
1243 if (j
< MAX_WIDTH
/ 2)
1244 //If upper part of field then move other lines down to center
1245 for (i
= 0; i
< MAX_WIDTH
; i
++)
1247 for (k
= j
; k
> 0; k
--)
1248 base
[k
][i
] = base
[k
- 1][i
];
1249 base
[0][i
].pmid
= EMPTY
;
1251 else //else move them up
1253 for (i
= 0; i
< MAX_WIDTH
; i
++)
1255 for (k
= j
; k
< MAX_WIDTH
- 1; k
++)
1256 base
[k
][i
] = base
[k
+ 1][i
];
1257 base
[MAX_WIDTH
- 1][i
].pmid
= EMPTY
;
1259 for (k
= j
; k
< MAX_WIDTH
- 1; k
++)
1260 //Fixing lSet position of moved lines
1261 lSet
[0][k
]=lSet
[0][k
+1];
1262 lSet
[0][MAX_WIDTH
-1]=0;
1266 if (nset
[1] > 0) //Do the same for vertical lines
1267 for (i
= 0; i
< MAX_WIDTH
; i
++)
1268 if (lSet
[1][i
] == MAX_WIDTH
)
1270 if (i
< MAX_WIDTH
/ 2)
1271 for (j
= 0; j
< MAX_WIDTH
; j
++)
1273 for (k
= i
; k
> 0; k
--)
1274 base
[j
][k
] = base
[j
][k
- 1];
1275 base
[j
][0].pmid
= EMPTY
;
1279 for (j
= 0; j
< MAX_WIDTH
; j
++)
1281 for (k
= i
; k
< MAX_WIDTH
- 1; k
++)
1282 base
[j
][k
] = base
[j
][k
+ 1];
1283 base
[j
][MAX_WIDTH
- 1].pmid
= EMPTY
;
1285 for (k
= i
; k
< MAX_WIDTH
- 1; k
++)
1286 lSet
[1][k
]=lSet
[1][k
+1];
1287 lSet
[1][MAX_WIDTH
-1]=0;
1292 //Now reDraw new field
1293 for (j
= 0; j
< MAX_WIDTH
; j
++)
1294 for (i
= 0; i
< MAX_WIDTH
; i
++)
1296 if (base
[j
][i
].pmid
>= 0)
1297 dre
->draw_square(base
[j
][i
].cid
, i
, j
);
1299 dre
->draw_square(BackColor
, i
, j
);
1301 //All done, beeping...
1308 return (nset
[0] + nset
[1]);
1312 //===========================================================================
1313 /// global check_update_lines()
1314 /// Calculating statistics ans SCORES! :) And redraw status
1316 void WellBase::check_update_lines()
1320 lines
= check_lines();
1321 score
+= lines
+ !gradualAppear
+ !grid
;
1322 mult
= showNext
? 5 : 7;
1323 mult
+= (rotation
? 1 : 0);
1324 score
+= mult
* level
* level
* lines
* lines
* lines
*
1325 squares
* squares
* (bonus
+ diagonal
+ 1) / (16 * (1 + mixed
));
1327 player_score
->set_params(score
,rows
,level
);
1328 if (rows
> rows_levelup
)
1334 player_score
->set_params(score
,rows
,level
);
1341 //===========================================================================
1342 /// global move_one_step(Actions move)
1343 /// Move figure one step down/left/right
1345 bool WellBase::move_one_step(Actions move
)
1347 if ((move
== DROP
) || ((move
== FALL
) && at_bottom())) {
1350 check_update_lines();
1356 dre
->sync(); /* discard all events */
1362 check_update_lines();
1367 if (rows
> THRESHOLD(level
)) {
1377 //===========================================================================
1378 /// global game_over()
1379 /// game is over :( you are looser
1381 void WellBase::game_over()
1383 dbgprintf(("WellBase::game_over() called\n"));
1385 player_score
->calc_play_time();
1386 player_score
=default_top_nine
->try_add_to_table(player_score
);
1387 delete player_score
;
1388 game_over_object
.call(wEvent(aGameOver
,this));
1391 //===========================================================================
1392 /// global redraw_all()
1395 void WellBase::redraw_all()
1407 while(steps_to_rotate
>0)
1411 udelay(FLUSH_DELAY
/10);
1417 //===========================================================================
1418 /// global make_pause()
1419 /// set/uset game pause
1421 void WellBase::make_pause()
1426 default_well_engine
->del_timer(this);
1427 dre
->clear_field(0);
1428 dre
->pixmap_copy(&geo
[GEO_PAUSE_IDX
]);
1433 default_well_engine
->add_timer(this,speeds
[level
]);
1434 dre
->clear_field(0);
1441 //===========================================================================
1442 /// global make_rotation()
1443 /// rotate field step by step
1445 void WellBase::make_rotation()
1447 dre
->outer_rotation();
1448 dre
->clear_field(0);
1455 //===========================================================================
1456 /// global process_event()
1457 /// process all events for this game object
1458 /// return false if we don't want to process this event for other objects
1460 bool WellBase::process_event(wEvent ev
)
1467 dbgprintf(("WellBase got time out event\n"));
1470 move_one_step(FALL
);
1481 dbgprintf(("WellBase got expose event\n"));
1491 action
=dre
->key_to_action(ev
.data
);
1494 return process_action(action
);
1514 //===========================================================================
1515 /// global process_action(Actions)
1516 /// process actions - moves/drops/other
1518 bool WellBase::process_action(Actions action
)
1529 move_one_step(action
);
1537 case OUTER_ROTATION
:
1550 if(level
+1<NUM_LEVELS
)