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;
20 .float tet_piece_bucket;
25 // 3 = waiting for VS players
27 var float tet_high_score = 0;
29 vector TET_START_PIECE_POS = '5 1 0';
31 float TET_DISPLAY_LINES = 20;
33 string TET_EMPTY_LINE = "0000000000"; // must match TET_WIDTH
35 float TET_BORDER = 139;
36 float TET_BLOCK = 133;
37 float TET_SPACE = 160; // blankness
42 float TETKEY_DOWN = 2;
43 float TETKEY_LEFT = 4;
44 float TETKEY_RIGHT = 8;
45 float TETKEY_ROTLEFT = 16;
46 float TETKEY_ROTRIGHT = 32;
47 float TETKEY_DROP = 64;
48 string TET_PADDING_RIGHT = "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0"; // get away from crosshair
54 float SVC_CENTERPRINTa = 26;
58 return ((floor((self.tet_lines / 10)) + 1));
61 void tetsnd(string snd)
63 play2(self, strcat("sounds/tetris/", snd));
67 *********************************
71 *********************************
73 void SetLine(float ln, string vl)
75 if(ln < 1 || ln > TET_LINES)
77 bufstr_set(tet_line_buf, ln + TET_LINES * num_for_edict(self), vl);
80 string GetLine(float ln)
82 if(ln < 1 || ln > TET_LINES)
84 if(ln < 1 || ln > TET_LINES)
85 return TET_EMPTY_LINE;
86 return bufstr_get(tet_line_buf, ln + TET_LINES * num_for_edict(self));
89 float GetXBlock(float x, string dat)
91 if(x < 1 || x > TET_WIDTH)
93 return stof(substring(dat, x-1, 1));
96 string SetXBlock(float x, string dat, float new)
99 substring(dat, 0, x-1),
101 substring(dat, x, -1)
106 float GetSquare(float x, float y)
108 return GetXBlock(x, GetLine(y));
111 void SetSquare(float x, float y, float val)
115 dat = SetXBlock(x, dat, val);
119 float PieceColor(float pc)
126 return 7; // L // we don't have orange, let's use white instead!
138 vector PieceShape(float pc)
141 return '20 20 0'; // O
143 return '1 21 0'; // J
145 return '16 21 0'; // L
147 return '0 85 0'; // I
149 return '5 20 0'; // Z
151 return '20 5 0'; // S
153 return '4 21 0'; // T
157 vector PieceSize(float pc)
176 vector PieceCenter(float pc)
179 return '2.5 1.5 0'; // O
185 return '2.5 2.5 0'; // I
196 // do x 1..4 and y 1..4 in case of rotation
197 float PieceMetric(float x, float y, float rot, float pc)
202 // return bits of a piece
203 ce = PieceCenter(pc);
204 if (rot == 1) // 90 degrees
206 // x+cx, y+cy -> -y+cx, x+cy
207 // X, Y -> -Y+cy+cx, X-cx+cy
212 x = -t + ce_x + ce_y;
214 else if (rot == 2)//180
219 else if (rot == 3) // 270
221 // x+cx, y+cy -> y+cx, -x+cy
222 // X, Y -> Y-cy+cx, -X+cx+cy
226 y = -x + ce_y + ce_x;
229 if (x < 1 || y < 1 || x > 4 || y > 2)
233 return !!(ce_x & pow(4, x-1)); // first row
235 return !!(ce_y & pow(4, x-1)); // second row
237 return 0; // illegal parms
239 vector tet_piecemins;
240 vector tet_piecemaxs;
241 void PieceMinsMaxs(float rot, float pc)
248 ce = PieceCenter(pc);
253 tet_piecemins_x = floor(3.0 - sz_x * 0.5);
254 tet_piecemaxs_x = floor(2.0 + sz_x * 0.5);
257 // special case for "I"
258 tet_piecemins_y = tet_piecemaxs_y = 2;
263 tet_piecemaxs_y = sz_y;
265 //print(sprintf("ce%v sz%v mi%v ma%v\n", ce, sz, tet_piecemins, tet_piecemaxs));
266 if (rot == 1) // 90 degrees
269 tet_piecemins_y = -tet_piecemins_x + ce_y + ce_x;
270 tet_piecemins_x = t - ce_y + ce_x;
272 tet_piecemaxs_y = -tet_piecemaxs_x + ce_y + ce_x;
273 tet_piecemaxs_x = t - ce_y + ce_x;
274 // swap mins_y, maxs_y
276 tet_piecemins_y = tet_piecemaxs_y;
280 else if (rot == 2)//180
283 tet_piecemins = 2 * ce - tet_piecemaxs;
284 tet_piecemaxs = 2 * ce - v;
286 else if (rot == 3) // 270
289 tet_piecemins_y = tet_piecemins_x - ce_x + ce_y;
290 tet_piecemins_x = -t + ce_x + ce_y;
292 tet_piecemaxs_y = tet_piecemaxs_x - ce_x + ce_y;
293 tet_piecemaxs_x = -t + ce_x + ce_y;
294 // swap mins_x, maxs_x
296 tet_piecemins_x = tet_piecemaxs_x;
301 print(vtos(tet_piecemins), "-");
302 print(vtos(tet_piecemaxs), "\n");
303 if(tet_piecemins_x > tet_piecemaxs_x)
304 error("inconsistent mins/maxs");
305 if(tet_piecemins_y > tet_piecemaxs_y)
306 error("inconsistent mins/maxs");
308 vector realmins, realmaxs;
311 for(i = 1; i <= 4; ++i)
312 for(j = 1; j <= 4; ++j)
313 if(PieceMetric(i, j, rot, pc))
315 realmins_x = min(realmins_x, i);
316 realmins_y = min(realmins_y, j);
317 realmaxs_x = max(realmaxs_x, i);
318 realmaxs_y = max(realmaxs_y, j);
320 if(realmins != tet_piecemins || realmaxs != tet_piecemaxs)
321 error(sprintf("incorrect mins/maxs: %v %v in %d rot %d mins %v maxs %v\n", realmins, realmaxs, rot, pc, tet_piecemins, tet_piecemaxs));
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 void WriteTetrisString(string s)
341 WriteUnterminatedString(MSG_ONE, strconv(0, 2, 2, s));
344 float pnum(float num, float dig)
349 WriteChar(MSG_ONE, 173);
353 num = num - (f * 10);
355 dig = pnum(f, dig+1);
359 for (i = 0; i < (5 - dig); i = i + 1)
360 WriteChar(MSG_ONE, TET_SPACE);
362 WriteChar(MSG_ONE, 176 + num);
366 void DrawLine(float ln)
369 WriteChar(MSG_ONE, TET_BORDER);
371 for (x = 1; x <= TET_WIDTH; x = x + 1)
373 d = GetSquare(x, ln + TET_LINES - TET_DISPLAY_LINES);
376 WriteChar(MSG_ONE, '^');
377 WriteChar(MSG_ONE, d + '0');
378 WriteChar(MSG_ONE, TET_BLOCK);
381 WriteChar(MSG_ONE, TET_SPACE);
383 WriteChar(MSG_ONE, '^');
384 WriteChar(MSG_ONE, '7');
385 WriteChar(MSG_ONE, TET_BORDER);
388 void DrawPiece(float pc, float ln)
390 float x, d, piece_ln, pcolor;
392 pcolor = PieceColor(pc);
393 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
395 piece_dat = PieceShape(pc);
397 piece_ln = piece_dat_x;
399 piece_ln = piece_dat_y;
400 for (x = 1; x <= 4; x = x + 1)
402 if (piece_ln & pow(4, x-1))
404 WriteChar(MSG_ONE, '^');
405 WriteChar(MSG_ONE, pcolor + '0');
406 WriteChar(MSG_ONE, TET_BLOCK);
409 WriteChar(MSG_ONE, TET_SPACE);
411 WriteChar(MSG_ONE, TET_SPACE); // pad to 6
418 WriteChar(MSG_ONE, SVC_CENTERPRINTa);
419 if(autocvar_g_bastet)
421 WriteTetrisString("NEVER GONNA GIVE YOU");
422 WriteChar(MSG_ONE, 10);
425 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
426 WriteChar(MSG_ONE, TET_BORDER);
427 WriteTetrisString(" ");
428 WriteUnterminatedString(MSG_ONE, TET_PADDING_RIGHT);
429 WriteChar(MSG_ONE, 10);
430 for (i = 1; i <= TET_DISPLAY_LINES; i = i + 1)
432 if(self.tetris_on == 2)
433 WriteTetrisString(" GAME OVER ");
434 else if(self.tetris_on == 3)
435 WriteTetrisString("PLEASE WAIT");
439 WriteTetrisString(autocvar_g_bastet ? " THAT " : " NEXT ");
441 DrawPiece(self.next_piece, 1);
443 DrawPiece(self.next_piece, 2);
445 WriteTetrisString(" LINES");
447 pnum(self.tet_lines, 0);
449 WriteTetrisString(" SCORE");
451 pnum(self.tet_score, 0);
453 WriteTetrisString(" HIGH ");
455 WriteTetrisString(" SCORE");
457 pnum(tet_high_score, 0);
459 WriteTetrisString(" LEVEL");
461 pnum(Tetris_Level(), 0);
463 WriteTetrisString(" ");
464 WriteUnterminatedString(MSG_ONE, TET_PADDING_RIGHT);
465 WriteChar(MSG_ONE, 10);
469 for (i = 1; i <= (TET_WIDTH + 2); i = i + 1)
470 WriteChar(MSG_ONE, TET_BORDER);
471 WriteTetrisString(" ");
472 WriteUnterminatedString(MSG_ONE, TET_PADDING_RIGHT);
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 WriteUnterminatedString(MSG_ONE, ">");
491 WriteUnterminatedString(MSG_ONE, " ");
492 if(head.tetris_on == 2)
493 WriteUnterminatedString(MSG_ONE, " X_X");
495 pnum(head.tet_highest_line, 0);
496 WriteUnterminatedString(MSG_ONE, " ");
497 WriteUnterminatedString(MSG_ONE, head.netname);
498 WriteChar(MSG_ONE, 10);
502 WriteChar(MSG_ONE, 0);
505 *********************************
509 *********************************
518 tet_line_buf = buf_create();
520 for (i=1; i<=TET_LINES; i = i + 1)
521 SetLine(i, TET_EMPTY_LINE);
522 self.piece_pos = '0 0 0';
524 self.next_piece = self.tet_lines = self.tet_score = 0;
525 self.tet_piece_bucket = 0;
530 centerprint(self, " ");
534 self.movetype = MOVETYPE_WALK;
541 for(r = 1; r <= TET_LINES; ++r)
545 for(c = 1; c <= TET_WIDTH; ++c)
547 print(ftos(GetXBlock(c, l)));
553 float BastetEvaluate()
558 float score, score_save;
559 string occupied, occupied_save;
560 float occupied_count, occupied_count_save;
565 // adds a bonus for each free dot above the occupied blocks profile
566 occupied = TET_EMPTY_LINE;
567 occupied_count = TET_WIDTH;
570 for(i = 1; i <= TET_LINES; ++i)
573 if(l == TET_EMPTY_LINE)
579 occupied_save = occupied;
580 occupied_count_save = occupied_count;
582 for(j = 1; j <= TET_WIDTH; ++j)
586 if(!GetXBlock(j, occupied))
588 occupied = SetXBlock(j, occupied, 1);
594 score += 10000 * occupied_count;
598 occupied = occupied_save;
599 occupied_count = occupied_count_save;
600 score = score_save + 100000000 + 10000 * TET_WIDTH + 1000;
605 score += 1000 * height;
610 float CheckMetrics(float piece, float orgx, float orgy, float rot);
611 void ClearPiece(float piece, float orgx, float orgy, float rot);
612 void CementPiece(float piece, float orgx, float orgy, float rot);
613 float bastet_profile_evaluate_time;
614 float bastet_profile_checkmetrics_time;
615 float BastetSearch(float buf, float pc, float x, float y, float rot, float move_bias)
616 // returns best score, or -1 if position is impossible
624 return 0; // DO NOT WANT
626 if(x < 1 || x > TET_WIDTH || y < 1 || y > TET_LINES)
627 return -1; // impossible
631 // did we already try?
632 b = x + (TET_WIDTH+2) * (y + (TET_LINES+2) * rot);
633 r = bufstr_get(buf, b);
634 if(r != "") // already tried
637 bufstr_set(buf, b, "0"); // in case we READ that, not that bad - we already got that value in another branch then anyway
641 t1 = gettime(GETTIME_HIRES);
642 if(CheckMetrics(pc, x, y, rot))
644 t2 = gettime(GETTIME_HIRES);
645 bastet_profile_checkmetrics_time += (t2 - t1);
648 s = BastetSearch(buf, pc, x-1, y, rot, move_bias - 1); if(s > sm) sm = s;
649 s = BastetSearch(buf, pc, x+1, y, rot, move_bias - 1); if(s > sm) sm = s;
650 s = BastetSearch(buf, pc, x, y, rot+1, move_bias - 1); if(s > sm) sm = s;
651 s = BastetSearch(buf, pc, x, y, rot-1, move_bias - 1); if(s > sm) sm = s;
653 s = BastetSearch(buf, pc, x, y+1, rot, move_bias + 2); if(s > sm) sm = s;
656 //print(sprintf("MAY CEMENT AT: %d %d %d\n", x, y, rot));
657 // moving down did not work - that means we can fixate the block here
658 t1 = gettime(GETTIME_HIRES);
660 CementPiece(pc, x, y, rot);
661 s = BastetEvaluate();
662 ClearPiece(pc, x, y, rot);
664 t2 = gettime(GETTIME_HIRES);
665 bastet_profile_evaluate_time += (t2 - t1);
672 t2 = gettime(GETTIME_HIRES);
673 bastet_profile_checkmetrics_time += (t2 - t1);
674 sm = -1; // impassible
677 bufstr_set(buf, b, ftos(sm));
682 float bastet_piece[7];
683 float bastet_score[7];
684 float bastet_piecetime[7];
689 bastet_profile_evaluate_time = 0;
690 bastet_profile_checkmetrics_time = 0;
691 var float t1 = gettime(GETTIME_HIRES);
693 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);
694 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);
695 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);
696 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);
697 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);
698 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);
699 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);
701 var float t2 = gettime(GETTIME_HIRES);
702 dprint(sprintf("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)));
708 for(i = 0; i < 7; ++i)
710 print(sprintf("piece %s value = %d\n", substring("OJLIZST", bastet_piece[i]-1, 1), bastet_score[i]));
714 for(i = 0; i < 7; ++i)
719 for(j = i + 1; j < 7; ++j)
721 if(bastet_score[j] < s)
730 bastet_score[k] = bastet_score[i];
731 bastet_piece[k] = bastet_piece[i];
748 for(i = 0; i < 7; ++i)
751 bastet_piecetime[i] = 0.2 * bastet_piecetime[i];
753 bastet_piecetime[i] = 1.8 * bastet_piecetime[i] + 1000;
761 *********************************
765 *********************************
767 .float tet_piece_bucket;
775 if(self.tet_piece_bucket > 1)
777 p = mod(self.tet_piece_bucket, 7);
778 self.tet_piece_bucket = floor(self.tet_piece_bucket / 7);
783 p = floor(random() * 7);
786 for(i = 6; i > 0; --i)
788 q = floor(random() * i);
789 for(j = 0; j <= q; ++j)
800 self.tet_piece_bucket = b;
805 void TetAddScore(float n)
807 self.tet_score = self.tet_score + n * Tetris_Level();
808 if (self.tet_score > tet_high_score)
809 tet_high_score = self.tet_score;
811 float CheckMetrics(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
813 // check to see if the piece, if moved to the locations will overlap
817 // why did I start counting from 1, damnit
821 PieceMinsMaxs(rot, piece);
822 if (tet_piecemins_x+orgx<1 || tet_piecemaxs_x+orgx > TET_WIDTH || tet_piecemins_y+orgy<1 || tet_piecemaxs_y+orgy> TET_LINES)
823 return FALSE; // ouside the level
824 for (y = tet_piecemins_y; y <= tet_piecemaxs_y; y = y + 1)
826 l = GetLine(y + orgy);
827 if(l != TET_EMPTY_LINE)
828 for (x = tet_piecemins_x; x <= tet_piecemaxs_x; x = x + 1)
829 if (PieceMetric(x, y, rot, piece))
830 if (GetXBlock(x + orgx, l))
831 return FALSE; // uhoh, gonna hit something.
836 void ClearPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
839 // why did I start counting from 1, damnit
843 PieceMinsMaxs(rot, piece);
844 for (y = tet_piecemins_y; y <= tet_piecemaxs_y; y = y + 1)
846 for (x = tet_piecemins_x; x <= tet_piecemaxs_x; x = x + 1)
848 if (PieceMetric(x, y, rot, piece))
850 SetSquare(x + orgx, y + orgy, 0);
855 void CementPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/
859 // why did I start counting from 1, damnit
863 pcolor = PieceColor(piece);
865 PieceMinsMaxs(rot, piece);
866 for (y = tet_piecemins_y; y <= tet_piecemaxs_y; y = y + 1)
868 for (x = tet_piecemins_x; x <= tet_piecemaxs_x; x = x + 1)
870 if (PieceMetric(x, y, rot, piece))
872 SetSquare(x + orgx, y + orgy, pcolor);
878 float LINE_LOW = 349525;
879 float LINE_HIGH = 699050; // above number times 2
881 void AddLines(float n)
886 FOR_EACH_REALCLIENT(head) if(head != self) if(head.tetris_on) if(head.tet_vs_id == self.tet_vs_id)
887 head.tet_vs_addlines += n;
890 void CompletedLines()
892 float y, cleared, added, pos, i;
900 if(strstrofs(ln, "0", 0) < 0)
901 cleared = cleared + 1;
909 ln = GetLine(y - cleared);
915 else if(cleared >= 1)
916 AddLines(cleared - 1);
918 self.tet_lines = self.tet_lines + cleared;
919 TetAddScore(cleared * cleared * 10);
921 added = self.tet_vs_addlines;
922 self.tet_vs_addlines = 0;
926 for(y = 1; y <= TET_LINES - added; ++y)
928 SetLine(y, GetLine(y + added));
930 for(y = max(1, TET_LINES - added + 1); y <= TET_LINES; ++y)
932 pos = floor(random() * TET_WIDTH);
934 for(i = 1; i <= TET_WIDTH; ++i)
936 ln = SetXBlock(i, ln, floor(random() * 7 + 1));
941 self.tet_highest_line = 0;
942 for(y = 1; y <= TET_LINES; ++y)
943 if(GetLine(y) != TET_EMPTY_LINE)
945 self.tet_highest_line = TET_LINES + 1 - y;
951 else if(cleared >= 4)
959 void HandleGame(float keyss)
962 // first off, we need to see if we need a new piece
971 if (self.piece_type == 0)
973 self.piece_pos = TET_START_PIECE_POS; // that's about middle top, we count from 1 ARGH
975 if(autocvar_g_bastet)
977 self.piece_type = BastetPiece();
978 self.next_piece = bastet_piece[6];
983 self.piece_type = self.next_piece;
985 self.piece_type = RandomPiece();
986 self.next_piece = RandomPiece();
988 keyss = 0; // no movement first frame
989 self.tet_autodown = time + 0.2;
993 ClearPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
995 // next we need to check the piece metrics against what's on the level
996 // based on the key order
998 old_pos = check_pos = self.piece_pos;
1002 if (keyss & TETKEY_RIGHT)
1004 check_pos_x = check_pos_x + 1;
1007 else if (keyss & TETKEY_LEFT)
1009 check_pos_x = check_pos_x - 1;
1012 else if (keyss & TETKEY_ROTRIGHT)
1014 check_pos_z = check_pos_z + 1;
1015 piece_data = PieceShape(self.piece_type);
1019 else if (keyss & TETKEY_ROTLEFT)
1021 check_pos_z = check_pos_z - 1;
1022 piece_data = PieceShape(self.piece_type);
1027 if (check_pos_z > 3)
1029 else if (check_pos_z < 0)
1033 if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
1034 self.piece_pos = check_pos;
1038 self.tet_gameovertime = time + 5;
1043 for(i = 1; i <= nudge; ++i)
1045 if(CheckMetrics(self.piece_type, check_pos_x + i, check_pos_y, check_pos_z))
1046 self.piece_pos = check_pos + '1 0 0' * i;
1047 else if(CheckMetrics(self.piece_type, check_pos_x - i, check_pos_y, check_pos_z))
1048 self.piece_pos = check_pos - '1 0 0' * i;
1054 check_pos = self.piece_pos;
1055 if(keyss & TETKEY_DROP)
1057 // drop to bottom, but do NOT cement it yet
1058 // this allows sliding it
1060 while(CheckMetrics(self.piece_type, check_pos_x, check_pos_y + 1, check_pos_z))
1062 self.tet_autodown = time + 2 / (1 + Tetris_Level());
1064 else if (keyss & TETKEY_DOWN)
1066 check_pos_y = check_pos_y + 1;
1067 self.tet_autodown = time + 2 / (1 + Tetris_Level());
1069 else if (self.tet_autodown < time)
1071 check_pos_y = check_pos_y + 1;
1072 self.tet_autodown = time + 2 / (1 + Tetris_Level());
1074 if (CheckMetrics(self.piece_type, check_pos_x, check_pos_y, check_pos_z))
1076 if(old_pos != check_pos)
1077 self.tet_drawtime = 0;
1078 self.piece_pos = check_pos;
1082 CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
1085 self.piece_type = 0;
1086 self.tet_drawtime = 0;
1089 CementPiece(self.piece_type, self.piece_pos_x, self.piece_pos_y, self.piece_pos_z);
1093 *********************************
1095 Important Linking Into Quake stuff
1097 *********************************
1101 void TetrisImpulse()
1103 if(self.tetris_on == 0 || self.tetris_on == 2) // from "off" or "game over"
1107 if(time < tet_vs_current_timeout)
1110 self.tet_vs_id = tet_vs_current_id;
1114 // start new VS game
1115 ++tet_vs_current_id;
1116 tet_vs_current_timeout = time + 15;
1117 self.tet_vs_id = tet_vs_current_id;
1118 bprint("^1TET^7R^1IS: ", self.netname, "^1 started a new game. Do ^7impulse 100^1 to join.\n");
1120 self.tet_highest_line = 0;
1122 self.tet_org = self.origin;
1123 self.movetype = MOVETYPE_NOCLIP;
1125 else if(self.tetris_on == 1) // from "on"
1133 float TetrisPreFrame()
1135 if (!self.tetris_on)
1138 self.tet_org = self.origin;
1139 if (self.tet_drawtime > time)
1142 if(self.tetris_on == 3)
1143 self.tet_drawtime = ceil(time - tet_vs_current_timeout + 0.1) + tet_vs_current_timeout;
1145 self.tet_drawtime = time + 0.5;
1148 float frik_anglemoda(float v)
1150 return v - floor(v/360) * 360;
1152 float angcompa(float y1, float y2)
1154 y1 = frik_anglemoda(y1);
1155 y2 = frik_anglemoda(y2);
1160 answer = answer - 360;
1161 else if (answer < -180)
1162 answer = answer + 360;
1166 .float tetkey_down, tetkey_rotright, tetkey_left, tetkey_right, tetkey_rotleft, tetkey_drop;
1168 float TetrisKeyRepeat(.float fld, float f)
1172 if(self.fld == 0) // initial key press
1174 self.fld = time + 0.3;
1177 else if(time > self.fld)
1179 self.fld = time + 0.1;
1184 // repeating too fast
1195 float TetrisPostFrame()
1201 if (!self.tetris_on)
1204 if(self.tetris_on == 2 && time > self.tet_gameovertime)
1210 if(self.tetris_on == 3 && time > tet_vs_current_timeout)
1212 self.tetris_on = 1; // start VS game
1213 self.tet_drawtime = 0;
1216 setorigin(self, self.tet_org);
1217 self.movetype = MOVETYPE_NONE;
1219 if(self.tetris_on == 1)
1221 if(TetrisKeyRepeat(tetkey_down, self.movement_x < 0))
1222 keysa |= TETKEY_DOWN;
1224 if(TetrisKeyRepeat(tetkey_rotright, self.movement_x > 0))
1225 keysa |= TETKEY_ROTRIGHT;
1227 if(TetrisKeyRepeat(tetkey_left, self.movement_y < 0))
1228 keysa |= TETKEY_LEFT;
1230 if(TetrisKeyRepeat(tetkey_right, self.movement_y > 0))
1231 keysa |= TETKEY_RIGHT;
1233 if(TetrisKeyRepeat(tetkey_rotleft, self.BUTTON_CROUCH))
1234 keysa |= TETKEY_ROTLEFT;
1236 if(TetrisKeyRepeat(tetkey_drop, self.BUTTON_JUMP))
1237 keysa |= TETKEY_DROP;
1247 FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(autocvar_g_bastet);