console.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  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. #ifdef NeXT
  17. #include <libc.h>
  18. #endif
  19. #ifndef _MSC_VER
  20. #include <unistd.h>
  21. #endif
  22. #include <fcntl.h>
  23. #include "quakedef.h"
  24. int con_linewidth;
  25. float con_cursorspeed = 4;
  26. #define CON_TEXTSIZE 16384
  27. qboolean con_forcedup; // because no entities to refresh
  28. int con_totallines; // total lines in console scrollback
  29. int con_backscroll; // lines up from bottom to display
  30. int con_current; // where next message will be printed
  31. int con_x; // offset in current line for next print
  32. char *con_text=0;
  33. cvar_t con_notifytime = {"con_notifytime","3"}; //seconds
  34. #define NUM_CON_TIMES 4
  35. float con_times[NUM_CON_TIMES]; // realtime time the line was generated
  36. // for transparent notify lines
  37. int con_vislines;
  38. qboolean con_debuglog;
  39. #define MAXCMDLINE 256
  40. extern char key_lines[32][MAXCMDLINE];
  41. extern int edit_line;
  42. extern int key_linepos;
  43. qboolean con_initialized;
  44. int con_notifylines; // scan lines to clear for notify lines
  45. extern void M_Menu_Main_f (void);
  46. /*
  47. ================
  48. Con_ToggleConsole_f
  49. ================
  50. */
  51. void Con_ToggleConsole_f (void)
  52. {
  53. if (key_dest == key_console)
  54. {
  55. if (cls.state == ca_connected)
  56. {
  57. key_dest = key_game;
  58. key_lines[edit_line][1] = 0; // clear any typing
  59. key_linepos = 1;
  60. }
  61. else
  62. {
  63. M_Menu_Main_f ();
  64. }
  65. }
  66. else
  67. key_dest = key_console;
  68. SCR_EndLoadingPlaque ();
  69. memset (con_times, 0, sizeof(con_times));
  70. }
  71. /*
  72. ================
  73. Con_Clear_f
  74. ================
  75. */
  76. void Con_Clear_f (void)
  77. {
  78. if (con_text)
  79. Q_memset (con_text, ' ', CON_TEXTSIZE);
  80. }
  81. /*
  82. ================
  83. Con_ClearNotify
  84. ================
  85. */
  86. void Con_ClearNotify (void)
  87. {
  88. int i;
  89. for (i=0 ; i<NUM_CON_TIMES ; i++)
  90. con_times[i] = 0;
  91. }
  92. /*
  93. ================
  94. Con_MessageMode_f
  95. ================
  96. */
  97. extern qboolean team_message;
  98. void Con_MessageMode_f (void)
  99. {
  100. key_dest = key_message;
  101. team_message = false;
  102. }
  103. /*
  104. ================
  105. Con_MessageMode2_f
  106. ================
  107. */
  108. void Con_MessageMode2_f (void)
  109. {
  110. key_dest = key_message;
  111. team_message = true;
  112. }
  113. /*
  114. ================
  115. Con_CheckResize
  116. If the line width has changed, reformat the buffer.
  117. ================
  118. */
  119. void Con_CheckResize (void)
  120. {
  121. int i, j, width, oldwidth, oldtotallines, numlines, numchars;
  122. char tbuf[CON_TEXTSIZE];
  123. width = (vid.width >> 3) - 2;
  124. if (width == con_linewidth)
  125. return;
  126. if (width < 1) // video hasn't been initialized yet
  127. {
  128. width = 38;
  129. con_linewidth = width;
  130. con_totallines = CON_TEXTSIZE / con_linewidth;
  131. Q_memset (con_text, ' ', CON_TEXTSIZE);
  132. }
  133. else
  134. {
  135. oldwidth = con_linewidth;
  136. con_linewidth = width;
  137. oldtotallines = con_totallines;
  138. con_totallines = CON_TEXTSIZE / con_linewidth;
  139. numlines = oldtotallines;
  140. if (con_totallines < numlines)
  141. numlines = con_totallines;
  142. numchars = oldwidth;
  143. if (con_linewidth < numchars)
  144. numchars = con_linewidth;
  145. Q_memcpy (tbuf, con_text, CON_TEXTSIZE);
  146. Q_memset (con_text, ' ', CON_TEXTSIZE);
  147. for (i=0 ; i<numlines ; i++)
  148. {
  149. for (j=0 ; j<numchars ; j++)
  150. {
  151. con_text[(con_totallines - 1 - i) * con_linewidth + j] =
  152. tbuf[((con_current - i + oldtotallines) %
  153. oldtotallines) * oldwidth + j];
  154. }
  155. }
  156. Con_ClearNotify ();
  157. }
  158. con_backscroll = 0;
  159. con_current = con_totallines - 1;
  160. }
  161. /*
  162. ================
  163. Con_Init
  164. ================
  165. */
  166. void Con_Init (void)
  167. {
  168. #define MAXGAMEDIRLEN 1000
  169. char temp[MAXGAMEDIRLEN+1];
  170. char *t2 = "/qconsole.log";
  171. con_debuglog = COM_CheckParm("-condebug");
  172. if (con_debuglog)
  173. {
  174. if (strlen (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
  175. {
  176. sprintf (temp, "%s%s", com_gamedir, t2);
  177. unlink (temp);
  178. }
  179. }
  180. con_text = Hunk_AllocName (CON_TEXTSIZE, "context");
  181. Q_memset (con_text, ' ', CON_TEXTSIZE);
  182. con_linewidth = -1;
  183. Con_CheckResize ();
  184. Con_Printf ("Console initialized.\n");
  185. //
  186. // register our commands
  187. //
  188. Cvar_RegisterVariable (&con_notifytime);
  189. Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
  190. Cmd_AddCommand ("messagemode", Con_MessageMode_f);
  191. Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
  192. Cmd_AddCommand ("clear", Con_Clear_f);
  193. con_initialized = true;
  194. }
  195. /*
  196. ===============
  197. Con_Linefeed
  198. ===============
  199. */
  200. void Con_Linefeed (void)
  201. {
  202. con_x = 0;
  203. con_current++;
  204. Q_memset (&con_text[(con_current%con_totallines)*con_linewidth]
  205. , ' ', con_linewidth);
  206. }
  207. /*
  208. ================
  209. Con_Print
  210. Handles cursor positioning, line wrapping, etc
  211. All console printing must go through this in order to be logged to disk
  212. If no console is visible, the notify window will pop up.
  213. ================
  214. */
  215. void Con_Print (char *txt)
  216. {
  217. int y;
  218. int c, l;
  219. static int cr;
  220. int mask;
  221. con_backscroll = 0;
  222. if (txt[0] == 1)
  223. {
  224. mask = 128; // go to colored text
  225. S_LocalSound ("misc/talk.wav");
  226. // play talk wav
  227. txt++;
  228. }
  229. else if (txt[0] == 2)
  230. {
  231. mask = 128; // go to colored text
  232. txt++;
  233. }
  234. else
  235. mask = 0;
  236. while ( (c = *txt) )
  237. {
  238. // count word length
  239. for (l=0 ; l< con_linewidth ; l++)
  240. if ( txt[l] <= ' ')
  241. break;
  242. // word wrap
  243. if (l != con_linewidth && (con_x + l > con_linewidth) )
  244. con_x = 0;
  245. txt++;
  246. if (cr)
  247. {
  248. con_current--;
  249. cr = false;
  250. }
  251. if (!con_x)
  252. {
  253. Con_Linefeed ();
  254. // mark time for transparent overlay
  255. if (con_current >= 0)
  256. con_times[con_current % NUM_CON_TIMES] = realtime;
  257. }
  258. switch (c)
  259. {
  260. case '\n':
  261. con_x = 0;
  262. break;
  263. case '\r':
  264. con_x = 0;
  265. cr = 1;
  266. break;
  267. default: // display character and advance
  268. y = con_current % con_totallines;
  269. con_text[y*con_linewidth+con_x] = c | mask;
  270. con_x++;
  271. if (con_x >= con_linewidth)
  272. con_x = 0;
  273. break;
  274. }
  275. }
  276. }
  277. /*
  278. ================
  279. Con_DebugLog
  280. ================
  281. */
  282. void Con_DebugLog(char *file, char *fmt, ...)
  283. {
  284. va_list argptr;
  285. static char data[1024];
  286. int fd;
  287. va_start(argptr, fmt);
  288. vsprintf(data, fmt, argptr);
  289. va_end(argptr);
  290. fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
  291. write(fd, data, strlen(data));
  292. close(fd);
  293. }
  294. /*
  295. ================
  296. Con_Printf
  297. Handles cursor positioning, line wrapping, etc
  298. ================
  299. */
  300. #define MAXPRINTMSG 4096
  301. // FIXME: make a buffer size safe vsprintf?
  302. void Con_Printf (char *fmt, ...)
  303. {
  304. va_list argptr;
  305. char msg[MAXPRINTMSG];
  306. static qboolean inupdate;
  307. va_start (argptr,fmt);
  308. vsprintf (msg,fmt,argptr);
  309. va_end (argptr);
  310. // also echo to debugging console
  311. Sys_Printf ("%s", msg); // also echo to debugging console
  312. // log all messages to file
  313. if (con_debuglog)
  314. Con_DebugLog(va("%s/qconsole.log",com_gamedir), "%s", msg);
  315. if (!con_initialized)
  316. return;
  317. if (cls.state == ca_dedicated)
  318. return; // no graphics mode
  319. // write it to the scrollable buffer
  320. Con_Print (msg);
  321. // update the screen if the console is displayed
  322. if (cls.signon != SIGNONS && !scr_disabled_for_loading )
  323. {
  324. // protect against infinite loop if something in SCR_UpdateScreen calls
  325. // Con_Printd
  326. if (!inupdate)
  327. {
  328. inupdate = true;
  329. SCR_UpdateScreen ();
  330. inupdate = false;
  331. }
  332. }
  333. }
  334. /*
  335. ================
  336. Con_DPrintf
  337. A Con_Printf that only shows up if the "developer" cvar is set
  338. ================
  339. */
  340. void Con_DPrintf (char *fmt, ...)
  341. {
  342. va_list argptr;
  343. char msg[MAXPRINTMSG];
  344. if (!developer.value)
  345. return; // don't confuse non-developers with techie stuff...
  346. va_start (argptr,fmt);
  347. vsprintf (msg,fmt,argptr);
  348. va_end (argptr);
  349. Con_Printf ("%s", msg);
  350. }
  351. /*
  352. ==================
  353. Con_SafePrintf
  354. Okay to call even when the screen can't be updated
  355. ==================
  356. */
  357. void Con_SafePrintf (char *fmt, ...)
  358. {
  359. va_list argptr;
  360. char msg[1024];
  361. int temp;
  362. va_start (argptr,fmt);
  363. vsprintf (msg,fmt,argptr);
  364. va_end (argptr);
  365. temp = scr_disabled_for_loading;
  366. scr_disabled_for_loading = true;
  367. Con_Printf ("%s", msg);
  368. scr_disabled_for_loading = temp;
  369. }
  370. /*
  371. ==============================================================================
  372. DRAWING
  373. ==============================================================================
  374. */
  375. /*
  376. ================
  377. Con_DrawInput
  378. The input line scrolls horizontally if typing goes beyond the right edge
  379. ================
  380. */
  381. void Con_DrawInput (void)
  382. {
  383. int y;
  384. int i;
  385. char *text;
  386. if (key_dest != key_console && !con_forcedup)
  387. return; // don't draw anything
  388. text = key_lines[edit_line];
  389. // add the cursor frame
  390. text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1);
  391. // fill out remainder with spaces
  392. for (i=key_linepos+1 ; i< con_linewidth ; i++)
  393. text[i] = ' ';
  394. // prestep if horizontally scrolling
  395. if (key_linepos >= con_linewidth)
  396. text += 1 + key_linepos - con_linewidth;
  397. // draw it
  398. y = con_vislines-16;
  399. for (i=0 ; i<con_linewidth ; i++)
  400. Draw_Character ( (i+1)<<3, con_vislines - 16, text[i]);
  401. // remove cursor
  402. key_lines[edit_line][key_linepos] = 0;
  403. }
  404. /*
  405. ================
  406. Con_DrawNotify
  407. Draws the last few lines of output transparently over the game top
  408. ================
  409. */
  410. void Con_DrawNotify (void)
  411. {
  412. int x, v;
  413. char *text;
  414. int i;
  415. float time;
  416. extern char chat_buffer[];
  417. v = 0;
  418. for (i= con_current-NUM_CON_TIMES+1 ; i<=con_current ; i++)
  419. {
  420. if (i < 0)
  421. continue;
  422. time = con_times[i % NUM_CON_TIMES];
  423. if (time == 0)
  424. continue;
  425. time = realtime - time;
  426. if (time > con_notifytime.value)
  427. continue;
  428. text = con_text + (i % con_totallines)*con_linewidth;
  429. clearnotify = 0;
  430. scr_copytop = 1;
  431. for (x = 0 ; x < con_linewidth ; x++)
  432. Draw_Character ( (x+1)<<3, v, text[x]);
  433. v += 8;
  434. }
  435. if (key_dest == key_message)
  436. {
  437. clearnotify = 0;
  438. scr_copytop = 1;
  439. x = 0;
  440. Draw_String (8, v, "say:");
  441. while(chat_buffer[x])
  442. {
  443. Draw_Character ( (x+5)<<3, v, chat_buffer[x]);
  444. x++;
  445. }
  446. Draw_Character ( (x+5)<<3, v, 10+((int)(realtime*con_cursorspeed)&1));
  447. v += 8;
  448. }
  449. if (v > con_notifylines)
  450. con_notifylines = v;
  451. }
  452. /*
  453. ================
  454. Con_DrawConsole
  455. Draws the console with the solid background
  456. The typing input line at the bottom should only be drawn if typing is allowed
  457. ================
  458. */
  459. void Con_DrawConsole (int lines, qboolean drawinput)
  460. {
  461. int i, x, y;
  462. int rows;
  463. char *text;
  464. int j;
  465. if (lines <= 0)
  466. return;
  467. // draw the background
  468. Draw_ConsoleBackground (lines);
  469. // draw the text
  470. con_vislines = lines;
  471. rows = (lines-16)>>3; // rows of text to draw
  472. y = lines - 16 - (rows<<3); // may start slightly negative
  473. for (i= con_current - rows + 1 ; i<=con_current ; i++, y+=8 )
  474. {
  475. j = i - con_backscroll;
  476. if (j<0)
  477. j = 0;
  478. text = con_text + (j % con_totallines)*con_linewidth;
  479. for (x=0 ; x<con_linewidth ; x++)
  480. Draw_Character ( (x+1)<<3, y, text[x]);
  481. }
  482. // draw the input prompt, user text, and cursor if desired
  483. if (drawinput)
  484. Con_DrawInput ();
  485. }
  486. /*
  487. ==================
  488. Con_NotifyBox
  489. ==================
  490. */
  491. void Con_NotifyBox (char *text)
  492. {
  493. double t1, t2;
  494. // during startup for sound / cd warnings
  495. 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");
  496. Con_Printf (text);
  497. Con_Printf ("Press a key.\n");
  498. 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");
  499. key_count = -2; // wait for a key down and up
  500. key_dest = key_console;
  501. do
  502. {
  503. t1 = Sys_FloatTime ();
  504. SCR_UpdateScreen ();
  505. Sys_SendKeyEvents ();
  506. t2 = Sys_FloatTime ();
  507. realtime += t2-t1; // make the cursor blink
  508. } while (key_count < 0);
  509. Con_Printf ("\n");
  510. key_dest = key_game;
  511. realtime = 0; // put the cursor back to invisible
  512. }