14 .float tetris_on, tet_gameovertime, tet_drawtime, tet_autodown;
16 .float piece_type, next_piece, tet_score, tet_lines;
18 var float tet_high_score = 0;
23 float TET_BORDER = 132;
24 float TET_BLOCKS = 132; // +1 = first color, +2, +3;
25 float TET_SPACE = 32; // blankness
30 float TETKEY_DOWN = 2;
31 float TETKEY_LEFT = 4;
32 float TETKEY_RIGHT = 8;
33 float TETKEY_ROTLEFT = 16;
34 float TETKEY_ROTRIGHT = 32;
35 float TETKEY_DROP = 64;
39 .float line1, line2, line3, line4, line5, line6, line7,
40 line8, line9, line10, line11, line12, line13, line14, line15,
41 line16, line17, line18, line19, line20;
44 float SVC_CENTERPRINTa = 26;
48 return ((floor((self.tet_lines / 20)) + 1));
51 void tetsnd(string snd)
53 play2(self, strcat("sounds/tetris/", snd));
57 *********************************
61 *********************************
63 void SetLine(float ln, float vl)
107 float GetLine(float ln)
153 float GetXBlock(float x, float dat)
158 return (dat & 12) / 4;
160 return (dat & 48) / 16;
162 return (dat & 192) / 64;
164 return (dat & 768) / 256;
166 return (dat & 3072) / 1024;
168 return (dat & 12288) / 4096;
170 return (dat & 49152) / 16384;
172 return (dat & 196608) / 65536;
174 return (dat & 786432) / 262144;
179 float SetXBlock(float x, float dat, float new)
182 return (dat - (dat & 3)) | new;
184 return (dat - (dat & 12)) | (new*4);
186 return (dat - (dat & 48)) | (new*16);
188 return (dat - (dat & 192)) | (new*64);
190 return (dat - (dat & 768)) | (new*256);
192 return (dat - (dat & 3072)) | (new*1024);
194 return (dat - (dat & 12288)) | (new*4096);
196 return (dat - (dat & 49152)) | (new*16384);
198 return (dat - (dat & 196608)) | (new*65536);
200 return (dat - (dat & 786432)) | (new*262144);
206 float GetSquare(float x, float y)
208 return GetXBlock(x, GetLine(y));
211 void SetSquare(float x, float y, float val)
216 dat = SetXBlock(x, dat, val & 3);
222 vector PieceShape(float pc)
231 return '5 5 2'; // 1 * 4 + 1 * 16
286 // do x 1..4 and y 1..4 in case of rotation
287 float PieceMetric(float x, float y, float rot, float pc)
293 // return bits of a piece
294 piece_dat = PieceShape(pc);
295 wid = piece_dat_z + 1;
296 if (rot == 1) // 90 degrees
302 else if (rot == 2)//180
307 else if (rot == 3) // 270
313 if (x < 1 || y < 1 || x > 4 || y > 2)
316 return GetXBlock(x, piece_dat_x); // first row
318 return GetXBlock(x, piece_dat_y); // second row
320 return GetXBlock(x, piece_dat_z); // third row (doesn't exist)
322 return 0; // illegal parms
325 *********************************
329 *********************************
333 /* some prydon gate functions to make life easier....
335 somewhat modified because we don't need all the fanciness Prydon Gate is capable of
339 // remove warnings by adding underscores, i hate warnings, warnings suck
341 void p6(float _c1, float _c2, float _c3, float _c4, float c5, float c6)
343 WriteChar(MSG_ONE, _c1);
344 WriteChar(MSG_ONE, _c2);
345 WriteChar(MSG_ONE, _c3);
346 WriteChar(MSG_ONE, _c4);
347 WriteChar(MSG_ONE, c5);
348 WriteChar(MSG_ONE, c6);
351 float pnum(float num, float dig)
356 WriteChar(MSG_ONE, 45);
360 num = num - (f * 10);
362 dig = pnum(f, dig+1);
366 for (i = 0; i < (5 - dig); i = i + 1)
367 WriteChar(MSG_ONE, TET_SPACE);
369 WriteChar(MSG_ONE, 48 + num);
373 void DrawLine(float ln)
376 WriteChar(MSG_ONE, TET_BORDER);
378 for (x = 1; x <= TET_WIDTH; x = x + 1)
380 d = GetSquare(x, ln);
382 WriteChar(MSG_ONE, TET_BLOCKS + d);
384 WriteChar(MSG_ONE, TET_SPACE);
386 WriteChar(MSG_ONE, TET_BORDER);
389 void DrawPiece(float pc, float ln)
391 float x, d, piece_ln, pcolor;
394 if (pcolor == 0) // 4
396 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
398 piece_dat = PieceShape(pc);
400 piece_ln = piece_dat_x;
402 piece_ln = piece_dat_y;
403 for (x = 1; x <= 4; x = x + 1)
405 d = GetXBlock(x, piece_ln) * pcolor;
407 WriteChar(MSG_ONE, TET_BLOCKS + d);
409 WriteChar(MSG_ONE, TET_SPACE);
411 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
417 WriteChar(MSG_ONE, SVC_CENTERPRINTa);
419 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
420 WriteChar(MSG_ONE, TET_BORDER);
421 p6(' ', ' ', ' ', ' ', ' ', ' ');
422 WriteChar(MSG_ONE, 10);
423 for (i = 1; i <= TET_LINES; i = i + 1)
425 if(self.tetris_on == 2 && i == 11)
427 p6(' ', ' ', ' ', ' ', ' ', ' ');
428 p6(' ', 'G', 'A', 'M', 'E', ' ');
429 p6(' ', 'O', 'V', 'E', 'R', ' ');
430 WriteChar(MSG_ONE, 10);
435 p6(' ', 'N', 'E', 'X', 'T', ' ');
437 DrawPiece(self.next_piece, 1);
439 DrawPiece(self.next_piece, 2);
441 p6(' ', 'L', 'I', 'N', 'E', 'S');
443 pnum(self.tet_lines, 0);
445 p6(' ', 'S', 'C', 'O', 'R', 'E');
447 pnum(self.tet_score, 0);
449 p6(' ', 'H', 'I', 'G', 'H', ' ');
451 p6(' ', 'S', 'C', 'O', 'R', 'E');
453 pnum(tet_high_score, 0);
455 p6(' ', 'L', 'E', 'V', 'E', 'L');
457 pnum(Tetris_Level(), 0);
459 p6(' ', ' ', ' ', ' ', ' ', ' ');
460 WriteChar(MSG_ONE, 10);
464 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
465 WriteChar(MSG_ONE, TET_BORDER);
466 p6(' ', ' ', ' ', ' ', ' ', ' ');
467 WriteChar(MSG_ONE, 10);
468 WriteChar(MSG_ONE, 0);
471 *********************************
475 *********************************
483 for (i=1; i<=TET_LINES; i = i + 1)
485 self.piece_pos = '0 0 0';
487 self.next_piece = self.tet_lines = self.tet_score = 0;
493 centerprint(self, "");
496 self.movetype = MOVETYPE_WALK;
497 stuffcmd(self, "loadfont user1 gfx/vera-sans\n");
503 *********************************
507 *********************************
511 return floor(random() * PIECES) + 1;
514 void TetAddScore(float n)
516 self.tet_score = self.tet_score + n * Tetris_Level();
517 if (self.tet_score > tet_high_score)
518 tet_high_score = self.tet_score;
520 float CheckMetrics(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
522 // check to see if the piece, if moved to the locations will overlap
525 // why did I start counting from 1, damnit
529 for (y = 1; y < 5; y = y + 1)
531 for (x = 1; x < 5; x = x + 1)
533 if (PieceMetric(x, y, rot, piece))
535 if (GetSquare(x + orgx, y + orgy))
536 return FALSE; // uhoh, gonna hit something.
537 if (x+orgx<1 || x+orgx > TET_WIDTH || y+orgy<1 || y+orgy> TET_LINES)
538 return FALSE; // ouside the level
545 void ClearPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
549 // why did I start counting from 1, damnit
553 for (y = 1; y < 5; y = y + 1)
555 for (x = 1; x < 5; x = x + 1)
557 if (PieceMetric(x, y, rot, piece))
559 SetSquare(x + orgx, y + orgy, 0);
564 void CementPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
568 // why did I start counting from 1, damnit
573 if (pcolor == 0) // 4
576 for (y = 1; y < 5; y = y + 1)
578 for (x = 1; x < 5; x = x + 1)
580 if (PieceMetric(x, y, rot, piece))
582 SetSquare(x + orgx, y + orgy, pcolor);
588 float LINE_LOW = 349525;
589 float LINE_HIGH = 699050; // above number times 2
591 void CompletedLines()
593 float y, cleared, ln;
600 if (((ln & LINE_LOW) | ((ln & LINE_HIGH)/2)) == LINE_LOW)
601 cleared = cleared + 1;
604 ln = GetLine(y - cleared);
613 self.tet_lines = self.tet_lines + cleared;
614 TetAddScore(cleared * cleared * 10);
617 void HandleGame(float keyss)
620 // first off, we need to see if we need a new piece
629 if (self.piece_type == 0)
631 self.piece_pos = '5 1 0'; // that's about middle top, we count from 1 ARGH
633 self.piece_type = self.next_piece;
635 self.piece_type = RandomPiece();
636 self.next_piece = RandomPiece();
637 keyss = 0; // no movement first frame
638 self.tet_autodown = time + 0.2;
642 ClearPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
644 // next we need to check the piece metrics against what's on the level
645 // based on the key order
647 old_pos = check_pos = self.piece_pos;
651 if (keyss & TETKEY_RIGHT)
653 check_pos_x = check_pos_x + 1;
656 else if (keyss & TETKEY_LEFT)
658 check_pos_x = check_pos_x - 1;
661 else if (keyss & TETKEY_ROTRIGHT)
663 check_pos_z = check_pos_z + 1;
664 piece_data = PieceShape(self.piece_type);
665 nudge = piece_data_z - 2;
668 else if (keyss & TETKEY_ROTLEFT)
670 check_pos_z = check_pos_z - 1;
671 piece_data = PieceShape(self.piece_type);
672 nudge = piece_data_z - 2;
678 else if (check_pos_z < 0)
682 if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
683 self.piece_pos = check_pos;
687 self.tet_gameovertime = time + 2;
692 for(i = 1; i <= nudge; ++i)
694 if(CheckMetrics(self.piece_type, check_pos_x + i, check_pos_y, check_pos_z))
696 self.piece_pos = check_pos + '1 0 0' * i;
699 else if(CheckMetrics(self.piece_type, check_pos_x - i, check_pos_y, check_pos_z))
701 self.piece_pos = check_pos - '1 0 0' * i;
706 check_pos = self.piece_pos;
707 if(keyss & TETKEY_DROP)
709 // drop to bottom, but do NOT cement it yet
710 // this allows sliding it
712 while(CheckMetrics(self.piece_type, check_pos_x, check_pos_y + 1, check_pos_z))
714 self.tet_autodown = time + 1 / Tetris_Level();
716 else if (keyss & TETKEY_DOWN)
718 check_pos_y = check_pos_y + 1;
719 self.tet_autodown = time + 1 / Tetris_Level();
721 else if (self.tet_autodown < time)
723 check_pos_y = check_pos_y + 1;
724 self.tet_autodown = time + 1 / Tetris_Level();
726 if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
728 if(old_pos != check_pos)
729 self.tet_drawtime = 0;
730 self.piece_pos = check_pos;
734 CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
738 self.tet_drawtime = 0;
741 CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
745 *********************************
747 Important Linking Into Quake stuff
749 *********************************
753 void TetrisImpulses(float imp)
757 if(self.tetris_on != 1)
761 self.tet_org = self.origin;
762 self.movetype = MOVETYPE_NOCLIP;
763 stuffcmd(self, "loadfont user1 gfx/conchars\n");
773 float TetrisPreFrame()
778 self.tet_org = self.origin;
779 if (self.tet_drawtime > time)
782 self.tet_drawtime = time + 0.5;
785 float frik_anglemoda(float v)
787 return v - floor(v/360) * 360;
789 float angcompa(float y1, float y2)
791 y1 = frik_anglemoda(y1);
792 y2 = frik_anglemoda(y2);
797 answer = answer - 360;
798 else if (answer < -180)
799 answer = answer + 360;
804 float TetrisPostFrame()
812 if(self.tetris_on == 2 && time > self.tet_gameovertime)
818 self.origin = self.tet_org;
820 if(self.movement_x < 0)
821 keysa |= TETKEY_DOWN;
822 else if(self.movement_x > 0)
823 keysa |= TETKEY_ROTRIGHT;
824 if(self.movement_y < 0)
825 keysa |= TETKEY_LEFT;
826 else if(self.movement_y > 0)
827 keysa |= TETKEY_RIGHT;
828 if (self.BUTTON_CROUCH)
829 keysa = keysa | TETKEY_ROTLEFT;
830 if (self.BUTTON_JUMP)
831 keysa = keysa | TETKEY_DROP;
834 keysa &~= self.tet_old_keys;
835 self.tet_old_keys = keysb;
837 if(self.tetris_on == 1)