]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/g_tetris.qc
proper key repeat for tetris
[divverent/nexuiz.git] / data / qcsrc / server / g_tetris.qc
1 /*
2
3 Installation:
4
5 compile with -DTETRIS
6
7 */
8
9 #ifdef TETRIS
10
11 .vector tet_org;
12
13 .float tetris_on, tet_gameovertime, tet_drawtime, tet_autodown;
14 .vector piece_pos;
15 .float piece_type, next_piece, tet_score, tet_lines;
16
17 var float tet_high_score = 0;
18
19 float TET_LINES = 20;
20 float TET_WIDTH = 10;
21 //character values
22 float TET_BORDER = 132;
23 float TET_BLOCKS = 132; // +1 = first color, +2, +3;
24 float TET_SPACE = 32; // blankness
25
26
27
28 float TETKEY_UP = 1;
29 float TETKEY_DOWN = 2;
30 float TETKEY_LEFT = 4;
31 float TETKEY_RIGHT = 8;
32 float TETKEY_ROTLEFT = 16;
33 float TETKEY_ROTRIGHT = 32;
34 float TETKEY_DROP = 64;
35
36 float PIECES = 7;
37
38 .float line1, line2, line3, line4, line5, line6, line7,
39 line8, line9, line10, line11, line12, line13, line14, line15,
40 line16, line17, line18, line19, line20;
41
42
43 float   SVC_CENTERPRINTa                = 26;
44
45 float Tetris_Level()
46
47         return ((floor((self.tet_lines / 20)) + 1)); 
48 }; 
49
50 void tetsnd(string snd)
51 {
52         play2(self, strcat("sounds/tetris/", snd));
53 }
54
55 /*
56 *********************************
57
58 Library Functions
59
60 *********************************
61 */
62 void SetLine(float ln, float vl)
63 {
64         if (ln == 1)
65                 self.line1 = vl;
66         else if (ln == 2)
67                 self.line2 = vl;
68         else if (ln == 3)
69                 self.line3 = vl;
70         else if (ln == 4)
71                 self.line4 = vl;
72         else if (ln == 5)
73                 self.line5 = vl;
74         else if (ln == 6)
75                 self.line6 = vl;
76         else if (ln == 7)
77                 self.line7 = vl;
78         else if (ln == 8)
79                 self.line8 = vl;
80         else if (ln == 9)
81                 self.line9 = vl;
82         else if (ln == 10)
83                 self.line10 = vl;
84         else if (ln == 11)
85                 self.line11 = vl;
86         else if (ln == 12)
87                 self.line12 = vl;
88         else if (ln == 13)
89                 self.line13 = vl;
90         else if (ln == 14)
91                 self.line14 = vl;
92         else if (ln == 15)
93                 self.line15 = vl;
94         else if (ln == 16)
95                 self.line16 = vl;
96         else if (ln == 17)
97                 self.line17 = vl;
98         else if (ln == 18)
99                 self.line18 = vl;
100         else if (ln == 19)
101                 self.line19 = vl;
102         else if (ln == 20)
103                 self.line20 = vl;
104 };
105
106 float GetLine(float ln)
107 {
108         if (ln == 1)
109                 return self.line1;
110         else if (ln == 2)
111                 return self.line2;
112         else if (ln == 3)
113                 return self.line3;
114         else if (ln == 4)
115                 return self.line4;
116         else if (ln == 5)
117                 return self.line5;
118         else if (ln == 6)
119                 return self.line6;
120         else if (ln == 7)
121                 return self.line7;
122         else if (ln == 8)
123                 return self.line8;
124         else if (ln == 9)
125                 return self.line9;
126         else if (ln == 10)
127                 return self.line10;
128         else if (ln == 11)
129                 return self.line11;
130         else if (ln == 12)
131                 return self.line12;
132         else if (ln == 13)
133                 return self.line13;
134         else if (ln == 14)
135                 return self.line14;
136         else if (ln == 15)
137                 return self.line15;
138         else if (ln == 16)
139                 return self.line16;
140         else if (ln == 17)
141                 return self.line17;
142         else if (ln == 18)
143                 return self.line18;
144         else if (ln == 19)
145                 return self.line19;
146         else if (ln == 20)
147                 return self.line20;
148         else
149                 return 0;
150 };
151
152 float GetXBlock(float x, float dat)
153 {
154         if (x == 1)
155                 return dat & 3;
156         else if (x == 2)
157                 return (dat & 12) / 4;
158         else if (x == 3)
159                 return (dat & 48) / 16;
160         else if (x == 4)
161                 return (dat & 192) / 64;
162         else if (x == 5)
163                 return (dat & 768) / 256;
164         else if (x == 6)
165                 return (dat & 3072) / 1024;
166         else if (x == 7)
167                 return (dat & 12288) / 4096;
168         else if (x == 8)
169                 return (dat & 49152) / 16384;
170         else if (x == 9)
171                 return (dat & 196608) / 65536;
172         else if (x == 10)
173                 return (dat & 786432) / 262144;
174         else
175                 return 0;
176 };
177
178 float SetXBlock(float x, float dat, float new)
179 {
180         if (x == 1)
181                 return (dat - (dat & 3)) | new;
182         else if (x == 2)
183                 return (dat - (dat & 12)) | (new*4);
184         else if (x == 3)
185                 return (dat - (dat & 48)) | (new*16);
186         else if (x == 4)
187                 return (dat - (dat & 192)) | (new*64);
188         else if (x == 5)
189                 return (dat - (dat & 768)) | (new*256);
190         else if (x == 6)
191                 return (dat - (dat & 3072)) | (new*1024);
192         else if (x == 7)
193                 return (dat - (dat & 12288)) | (new*4096);
194         else if (x == 8)
195                 return (dat - (dat & 49152)) | (new*16384);
196         else if (x == 9)
197                 return (dat - (dat & 196608)) | (new*65536);
198         else if (x == 10)
199                 return (dat - (dat & 786432)) | (new*262144);
200         else
201                 return dat;
202 };
203
204
205 float GetSquare(float x, float y)
206 {
207         return GetXBlock(x,  GetLine(y));
208 };
209
210 void SetSquare(float x, float y, float val)
211 {
212         float dat;
213
214         dat = GetLine(y);
215         dat  = SetXBlock(x, dat, val & 3);
216         SetLine(y, dat);
217 };
218
219
220
221 vector PieceShape(float pc)
222 {
223
224 /*
225 1 =
226  ##
227  ##
228 */
229         if (pc == 1)
230                 return '5 5 2'; // 1 * 4 + 1 * 16
231 /*
232 2 =
233
234 ####
235 */
236         else if (pc == 2)
237                 return '85 0 4';
238
239 /*
240 3 =
241
242 ###
243 #
244 */
245         else if (pc == 3)
246                 return '21 1 3';
247 /*
248 4 =
249
250 #
251 ###
252 */
253         else if (pc == 4)
254                 return '1 21 3';
255 /*
256 5 =
257 ##
258  ##
259 */
260         else if (pc == 5)
261                 return '5 20 3';
262
263 /*
264 6 =
265  ##
266 ##
267 */
268         else if (pc == 6)
269                 return '20 5 3';
270
271 /*
272 7 =
273  #
274 ###
275 */
276         else if (pc == 7)
277                 return '4 21 3';
278
279
280         else
281                 return '0 0 0';
282
283 }
284
285 // do x 1..4 and y 1..4 in case of rotation
286 float PieceMetric(float x, float y, float rot, float pc)
287 {
288         float t;
289         vector piece_dat;
290         float wid;
291
292         // return bits of a piece
293         piece_dat = PieceShape(pc);
294         wid = piece_dat_z + 1;
295         if (rot == 1) // 90 degrees
296         {
297                 t = y;
298                 y = x;
299                 x = wid - t;
300         }
301         else if (rot == 2)//180
302         {
303                 x = wid - x;
304                 y = 3 - y;
305         }
306         else if (rot == 3) // 270
307         {
308                 t = y;
309                 y = wid - x;
310                 x = t;
311         }
312         if (x < 1 || y < 1 || x > 4 || y > 2)
313                 return 0;
314         if (y == 1)
315                 return GetXBlock(x, piece_dat_x); // first row
316         else if (y == 2)
317                 return GetXBlock(x, piece_dat_y); // second row
318         else if (y == 3)
319                 return GetXBlock(x, piece_dat_z); // third row (doesn't exist)
320         else
321                 return 0; // illegal parms
322 };
323 /*
324 *********************************
325
326 Draw
327
328 *********************************
329 */
330
331
332 /* some prydon gate functions to make life easier....
333
334 somewhat modified because we don't need all the fanciness Prydon Gate is capable of
335
336 */
337
338 // remove warnings by adding underscores, i hate warnings, warnings suck
339 // --blub
340 void p6(float _c1, float _c2, float _c3, float _c4, float c5, float c6)
341 {
342         WriteChar(MSG_ONE, _c1);
343         WriteChar(MSG_ONE, _c2);
344         WriteChar(MSG_ONE, _c3);
345         WriteChar(MSG_ONE, _c4);
346         WriteChar(MSG_ONE, c5);
347         WriteChar(MSG_ONE, c6);
348 };
349
350 float pnum(float num, float dig)
351 {
352         local float f, i;
353         if (num < 0)
354         {
355                 WriteChar(MSG_ONE, 45);
356                 num = 0 - num;
357         }
358         f = floor(num / 10);
359         num = num - (f * 10);
360         if (f)
361                 dig = pnum(f, dig+1);
362         else
363         {
364                 // pad to 6
365                 for (i = 0; i < (5 - dig); i = i + 1)
366                         WriteChar(MSG_ONE, TET_SPACE);
367         }
368         WriteChar(MSG_ONE, 48 + num);
369         return dig;
370 };
371
372 void DrawLine(float ln)
373 {
374         float x, d;
375         WriteChar(MSG_ONE, TET_BORDER);
376
377         for (x = 1; x <= TET_WIDTH; x = x + 1)
378         {
379                 d = GetSquare(x, ln);
380                 if (d)
381                         WriteChar(MSG_ONE, TET_BLOCKS + d);
382                 else
383                         WriteChar(MSG_ONE, TET_SPACE);
384         }
385         WriteChar(MSG_ONE, TET_BORDER);
386 }
387
388 void DrawPiece(float pc, float ln)
389 {
390         float x, d, piece_ln, pcolor;
391         vector piece_dat;
392         pcolor = pc & 3;
393         if (pcolor == 0) // 4
394                 pcolor = 1;
395         WriteChar(MSG_ONE, TET_SPACE); // pad to 6
396
397         piece_dat = PieceShape(pc);
398         if (ln == 1)
399                 piece_ln = piece_dat_x;
400         else
401                 piece_ln = piece_dat_y;
402         for (x = 1; x <= 4; x = x + 1)
403         {
404                 d = GetXBlock(x, piece_ln) * pcolor;
405                 if (d)
406                         WriteChar(MSG_ONE, TET_BLOCKS + d);
407                 else
408                         WriteChar(MSG_ONE, TET_SPACE);
409         }
410         WriteChar(MSG_ONE, TET_SPACE);  // pad to 6
411 }
412 void Draw_Tetris()
413 {
414         float i;
415         msg_entity = self;
416         WriteChar(MSG_ONE, SVC_CENTERPRINTa);
417         // decoration
418         for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
419                 WriteChar(MSG_ONE, TET_BORDER);
420         p6(' ', ' ', ' ', ' ', ' ', ' ');
421         WriteChar(MSG_ONE, 10);
422         for (i = 1; i <= TET_LINES; i = i + 1)
423         {
424                 if(self.tetris_on == 2 && i == 11)
425                 {
426                         p6(' ', ' ', ' ', ' ', ' ', ' ');
427                         p6(' ', 'G', 'A', 'M', 'E', ' ');
428                         p6(' ', 'O', 'V', 'E', 'R', ' ');
429                         WriteChar(MSG_ONE, 10);
430                         continue;
431                 }
432                 DrawLine(i);
433                 if (i == 1)
434                         p6(' ', 'N', 'E', 'X', 'T', ' ');
435                 else if (i == 3)
436                         DrawPiece(self.next_piece, 1);
437                 else if (i == 4)
438                         DrawPiece(self.next_piece, 2);
439                 else if (i == 6)
440                         p6(' ', 'L', 'I', 'N', 'E', 'S');
441                 else if (i == 7)
442                         pnum(self.tet_lines, 0);
443                 else if (i == 9)
444                         p6(' ', 'S', 'C', 'O', 'R', 'E');
445                 else if (i == 10)
446                         pnum(self.tet_score, 0);
447                 else if (i == 12)
448                         p6(' ', 'H', 'I', 'G', 'H', ' ');
449                 else if (i == 13)
450                         p6(' ', 'S', 'C', 'O', 'R', 'E');
451                 else if (i == 14)
452                         pnum(tet_high_score, 0);
453                 else if (i == 16)
454                         p6(' ', 'L', 'E', 'V', 'E', 'L');
455                 else if (i == 17)
456                         pnum(Tetris_Level(), 0);
457                 else
458                         p6(' ', ' ', ' ', ' ', ' ', ' ');
459                 WriteChar(MSG_ONE, 10);
460         }
461         // decoration
462
463         for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
464                 WriteChar(MSG_ONE, TET_BORDER);
465         p6(' ', ' ', ' ', ' ', ' ', ' ');
466         WriteChar(MSG_ONE, 10);
467         WriteChar(MSG_ONE, 0);
468 }
469 /*
470 *********************************
471
472 Game Functions
473
474 *********************************
475 */
476
477 // reset the game
478 void ResetTetris()
479 {
480         float i;
481
482         for (i=1; i<=TET_LINES; i = i + 1)
483                 SetLine(i, 0);
484         self.piece_pos = '0 0 0';
485         self.piece_type = 0;
486         self.next_piece = self.tet_lines = self.tet_score = 0;
487
488 };
489
490 void Tet_GameExit()
491 {
492         centerprint(self, "");
493         self.tetris_on = 0;
494         ResetTetris();
495         self.movetype = MOVETYPE_WALK;
496         stuffcmd(self, "loadfont user1 gfx/vera-sans\n");
497 };
498
499
500
501 /*
502 *********************************
503
504 Game Mechanics
505
506 *********************************
507 */
508 float RandomPiece()
509 {
510         return floor(random() * PIECES) + 1;
511 };
512
513 void TetAddScore(float n)
514 {
515         self.tet_score = self.tet_score + n * Tetris_Level();
516         if (self.tet_score > tet_high_score)
517                 tet_high_score = self.tet_score;
518 };
519 float CheckMetrics(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
520 {
521         // check to see if the piece, if moved to the locations will overlap
522
523         float x, y;
524         // why did I start counting from 1, damnit
525         orgx = orgx - 1;
526         orgy = orgy - 1;
527
528         for (y = 1; y < 5; y = y + 1)
529         {
530                 for (x = 1; x < 5; x = x + 1)
531                 {
532                         if (PieceMetric(x, y, rot, piece))
533                         {
534                                 if (GetSquare(x + orgx, y + orgy))
535                                         return FALSE; // uhoh, gonna hit something.
536                                 if (x+orgx<1 || x+orgx > TET_WIDTH || y+orgy<1 || y+orgy> TET_LINES)
537                                         return FALSE; // ouside the level
538                         }
539                 }
540         }
541         return TRUE;
542 }
543
544 void ClearPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
545 {
546
547         float x, y;
548         // why did I start counting from 1, damnit
549         orgx = orgx - 1;
550         orgy = orgy - 1;
551
552         for (y = 1; y < 5; y = y + 1)
553         {
554                 for (x = 1; x < 5; x = x + 1)
555                 {
556                         if (PieceMetric(x, y, rot, piece))
557                         {
558                                 SetSquare(x + orgx, y + orgy, 0);
559                         }
560                 }
561         }
562 }
563 void CementPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
564 {
565         float pcolor;
566         float x, y;
567         // why did I start counting from 1, damnit
568         orgx = orgx - 1;
569         orgy = orgy - 1;
570
571         pcolor = piece & 3;
572         if (pcolor == 0) // 4
573                 pcolor = 1;
574
575         for (y = 1; y < 5; y = y + 1)
576         {
577                 for (x = 1; x < 5; x = x + 1)
578                 {
579                         if (PieceMetric(x, y, rot, piece))
580                         {
581                                 SetSquare(x + orgx, y + orgy, pcolor);
582                         }
583                 }
584         }
585 }
586
587 float LINE_LOW = 349525;
588 float LINE_HIGH = 699050; // above number times 2
589
590 void CompletedLines()
591 {
592         float y, cleared, ln;
593
594         cleared = 0;
595         y = TET_LINES;
596         while(y >= 1)
597         {
598                 ln = GetLine(y);
599                 if (((ln & LINE_LOW) | ((ln & LINE_HIGH)/2)) == LINE_LOW)
600                         cleared = cleared + 1;
601                 else
602                         y = y - 1;
603                 ln = GetLine(y - cleared);
604                 SetLine(y, ln);
605         }
606         if(cleared == 4)
607                 tetsnd("tetris");
608         else if(cleared)
609                 tetsnd("tetline");
610         else
611                 tetsnd("tetland");
612         self.tet_lines = self.tet_lines + cleared;
613         TetAddScore(cleared * cleared * 10);
614 };
615
616 void HandleGame(float keyss)
617 {
618
619         // first off, we need to see if we need a new piece
620         vector piece_data;
621         vector check_pos;
622         vector old_pos;
623         float brand_new;
624         float i;
625         brand_new = 0;
626
627
628         if (self.piece_type == 0)
629         {
630                 self.piece_pos = '5 1 0'; // that's about middle top, we count from 1 ARGH
631                 if (self.next_piece)
632                         self.piece_type = self.next_piece;
633                 else
634                         self.piece_type = RandomPiece();
635                 self.next_piece =  RandomPiece();
636                 keyss = 0; // no movement first frame
637                 self.tet_autodown = time + 0.2;
638                 brand_new = 1;
639         }
640         else
641                 ClearPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
642
643         // next we need to check the piece metrics against what's on the level
644         // based on the key order
645
646         old_pos = check_pos = self.piece_pos;
647
648         float nudge;
649         nudge = 0;
650         if (keyss & TETKEY_RIGHT)
651         {
652                 check_pos_x = check_pos_x + 1;
653                 tetsnd("tetmove");
654         }
655         else if (keyss & TETKEY_LEFT)
656         {
657                 check_pos_x = check_pos_x - 1;
658                 tetsnd("tetmove");
659         }
660         else if (keyss & TETKEY_ROTRIGHT)
661         {
662                 check_pos_z = check_pos_z + 1;
663                 piece_data = PieceShape(self.piece_type);
664                 nudge = piece_data_z - 2;
665                 tetsnd("tetrot");
666         }
667         else if (keyss & TETKEY_ROTLEFT)
668         {
669                 check_pos_z = check_pos_z - 1;
670                 piece_data = PieceShape(self.piece_type);
671                 nudge = piece_data_z - 2;
672                 tetsnd("tetrot");
673         }
674         // bounds check
675         if (check_pos_z > 3)
676                 check_pos_z = 0;
677         else if (check_pos_z < 0)
678                 check_pos_z = 3;
679
680         // reality check
681         if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
682                 self.piece_pos = check_pos;
683         else if (brand_new)
684         {
685                 self.tetris_on = 2;
686                 self.tet_gameovertime = time + 2;
687                 return;
688         }
689         else
690         {
691                 for(i = 1; i <= nudge; ++i)
692                 {
693                         if(CheckMetrics(self.piece_type, check_pos_x + i, check_pos_y, check_pos_z))
694                         {
695                                 self.piece_pos = check_pos + '1 0 0' * i;
696                                 break;
697                         }
698                         else if(CheckMetrics(self.piece_type, check_pos_x - i, check_pos_y, check_pos_z))
699                         {
700                                 self.piece_pos = check_pos - '1 0 0' * i;
701                                 break;
702                         }
703                 }
704         }
705         check_pos = self.piece_pos;
706         if(keyss & TETKEY_DROP)
707         {
708                 // drop to bottom, but do NOT cement it yet
709                 // this allows sliding it
710                 ++check_pos_y;
711                 while(CheckMetrics(self.piece_type, check_pos_x, check_pos_y + 1, check_pos_z))
712                         ++check_pos_y;
713                 self.tet_autodown = time + 1 / Tetris_Level();
714         }
715         else if (keyss & TETKEY_DOWN)
716         {
717                 check_pos_y = check_pos_y + 1;
718                 self.tet_autodown = time + 1 / Tetris_Level();
719         }
720         else if (self.tet_autodown < time)
721         {
722                 check_pos_y = check_pos_y + 1;
723                 self.tet_autodown = time + 1 / Tetris_Level();
724         }
725         if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
726         {
727                 if(old_pos != check_pos)
728                         self.tet_drawtime = 0;
729                 self.piece_pos = check_pos;
730         }
731         else
732         {
733                 CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
734                 TetAddScore(1);
735                 CompletedLines();
736                 self.piece_type = 0;
737                 self.tet_drawtime = 0;
738                 return;
739         }
740         CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
741 };
742
743 /*
744 *********************************
745
746 Important Linking Into Quake stuff
747
748 *********************************
749 */
750
751
752 void TetrisImpulses(float imp)
753 {
754         if (imp != 100)
755                 return;
756         if(self.tetris_on != 1)
757         {
758                 self.tetris_on = 1;
759                 ResetTetris();
760                 self.tet_org = self.origin;
761                 self.movetype = MOVETYPE_NOCLIP;
762                 stuffcmd(self, "loadfont user1 gfx/conchars\n");
763         }
764         else
765         {
766                 Tet_GameExit();
767                 self.impulse = 0;
768         }
769 };
770
771
772 float TetrisPreFrame()
773 {
774         if (!self.tetris_on)
775                 return 0;
776
777         self.tet_org = self.origin;
778         if (self.tet_drawtime > time)
779                 return 1;
780         Draw_Tetris();
781         self.tet_drawtime = time + 0.5;
782         return 1;
783 };
784 float frik_anglemoda(float v)
785 {
786         return v - floor(v/360) * 360;
787 };
788 float angcompa(float y1, float y2)
789 {
790         y1 = frik_anglemoda(y1);
791         y2 = frik_anglemoda(y2);
792
793         local float answer;
794         answer = y1 - y2;
795         if (answer > 180)
796                 answer = answer - 360;
797         else if (answer < -180)
798                 answer = answer + 360;
799         return answer;
800 };
801
802 .float tetkey_down, tetkey_rotright, tetkey_left, tetkey_right, tetkey_rotleft, tetkey_drop;
803
804 float TetrisKeyRepeat(.float fld, float f)
805 {
806         if(f)
807         {
808                 if(self.fld == 0) // initial key press
809                 {
810                         self.fld = time + 0.3;
811                         return 1;
812                 }
813                 else if(time > self.fld)
814                 {
815                         self.fld = time + 0.1;
816                         return 1;
817                 }
818                 else
819                 {
820                         // repeating too fast
821                         return 0;
822                 }
823         }
824         else
825         {
826                 self.fld = 0;
827                 return 0;
828         }
829 }
830
831 float TetrisPostFrame()
832 {
833         float keysa, keysb;
834
835         keysa = 0;
836
837         if (!self.tetris_on)
838                 return 0;
839         if(self.tetris_on == 2 && time > self.tet_gameovertime)
840         {
841                 Tet_GameExit();
842                 return 0;
843         }
844         
845         self.origin = self.tet_org;
846
847         if(self.tetris_on == 1)
848         {
849                 if(TetrisKeyRepeat(tetkey_down, self.movement_x < 0))
850                         keysa |= TETKEY_DOWN;
851
852                 if(TetrisKeyRepeat(tetkey_rotright, self.movement_x > 0))
853                         keysa |= TETKEY_ROTRIGHT;
854
855                 if(TetrisKeyRepeat(tetkey_left, self.movement_y < 0))
856                         keysa |= TETKEY_LEFT;
857
858                 if(TetrisKeyRepeat(tetkey_right, self.movement_y > 0))
859                         keysa |= TETKEY_RIGHT;
860                 
861                 if(TetrisKeyRepeat(tetkey_rotleft, self.BUTTON_CROUCH))
862                         keysa = keysa | TETKEY_ROTLEFT;
863
864                 if(TetrisKeyRepeat(tetkey_drop, self.BUTTON_JUMP))
865                         keysa = keysa | TETKEY_DROP;
866
867                 HandleGame(keysa);
868         }
869
870         return 1;
871 };
872
873 #endif