|
|
1.1.1.3 ! root 1: /* ! 2: Copyright (C) 1997-2001 Id Software, Inc. ! 3: ! 4: This program is free software; you can redistribute it and/or ! 5: modify it under the terms of the GNU General Public License ! 6: as published by the Free Software Foundation; either version 2 ! 7: of the License, or (at your option) any later version. ! 8: ! 9: This program is distributed in the hope that it will be useful, ! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ! 12: ! 13: See the GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with this program; if not, write to the Free Software ! 17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ! 18: ! 19: */ 1.1 root 20: // console.c 21: 22: #include "client.h" 23: 24: console_t con; 25: 26: cvar_t *con_notifytime; 27: 28: 29: #define MAXCMDLINE 256 30: extern char key_lines[32][MAXCMDLINE]; 31: extern int edit_line; 32: extern int key_linepos; 33: 34: 35: void DrawString (int x, int y, char *s) 36: { 37: while (*s) 38: { 39: re.DrawChar (x, y, *s); 40: x+=8; 41: s++; 42: } 43: } 44: 45: void DrawAltString (int x, int y, char *s) 46: { 47: while (*s) 48: { 49: re.DrawChar (x, y, *s ^ 0x80); 50: x+=8; 51: s++; 52: } 53: } 54: 55: 56: void Key_ClearTyping (void) 57: { 58: key_lines[edit_line][1] = 0; // clear any typing 59: key_linepos = 1; 60: } 61: 62: /* 63: ================ 64: Con_ToggleConsole_f 65: ================ 66: */ 67: void Con_ToggleConsole_f (void) 68: { 69: SCR_EndLoadingPlaque (); // get rid of loading plaque 70: 71: if (cl.attractloop) 72: { 73: Cbuf_AddText ("killserver\n"); 74: return; 75: } 76: 77: if (cls.state == ca_disconnected) 78: { // start the demo loop again 79: Cbuf_AddText ("d1\n"); 80: return; 81: } 82: 83: Key_ClearTyping (); 84: Con_ClearNotify (); 85: 86: if (cls.key_dest == key_console) 87: { 88: M_ForceMenuOff (); 89: Cvar_Set ("paused", "0"); 90: } 91: else 92: { 93: M_ForceMenuOff (); 94: cls.key_dest = key_console; 95: 96: if (Cvar_VariableValue ("maxclients") == 1 97: && Com_ServerState ()) 98: Cvar_Set ("paused", "1"); 99: } 100: } 101: 102: /* 103: ================ 104: Con_ToggleChat_f 105: ================ 106: */ 107: void Con_ToggleChat_f (void) 108: { 109: Key_ClearTyping (); 110: 111: if (cls.key_dest == key_console) 112: { 113: if (cls.state == ca_active) 114: { 115: M_ForceMenuOff (); 116: cls.key_dest = key_game; 117: } 118: } 119: else 120: cls.key_dest = key_console; 121: 122: Con_ClearNotify (); 123: } 124: 125: /* 126: ================ 127: Con_Clear_f 128: ================ 129: */ 130: void Con_Clear_f (void) 131: { 132: memset (con.text, ' ', CON_TEXTSIZE); 133: } 134: 135: 136: /* 137: ================ 138: Con_Dump_f 139: 140: Save the console contents out to a file 141: ================ 142: */ 143: void Con_Dump_f (void) 144: { 145: int l, x; 146: char *line; 147: FILE *f; 148: char buffer[1024]; 149: char name[MAX_OSPATH]; 150: 151: if (Cmd_Argc() != 2) 152: { 153: Com_Printf ("usage: condump <filename>\n"); 154: return; 155: } 156: 157: Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1)); 158: 159: Com_Printf ("Dumped console text to %s.\n", name); 160: FS_CreatePath (name); 161: f = fopen (name, "w"); 162: if (!f) 163: { 164: Com_Printf ("ERROR: couldn't open.\n"); 165: return; 166: } 167: 168: // skip empty lines 169: for (l = con.current - con.totallines + 1 ; l <= con.current ; l++) 170: { 171: line = con.text + (l%con.totallines)*con.linewidth; 172: for (x=0 ; x<con.linewidth ; x++) 173: if (line[x] != ' ') 174: break; 175: if (x != con.linewidth) 176: break; 177: } 178: 179: // write the remaining lines 180: buffer[con.linewidth] = 0; 181: for ( ; l <= con.current ; l++) 182: { 183: line = con.text + (l%con.totallines)*con.linewidth; 184: strncpy (buffer, line, con.linewidth); 185: for (x=con.linewidth-1 ; x>=0 ; x--) 186: { 187: if (buffer[x] == ' ') 188: buffer[x] = 0; 189: else 190: break; 191: } 1.1.1.2 root 192: for (x=0; buffer[x]; x++) 193: buffer[x] &= 0x7f; 1.1 root 194: 195: fprintf (f, "%s\n", buffer); 196: } 197: 198: fclose (f); 199: } 200: 201: 202: /* 203: ================ 204: Con_ClearNotify 205: ================ 206: */ 207: void Con_ClearNotify (void) 208: { 209: int i; 210: 211: for (i=0 ; i<NUM_CON_TIMES ; i++) 212: con.times[i] = 0; 213: } 214: 215: 216: /* 217: ================ 218: Con_MessageMode_f 219: ================ 220: */ 221: void Con_MessageMode_f (void) 222: { 223: chat_team = false; 224: cls.key_dest = key_message; 225: } 226: 227: /* 228: ================ 229: Con_MessageMode2_f 230: ================ 231: */ 232: void Con_MessageMode2_f (void) 233: { 234: chat_team = true; 235: cls.key_dest = key_message; 236: } 237: 238: /* 239: ================ 240: Con_CheckResize 241: 242: If the line width has changed, reformat the buffer. 243: ================ 244: */ 245: void Con_CheckResize (void) 246: { 247: int i, j, width, oldwidth, oldtotallines, numlines, numchars; 248: char tbuf[CON_TEXTSIZE]; 249: 250: width = (viddef.width >> 3) - 2; 251: 252: if (width == con.linewidth) 253: return; 254: 255: if (width < 1) // video hasn't been initialized yet 256: { 257: width = 38; 258: con.linewidth = width; 259: con.totallines = CON_TEXTSIZE / con.linewidth; 260: memset (con.text, ' ', CON_TEXTSIZE); 261: } 262: else 263: { 264: oldwidth = con.linewidth; 265: con.linewidth = width; 266: oldtotallines = con.totallines; 267: con.totallines = CON_TEXTSIZE / con.linewidth; 268: numlines = oldtotallines; 269: 270: if (con.totallines < numlines) 271: numlines = con.totallines; 272: 273: numchars = oldwidth; 274: 275: if (con.linewidth < numchars) 276: numchars = con.linewidth; 277: 278: memcpy (tbuf, con.text, CON_TEXTSIZE); 279: memset (con.text, ' ', CON_TEXTSIZE); 280: 281: for (i=0 ; i<numlines ; i++) 282: { 283: for (j=0 ; j<numchars ; j++) 284: { 285: con.text[(con.totallines - 1 - i) * con.linewidth + j] = 286: tbuf[((con.current - i + oldtotallines) % 287: oldtotallines) * oldwidth + j]; 288: } 289: } 290: 291: Con_ClearNotify (); 292: } 293: 294: con.current = con.totallines - 1; 295: con.display = con.current; 296: } 297: 298: 299: /* 300: ================ 301: Con_Init 302: ================ 303: */ 304: void Con_Init (void) 305: { 306: con.linewidth = -1; 307: 308: Con_CheckResize (); 309: 310: Com_Printf ("Console initialized.\n"); 311: 312: // 313: // register our commands 314: // 315: con_notifytime = Cvar_Get ("con_notifytime", "3", 0); 316: 317: Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); 318: Cmd_AddCommand ("togglechat", Con_ToggleChat_f); 319: Cmd_AddCommand ("messagemode", Con_MessageMode_f); 320: Cmd_AddCommand ("messagemode2", Con_MessageMode2_f); 321: Cmd_AddCommand ("clear", Con_Clear_f); 322: Cmd_AddCommand ("condump", Con_Dump_f); 323: con.initialized = true; 324: } 325: 326: 327: /* 328: =============== 329: Con_Linefeed 330: =============== 331: */ 332: void Con_Linefeed (void) 333: { 334: con.x = 0; 335: if (con.display == con.current) 336: con.display++; 337: con.current++; 338: memset (&con.text[(con.current%con.totallines)*con.linewidth] 339: , ' ', con.linewidth); 340: } 341: 342: /* 343: ================ 344: Con_Print 345: 346: Handles cursor positioning, line wrapping, etc 347: All console printing must go through this in order to be logged to disk 348: If no console is visible, the text will appear at the top of the game window 349: ================ 350: */ 351: void Con_Print (char *txt) 352: { 353: int y; 354: int c, l; 355: static int cr; 356: int mask; 357: 358: if (!con.initialized) 359: return; 360: 361: if (txt[0] == 1 || txt[0] == 2) 362: { 363: mask = 128; // go to colored text 364: txt++; 365: } 366: else 367: mask = 0; 368: 369: 370: while ( (c = *txt) ) 371: { 372: // count word length 373: for (l=0 ; l< con.linewidth ; l++) 374: if ( txt[l] <= ' ') 375: break; 376: 377: // word wrap 378: if (l != con.linewidth && (con.x + l > con.linewidth) ) 379: con.x = 0; 380: 381: txt++; 382: 383: if (cr) 384: { 385: con.current--; 386: cr = false; 387: } 388: 389: 390: if (!con.x) 391: { 392: Con_Linefeed (); 393: // mark time for transparent overlay 394: if (con.current >= 0) 395: con.times[con.current % NUM_CON_TIMES] = cls.realtime; 396: } 397: 398: switch (c) 399: { 400: case '\n': 401: con.x = 0; 402: break; 403: 404: case '\r': 405: con.x = 0; 406: cr = 1; 407: break; 408: 409: default: // display character and advance 410: y = con.current % con.totallines; 411: con.text[y*con.linewidth+con.x] = c | mask | con.ormask; 412: con.x++; 413: if (con.x >= con.linewidth) 414: con.x = 0; 415: break; 416: } 417: 418: } 419: } 420: 421: 422: /* 423: ============== 424: Con_CenteredPrint 425: ============== 426: */ 427: void Con_CenteredPrint (char *text) 428: { 429: int l; 430: char buffer[1024]; 431: 432: l = strlen(text); 433: l = (con.linewidth-l)/2; 434: if (l < 0) 435: l = 0; 436: memset (buffer, ' ', l); 437: strcpy (buffer+l, text); 438: strcat (buffer, "\n"); 439: Con_Print (buffer); 440: } 441: 442: /* 443: ============================================================================== 444: 445: DRAWING 446: 447: ============================================================================== 448: */ 449: 450: 451: /* 452: ================ 453: Con_DrawInput 454: 455: The input line scrolls horizontally if typing goes beyond the right edge 456: ================ 457: */ 458: void Con_DrawInput (void) 459: { 460: int y; 461: int i; 462: char *text; 463: 464: if (cls.key_dest == key_menu) 465: return; 466: if (cls.key_dest != key_console && cls.state == ca_active) 467: return; // don't draw anything (always draw if not active) 468: 469: text = key_lines[edit_line]; 470: 471: // add the cursor frame 472: text[key_linepos] = 10+((int)(cls.realtime>>8)&1); 473: 474: // fill out remainder with spaces 475: for (i=key_linepos+1 ; i< con.linewidth ; i++) 476: text[i] = ' '; 477: 478: // prestep if horizontally scrolling 479: if (key_linepos >= con.linewidth) 480: text += 1 + key_linepos - con.linewidth; 481: 482: // draw it 483: y = con.vislines-16; 484: 485: for (i=0 ; i<con.linewidth ; i++) 1.1.1.2 root 486: re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]); 1.1 root 487: 488: // remove cursor 489: key_lines[edit_line][key_linepos] = 0; 490: } 491: 492: 493: /* 494: ================ 495: Con_DrawNotify 496: 497: Draws the last few lines of output transparently over the game top 498: ================ 499: */ 500: void Con_DrawNotify (void) 501: { 502: int x, v; 503: char *text; 504: int i; 505: int time; 506: char *s; 507: int skip; 508: 509: v = 0; 510: for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++) 511: { 512: if (i < 0) 513: continue; 514: time = con.times[i % NUM_CON_TIMES]; 515: if (time == 0) 516: continue; 517: time = cls.realtime - time; 518: if (time > con_notifytime->value*1000) 519: continue; 520: text = con.text + (i % con.totallines)*con.linewidth; 521: 522: for (x = 0 ; x < con.linewidth ; x++) 523: re.DrawChar ( (x+1)<<3, v, text[x]); 524: 525: v += 8; 526: } 527: 528: 529: if (cls.key_dest == key_message) 530: { 531: if (chat_team) 532: { 533: DrawString (8, v, "say_team:"); 534: skip = 11; 535: } 536: else 537: { 538: DrawString (8, v, "say:"); 539: skip = 5; 540: } 541: 542: s = chat_buffer; 543: if (chat_bufferlen > (viddef.width>>3)-(skip+1)) 544: s += chat_bufferlen - ((viddef.width>>3)-(skip+1)); 545: x = 0; 546: while(s[x]) 547: { 548: re.DrawChar ( (x+skip)<<3, v, s[x]); 549: x++; 550: } 551: re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1)); 552: v += 8; 553: } 554: 555: if (v) 556: { 557: SCR_AddDirtyPoint (0,0); 558: SCR_AddDirtyPoint (viddef.width-1, v); 559: } 560: } 561: 562: /* 563: ================ 564: Con_DrawConsole 565: 566: Draws the console with the solid background 567: ================ 568: */ 569: void Con_DrawConsole (float frac) 570: { 1.1.1.2 root 571: int i, j, x, y, n; 1.1 root 572: int rows; 573: char *text; 574: int row; 575: int lines; 576: char version[64]; 1.1.1.2 root 577: char dlbar[1024]; 1.1 root 578: 579: lines = viddef.height * frac; 580: if (lines <= 0) 581: return; 582: 583: if (lines > viddef.height) 584: lines = viddef.height; 585: 586: // draw the background 587: re.DrawStretchPic (0, -viddef.height+lines, viddef.width, viddef.height, "conback"); 588: SCR_AddDirtyPoint (0,0); 589: SCR_AddDirtyPoint (viddef.width-1,lines-1); 590: 591: Com_sprintf (version, sizeof(version), "v%4.2f", VERSION); 592: for (x=0 ; x<5 ; x++) 593: re.DrawChar (viddef.width-44+x*8, lines-12, 128 + version[x] ); 594: 595: // draw the text 596: con.vislines = lines; 597: 1.1.1.2 root 598: #if 0 1.1 root 599: rows = (lines-8)>>3; // rows of text to draw 600: 601: y = lines - 24; 1.1.1.2 root 602: #else 603: rows = (lines-22)>>3; // rows of text to draw 604: 605: y = lines - 30; 606: #endif 1.1 root 607: 608: // draw from the bottom up 609: if (con.display != con.current) 610: { 611: // draw arrows to show the buffer is backscrolled 612: for (x=0 ; x<con.linewidth ; x+=4) 613: re.DrawChar ( (x+1)<<3, y, '^'); 614: 615: y -= 8; 616: rows--; 617: } 618: 619: row = con.display; 620: for (i=0 ; i<rows ; i++, y-=8, row--) 621: { 622: if (row < 0) 623: break; 624: if (con.current - row >= con.totallines) 625: break; // past scrollback wrap point 626: 627: text = con.text + (row % con.totallines)*con.linewidth; 628: 629: for (x=0 ; x<con.linewidth ; x++) 630: re.DrawChar ( (x+1)<<3, y, text[x]); 631: } 632: 1.1.1.2 root 633: //ZOID 634: // draw the download bar 635: // figure out width 636: if (cls.download) { 637: if ((text = strrchr(cls.downloadname, '/')) != NULL) 638: text++; 639: else 640: text = cls.downloadname; 641: 642: x = con.linewidth - ((con.linewidth * 7) / 40); 643: y = x - strlen(text) - 8; 644: i = con.linewidth/3; 645: if (strlen(text) > i) { 646: y = x - i - 11; 647: strncpy(dlbar, text, i); 648: dlbar[i] = 0; 649: strcat(dlbar, "..."); 650: } else 651: strcpy(dlbar, text); 652: strcat(dlbar, ": "); 653: i = strlen(dlbar); 654: dlbar[i++] = '\x80'; 655: // where's the dot go? 656: if (cls.downloadpercent == 0) 657: n = 0; 658: else 659: n = y * cls.downloadpercent / 100; 660: 661: for (j = 0; j < y; j++) 662: if (j == n) 663: dlbar[i++] = '\x83'; 664: else 665: dlbar[i++] = '\x81'; 666: dlbar[i++] = '\x82'; 667: dlbar[i] = 0; 668: 669: sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent); 670: 671: // draw it 672: y = con.vislines-12; 673: for (i = 0; i < strlen(dlbar); i++) 674: re.DrawChar ( (i+1)<<3, y, dlbar[i]); 675: } 676: //ZOID 677: 1.1 root 678: // draw the input prompt, user text, and cursor if desired 679: Con_DrawInput (); 680: } 681: 682:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.