console.c 13 KB

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