|
|
1.1 ! root 1: /* ! 2: Copyright (C) 1996-1997 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: */ ! 20: // console.c ! 21: ! 22: #include "quakedef.h" ! 23: ! 24: int con_ormask; ! 25: console_t con_main; ! 26: console_t con_chat; ! 27: console_t *con; // point to either con_main or con_chat ! 28: ! 29: int con_linewidth; // characters across screen ! 30: int con_totallines; // total lines in console scrollback ! 31: ! 32: float con_cursorspeed = 4; ! 33: ! 34: ! 35: cvar_t con_notifytime = {"con_notifytime","3"}; //seconds ! 36: ! 37: #define NUM_CON_TIMES 4 ! 38: float con_times[NUM_CON_TIMES]; // realtime time the line was generated ! 39: // for transparent notify lines ! 40: ! 41: int con_vislines; ! 42: int con_notifylines; // scan lines to clear for notify lines ! 43: ! 44: qboolean con_debuglog; ! 45: ! 46: #define MAXCMDLINE 256 ! 47: extern char key_lines[32][MAXCMDLINE]; ! 48: extern int edit_line; ! 49: extern int key_linepos; ! 50: ! 51: ! 52: qboolean con_initialized; ! 53: ! 54: ! 55: void Key_ClearTyping (void) ! 56: { ! 57: key_lines[edit_line][1] = 0; // clear any typing ! 58: key_linepos = 1; ! 59: } ! 60: ! 61: /* ! 62: ================ ! 63: Con_ToggleConsole_f ! 64: ================ ! 65: */ ! 66: void Con_ToggleConsole_f (void) ! 67: { ! 68: Key_ClearTyping (); ! 69: ! 70: if (key_dest == key_console) ! 71: { ! 72: if (cls.state == ca_active) ! 73: key_dest = key_game; ! 74: } ! 75: else ! 76: key_dest = key_console; ! 77: ! 78: Con_ClearNotify (); ! 79: } ! 80: ! 81: /* ! 82: ================ ! 83: Con_ToggleChat_f ! 84: ================ ! 85: */ ! 86: void Con_ToggleChat_f (void) ! 87: { ! 88: Key_ClearTyping (); ! 89: ! 90: if (key_dest == key_console) ! 91: { ! 92: if (cls.state == ca_active) ! 93: key_dest = key_game; ! 94: } ! 95: else ! 96: key_dest = key_console; ! 97: ! 98: Con_ClearNotify (); ! 99: } ! 100: ! 101: /* ! 102: ================ ! 103: Con_Clear_f ! 104: ================ ! 105: */ ! 106: void Con_Clear_f (void) ! 107: { ! 108: Q_memset (con_main.text, ' ', CON_TEXTSIZE); ! 109: Q_memset (con_chat.text, ' ', CON_TEXTSIZE); ! 110: } ! 111: ! 112: ! 113: /* ! 114: ================ ! 115: Con_ClearNotify ! 116: ================ ! 117: */ ! 118: void Con_ClearNotify (void) ! 119: { ! 120: int i; ! 121: ! 122: for (i=0 ; i<NUM_CON_TIMES ; i++) ! 123: con_times[i] = 0; ! 124: } ! 125: ! 126: ! 127: /* ! 128: ================ ! 129: Con_MessageMode_f ! 130: ================ ! 131: */ ! 132: void Con_MessageMode_f (void) ! 133: { ! 134: chat_team = false; ! 135: key_dest = key_message; ! 136: } ! 137: ! 138: /* ! 139: ================ ! 140: Con_MessageMode2_f ! 141: ================ ! 142: */ ! 143: void Con_MessageMode2_f (void) ! 144: { ! 145: chat_team = true; ! 146: key_dest = key_message; ! 147: } ! 148: ! 149: /* ! 150: ================ ! 151: Con_Resize ! 152: ! 153: ================ ! 154: */ ! 155: void Con_Resize (console_t *con) ! 156: { ! 157: int i, j, width, oldwidth, oldtotallines, numlines, numchars; ! 158: char tbuf[CON_TEXTSIZE]; ! 159: ! 160: width = (vid.width >> 3) - 2; ! 161: ! 162: if (width == con_linewidth) ! 163: return; ! 164: ! 165: if (width < 1) // video hasn't been initialized yet ! 166: { ! 167: width = 38; ! 168: con_linewidth = width; ! 169: con_totallines = CON_TEXTSIZE / con_linewidth; ! 170: Q_memset (con->text, ' ', CON_TEXTSIZE); ! 171: } ! 172: else ! 173: { ! 174: oldwidth = con_linewidth; ! 175: con_linewidth = width; ! 176: oldtotallines = con_totallines; ! 177: con_totallines = CON_TEXTSIZE / con_linewidth; ! 178: numlines = oldtotallines; ! 179: ! 180: if (con_totallines < numlines) ! 181: numlines = con_totallines; ! 182: ! 183: numchars = oldwidth; ! 184: ! 185: if (con_linewidth < numchars) ! 186: numchars = con_linewidth; ! 187: ! 188: Q_memcpy (tbuf, con->text, CON_TEXTSIZE); ! 189: Q_memset (con->text, ' ', CON_TEXTSIZE); ! 190: ! 191: for (i=0 ; i<numlines ; i++) ! 192: { ! 193: for (j=0 ; j<numchars ; j++) ! 194: { ! 195: con->text[(con_totallines - 1 - i) * con_linewidth + j] = ! 196: tbuf[((con->current - i + oldtotallines) % ! 197: oldtotallines) * oldwidth + j]; ! 198: } ! 199: } ! 200: ! 201: Con_ClearNotify (); ! 202: } ! 203: ! 204: con->current = con_totallines - 1; ! 205: con->display = con->current; ! 206: } ! 207: ! 208: ! 209: /* ! 210: ================ ! 211: Con_CheckResize ! 212: ! 213: If the line width has changed, reformat the buffer. ! 214: ================ ! 215: */ ! 216: void Con_CheckResize (void) ! 217: { ! 218: Con_Resize (&con_main); ! 219: Con_Resize (&con_chat); ! 220: } ! 221: ! 222: ! 223: /* ! 224: ================ ! 225: Con_Init ! 226: ================ ! 227: */ ! 228: void Con_Init (void) ! 229: { ! 230: con_debuglog = COM_CheckParm("-condebug"); ! 231: ! 232: con = &con_main; ! 233: con_linewidth = -1; ! 234: Con_CheckResize (); ! 235: ! 236: Con_Printf ("Console initialized.\n"); ! 237: ! 238: // ! 239: // register our commands ! 240: // ! 241: Cvar_RegisterVariable (&con_notifytime); ! 242: ! 243: Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); ! 244: Cmd_AddCommand ("togglechat", Con_ToggleChat_f); ! 245: Cmd_AddCommand ("messagemode", Con_MessageMode_f); ! 246: Cmd_AddCommand ("messagemode2", Con_MessageMode2_f); ! 247: Cmd_AddCommand ("clear", Con_Clear_f); ! 248: con_initialized = true; ! 249: } ! 250: ! 251: ! 252: /* ! 253: =============== ! 254: Con_Linefeed ! 255: =============== ! 256: */ ! 257: void Con_Linefeed (void) ! 258: { ! 259: con->x = 0; ! 260: if (con->display == con->current) ! 261: con->display++; ! 262: con->current++; ! 263: Q_memset (&con->text[(con->current%con_totallines)*con_linewidth] ! 264: , ' ', con_linewidth); ! 265: } ! 266: ! 267: /* ! 268: ================ ! 269: Con_Print ! 270: ! 271: Handles cursor positioning, line wrapping, etc ! 272: All console printing must go through this in order to be logged to disk ! 273: If no console is visible, the notify window will pop up. ! 274: ================ ! 275: */ ! 276: void Con_Print (char *txt) ! 277: { ! 278: int y; ! 279: int c, l; ! 280: static int cr; ! 281: int mask; ! 282: ! 283: if (txt[0] == 1 || txt[0] == 2) ! 284: { ! 285: mask = 128; // go to colored text ! 286: txt++; ! 287: } ! 288: else ! 289: mask = 0; ! 290: ! 291: ! 292: while ( (c = *txt) ) ! 293: { ! 294: // count word length ! 295: for (l=0 ; l< con_linewidth ; l++) ! 296: if ( txt[l] <= ' ') ! 297: break; ! 298: ! 299: // word wrap ! 300: if (l != con_linewidth && (con->x + l > con_linewidth) ) ! 301: con->x = 0; ! 302: ! 303: txt++; ! 304: ! 305: if (cr) ! 306: { ! 307: con->current--; ! 308: cr = false; ! 309: } ! 310: ! 311: ! 312: if (!con->x) ! 313: { ! 314: Con_Linefeed (); ! 315: // mark time for transparent overlay ! 316: if (con->current >= 0) ! 317: con_times[con->current % NUM_CON_TIMES] = realtime; ! 318: } ! 319: ! 320: switch (c) ! 321: { ! 322: case '\n': ! 323: con->x = 0; ! 324: break; ! 325: ! 326: case '\r': ! 327: con->x = 0; ! 328: cr = 1; ! 329: break; ! 330: ! 331: default: // display character and advance ! 332: y = con->current % con_totallines; ! 333: con->text[y*con_linewidth+con->x] = c | mask | con_ormask; ! 334: con->x++; ! 335: if (con->x >= con_linewidth) ! 336: con->x = 0; ! 337: break; ! 338: } ! 339: ! 340: } ! 341: } ! 342: ! 343: ! 344: /* ! 345: ================ ! 346: Con_Printf ! 347: ! 348: Handles cursor positioning, line wrapping, etc ! 349: ================ ! 350: */ ! 351: #define MAXPRINTMSG 4096 ! 352: // FIXME: make a buffer size safe vsprintf? ! 353: void Con_Printf (char *fmt, ...) ! 354: { ! 355: va_list argptr; ! 356: char msg[MAXPRINTMSG]; ! 357: static qboolean inupdate; ! 358: ! 359: va_start (argptr,fmt); ! 360: vsprintf (msg,fmt,argptr); ! 361: va_end (argptr); ! 362: ! 363: // also echo to debugging console ! 364: Sys_Printf ("%s", msg); // also echo to debugging console ! 365: ! 366: // log all messages to file ! 367: if (con_debuglog) ! 368: Sys_DebugLog(va("%s/qconsole.log",com_gamedir), "%s", msg); ! 369: ! 370: if (!con_initialized) ! 371: return; ! 372: ! 373: // write it to the scrollable buffer ! 374: Con_Print (msg); ! 375: ! 376: // update the screen immediately if the console is displayed ! 377: if (cls.state != ca_active) ! 378: { ! 379: // protect against infinite loop if something in SCR_UpdateScreen calls ! 380: // Con_Printd ! 381: if (!inupdate) ! 382: { ! 383: inupdate = true; ! 384: SCR_UpdateScreen (); ! 385: inupdate = false; ! 386: } ! 387: } ! 388: } ! 389: ! 390: /* ! 391: ================ ! 392: Con_DPrintf ! 393: ! 394: A Con_Printf that only shows up if the "developer" cvar is set ! 395: ================ ! 396: */ ! 397: void Con_DPrintf (char *fmt, ...) ! 398: { ! 399: va_list argptr; ! 400: char msg[MAXPRINTMSG]; ! 401: ! 402: if (!developer.value) ! 403: return; // don't confuse non-developers with techie stuff... ! 404: ! 405: va_start (argptr,fmt); ! 406: vsprintf (msg,fmt,argptr); ! 407: va_end (argptr); ! 408: ! 409: Con_Printf ("%s", msg); ! 410: } ! 411: ! 412: /* ! 413: ============================================================================== ! 414: ! 415: DRAWING ! 416: ! 417: ============================================================================== ! 418: */ ! 419: ! 420: ! 421: /* ! 422: ================ ! 423: Con_DrawInput ! 424: ! 425: The input line scrolls horizontally if typing goes beyond the right edge ! 426: ================ ! 427: */ ! 428: void Con_DrawInput (void) ! 429: { ! 430: int y; ! 431: int i; ! 432: char *text; ! 433: ! 434: if (key_dest != key_console && cls.state == ca_active) ! 435: return; // don't draw anything (allways draw if not active) ! 436: ! 437: text = key_lines[edit_line]; ! 438: ! 439: // add the cursor frame ! 440: text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1); ! 441: ! 442: // fill out remainder with spaces ! 443: for (i=key_linepos+1 ; i< con_linewidth ; i++) ! 444: text[i] = ' '; ! 445: ! 446: // prestep if horizontally scrolling ! 447: if (key_linepos >= con_linewidth) ! 448: text += 1 + key_linepos - con_linewidth; ! 449: ! 450: // draw it ! 451: y = con_vislines-22; ! 452: ! 453: for (i=0 ; i<con_linewidth ; i++) ! 454: Draw_Character ( (i+1)<<3, con_vislines - 22, text[i]); ! 455: ! 456: // remove cursor ! 457: key_lines[edit_line][key_linepos] = 0; ! 458: } ! 459: ! 460: ! 461: /* ! 462: ================ ! 463: Con_DrawNotify ! 464: ! 465: Draws the last few lines of output transparently over the game top ! 466: ================ ! 467: */ ! 468: void Con_DrawNotify (void) ! 469: { ! 470: int x, v; ! 471: char *text; ! 472: int i; ! 473: float time; ! 474: char *s; ! 475: int skip; ! 476: ! 477: v = 0; ! 478: for (i= con->current-NUM_CON_TIMES+1 ; i<=con->current ; i++) ! 479: { ! 480: if (i < 0) ! 481: continue; ! 482: time = con_times[i % NUM_CON_TIMES]; ! 483: if (time == 0) ! 484: continue; ! 485: time = realtime - time; ! 486: if (time > con_notifytime.value) ! 487: continue; ! 488: text = con->text + (i % con_totallines)*con_linewidth; ! 489: ! 490: clearnotify = 0; ! 491: scr_copytop = 1; ! 492: ! 493: for (x = 0 ; x < con_linewidth ; x++) ! 494: Draw_Character ( (x+1)<<3, v, text[x]); ! 495: ! 496: v += 8; ! 497: } ! 498: ! 499: ! 500: if (key_dest == key_message) ! 501: { ! 502: clearnotify = 0; ! 503: scr_copytop = 1; ! 504: ! 505: if (chat_team) ! 506: { ! 507: Draw_String (8, v, "say_team:"); ! 508: skip = 11; ! 509: } ! 510: else ! 511: { ! 512: Draw_String (8, v, "say:"); ! 513: skip = 5; ! 514: } ! 515: ! 516: s = chat_buffer; ! 517: if (chat_bufferlen > (vid.width>>3)-(skip+1)) ! 518: s += chat_bufferlen - ((vid.width>>3)-(skip+1)); ! 519: x = 0; ! 520: while(s[x]) ! 521: { ! 522: Draw_Character ( (x+skip)<<3, v, s[x]); ! 523: x++; ! 524: } ! 525: Draw_Character ( (x+skip)<<3, v, 10+((int)(realtime*con_cursorspeed)&1)); ! 526: v += 8; ! 527: } ! 528: ! 529: if (v > con_notifylines) ! 530: con_notifylines = v; ! 531: } ! 532: ! 533: /* ! 534: ================ ! 535: Con_DrawConsole ! 536: ! 537: Draws the console with the solid background ! 538: ================ ! 539: */ ! 540: void Con_DrawConsole (int lines) ! 541: { ! 542: int i, j, x, y, n; ! 543: int rows; ! 544: char *text; ! 545: int row; ! 546: char dlbar[1024]; ! 547: ! 548: if (lines <= 0) ! 549: return; ! 550: ! 551: // draw the background ! 552: Draw_ConsoleBackground (lines); ! 553: ! 554: // draw the text ! 555: con_vislines = lines; ! 556: ! 557: // changed to line things up better ! 558: rows = (lines-22)>>3; // rows of text to draw ! 559: ! 560: y = lines - 30; ! 561: ! 562: // draw from the bottom up ! 563: if (con->display != con->current) ! 564: { ! 565: // draw arrows to show the buffer is backscrolled ! 566: for (x=0 ; x<con_linewidth ; x+=4) ! 567: Draw_Character ( (x+1)<<3, y, '^'); ! 568: ! 569: y -= 8; ! 570: rows--; ! 571: } ! 572: ! 573: row = con->display; ! 574: for (i=0 ; i<rows ; i++, y-=8, row--) ! 575: { ! 576: if (row < 0) ! 577: break; ! 578: if (con->current - row >= con_totallines) ! 579: break; // past scrollback wrap point ! 580: ! 581: text = con->text + (row % con_totallines)*con_linewidth; ! 582: ! 583: for (x=0 ; x<con_linewidth ; x++) ! 584: Draw_Character ( (x+1)<<3, y, text[x]); ! 585: } ! 586: ! 587: // draw the download bar ! 588: // figure out width ! 589: if (cls.download) { ! 590: if ((text = strrchr(cls.downloadname, '/')) != NULL) ! 591: text++; ! 592: else ! 593: text = cls.downloadname; ! 594: ! 595: x = con_linewidth - ((con_linewidth * 7) / 40); ! 596: y = x - strlen(text) - 8; ! 597: i = con_linewidth/3; ! 598: if (strlen(text) > i) { ! 599: y = x - i - 11; ! 600: strncpy(dlbar, text, i); ! 601: dlbar[i] = 0; ! 602: strcat(dlbar, "..."); ! 603: } else ! 604: strcpy(dlbar, text); ! 605: strcat(dlbar, ": "); ! 606: i = strlen(dlbar); ! 607: dlbar[i++] = '\x80'; ! 608: // where's the dot go? ! 609: if (cls.downloadpercent == 0) ! 610: n = 0; ! 611: else ! 612: n = y * cls.downloadpercent / 100; ! 613: ! 614: for (j = 0; j < y; j++) ! 615: if (j == n) ! 616: dlbar[i++] = '\x83'; ! 617: else ! 618: dlbar[i++] = '\x81'; ! 619: dlbar[i++] = '\x82'; ! 620: dlbar[i] = 0; ! 621: ! 622: sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent); ! 623: ! 624: // draw it ! 625: y = con_vislines-22 + 8; ! 626: for (i = 0; i < strlen(dlbar); i++) ! 627: Draw_Character ( (i+1)<<3, y, dlbar[i]); ! 628: } ! 629: ! 630: ! 631: // draw the input prompt, user text, and cursor if desired ! 632: Con_DrawInput (); ! 633: } ! 634: ! 635: ! 636: /* ! 637: ================== ! 638: Con_NotifyBox ! 639: ================== ! 640: */ ! 641: void Con_NotifyBox (char *text) ! 642: { ! 643: double t1, t2; ! 644: ! 645: // during startup for sound / cd warnings ! 646: Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); ! 647: ! 648: Con_Printf (text); ! 649: ! 650: Con_Printf ("Press a key.\n"); ! 651: Con_Printf("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); ! 652: ! 653: key_count = -2; // wait for a key down and up ! 654: key_dest = key_console; ! 655: ! 656: do ! 657: { ! 658: t1 = Sys_DoubleTime (); ! 659: SCR_UpdateScreen (); ! 660: Sys_SendKeyEvents (); ! 661: t2 = Sys_DoubleTime (); ! 662: realtime += t2-t1; // make the cursor blink ! 663: } while (key_count < 0); ! 664: ! 665: Con_Printf ("\n"); ! 666: key_dest = key_game; ! 667: realtime = 0; // put the cursor back to invisible ! 668: } ! 669: ! 670: ! 671: /* ! 672: ================== ! 673: Con_SafePrintf ! 674: ! 675: Okay to call even when the screen can't be updated ! 676: ================== ! 677: */ ! 678: void Con_SafePrintf (char *fmt, ...) ! 679: { ! 680: va_list argptr; ! 681: char msg[1024]; ! 682: int temp; ! 683: ! 684: va_start (argptr,fmt); ! 685: vsprintf (msg,fmt,argptr); ! 686: va_end (argptr); ! 687: ! 688: temp = scr_disabled_for_loading; ! 689: scr_disabled_for_loading = true; ! 690: Con_Printf ("%s", msg); ! 691: scr_disabled_for_loading = temp; ! 692: } ! 693:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.