1 /*
2  *		     PLEASE DO NOT EDIT THIS FILE
3  *		see documentation for more information
4  *
5  *
6  *                  System Independent Trojka Core
7  *                Copyright (c) 1989-1996 Maarten Los
8  *                             --------
9  */
10 static char *_TROJKA_CORE_TAG_ = "System Independent Trojka Core 1.1";
11 
12 #include "tr_core.h"
13 
14 #include <stdlib.h>
15 #include <time.h>
16 
17 /*
18  *	variables
19  */
20 tt_char		tv_field[tc_v_xsize][tc_v_ysize];  /* the playing matrix */
21 tt_char		tv_shadow[tc_v_xsize][tc_v_ysize]; /* shadow of it for scan */
22 tt_int		tv_shape;		/* the current block */
23 tt_long		tv_block_count[tc_blocks];	/* blocks/type */
24 tt_long		tv_blocks;		/* total blocks */
25 tt_long		tv_last_blocks;		/* total blocks */
26 tt_bool		tv_blocks_reset;	/* true if tv_blocks > MAXLONG */
27 tt_int		tv_x;		/* x position in field */
28 tt_int		tv_y;		/* y position in field */
29 tt_int		tv_speed;	/* current speed (0-9) */
30 tt_int		tv_ticks;	/* number of ticks in milliseconds for delay */
31 tt_int		tv_stacklevel;	/* height of the block stack */
32 tt_long		tv_score;	/* the score */
33 tt_long		tv_last_score;	/* the last score */
34 tt_bool		tv_score_reset;	/* true  if tv_score > MAXLONG */
35 tt_long		tv_trojkas;	/* number of trojka's */
36 tt_long		tv_last_trojkas;	/* the last number of trojkas */
37 tt_bool		tv_trojkas_reset;	/* true if tv_trojkas > MAXLONG */
38 tt_long		tv_wipes;	/* number of wipes */
39 tt_long		tv_last_wipes;	/* number of wipes */
40 tt_long		tv_wipes_reset;	/* true if tv_wipes > MAXLONG */
41 tt_long		tv_speed_switch;	/* score for spead increase */
42 tt_long		tv_wizard_switch;	/* score for next layout */
43 tt_bool		tv_is_wizard;	/* are we in wizard mode? */
44 tt_bool		tv_is_gaps;	/* are there gaps in the field pattern? */
45 tt_int		tv_lran_q_ptr;	/* layout random pointer */
46 tt_int		tv_lran_q[tc_layouts];
47 tt_int 		tv_layout[tc_layouts][5] =
48 {	{ 011331, 024413, 040000,      0,      0 },
49 	{ 010101, 040303, 010101, 040303, 010101 },
50 	{ 001210, 040004, 030003, 030003, 002120 },
51 	{ 010101, 000003, 030303, 000000, 040404 },
52 	{ 020202, 005050, 040404, 003030, 010101 },
53 	{ 035353, 041014, 040204,      0,      0 },
54 	{ 054245, 050005, 050005, 002020, 000200 },
55 	{ 010001, 031013, 011011, 031013, 010001 },
56 	{ 030003, 001130, 003110, 001130, 030003 },
57 	{ 011511, 040004, 020202, 040004, 011511 },
58 	{ 025341, 050000, 030350, 040010, 014320 },
59 	{ 010201, 021212, 003003, 001010, 010001 },
60 	{ 000300, 000300, 000300, 000300, 054345 },
61 	{      0, 005050, 033133, 005050,      0 },
62 	{ 000400, 000300, 000200, 000300, 000400 },
63 	{ 000300, 001010, 040004, 001010, 000300 },
64 	{ 013531, 002520, 000400, 002520, 013531 },
65 	{ 000300, 000400, 010501, 005050, 000500 },
66 	{ 000200, 000400, 033533, 000400, 000200 },
67 	{ 030303, 001010, 000400, 000200, 000200 },
68 	{ 010001, 003030, 000100, 003030, 010001 },
69 	{ 004240, 030003,      0, 004040,      0 },
70 	{ 000100, 004040, 030303, 020202, 050505 },
71 	{ 050505, 053535, 003030, 023232, 020202 },
72 	{ 055355, 005000, 000300, 000050, 055355 },
73 	{ 053535, 030203, 052525, 030203, 053535 },
74 	{ 052505, 030303, 010101, 030303, 050525 },
75 	{      0,      0,      0,      0, 055455 },
76 	{ 004253,      0, 031450,      0, 002143 },
77 	{ 053035, 002120, 053035, 002120, 053035 },
78 	{ 012121, 004340, 000300, 004340, 012121 },
79 	{ 005250, 020502, 012021, 020502, 005250 },
80 	{ 011022, 011022,      0, 033055, 033055 },
81 	{ 010001, 053035, 012421, 053035, 010001 },
82 	{ 043035, 020003, 020003, 020003, 043035 },
83 	{ 000055, 003300, 020000, 001100, 000044 },
84 	{ 033033, 000500, 005050, 002020, 004040 },
85 	{ 011000, 001100, 000440, 000044,      0 },
86 	{ 010001, 000300, 003530, 000300, 010001 },
87 	{ 000550, 000550, 033000, 033000,      0 },
88 	{ 055055, 044044, 033033, 022022, 011011 },
89 	{ 055110, 033550, 022330, 044220, 011440 }
90 };
91 
92 /*
93  *	function prototypes
94  */
95 int	trojka_api(tt_command*);
96 void	tf_init(int, int);
97 int	tf_block_down(void);
98 void	tf_block_left(void);
99 void	tf_block_right(void);
100 void	tf_drop_block(void);
101 void	tf_check_speed(void);
102 void	tf_inc_speed(void);
103 void	tf_set_speed_var(void);
104 void	tf_check_wizard(void);
105 void	tf_set_wizard_switch(void);
106 void	tf_inc_score(int, tt_long);
107 void	tf_scan(void);
108 int	tf_field_scan(void);
109 void	tf_check_spider(void);
110 tt_bool	tf_has_gaps(void);
111 void	tf_shift_blocks(void);
112 void	tf_shift_down(int, int);
113 void	tf_explode(int, int);
114 int	tf_get_stack_level(void);
115 tt_bool tf_empty_row(int);
116 void	tf_reset_shadow(void);
117 void	tf_reset_block(void);
118 void	tf_build_layout(void);
119 void	tf_init_layout_random_q(void);
120 void	tf_draw_field(void);
121 int	tf_get_layout_random(void);
122 void	tf_constrain_speed(tt_int);
123 
124 
125 /********************************************************************
126  * MAIN FUNCTIONS                                                   *
127  ********************************************************************/
128 
129 
trojka_api(cmd)130 int trojka_api(cmd)
131 tt_command *cmd;
132 {
133 	/*
134 	 *	this is the main api to the core. The function can
135 	 *	be given multiple commands.
136 	 *	The return value and the parameters passed depend
137 	 *	on the command. See documentation.
138 	 */
139 	int res;	/* call-result */
140 
141 	res = tc_res_normal;
142 
143 
144 	switch(cmd->command) {
145 		case tc_c_init:
146 			tf_init((tt_int)cmd->param1, (tt_bool)cmd->param2);
147 			break;
148 
149 		case tc_c_drawfield:
150 			tf_draw_field();
151 			break;
152 
153 		case tc_c_blockdown:
154 			res = tf_block_down();
155 			break;
156 
157 		case tc_c_blockleft:
158 			tf_block_left();
159 			break;
160 
161 		case tc_c_blockright:
162 			tf_block_right();
163 			break;
164 
165 		case tc_c_dropblock:
166 			tf_drop_block();
167 			break;
168 
169 		case tc_c_speedup:
170 			tf_inc_speed();
171 			break;
172 
173 		case tc_c_setspeed:
174 			tf_constrain_speed((tt_int)cmd->param1);
175 			tf_set_speed_var();
176 			break;
177 
178 		case tc_c_setwizard:
179 			tv_is_wizard = 1;
180 			break;
181 
182 	}
183 
184 	return res;
185 }
186 
187 
188 /*********************************************************************
189  *	basic functions, called by the api.
190  *********************************************************************/
191 
192 
tf_init(speed,wizard)193 void tf_init(speed, wizard)
194 tt_int speed;
195 tt_bool wizard;
196 /*
197  *	initialize the game
198  */
199 {
200 	int x,y;
201 
202 	/*
203 	 *	reset the variables
204  	 */
205 	tv_stacklevel = 0;
206 	tv_blocks = tv_last_blocks = (tt_long)0;
207 	tv_trojkas = tv_last_trojkas = (tt_long)0;
208 	tv_wipes = tv_last_wipes = (tt_long)0;
209 	tv_score = tv_last_score = (tt_long)0;
210 	tv_is_wizard = wizard;
211 
212 	tf_set_wizard_switch();
213 
214 	tv_blocks_reset = 0;
215 	tv_trojkas_reset = 0;
216 	tv_wipes_reset = 0;
217 	tv_score_reset = 0;
218 
219 	tf_constrain_speed(speed);
220 
221 	tf_set_speed_var();
222 	tf_reset_block();
223 
224 	for(x = 0; x < tc_blocks; x++)
225 		tv_block_count[x] = (tt_long)0;
226 
227 
228 	/*
229 	 *	clear the playfield
230 	 */
231 	for(x = 0; x < tc_v_xsize; x++)	/* clear virt. field */
232 		for(y = 1; y < tc_v_ysize; y++)
233 			tv_field[x][y] = tc_clear;
234 	for(x = 0;x < tc_v_xsize; x++)		/* fill bottom-line */
235 		tv_field[x][0] = tc_tagged;
236 
237 	/*
238 	 *	init the layout queue
239 	 */
240 	tf_init_layout_random_q();
241 
242 	if(tv_is_wizard)
243 		tf_build_layout();
244 }
245 
246 
247 
tf_draw_field(void)248 void tf_draw_field(void)
249 /*
250  *	draws the field, and puts a layout on it, if in
251  *	wizard mode
252  */
253 {
254 	int x,y;
255 
256 	/*
257 	 *	draw all the blocks in the entire field
258 	 */
259 	for(y = tc_pm_top; y >= tc_pm_bottom; y--) {
260 		for(x = 0; x < tc_v_xsize; x++)
261 			trojka_make_block_callback(x,y,tv_field[x][y]);
262 	}
263 
264 	if(tv_y <= tc_pm_top + 1)
265 		trojka_make_block_callback(tv_x, tv_y, tv_shape);
266 }
267 
268 
269 
tf_block_down(void)270 int tf_block_down(void)
271 /*
272  *	move the block one down
273  *
274  *	returns one of the following:
275  *		tc_res_touchdown	a block hit the ground
276  *		tc_res_gameover		the game is over
277  *		tc_res_normal		continue normal play
278  *
279  */
280 {
281 	tv_y--;
282 	if(tv_field[tv_x][tv_y] != tc_clear) {
283 
284 		/*
285 		 *	the block has hit something
286 		 */
287 
288 		tv_field[tv_x][tv_y + 1] = tv_shape;
289 
290 
291 		if(tv_blocks_reset)
292 			tv_blocks_reset = 0;
293 		if(tv_blocks < tv_last_blocks) {
294 			tv_blocks = (tt_long)0;
295 			tv_blocks_reset = 1;
296 		}
297 		tv_last_blocks = tv_blocks;
298 		tv_blocks++;
299 
300 
301 		tv_block_count[tv_shape-1]++;
302 
303 		tf_check_speed();
304 
305 		tf_reset_block();
306 
307 		tf_inc_score(tc_i_touchdown,0);
308 
309 		tf_scan();
310 
311 		if(tv_stacklevel == tc_pm_top)
312 			return tc_res_gameover;
313 
314 		tf_check_wizard();
315 
316 		return tc_res_touchdown;
317 
318 	} else {
319 		trojka_wipe_block_callback(tv_x, tv_y+1);
320 		trojka_make_block_callback(tv_x, tv_y, tv_shape);
321 
322 		return tc_res_normal;
323 	}
324 }
325 
326 
327 
tf_block_left(void)328 void tf_block_left(void)
329 /*
330  *	this function move the block one position to the left,
331  *	if possible
332  */
333 {
334 	if((tv_x > 0) && (tv_field[tv_x-1][tv_y] == tc_clear)) {
335 
336 			trojka_wipe_block_callback(tv_x, tv_y);
337 			tv_x--;
338 			trojka_make_block_callback(tv_x, tv_y, tv_shape);
339 	}
340 }
341 
342 
tf_block_right(void)343 void tf_block_right(void)
344 /*
345  *	this function move the block one position to the right,
346  *	if possible
347  */
348 {
349 	if((tv_x < tc_v_xsize-1) && (tv_field[tv_x+1][tv_y] == tc_clear)) {
350 		trojka_wipe_block_callback(tv_x, tv_y);
351 		tv_x++;
352 		trojka_make_block_callback(tv_x, tv_y, tv_shape);
353 	}
354 }
355 
356 
tf_drop_block(void)357 void tf_drop_block(void)
358 /*
359  *	drop a block until the bottom is reached
360  */
361 {
362 	tf_inc_score(tc_i_dropblock, 0);
363 
364 	trojka_wipe_block_callback(tv_x, tv_y);
365 	while(tv_field[tv_x][tv_y] == tc_clear)
366 		tv_y--;
367 	tv_y++;
368 	trojka_make_block_callback(tv_x, tv_y, tv_shape);
369 }
370 
371 
372 /**********************************************************************
373  *	support functions
374  **********************************************************************/
375 
376 
tf_check_speed(void)377 void tf_check_speed(void)
378 /*
379  *	Increase the game speed if possible
380  */
381 {
382 	if(tv_blocks > tv_speed_switch)
383 		tf_inc_speed();
384 }
385 
386 
tf_inc_speed(void)387 void tf_inc_speed(void)
388 /*
389  *	increase the speed. This function is called forcedly
390  *	on a manual speed increase, and implicitely by
391  *	'tf_check_speed()'
392  */
393 {
394 	if(tv_speed < tc_max_speed) {
395 		tv_speed++;
396 		tf_set_speed_var();
397 		trojka_speedup_callback(tv_speed);
398 	}
399 }
400 
401 
tf_set_speed_var(void)402 void tf_set_speed_var(void)
403 /*
404  *	this function sets the parameters depending on speed
405  */
406 {
407 	tv_ticks = 200 - ((tv_speed)*15);
408 	tv_speed_switch = tc_speed_switch * tv_speed;
409 }
410 
411 
tf_check_wizard(void)412 void tf_check_wizard(void)
413 /*
414  *	See if wizard needs a layout. If so, put a new layout
415  *	in the playfield.
416  *	Returns 1 on wizard change, 0 otherwise
417  *	Only call after a tf_scanfield() ! ! ! ! !
418  */
419 {
420 	if(!tv_is_wizard)
421 		return;
422 
423 	if((!tv_is_gaps) && (tv_score > tv_wizard_switch)
424 	&& (tv_stacklevel <= 9)) {
425 		tf_build_layout();
426 		tf_draw_field();
427 		tf_set_wizard_switch();
428 	}
429 }
430 
tf_set_wizard_switch()431 void tf_set_wizard_switch()
432 /*
433  *	set the wizard switch. (it is called from 'check_wizard' and
434  *	'init_game()'
435  */
436 {
437 	tv_wizard_switch = tv_score + (tt_long)(2+((rand()%10))*500)+2000;
438 }
439 
tf_inc_score(type,amount)440 void tf_inc_score(type, amount)
441 int type;
442 tt_long amount;
443 /*
444  *	increase the score depending on the type in the call:
445  *	tc_i_touchdown:	the block has just normally hit another block
446  *			or the ground
447  *	tc_i_dropblock:	the drop is forcedly dropped
448  *	tc_i_force:	add the amount 'amount' to the score.
449  */
450 {
451 	tt_long add;
452 
453 	switch(type) {
454 
455 	  case tc_i_touchdown:
456 		add = (tt_long)((((tv_shape*tv_speed)+(tv_speed-1))/3)+1);
457 		break;
458 
459 	  case tc_i_dropblock:
460 		add =  (tt_long)((tv_y * tv_speed) / 5);
461 		break;
462 
463 	  case tc_i_force:
464 		add = amount;
465 		break;
466 	}
467 
468 	if(tv_is_wizard)
469 		add += 2 + (rand() % tc_blocks);
470 
471 	if(tv_score_reset)
472 		tv_score_reset = 0;
473 
474 	if(tv_last_score > tv_score) {
475 		tv_score_reset = 1;
476 		tv_score = (tt_long)0;
477 	}
478 	tv_last_score = tv_score;
479 	tv_score += add;
480 
481 }
482 
483 
484 
tf_scan(void)485 void tf_scan(void)
486 {
487 /*
488  *	NOTE: this is a very inefficient algorithm!
489  *	Return values:
490  *		height of blockstack
491  *
492  */
493 	tt_long	trojka_score;
494 
495 	int wipe_bonus, wipe_count, wiped;
496 
497 	tv_stacklevel = tf_get_stack_level();
498 	wiped = 0;
499 
500 
501 	trojka_score = (tt_long)tc_trojkabonus;
502 	wipe_bonus = 1;
503 	wipe_count = 0;
504 	tf_reset_shadow();
505 
506 	while((wiped = tf_field_scan()) > 0) {
507 
508 		tf_shift_blocks();
509 
510 		wipe_bonus *= 2;
511 		tf_inc_score(tc_i_force, (tt_long)(wipe_bonus*wiped*10));
512 
513 		wipe_count++;
514 		if(((int)wipe_count % tc_trojka) == 0) {
515 
516 			tf_inc_score(tc_i_force, trojka_score);
517 			trojka_trojka_callback(trojka_score);
518 
519 			trojka_score *= 2;
520 
521 			if(tv_trojkas_reset)
522 				tv_trojkas_reset = 0;
523 			if(tv_trojkas < tv_last_trojkas) {
524 				tv_trojkas = (tt_long)0;
525 				tv_trojkas_reset = 1;
526 			}
527 			tv_last_trojkas = tv_trojkas;
528 			tv_trojkas++;
529 
530 		}
531 
532 		if(tv_wipes_reset)
533 			tv_wipes_reset = 0;
534 		if(tv_wipes < tv_last_wipes) {
535 			tv_wipes = (tt_long)0;
536 			tv_wipes_reset = 1;
537 		}
538 		tv_last_wipes = tv_wipes;
539 		tv_wipes++;
540 	}
541 
542 	if((tv_stacklevel <= tc_pm_bottom) && (tv_wipes > 0)
543 	&& (tf_empty_row(tc_pm_bottom)))
544 	{
545 		tf_inc_score(tc_i_force, tc_bottombonus);
546 		trojka_bottom_callback(tc_bottombonus);
547 	}
548 
549 	tv_is_gaps = tf_has_gaps();
550 
551 }
552 
553 
554 
tf_field_scan(void)555 int tf_field_scan(void)
556 /*
557  *	do an actual scan of the playing matrix
558  *	returns the number of wipes times 3.
559  */
560 {
561 	tt_int x,y, wiped;
562 	tt_char cur;
563 
564 	tv_stacklevel = tf_get_stack_level();
565 
566 
567 	wiped = 0;
568 
569 	tf_check_spider();
570 
571 	for(x = 1; x < tc_v_xsize - 1; x++) {
572 		for(y = tv_stacklevel; y >= tc_pm_bottom; y--) {
573 			if((cur = tv_field[x][y]) > 0) {
574 /* "\" */			if ((tv_field[x-1][y-1] == cur)
575 				&& (tv_field[x+1][y+1] == cur)) {
576 				   tv_shadow[x-1][y-1]
577 					= tv_shadow[x+1][y+1]
578 					= tv_shadow[x][y] = tc_tagged;
579 				   wiped++;
580 				}
581 /* "/" */			if ((tv_field[x-1][y+1] == cur)
582 				&& (tv_field[x+1][y-1] == cur)) {
583 				   tv_shadow[x-1][y+1]
584 					= tv_shadow[x][y]
585 					= tv_shadow[x+1][y-1] = tc_tagged;
586 				   wiped++;
587 				}
588 /* "--" */			if ((tv_field[x-1][y] == cur)
589 				&& (tv_field[x+1][y] == cur)) {
590 				   tv_shadow[x-1][y]
591 					= tv_shadow[x+1][y]
592 					= tv_shadow[x][y] = tc_tagged;
593 				   wiped++;
594 				}
595 			}
596 		}
597 	}
598 	return wiped * 3;
599 }
600 
601 
tf_check_spider(void)602 void tf_check_spider(void)
603 {
604 	tt_long spider_score;
605 	tt_char cur;
606 	tt_int y;
607 
608 	for(y = tv_stacklevel; y >= (tc_pm_bottom + 2); y--) {
609 	/*
610 	 *	ok, what follows is not your typical fine art of programming,
611 	 *	but it should do it.
612 	 */
613 		spider_score = (tt_long)0;
614 		if((cur = tv_field[tc_virt_middle][y]) <= 0)
615 			cur = -9;
616 
617 		if((cur == tv_field[tc_virt_middle-1][y+1])
618 		&& (cur == tv_field[tc_virt_middle-2][y+2])
619 		&& (cur == tv_field[tc_virt_middle+1][y+1])
620 		&& (cur == tv_field[tc_virt_middle+2][y+2])
621 		&& (cur == tv_field[tc_virt_middle+1][y-1])
622 		&& (cur == tv_field[tc_virt_middle+2][y-2])
623 		&& (cur == tv_field[tc_virt_middle-1][y-1])
624 		&& (cur == tv_field[tc_virt_middle-2][y-2])) {
625 
626 			spider_score = tc_spiderbonus;
627 
628 			if((cur == tv_field[tc_virt_middle-1][y])
629 			&& (cur == tv_field[tc_virt_middle-2][y])
630 			&& (cur == tv_field[tc_virt_middle+1][y])
631 			&& (cur == tv_field[tc_virt_middle+2][y])) {
632 
633 				spider_score = tc_bigspiderbonus;
634 
635 			}
636 
637 			tf_inc_score(tc_i_force, spider_score);
638 			trojka_spider_callback(spider_score);
639 
640 		}
641 	}
642 }
643 
644 
tf_has_gaps(void)645 tt_bool tf_has_gaps(void)
646 {
647 	int x,y;
648 	tt_bool gap_found;
649 
650 	for(x = 0; x < tc_v_xsize; x++) {
651 		gap_found = 0;
652 		for(y = tc_pm_bottom; y < tv_stacklevel; y++) {
653 			if((tv_field[x][y] > 0) && (gap_found))
654 				return 1;
655 			else if(tv_field[x][y] == 0)
656 				gap_found = 1;
657 		}
658 	}
659 	return 0;
660 }
661 
662 
tf_shift_blocks(void)663 void tf_shift_blocks(void)
664 /*
665  *	shift all the blocks in the playing field,
666  *	after a collapse.
667  */
668 {
669 	int x, y;
670 
671 	for(x = 0; x < tc_v_xsize; x++) {
672 		for(y = tv_stacklevel; y > 0; y--) {
673 			if(tv_shadow[x][y] == tc_tagged) {
674 				tf_explode(x, y);
675 				tf_shift_down(x, y);
676 				tv_shadow[x][y] = tc_clear;
677 			}
678 		}
679 	}
680 }
681 
682 
683 
tf_shift_down(x,y)684 void tf_shift_down(x, y)
685 int x, y;
686 /*
687  *	shift down a row of blocks, both  on-screen and in the matrix
688  */
689 {
690 	while(tv_field[x][y] != tc_clear) {
691 		tv_field[x][y] = tv_field[x][y+1];
692 		trojka_make_block_callback(x, y, tv_field[x][y]);
693 		y++;
694 	}
695 }
696 
697 
tf_explode(x,y)698 void tf_explode(x, y)
699 int x, y;
700 {
701 	trojka_explode_callback(x,y);
702 	trojka_wipe_block_callback(x,y);
703 }
704 
705 
tf_get_stack_level(void)706 int tf_get_stack_level(void)
707 /*
708  *	returns the last empty line in the virtual field
709  */
710 {
711 	int y = tc_pm_top;
712 
713 	while(tf_empty_row(y))
714 		y--;
715 
716 	return y ;
717 }
718 
719 
tf_empty_row(y)720 tt_bool tf_empty_row(y)
721 int y;
722 {
723 	int x;
724 
725 	for(x = 0; x < tc_v_xsize; x++)
726 		if(tv_field[x][y] != tc_clear)
727 			return 0;
728 	return 1;
729 }
730 
731 
tf_reset_shadow(void)732 void tf_reset_shadow(void)
733 {
734 	int x,y;
735 
736 	for(x = 0; x < tc_v_xsize;x++)
737 		for(y = 0; y < tc_v_ysize;y++)
738 			tv_shadow[x][y] = tc_clear;
739 }
740 
741 
tf_reset_block(void)742 void tf_reset_block(void)
743 /*
744  *	reset the falling block to the top of the playing field
745  *
746  */
747 {
748 	tv_y = tc_pm_top + 1;
749 	tv_x = tc_virt_middle;
750 	tv_shape = (rand() % tc_blocks) + 1;
751 
752 }
753 
754 /**********************************************************************
755  *	layout functions
756  **********************************************************************/
757 
758 
tf_build_layout(void)759 void tf_build_layout(void)
760 /*
761  *	put a layout patter in the playing field (but don't draw it)
762  */
763 {
764 	int x,y;
765 	int pattern;
766 	tt_char block;
767 	int layout = tf_get_layout_random();
768 
769 	for(y = tc_pm_bottom; y < (tc_pm_bottom + 5); y++) {
770 		for(x = 0; x < tc_blocks; x++) {
771 			pattern = tv_layout[layout][y-1];
772 			block = (pattern >> (x*3)) & tc_layout_mask;
773 			tv_field[x][y] = block;
774 		}
775 	}
776 }
777 
778 
779 
tf_init_layout_random_q(void)780 void tf_init_layout_random_q(void)
781 /*
782  *	initialize the random queue
783  */
784 {
785 	int i;
786 	srand(time(0));
787 
788 	tv_lran_q_ptr = tc_layouts;
789 	for(i = 0; i < tv_lran_q_ptr; i++)
790 		tv_lran_q[i] = i;
791 }
792 
793 
tf_get_layout_random(void)794 int tf_get_layout_random(void)
795 /*
796  *	get a random queue element, and swap it with one already
797  *	used
798  */
799 {
800 	int rnd;
801 
802 	rnd = tv_lran_q[rand() % tv_lran_q_ptr];
803 
804 	tv_lran_q[rnd] = tv_lran_q[--tv_lran_q_ptr];
805 	tv_lran_q[tv_lran_q_ptr] = rnd;
806 
807 	if(tv_lran_q_ptr == 0)
808 		tf_init_layout_random_q();
809 
810 	return rnd;
811 }
812 
813 
tf_constrain_speed(speed)814 void tf_constrain_speed(speed)
815 int speed;
816 /*
817  * constrain the speed between a value of 1 and 9
818  */
819 {
820 	tv_speed = (speed > tc_max_speed) ? tc_max_speed :
821 					(speed < tc_min_speed) ? 1 : speed;
822 }
823