5 in weapons.qc add TetrisImpulses(); to ImpulseCommands
7 in progs.src add tetris.qc after subs.qc
8 in client.qc add if (TetrisPreFrame()) return; to PlayerPreThink
9 in client.qc add if (TetrisPostFrame()) return; to PlayerPostThink
15 .float tetris_on, tet_time, tet_autodown;
17 .float piece_type, next_piece, tet_score, tet_lines;
19 var float tet_high_score = 0;
24 float TET_BORDER = 132;
25 float TET_BLOCKS = 132; // +1 = first color, +2, +3;
26 float TET_SPACE = 32; // blankness
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;
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 *********************************
52 *********************************
54 void (float ln, float vl) SetLine =
98 float (float ln) GetLine =
144 float(float x, float dat) GetXBlock =
149 return (dat & 12) / 4;
151 return (dat & 48) / 16;
153 return (dat & 192) / 64;
155 return (dat & 768) / 256;
157 return (dat & 3072) / 1024;
159 return (dat & 12288) / 4096;
161 return (dat & 49152) / 16384;
163 return (dat & 196608) / 65536;
165 return (dat & 786432) / 262144;
170 float(float x, float dat, float new) SetXBlock =
173 return (dat - (dat & 3)) | new;
175 return (dat - (dat & 12)) | (new*4);
177 return (dat - (dat & 48)) | (new*16);
179 return (dat - (dat & 192)) | (new*64);
181 return (dat - (dat & 768)) | (new*256);
183 return (dat - (dat & 3072)) | (new*1024);
185 return (dat - (dat & 12288)) | (new*4096);
187 return (dat - (dat & 49152)) | (new*16384);
189 return (dat - (dat & 196608)) | (new*65536);
191 return (dat - (dat & 786432)) | (new*262144);
197 float(float x, float y) GetSquare =
199 return GetXBlock(x, GetLine(y));
202 void (float x, float y, float val) SetSquare =
207 dat = SetXBlock(x, dat, val & 3);
213 vector(float pc) PieceShape =
222 return '20 20 0'; // 1 * 4 + 1 * 16
277 // do x 1..4 and y 1..4 in case of rotation
278 float(float x, float y, float rot, float pc) PieceMetric =
283 // return bits of a piece
284 if (rot == 1) // 90 degrees
290 else if (rot == 2)//180
295 else if (rot == 3) // 270
301 if (x < 1 || y < 1 || x > 4 || y > 2)
303 piece_dat = PieceShape(pc);
305 return GetXBlock(x, piece_dat_x); // first row
307 return GetXBlock(x, piece_dat_y); // second row
309 return GetXBlock(x, piece_dat_z); // third row (doesn't exist)
311 return 0; // illegal parms
314 *********************************
318 *********************************
322 /* some prydon gate functions to make life easier....
324 somewhat modified because we don't need all the fanciness Prydon Gate is capable of
328 void(float c1, float c2, float c3, float c4, float c5, float c6) p6 =
330 WriteChar(MSG_ONE, c1);
331 WriteChar(MSG_ONE, c2);
332 WriteChar(MSG_ONE, c3);
333 WriteChar(MSG_ONE, c4);
334 WriteChar(MSG_ONE, c5);
335 WriteChar(MSG_ONE, c6);
338 float(float num, float dig) pnum =
343 WriteChar(MSG_ONE, 45);
347 num = num - (f * 10);
349 dig = pnum(f, dig+1);
353 for (i = 0; i < (5 - dig); i = i + 1)
354 WriteChar(MSG_ONE, TET_SPACE);
356 WriteChar(MSG_ONE, 48 + num);
360 void (float ln) DrawLine =
363 WriteChar(MSG_ONE, TET_BORDER);
365 for (x = 1; x <= TET_WIDTH; x = x + 1)
367 d = GetSquare(x, ln);
369 WriteChar(MSG_ONE, TET_BLOCKS + d);
371 WriteChar(MSG_ONE, TET_SPACE);
373 WriteChar(MSG_ONE, TET_BORDER);
376 void (float pc, float ln) DrawPiece =
378 float x, d, piece_ln, color;
383 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
385 piece_dat = PieceShape(pc);
387 piece_ln = piece_dat_x;
389 piece_ln = piece_dat_y;
390 for (x = 1; x <= 4; x = x + 1)
392 d = GetXBlock(x, piece_ln) * color;
394 WriteChar(MSG_ONE, TET_BLOCKS + d);
396 WriteChar(MSG_ONE, TET_SPACE);
398 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
404 WriteChar(MSG_ONE, SVC_CENTERPRINTa);
406 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
407 WriteChar(MSG_ONE, TET_BORDER);
408 p6(' ', ' ', ' ', ' ', ' ', ' ');
409 WriteChar(MSG_ONE, 10);
410 for (i = 1; i <= TET_LINES; i = i + 1)
414 p6(' ', 'N', 'E', 'X', 'T', ' ');
416 DrawPiece(self.next_piece, 1);
418 DrawPiece(self.next_piece, 2);
420 p6(' ', 'L', 'I', 'N', 'E', 'S');
422 pnum(self.tet_lines, 0);
424 p6(' ', 'S', 'C', 'O', 'R', 'E');
426 pnum(self.tet_score, 0);
428 p6(' ', 'H', 'I', 'G', 'H', ' ');
430 p6(' ', 'S', 'C', 'O', 'R', 'E');
432 pnum(tet_high_score, 0);
434 p6(' ', 'L', 'E', 'V', 'E', 'L');
436 pnum(floor(self.tet_lines / 20)+ 1, 0);
438 p6(' ', ' ', ' ', ' ', ' ', ' ');
439 WriteChar(MSG_ONE, 10);
443 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
444 WriteChar(MSG_ONE, TET_BORDER);
445 p6(' ', ' ', ' ', ' ', ' ', ' ');
446 WriteChar(MSG_ONE, 10);
447 WriteChar(MSG_ONE, 0);
450 *********************************
454 *********************************
462 for (i=1; i<=TET_LINES; i = i + 1)
464 self.piece_pos = '0 0 0';
466 self.next_piece = self.tet_lines = self.tet_score = 0;
470 void () Tet_GameOver =
472 centerprint(self, "Game Over");
475 self.movetype = MOVETYPE_WALK;
481 *********************************
485 *********************************
487 float() RandomPiece =
489 return floor(random() * PIECES) + 1;
492 void(float n) TetAddScore =
494 self.tet_score = self.tet_score + n;
495 if (self.tet_score > tet_high_score)
496 tet_high_score = self.tet_score;
498 float CheckMetrics(float piece, float orgx, float orgy, float rot) =
500 // check to see if the piece, if moved to the locations will overlap
503 // why did I start counting from 1, damnit
507 for (y = 1; y < 5; y = y + 1)
509 for (x = 1; x < 5; x = x + 1)
511 if (PieceMetric(x, y, rot, piece))
513 if (GetSquare(x + orgx, y + orgy))
514 return FALSE; // uhoh, gonna hit something.
515 if (x+orgx<1 || x+orgx > TET_WIDTH || y+orgy<1 || y+orgy> TET_LINES)
516 return FALSE; // ouside the level
523 void ClearPiece(float piece, float orgx, float orgy, float rot) =
527 // why did I start counting from 1, damnit
531 for (y = 1; y < 5; y = y + 1)
533 for (x = 1; x < 5; x = x + 1)
535 if (PieceMetric(x, y, rot, piece))
537 SetSquare(x + orgx, y + orgy, 0);
542 void CementPiece(float piece, float orgx, float orgy, float rot) =
546 // why did I start counting from 1, damnit
554 for (y = 1; y < 5; y = y + 1)
556 for (x = 1; x < 5; x = x + 1)
558 if (PieceMetric(x, y, rot, piece))
560 SetSquare(x + orgx, y + orgy, color);
566 float LINE_LOW = 349525;
567 float LINE_HIGH = 699050; // above number times 2
569 void() CompletedLines =
571 float y, cleared, ln;
578 if (((ln & LINE_LOW) | ((ln & LINE_HIGH)/2)) == LINE_LOW)
579 cleared = cleared + 1;
582 ln = GetLine(y - cleared);
585 self.tet_lines = self.tet_lines + cleared;
586 TetAddScore(cleared * cleared * 10);
589 void(float keyss) HandleGame =
592 // first off, we need to see if we need a new piece
596 if (self.tet_time > time)
598 self.tet_time = time + 0.1;
601 if (self.piece_type == 0)
603 self.piece_pos = '5 1 0'; // that's about middle top, we count from 1 ARGH
605 self.piece_type = self.next_piece;
607 self.piece_type = RandomPiece();
608 self.next_piece = RandomPiece();
609 keyss = 0; // no movement first frame
610 self.tet_autodown = time + 0.2;
614 ClearPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
616 // next we need to check the piece metrics against what's on the level
617 // based on the key order
619 check_pos = self.piece_pos;
621 if (keyss & TETKEY_RIGHT)
622 check_pos_x = check_pos_x + 1;
623 else if (keyss & TETKEY_LEFT)
624 check_pos_x = check_pos_x - 1;
625 else if (keyss & TETKEY_ROTRIGHT)
626 check_pos_z = check_pos_z + 1;
627 else if (keyss & TETKEY_ROTLEFT)
628 check_pos_z = check_pos_z - 1;
632 else if (check_pos_z < 0)
636 if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
637 self.piece_pos = check_pos;
640 check_pos = self.piece_pos;
641 if (keyss & TETKEY_DOWN)
642 check_pos_y = check_pos_y + 1;
643 else if (self.tet_autodown < time)
645 check_pos_y = check_pos_y + 1;
646 self.tet_autodown = time + 1 / (floor(self.tet_lines / 20) + 1);
648 if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
649 self.piece_pos = check_pos;
652 CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
658 CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
662 *********************************
664 Important Linking Into Quake stuff
666 *********************************
670 void() TetrisImpulses =
672 if (self.impulse == 200)
676 self.tet_org = self.origin;
677 self.movetype = MOVETYPE_NOCLIP;
678 stuffcmd(self, "cl_bob 0\ncl_rollangle 0\n");
683 float() TetrisPreFrame =
688 self.tet_org = self.origin;
689 if (self.tet_time > time)
695 float(float v) frik_anglemoda =
697 return v - floor(v/360) * 360;
699 float (float y1, float y2) angcompa =
701 y1 = frik_anglemoda(y1);
702 y2 = frik_anglemoda(y2);
707 answer = answer - 360;
708 else if (answer < -180)
709 answer = answer + 360;
714 float() TetrisPostFrame =
723 if (self.origin != self.tet_org)
725 mov = vectoangles(self.origin - self.tet_org);
726 self.origin = self.tet_org;
728 norm = angcompa(self.v_angle_y, mov_y);
730 if (norm > -80 && norm < 80)
731 keysa = keysa | TETKEY_UP;
732 if (norm > 10 && norm < 170)
733 keysa = keysa | TETKEY_RIGHT;
734 if (norm > 100 || norm < -260)
735 keysa = keysa | TETKEY_DOWN;
736 if (norm > -170 && norm < -10)
737 keysa = keysa | TETKEY_LEFT;
740 keysa = keysa | TETKEY_ROTRIGHT;
742 keysa = keysa | TETKEY_ROTLEFT;