4 #include "../dpdefs/dpextensions.qh"
5 #include "autocvars.qh"
20 float tet_vs_current_id;
21 float tet_vs_current_timeout;
22 .float tet_vs_id, tet_vs_addlines;
23 .float tet_highest_line;
24 .float tetris_on, tet_gameovertime, tet_drawtime, tet_autodown;
26 .float piece_type, next_piece, tet_score, tet_lines;
27 .float tet_piece_bucket;
32 // 3 = waiting for VS players
34 float tet_high_score = 0;
36 const vector TET_START_PIECE_POS = '5 1 0';
37 const float TET_LINES = 22;
38 const float TET_DISPLAY_LINES = 20;
39 const float TET_WIDTH = 10;
40 const string TET_EMPTY_LINE = "0000000000"; // must match TET_WIDTH
42 const float TET_BORDER = 139;
43 const float TET_BLOCK = 133;
44 const float TET_SPACE = 160; // blankness
48 const float TETKEY_UP = 1;
49 const float TETKEY_DOWN = 2;
50 const float TETKEY_LEFT = 4;
51 const float TETKEY_RIGHT = 8;
52 const float TETKEY_ROTLEFT = 16;
53 const float TETKEY_ROTRIGHT = 32;
54 const float TETKEY_DROP = 64;
55 const string TET_PADDING_RIGHT = "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0"; // get away from crosshair
57 const float PIECES = 7;
61 float SVC_CENTERPRINTa = 26;
65 return ((floor((self.tet_lines / 10)) + 1));
68 void tetsnd(string snd)
70 play2(self, strcat("sounds/tetris/", snd));
74 *********************************
78 *********************************
80 void SetLine(float ln, string vl)
82 if(ln < 1 || ln > TET_LINES)
84 bufstr_set(tet_line_buf, ln + TET_LINES * num_for_edict(self), vl);
87 string GetLine(float ln)
89 if(ln < 1 || ln > TET_LINES)
91 if(ln < 1 || ln > TET_LINES)
92 return TET_EMPTY_LINE;
93 return bufstr_get(tet_line_buf, ln + TET_LINES * num_for_edict(self));
96 float GetXBlock(float x, string dat)
98 if(x < 1 || x > TET_WIDTH)
100 return stof(substring(dat, x-1, 1));
103 string SetXBlock(float x, string dat, float new)
106 substring(dat, 0, x-1),
108 substring(dat, x, -1)
113 float GetSquare(float x, float y)
115 return GetXBlock(x, GetLine(y));
118 void SetSquare(float x, float y, float val)
122 dat = SetXBlock(x, dat, val);
126 float PieceColor(float pc)
133 return 7; // L // we don't have orange, let's use white instead!
145 vector PieceShape(float pc)
148 return '20 20 0'; // O
150 return '1 21 0'; // J
152 return '16 21 0'; // L
154 return '0 85 0'; // I
156 return '5 20 0'; // Z
158 return '20 5 0'; // S
160 return '4 21 0'; // T
164 vector PieceSize(float pc)
183 vector PieceCenter(float pc)
186 return '2.5 1.5 0'; // O
192 return '2.5 2.5 0'; // I
203 // do x 1..4 and y 1..4 in case of rotation
204 float PieceMetric(float x, float y, float rot, float pc)
209 // return bits of a piece
210 ce = PieceCenter(pc);
211 if (rot == 1) // 90 degrees
213 // x+cx, y+cy -> -y+cx, x+cy
214 // X, Y -> -Y+cy+cx, X-cx+cy
219 x = -t + ce.x + ce.y;
221 else if (rot == 2)//180
226 else if (rot == 3) // 270
228 // x+cx, y+cy -> y+cx, -x+cy
229 // X, Y -> Y-cy+cx, -X+cx+cy
233 y = -x + ce.y + ce.x;
236 if (x < 1 || y < 1 || x > 4 || y > 2)
240 return !!(ce.x & pow(4, x-1)); // first row
242 return !!(ce.y & pow(4, x-1)); // second row
244 return 0; // illegal parms
246 vector tet_piecemins;
247 vector tet_piecemaxs;
248 void PieceMinsMaxs(float rot, float pc)
255 ce = PieceCenter(pc);
260 tet_piecemins.x = floor(3.0 - sz.x * 0.5);
261 tet_piecemaxs.x = floor(2.0 + sz.x * 0.5);
264 // special case for "I"
265 tet_piecemins.y = tet_piecemaxs.y = 2;
270 tet_piecemaxs.y = sz.y;
272 //printf("ce%v sz%v mi%v ma%v\n", ce, sz, tet_piecemins, tet_piecemaxs);
273 if (rot == 1) // 90 degrees
276 tet_piecemins.y = -tet_piecemins.x + ce.y + ce.x;
277 tet_piecemins.x = t - ce.y + ce.x;
279 tet_piecemaxs.y = -tet_piecemaxs.x + ce.y + ce.x;
280 tet_piecemaxs.x = t - ce.y + ce.x;
281 // swap mins_y, maxs_y
283 tet_piecemins.y = tet_piecemaxs.y;
287 else if (rot == 2)//180
290 tet_piecemins = 2 * ce - tet_piecemaxs;
291 tet_piecemaxs = 2 * ce - v;
293 else if (rot == 3) // 270
296 tet_piecemins.y = tet_piecemins.x - ce.x + ce.y;
297 tet_piecemins.x = -t + ce.x + ce.y;
299 tet_piecemaxs.y = tet_piecemaxs.x - ce.x + ce.y;
300 tet_piecemaxs.x = -t + ce.x + ce.y;
301 // swap mins_x, maxs_x
303 tet_piecemins.x = tet_piecemaxs.x;
308 print(vtos(tet_piecemins), "-");
309 print(vtos(tet_piecemaxs), "\n");
310 if(tet_piecemins.x > tet_piecemaxs.x)
311 error("inconsistent mins/maxs");
312 if(tet_piecemins.y > tet_piecemaxs.y)
313 error("inconsistent mins/maxs");
315 vector realmins, realmaxs;
318 for(i = 1; i <= 4; ++i)
319 for(j = 1; j <= 4; ++j)
320 if(PieceMetric(i, j, rot, pc))
322 realmins.x = min(realmins.x, i);
323 realmins.y = min(realmins.y, j);
324 realmaxs.x = max(realmaxs.x, i);
325 realmaxs.y = max(realmaxs.y, j);
327 if(realmins != tet_piecemins || realmaxs != tet_piecemaxs)
328 error(sprintf("incorrect mins/maxs: %v %v in %d rot %d mins %v maxs %v\n", realmins, realmaxs, rot, pc, tet_piecemins, tet_piecemaxs));
332 *********************************
336 *********************************
340 /* some prydon gate functions to make life easier....
342 somewhat modified because we don't need all the fanciness Prydon Gate is capable of
346 void WriteTetrisString(string s)
348 WriteUnterminatedString(MSG_ONE, strconv(0, 2, 2, s));
351 float pnum(float num, float dig)
356 WriteChar(MSG_ONE, 173);
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, 176 + 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 + TET_LINES - TET_DISPLAY_LINES);
383 WriteChar(MSG_ONE, '^');
384 WriteChar(MSG_ONE, d + '0');
385 WriteChar(MSG_ONE, TET_BLOCK);
388 WriteChar(MSG_ONE, TET_SPACE);
390 WriteChar(MSG_ONE, '^');
391 WriteChar(MSG_ONE, '7');
392 WriteChar(MSG_ONE, TET_BORDER);
395 void DrawPiece(float pc, float ln)
397 float x, d, piece_ln, pcolor;
399 pcolor = PieceColor(pc);
400 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
402 piece_dat = PieceShape(pc);
404 piece_ln = piece_dat.x;
406 piece_ln = piece_dat.y;
407 for (x = 1; x <= 4; x = x + 1)
409 if (piece_ln & pow(4, x-1))
411 WriteChar(MSG_ONE, '^');
412 WriteChar(MSG_ONE, pcolor + '0');
413 WriteChar(MSG_ONE, TET_BLOCK);
416 WriteChar(MSG_ONE, TET_SPACE);
418 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
425 WriteChar(MSG_ONE, SVC_CENTERPRINTa);
426 if(autocvar_g_bastet)
428 WriteTetrisString("NEVER GONNA GIVE YOU");
429 WriteChar(MSG_ONE, 10);
432 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
433 WriteChar(MSG_ONE, TET_BORDER);
434 WriteTetrisString(" ");
435 WriteUnterminatedString(MSG_ONE, TET_PADDING_RIGHT);
436 WriteChar(MSG_ONE, 10);
437 for (i = 1; i <= TET_DISPLAY_LINES; i = i + 1)
439 if(self.tetris_on == 2)
440 WriteTetrisString(" GAME OVER ");
441 else if(self.tetris_on == 3)
442 WriteTetrisString("PLEASE WAIT");
446 WriteTetrisString(autocvar_g_bastet ? " THAT " : " NEXT ");
448 DrawPiece(self.next_piece, 1);
450 DrawPiece(self.next_piece, 2);
452 WriteTetrisString(" LINES");
454 pnum(self.tet_lines, 0);
456 WriteTetrisString(" SCORE");
458 pnum(self.tet_score, 0);
460 WriteTetrisString(" HIGH ");
462 WriteTetrisString(" SCORE");
464 pnum(tet_high_score, 0);
466 WriteTetrisString(" LEVEL");
468 pnum(Tetris_Level(), 0);
470 WriteTetrisString(" ");
471 WriteUnterminatedString(MSG_ONE, TET_PADDING_RIGHT);
472 WriteChar(MSG_ONE, 10);
476 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
477 WriteChar(MSG_ONE, TET_BORDER);
478 WriteTetrisString(" ");
479 WriteUnterminatedString(MSG_ONE, TET_PADDING_RIGHT);
480 WriteChar(MSG_ONE, 10);
485 WriteChar(MSG_ONE, 10);
486 WriteChar(MSG_ONE, 10);
487 if(self.tetris_on == 3)
489 WriteUnterminatedString(MSG_ONE, strcat("WAITING FOR OTHERS (", ftos(ceil(tet_vs_current_timeout - time)), " SEC)\n"));
492 WriteChar(MSG_ONE, 10);
493 FOR_EACH_REALCLIENT(head) if(head.tetris_on) if(head.tet_vs_id == self.tet_vs_id)
496 WriteUnterminatedString(MSG_ONE, ">");
498 WriteUnterminatedString(MSG_ONE, " ");
499 if(head.tetris_on == 2)
500 WriteUnterminatedString(MSG_ONE, " X_X");
502 pnum(head.tet_highest_line, 0);
503 WriteUnterminatedString(MSG_ONE, " ");
504 WriteUnterminatedString(MSG_ONE, head.netname);
505 WriteChar(MSG_ONE, 10);
509 WriteChar(MSG_ONE, 0);
512 *********************************
516 *********************************
525 tet_line_buf = buf_create();
527 for (i=1; i<=TET_LINES; i = i + 1)
528 SetLine(i, TET_EMPTY_LINE);
529 self.piece_pos = '0 0 0';
531 self.next_piece = self.tet_lines = self.tet_score = 0;
532 self.tet_piece_bucket = 0;
537 centerprint(self, " ");
541 self.movetype = MOVETYPE_WALK;
548 for(r = 1; r <= TET_LINES; ++r)
552 for(c = 1; c <= TET_WIDTH; ++c)
554 print(ftos(GetXBlock(c, l)));
560 float BastetEvaluate()
565 float score, score_save;
566 string occupied, occupied_save;
567 float occupied_count, occupied_count_save;
572 // adds a bonus for each free dot above the occupied blocks profile
573 occupied = TET_EMPTY_LINE;
574 occupied_count = TET_WIDTH;
577 for(i = 1; i <= TET_LINES; ++i)
580 if(l == TET_EMPTY_LINE)
586 occupied_save = occupied;
587 occupied_count_save = occupied_count;
589 for(j = 1; j <= TET_WIDTH; ++j)
593 if(!GetXBlock(j, occupied))
595 occupied = SetXBlock(j, occupied, 1);
601 score += 10000 * occupied_count;
605 occupied = occupied_save;
606 occupied_count = occupied_count_save;
607 score = score_save + 100000000 + 10000 * TET_WIDTH + 1000;
612 score += 1000 * height;
617 float CheckMetrics(float piece, float orgx, float orgy, float rot);
618 void ClearPiece(float piece, float orgx, float orgy, float rot);
619 void CementPiece(float piece, float orgx, float orgy, float rot);
620 float bastet_profile_evaluate_time;
621 float bastet_profile_checkmetrics_time;
622 float BastetSearch(float buf, float pc, float x, float y, float rot, float move_bias)
623 // returns best score, or -1 if position is impossible
631 return 0; // DO NOT WANT
633 if(x < 1 || x > TET_WIDTH || y < 1 || y > TET_LINES)
634 return -1; // impossible
638 // did we already try?
639 b = x + (TET_WIDTH+2) * (y + (TET_LINES+2) * rot);
640 r = bufstr_get(buf, b);
641 if(r != "") // already tried
644 bufstr_set(buf, b, "0"); // in case we READ that, not that bad - we already got that value in another branch then anyway
648 t1 = gettime(GETTIME_HIRES);
649 if(CheckMetrics(pc, x, y, rot))
651 t2 = gettime(GETTIME_HIRES);
652 bastet_profile_checkmetrics_time += (t2 - t1);
655 s = BastetSearch(buf, pc, x-1, y, rot, move_bias - 1); if(s > sm) sm = s;
656 s = BastetSearch(buf, pc, x+1, y, rot, move_bias - 1); if(s > sm) sm = s;
657 s = BastetSearch(buf, pc, x, y, rot+1, move_bias - 1); if(s > sm) sm = s;
658 s = BastetSearch(buf, pc, x, y, rot-1, move_bias - 1); if(s > sm) sm = s;
660 s = BastetSearch(buf, pc, x, y+1, rot, move_bias + 2); if(s > sm) sm = s;
663 //printf("MAY CEMENT AT: %d %d %d\n", x, y, rot);
664 // moving down did not work - that means we can fixate the block here
665 t1 = gettime(GETTIME_HIRES);
667 CementPiece(pc, x, y, rot);
668 s = BastetEvaluate();
669 ClearPiece(pc, x, y, rot);
671 t2 = gettime(GETTIME_HIRES);
672 bastet_profile_evaluate_time += (t2 - t1);
679 t2 = gettime(GETTIME_HIRES);
680 bastet_profile_checkmetrics_time += (t2 - t1);
681 sm = -1; // impassible
684 bufstr_set(buf, b, ftos(sm));
689 float bastet_piece[7];
690 float bastet_score[7];
691 float bastet_piecetime[7];
696 bastet_profile_evaluate_time = 0;
697 bastet_profile_checkmetrics_time = 0;
698 float t1 = gettime(GETTIME_HIRES);
700 b = buf_create(); bastet_piece[0] = 1; bastet_score[0] = BastetSearch(b, 1, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[0]; buf_del(b);
701 b = buf_create(); bastet_piece[1] = 2; bastet_score[1] = BastetSearch(b, 2, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[1]; buf_del(b);
702 b = buf_create(); bastet_piece[2] = 3; bastet_score[2] = BastetSearch(b, 3, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[2]; buf_del(b);
703 b = buf_create(); bastet_piece[3] = 4; bastet_score[3] = BastetSearch(b, 4, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[3]; buf_del(b);
704 b = buf_create(); bastet_piece[4] = 5; bastet_score[4] = BastetSearch(b, 5, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[4]; buf_del(b);
705 b = buf_create(); bastet_piece[5] = 6; bastet_score[5] = BastetSearch(b, 6, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[5]; buf_del(b);
706 b = buf_create(); bastet_piece[6] = 7; bastet_score[6] = BastetSearch(b, 7, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[6]; buf_del(b);
708 float t2 = gettime(GETTIME_HIRES);
709 dprintf("Time taken: %.6f seconds (of this, ev = %.2f%%, cm = %.2f%%)\n", t2 - t1, 100 * bastet_profile_evaluate_time / (t2 - t1), 100 * bastet_profile_checkmetrics_time / (t2 - t1));
715 for(i = 0; i < 7; ++i)
717 printf("piece %s value = %d\n", substring("OJLIZST", bastet_piece[i]-1, 1), bastet_score[i]);
721 for(i = 0; i < 7; ++i)
726 for(j = i + 1; j < 7; ++j)
728 if(bastet_score[j] < s)
737 bastet_score[k] = bastet_score[i];
738 bastet_piece[k] = bastet_piece[i];
755 for(i = 0; i < 7; ++i)
758 bastet_piecetime[i] = 0.2 * bastet_piecetime[i];
760 bastet_piecetime[i] = 1.8 * bastet_piecetime[i] + 1000;
768 *********************************
772 *********************************
774 .float tet_piece_bucket;
782 if(self.tet_piece_bucket > 1)
784 p = mod(self.tet_piece_bucket, 7);
785 self.tet_piece_bucket = floor(self.tet_piece_bucket / 7);
790 p = floor(random() * 7);
793 for(i = 6; i > 0; --i)
795 q = floor(random() * i);
796 for(j = 0; j <= q; ++j)
807 self.tet_piece_bucket = b;
812 void TetAddScore(float n)
814 self.tet_score = self.tet_score + n * Tetris_Level();
815 if (self.tet_score > tet_high_score)
816 tet_high_score = self.tet_score;
818 float CheckMetrics(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
820 // check to see if the piece, if moved to the locations will overlap
824 // why did I start counting from 1, damnit
828 PieceMinsMaxs(rot, piece);
829 if (tet_piecemins.x+orgx<1 || tet_piecemaxs.x+orgx > TET_WIDTH || tet_piecemins.y+orgy<1 || tet_piecemaxs.y+orgy> TET_LINES)
830 return false; // ouside the level
831 for (y = tet_piecemins.y; y <= tet_piecemaxs.y; y = y + 1)
833 l = GetLine(y + orgy);
834 if(l != TET_EMPTY_LINE)
835 for (x = tet_piecemins.x; x <= tet_piecemaxs.x; x = x + 1)
836 if (PieceMetric(x, y, rot, piece))
837 if (GetXBlock(x + orgx, l))
838 return false; // uhoh, gonna hit something.
843 void ClearPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
846 // why did I start counting from 1, damnit
850 PieceMinsMaxs(rot, piece);
851 for (y = tet_piecemins.y; y <= tet_piecemaxs.y; y = y + 1)
853 for (x = tet_piecemins.x; x <= tet_piecemaxs.x; x = x + 1)
855 if (PieceMetric(x, y, rot, piece))
857 SetSquare(x + orgx, y + orgy, 0);
862 void CementPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
866 // why did I start counting from 1, damnit
870 pcolor = PieceColor(piece);
872 PieceMinsMaxs(rot, piece);
873 for (y = tet_piecemins.y; y <= tet_piecemaxs.y; y = y + 1)
875 for (x = tet_piecemins.x; x <= tet_piecemaxs.x; x = x + 1)
877 if (PieceMetric(x, y, rot, piece))
879 SetSquare(x + orgx, y + orgy, pcolor);
885 const float LINE_LOW = 349525;
886 const float LINE_HIGH = 699050; // above number times 2
888 void AddLines(float n)
893 FOR_EACH_REALCLIENT(head) if(head != self) if(head.tetris_on) if(head.tet_vs_id == self.tet_vs_id)
894 head.tet_vs_addlines += n;
897 void CompletedLines()
899 float y, cleared, added, pos, i;
907 if(strstrofs(ln, "0", 0) < 0)
908 cleared = cleared + 1;
916 ln = GetLine(y - cleared);
922 else if(cleared >= 1)
923 AddLines(cleared - 1);
925 self.tet_lines = self.tet_lines + cleared;
926 TetAddScore(cleared * cleared * 10);
928 added = self.tet_vs_addlines;
929 self.tet_vs_addlines = 0;
933 for(y = 1; y <= TET_LINES - added; ++y)
935 SetLine(y, GetLine(y + added));
937 for(y = max(1, TET_LINES - added + 1); y <= TET_LINES; ++y)
939 pos = floor(random() * TET_WIDTH);
941 for(i = 1; i <= TET_WIDTH; ++i)
943 ln = SetXBlock(i, ln, floor(random() * 7 + 1));
948 self.tet_highest_line = 0;
949 for(y = 1; y <= TET_LINES; ++y)
950 if(GetLine(y) != TET_EMPTY_LINE)
952 self.tet_highest_line = TET_LINES + 1 - y;
958 else if(cleared >= 4)
966 void HandleGame(float keyss)
969 // first off, we need to see if we need a new piece
978 if (self.piece_type == 0)
980 self.piece_pos = TET_START_PIECE_POS; // that's about middle top, we count from 1 ARGH
982 if(autocvar_g_bastet)
984 self.piece_type = BastetPiece();
985 self.next_piece = bastet_piece[6];
990 self.piece_type = self.next_piece;
992 self.piece_type = RandomPiece();
993 self.next_piece = RandomPiece();
995 keyss = 0; // no movement first frame
996 self.tet_autodown = time + 0.2;
1000 ClearPiece(self.piece_type, self.piece_pos.x, self.piece_pos.y, self.piece_pos.z);
1002 // next we need to check the piece metrics against what's on the level
1003 // based on the key order
1005 old_pos = check_pos = self.piece_pos;
1009 if (keyss & TETKEY_RIGHT)
1011 check_pos.x = check_pos.x + 1;
1014 else if (keyss & TETKEY_LEFT)
1016 check_pos.x = check_pos.x - 1;
1019 else if (keyss & TETKEY_ROTRIGHT)
1021 check_pos.z = check_pos.z + 1;
1022 piece_data = PieceShape(self.piece_type);
1026 else if (keyss & TETKEY_ROTLEFT)
1028 check_pos.z = check_pos.z - 1;
1029 piece_data = PieceShape(self.piece_type);
1034 if (check_pos.z > 3)
1036 else if (check_pos.z < 0)
1040 if (CheckMetrics(self.piece_type, check_pos.x, check_pos.y, check_pos.z))
1041 self.piece_pos = check_pos;
1045 self.tet_gameovertime = time + 5;
1050 for(i = 1; i <= nudge; ++i)
1052 if(CheckMetrics(self.piece_type, check_pos.x + i, check_pos.y, check_pos.z))
1053 self.piece_pos = check_pos + '1 0 0' * i;
1054 else if(CheckMetrics(self.piece_type, check_pos.x - i, check_pos.y, check_pos.z))
1055 self.piece_pos = check_pos - '1 0 0' * i;
1061 check_pos = self.piece_pos;
1062 if(keyss & TETKEY_DROP)
1064 // drop to bottom, but do NOT cement it yet
1065 // this allows sliding it
1067 while(CheckMetrics(self.piece_type, check_pos.x, check_pos.y + 1, check_pos.z))
1069 self.tet_autodown = time + 2 / (1 + Tetris_Level());
1071 else if (keyss & TETKEY_DOWN)
1073 check_pos.y = check_pos.y + 1;
1074 self.tet_autodown = time + 2 / (1 + Tetris_Level());
1076 else if (self.tet_autodown < time)
1078 check_pos.y = check_pos.y + 1;
1079 self.tet_autodown = time + 2 / (1 + Tetris_Level());
1081 if (CheckMetrics(self.piece_type, check_pos.x, check_pos.y, check_pos.z))
1083 if(old_pos != check_pos)
1084 self.tet_drawtime = 0;
1085 self.piece_pos = check_pos;
1089 CementPiece(self.piece_type, self.piece_pos.x, self.piece_pos.y, self.piece_pos.z);
1092 self.piece_type = 0;
1093 self.tet_drawtime = 0;
1096 CementPiece(self.piece_type, self.piece_pos.x, self.piece_pos.y, self.piece_pos.z);
1100 *********************************
1102 Important Linking Into Quake stuff
1104 *********************************
1108 void TetrisImpulse()
1110 if(self.tetris_on == 0 || self.tetris_on == 2) // from "off" or "game over"
1114 if(time < tet_vs_current_timeout)
1117 self.tet_vs_id = tet_vs_current_id;
1121 // start new VS game
1122 ++tet_vs_current_id;
1123 tet_vs_current_timeout = time + 15;
1124 self.tet_vs_id = tet_vs_current_id;
1125 bprint("^1TET^7R^1IS: ", self.netname, "^1 started a new game. Do ^7impulse 100^1 to join.\n");
1127 self.tet_highest_line = 0;
1129 self.tet_org = self.origin;
1130 self.movetype = MOVETYPE_NOCLIP;
1132 else if(self.tetris_on == 1) // from "on"
1140 float TetrisPreFrame()
1142 if (!self.tetris_on)
1145 self.tet_org = self.origin;
1146 if (self.tet_drawtime > time)
1149 if(self.tetris_on == 3)
1150 self.tet_drawtime = ceil(time - tet_vs_current_timeout + 0.1) + tet_vs_current_timeout;
1152 self.tet_drawtime = time + 0.5;
1155 float frik_anglemoda(float v)
1157 return v - floor(v/360) * 360;
1159 float angcompa(float y1, float y2)
1161 y1 = frik_anglemoda(y1);
1162 y2 = frik_anglemoda(y2);
1167 answer = answer - 360;
1168 else if (answer < -180)
1169 answer = answer + 360;
1173 .float tetkey_down, tetkey_rotright, tetkey_left, tetkey_right, tetkey_rotleft, tetkey_drop;
1175 float TetrisKeyRepeat(.float fld, float f)
1179 if(self.fld == 0) // initial key press
1181 self.fld = time + 0.3;
1184 else if(time > self.fld)
1186 self.fld = time + 0.1;
1191 // repeating too fast
1202 float TetrisPostFrame()
1208 if (!self.tetris_on)
1211 if(self.tetris_on == 2 && time > self.tet_gameovertime)
1217 if(self.tetris_on == 3 && time > tet_vs_current_timeout)
1219 self.tetris_on = 1; // start VS game
1220 self.tet_drawtime = 0;
1223 setorigin(self, self.tet_org);
1224 self.movetype = MOVETYPE_NONE;
1226 if(self.tetris_on == 1)
1228 if(TetrisKeyRepeat(tetkey_down, self.movement.x < 0))
1229 keysa |= TETKEY_DOWN;
1231 if(TetrisKeyRepeat(tetkey_rotright, self.movement.x > 0))
1232 keysa |= TETKEY_ROTRIGHT;
1234 if(TetrisKeyRepeat(tetkey_left, self.movement.y < 0))
1235 keysa |= TETKEY_LEFT;
1237 if(TetrisKeyRepeat(tetkey_right, self.movement.y > 0))
1238 keysa |= TETKEY_RIGHT;
1240 if(TetrisKeyRepeat(tetkey_rotleft, self.BUTTON_CROUCH))
1241 keysa |= TETKEY_ROTLEFT;
1243 if(TetrisKeyRepeat(tetkey_drop, self.BUTTON_JUMP))
1244 keysa |= TETKEY_DROP;
1254 float TetrisPostFrame()
1256 if (autocvar_g_bastet)
1258 cvar_set("g_bastet", "0");
1259 print("The useless cvar has been toggled.\n");