13 float tet_vs_current_id;
14 float tet_vs_current_timeout;
15 .float tet_vs_id, tet_vs_addlines;
16 .float tet_highest_line;
17 .float tetris_on, tet_gameovertime, tet_drawtime, tet_autodown;
19 .float piece_type, next_piece, tet_score, tet_lines;
24 // 3 = waiting for VS players
26 var float tet_high_score = 0;
31 float TET_BORDER = 132;
32 float TET_BLOCKS = 132; // +1 = first color, +2, +3;
33 float TET_SPACE = 32; // blankness
38 float TETKEY_DOWN = 2;
39 float TETKEY_LEFT = 4;
40 float TETKEY_RIGHT = 8;
41 float TETKEY_ROTLEFT = 16;
42 float TETKEY_ROTRIGHT = 32;
43 float TETKEY_DROP = 64;
47 .float line1, line2, line3, line4, line5, line6, line7,
48 line8, line9, line10, line11, line12, line13, line14, line15,
49 line16, line17, line18, line19, line20;
52 float SVC_CENTERPRINTa = 26;
56 return ((floor((self.tet_lines / 20)) + 1));
59 void tetsnd(string snd)
61 play2(self, strcat("sounds/tetris/", snd));
65 *********************************
69 *********************************
71 void SetLine(float ln, float vl)
115 float GetLine(float ln)
161 float GetXBlock(float x, float dat)
166 return (dat & 12) / 4;
168 return (dat & 48) / 16;
170 return (dat & 192) / 64;
172 return (dat & 768) / 256;
174 return (dat & 3072) / 1024;
176 return (dat & 12288) / 4096;
178 return (dat & 49152) / 16384;
180 return (dat & 196608) / 65536;
182 return (dat & 786432) / 262144;
187 float SetXBlock(float x, float dat, float new)
190 return (dat - (dat & 3)) | new;
192 return (dat - (dat & 12)) | (new*4);
194 return (dat - (dat & 48)) | (new*16);
196 return (dat - (dat & 192)) | (new*64);
198 return (dat - (dat & 768)) | (new*256);
200 return (dat - (dat & 3072)) | (new*1024);
202 return (dat - (dat & 12288)) | (new*4096);
204 return (dat - (dat & 49152)) | (new*16384);
206 return (dat - (dat & 196608)) | (new*65536);
208 return (dat - (dat & 786432)) | (new*262144);
214 float GetSquare(float x, float y)
216 return GetXBlock(x, GetLine(y));
219 void SetSquare(float x, float y, float val)
224 dat = SetXBlock(x, dat, val & 3);
230 vector PieceShape(float pc)
239 return '5 5 2'; // 1 * 4 + 1 * 16
294 // do x 1..4 and y 1..4 in case of rotation
295 float PieceMetric(float x, float y, float rot, float pc)
301 // return bits of a piece
302 piece_dat = PieceShape(pc);
303 wid = piece_dat_z + 1;
304 if (rot == 1) // 90 degrees
310 else if (rot == 2)//180
315 else if (rot == 3) // 270
321 if (x < 1 || y < 1 || x > 4 || y > 2)
324 return GetXBlock(x, piece_dat_x); // first row
326 return GetXBlock(x, piece_dat_y); // second row
328 return GetXBlock(x, piece_dat_z); // third row (doesn't exist)
330 return 0; // illegal parms
333 *********************************
337 *********************************
341 /* some prydon gate functions to make life easier....
343 somewhat modified because we don't need all the fanciness Prydon Gate is capable of
347 // remove warnings by adding underscores, i hate warnings, warnings suck
349 void p6(float _c1, float _c2, float _c3, float _c4, float c5, float c6)
351 WriteChar(MSG_ONE, _c1);
352 WriteChar(MSG_ONE, _c2);
353 WriteChar(MSG_ONE, _c3);
354 WriteChar(MSG_ONE, _c4);
355 WriteChar(MSG_ONE, c5);
356 WriteChar(MSG_ONE, c6);
359 float pnum(float num, float dig)
364 WriteChar(MSG_ONE, 45);
368 num = num - (f * 10);
370 dig = pnum(f, dig+1);
374 for (i = 0; i < (5 - dig); i = i + 1)
375 WriteChar(MSG_ONE, TET_SPACE);
377 WriteChar(MSG_ONE, 48 + num);
381 void DrawLine(float ln)
384 WriteChar(MSG_ONE, TET_BORDER);
386 for (x = 1; x <= TET_WIDTH; x = x + 1)
388 d = GetSquare(x, ln);
390 WriteChar(MSG_ONE, TET_BLOCKS + d);
392 WriteChar(MSG_ONE, TET_SPACE);
394 WriteChar(MSG_ONE, TET_BORDER);
397 void DrawPiece(float pc, float ln)
399 float x, d, piece_ln, pcolor;
402 if (pcolor == 0) // 4
404 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
406 piece_dat = PieceShape(pc);
408 piece_ln = piece_dat_x;
410 piece_ln = piece_dat_y;
411 for (x = 1; x <= 4; x = x + 1)
413 d = GetXBlock(x, piece_ln) * pcolor;
415 WriteChar(MSG_ONE, TET_BLOCKS + d);
417 WriteChar(MSG_ONE, TET_SPACE);
419 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
426 WriteChar(MSG_ONE, SVC_CENTERPRINTa);
428 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
429 WriteChar(MSG_ONE, TET_BORDER);
430 p6(' ', ' ', ' ', ' ', ' ', ' ');
431 WriteChar(MSG_ONE, 10);
432 for (i = 1; i <= TET_LINES; i = i + 1)
434 if(self.tetris_on == 2)
435 WriteUnterminatedString(MSG_ONE, " GAME OVER ");
436 else if(self.tetris_on == 3)
437 WriteUnterminatedString(MSG_ONE, "PLEASE WAIT");
441 p6(' ', 'N', 'E', 'X', 'T', ' ');
443 DrawPiece(self.next_piece, 1);
445 DrawPiece(self.next_piece, 2);
447 p6(' ', 'L', 'I', 'N', 'E', 'S');
449 pnum(self.tet_lines, 0);
451 p6(' ', 'S', 'C', 'O', 'R', 'E');
453 pnum(self.tet_score, 0);
455 p6(' ', 'H', 'I', 'G', 'H', ' ');
457 p6(' ', 'S', 'C', 'O', 'R', 'E');
459 pnum(tet_high_score, 0);
461 p6(' ', 'L', 'E', 'V', 'E', 'L');
463 pnum(Tetris_Level(), 0);
465 p6(' ', ' ', ' ', ' ', ' ', ' ');
466 WriteChar(MSG_ONE, 10);
470 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
471 WriteChar(MSG_ONE, TET_BORDER);
472 p6(' ', ' ', ' ', ' ', ' ', ' ');
473 WriteChar(MSG_ONE, 10);
478 WriteChar(MSG_ONE, 10);
479 WriteChar(MSG_ONE, 10);
480 if(self.tetris_on == 3)
482 WriteUnterminatedString(MSG_ONE, strcat("WAITING FOR OTHERS (", ftos(ceil(tet_vs_current_timeout - time)), " SEC)\n"));
485 WriteChar(MSG_ONE, 10);
486 FOR_EACH_REALCLIENT(head) if(head.tetris_on) if(head.tet_vs_id == self.tet_vs_id)
489 WriteChar(MSG_ONE, '>');
491 WriteChar(MSG_ONE, ' ');
492 if(head.tetris_on == 2)
493 WriteUnterminatedString(MSG_ONE, " X_X");
495 pnum(head.tet_highest_line, 0);
496 WriteChar(MSG_ONE, 32);
497 WriteUnterminatedString(MSG_ONE, head.netname);
499 WriteChar(MSG_ONE, 10);
502 WriteChar(MSG_ONE, 0);
505 *********************************
509 *********************************
517 for (i=1; i<=TET_LINES; i = i + 1)
519 self.piece_pos = '0 0 0';
521 self.next_piece = self.tet_lines = self.tet_score = 0;
527 centerprint(self, " ");
530 self.movetype = MOVETYPE_WALK;
531 stuffcmd(self, "loadfont user1 gfx/vera-sans\n");
537 *********************************
541 *********************************
545 return floor(random() * PIECES) + 1;
548 void TetAddScore(float n)
550 self.tet_score = self.tet_score + n * Tetris_Level();
551 if (self.tet_score > tet_high_score)
552 tet_high_score = self.tet_score;
554 float CheckMetrics(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
556 // check to see if the piece, if moved to the locations will overlap
559 // why did I start counting from 1, damnit
563 for (y = 1; y < 5; y = y + 1)
565 for (x = 1; x < 5; x = x + 1)
567 if (PieceMetric(x, y, rot, piece))
569 if (GetSquare(x + orgx, y + orgy))
570 return FALSE; // uhoh, gonna hit something.
571 if (x+orgx<1 || x+orgx > TET_WIDTH || y+orgy<1 || y+orgy> TET_LINES)
572 return FALSE; // ouside the level
579 void ClearPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
583 // why did I start counting from 1, damnit
587 for (y = 1; y < 5; y = y + 1)
589 for (x = 1; x < 5; x = x + 1)
591 if (PieceMetric(x, y, rot, piece))
593 SetSquare(x + orgx, y + orgy, 0);
598 void CementPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
602 // why did I start counting from 1, damnit
607 if (pcolor == 0) // 4
610 for (y = 1; y < 5; y = y + 1)
612 for (x = 1; x < 5; x = x + 1)
614 if (PieceMetric(x, y, rot, piece))
616 SetSquare(x + orgx, y + orgy, pcolor);
622 float LINE_LOW = 349525;
623 float LINE_HIGH = 699050; // above number times 2
625 void AddLines(float n)
630 FOR_EACH_REALCLIENT(head) if(head != self) if(head.tetris_on) if(head.tet_vs_id == self.tet_vs_id)
631 head.tet_vs_addlines += n;
634 void CompletedLines()
636 float y, cleared, ln, added, pos, i;
643 if (((ln & LINE_LOW) | ((ln & LINE_HIGH)/2)) == LINE_LOW)
644 cleared = cleared + 1;
647 ln = GetLine(y - cleared);
653 else if(cleared >= 1)
654 AddLines(cleared - 1);
656 self.tet_lines = self.tet_lines + cleared;
657 TetAddScore(cleared * cleared * 10);
659 added = self.tet_vs_addlines;
660 self.tet_vs_addlines = 0;
664 for(y = 1; y <= TET_LINES - added; ++y)
666 SetLine(y, GetLine(y + added));
668 for(y = max(1, TET_LINES - added + 1); y <= TET_LINES; ++y)
670 pos = floor(random() * TET_WIDTH);
672 for(i = 1; i <= TET_WIDTH; ++i)
674 ln = SetXBlock(i, ln, floor(random() * 3 + 1));
679 self.tet_highest_line = 0;
680 for(y = 1; y <= TET_LINES; ++y)
683 self.tet_highest_line = TET_LINES + 1 - y;
689 else if(cleared >= 4)
697 void HandleGame(float keyss)
700 // first off, we need to see if we need a new piece
709 if (self.piece_type == 0)
711 self.piece_pos = '5 1 0'; // that's about middle top, we count from 1 ARGH
713 self.piece_type = self.next_piece;
715 self.piece_type = RandomPiece();
716 self.next_piece = RandomPiece();
717 keyss = 0; // no movement first frame
718 self.tet_autodown = time + 0.2;
722 ClearPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
724 // next we need to check the piece metrics against what's on the level
725 // based on the key order
727 old_pos = check_pos = self.piece_pos;
731 if (keyss & TETKEY_RIGHT)
733 check_pos_x = check_pos_x + 1;
736 else if (keyss & TETKEY_LEFT)
738 check_pos_x = check_pos_x - 1;
741 else if (keyss & TETKEY_ROTRIGHT)
743 check_pos_z = check_pos_z + 1;
744 piece_data = PieceShape(self.piece_type);
745 nudge = piece_data_z - 2;
748 else if (keyss & TETKEY_ROTLEFT)
750 check_pos_z = check_pos_z - 1;
751 piece_data = PieceShape(self.piece_type);
752 nudge = piece_data_z - 2;
758 else if (check_pos_z < 0)
762 if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
763 self.piece_pos = check_pos;
767 self.tet_gameovertime = time + 2;
772 for(i = 1; i <= nudge; ++i)
774 if(CheckMetrics(self.piece_type, check_pos_x + i, check_pos_y, check_pos_z))
776 self.piece_pos = check_pos + '1 0 0' * i;
779 else if(CheckMetrics(self.piece_type, check_pos_x - i, check_pos_y, check_pos_z))
781 self.piece_pos = check_pos - '1 0 0' * i;
786 check_pos = self.piece_pos;
787 if(keyss & TETKEY_DROP)
789 // drop to bottom, but do NOT cement it yet
790 // this allows sliding it
792 while(CheckMetrics(self.piece_type, check_pos_x, check_pos_y + 1, check_pos_z))
794 self.tet_autodown = time + 1 / Tetris_Level();
796 else if (keyss & TETKEY_DOWN)
798 check_pos_y = check_pos_y + 1;
799 self.tet_autodown = time + 1 / Tetris_Level();
801 else if (self.tet_autodown < time)
803 check_pos_y = check_pos_y + 1;
804 self.tet_autodown = time + 1 / Tetris_Level();
806 if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
808 if(old_pos != check_pos)
809 self.tet_drawtime = 0;
810 self.piece_pos = check_pos;
814 CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
818 self.tet_drawtime = 0;
821 CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
825 *********************************
827 Important Linking Into Quake stuff
829 *********************************
835 if(self.tetris_on != 1)
839 if(time < tet_vs_current_timeout)
842 self.tet_vs_id = tet_vs_current_id;
848 tet_vs_current_timeout = time + 15;
849 self.tet_vs_id = tet_vs_current_id;
850 bprint("^2TET^4R^2IS: ", self.netname, "^2 started a new game. Do 'impulse 100' to join.\n");
852 self.tet_highest_line = 0;
854 self.tet_org = self.origin;
855 self.movetype = MOVETYPE_NOCLIP;
856 stuffcmd(self, "loadfont user1 gfx/conchars\n");
866 float TetrisPreFrame()
871 self.tet_org = self.origin;
872 if (self.tet_drawtime > time)
875 if(self.tetris_on == 3)
876 self.tet_drawtime = ceil(time - tet_vs_current_timeout + 0.1) + tet_vs_current_timeout;
878 self.tet_drawtime = time + 0.5;
881 float frik_anglemoda(float v)
883 return v - floor(v/360) * 360;
885 float angcompa(float y1, float y2)
887 y1 = frik_anglemoda(y1);
888 y2 = frik_anglemoda(y2);
893 answer = answer - 360;
894 else if (answer < -180)
895 answer = answer + 360;
899 .float tetkey_down, tetkey_rotright, tetkey_left, tetkey_right, tetkey_rotleft, tetkey_drop;
901 float TetrisKeyRepeat(.float fld, float f)
905 if(self.fld == 0) // initial key press
907 self.fld = time + 0.3;
910 else if(time > self.fld)
912 self.fld = time + 0.1;
917 // repeating too fast
928 float TetrisPostFrame()
936 if(self.tetris_on == 2 && time > self.tet_gameovertime)
941 if(self.tetris_on == 3 && time > tet_vs_current_timeout)
943 self.tetris_on = 1; // start VS game
944 self.tet_drawtime = 0;
947 self.origin = self.tet_org;
949 if(self.tetris_on == 1)
951 if(TetrisKeyRepeat(tetkey_down, self.movement_x < 0))
952 keysa |= TETKEY_DOWN;
954 if(TetrisKeyRepeat(tetkey_rotright, self.movement_x > 0))
955 keysa |= TETKEY_ROTRIGHT;
957 if(TetrisKeyRepeat(tetkey_left, self.movement_y < 0))
958 keysa |= TETKEY_LEFT;
960 if(TetrisKeyRepeat(tetkey_right, self.movement_y > 0))
961 keysa |= TETKEY_RIGHT;
963 if(TetrisKeyRepeat(tetkey_rotleft, self.BUTTON_CROUCH))
964 keysa |= TETKEY_ROTLEFT;
966 if(TetrisKeyRepeat(tetkey_drop, self.BUTTON_JUMP))
967 keysa |= TETKEY_DROP;