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