ConsoleMode.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** 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, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/ConsoleMode.cpp $*
  25. * *
  26. * $Author:: Bhayes $*
  27. * *
  28. * $Modtime:: 1/21/03 11:09a $*
  29. * *
  30. * $Revision:: 12 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "consolemode.h"
  36. #include "consolefunction.h"
  37. #include "wwdebug.h"
  38. #include "conio.h"
  39. #include "slavemaster.h"
  40. #include <stdio.h>
  41. #include "systimer.h"
  42. #include "widestring.h"
  43. #include "vector3.h"
  44. #include "cnetwork.h"
  45. #include "textdisplay.h"
  46. #include "console.h"
  47. #include "crc.h"
  48. #include "buildnum.h"
  49. #include "init.h"
  50. #include "gamesideservercontrol.h"
  51. #include "specialbuilds.h"
  52. #include "serversettings.h"
  53. /*
  54. ** Single instance of console.
  55. */
  56. ConsoleModeClass ConsoleBox;
  57. /*
  58. ** Console title bar text
  59. */
  60. #define MASTER_TITLE_BASE "Renegade Master Server"
  61. #define SLAVE_TITLE_BASE "Renegade Slave Server"
  62. #define MASTER_COLORS (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY | BACKGROUND_BLUE)
  63. #define SLAVE_COLORS (BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE)
  64. /***********************************************************************************************
  65. * ConsoleModeClass::ConsoleModeClass -- Class constructor *
  66. * *
  67. * *
  68. * *
  69. * INPUT: Nothing *
  70. * *
  71. * OUTPUT: Nothing *
  72. * *
  73. * WARNINGS: None *
  74. * *
  75. * HISTORY: *
  76. * 12/17/2001 5:00PM ST : Created *
  77. *=============================================================================================*/
  78. ConsoleModeClass::ConsoleModeClass(void)
  79. {
  80. ConsoleOutputHandle = INVALID_HANDLE_VALUE;
  81. ConsoleInputHandle = INVALID_HANDLE_VALUE;
  82. LastKeypressTime = 0;
  83. Pos = 1;
  84. IsExclusive = false;
  85. LastProfileCRC = 0;
  86. LastProfilePrint = 0;
  87. ProfileMode = false;
  88. }
  89. /***********************************************************************************************
  90. * ConsoleModeClass::~ConsoleModeClass -- Class destructor *
  91. * *
  92. * *
  93. * *
  94. * INPUT: Nothing *
  95. * *
  96. * OUTPUT: Nothing *
  97. * *
  98. * WARNINGS: None *
  99. * *
  100. * HISTORY: *
  101. * 12/17/2001 5:01PM ST : Created *
  102. *=============================================================================================*/
  103. ConsoleModeClass::~ConsoleModeClass(void)
  104. {
  105. if (ConsoleOutputHandle != INVALID_HANDLE_VALUE) {
  106. FreeConsole();
  107. ConsoleOutputHandle = INVALID_HANDLE_VALUE;
  108. }
  109. }
  110. /***********************************************************************************************
  111. * ConsoleModeClass::Init -- Enable console mode - start up a console *
  112. * *
  113. * *
  114. * *
  115. * INPUT: Nothing *
  116. * *
  117. * OUTPUT: Nothing *
  118. * *
  119. * WARNINGS: None *
  120. * *
  121. * HISTORY: *
  122. * 12/17/2001 5:01PM ST : Created *
  123. *=============================================================================================*/
  124. void ConsoleModeClass::Init(void)
  125. {
  126. if (ConsoleOutputHandle == INVALID_HANDLE_VALUE) {
  127. /*
  128. ** Create a console.
  129. */
  130. if (AllocConsole()) {
  131. /*
  132. ** Get the input and output handles.
  133. */
  134. ConsoleOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  135. WWASSERT(ConsoleOutputHandle != INVALID_HANDLE_VALUE);
  136. ConsoleInputHandle = GetStdHandle(STD_INPUT_HANDLE);
  137. WWASSERT(ConsoleInputHandle != INVALID_HANDLE_VALUE);
  138. /*
  139. ** Set the size of the console buffer.
  140. */
  141. COORD coord;
  142. coord.X=80;
  143. coord.Y=4192;
  144. SetConsoleScreenBufferSize(ConsoleOutputHandle, coord);
  145. unsigned long written = 0;
  146. coord.X=0;
  147. coord.Y=0;
  148. /*
  149. ** Use different colors for master and slaves.
  150. */
  151. if (!SlaveMaster.Am_I_Slave()) {
  152. FillConsoleOutputAttribute(ConsoleOutputHandle, MASTER_COLORS, 4192*50, coord, &written);
  153. SetConsoleTextAttribute(ConsoleOutputHandle, MASTER_COLORS);
  154. } else {
  155. FillConsoleOutputAttribute(ConsoleOutputHandle, SLAVE_COLORS, 4192*50, coord, &written);
  156. SetConsoleTextAttribute(ConsoleOutputHandle, SLAVE_COLORS);
  157. }
  158. /*
  159. ** Set the text in the console title bar.
  160. */
  161. Set_Title(NULL, NULL);
  162. /*
  163. ** Get an HWND for the console window.
  164. */
  165. ConsoleWindow = FindWindow("ConsoleWindowClass", Title);
  166. /*
  167. ** Bring up the console window to the foreground.
  168. */
  169. SetForegroundWindow(ConsoleWindow);
  170. /*
  171. ** Print up version info.
  172. */
  173. DWORD version_major = 1;
  174. DWORD version_minor = 0;
  175. Get_Version_Number(&version_major, &version_minor);
  176. #ifdef FREEDEDICATEDSERVER
  177. Print("Renegade Free Dedicated Server ");
  178. #else //FREEDEDICATEDSERVER
  179. Print("Renegade ");
  180. #endif //FREEDEDICATEDSERVER
  181. Print("v%d.%.3d %s-%s %s\n", (version_major >> 16), (version_major & 0xFFFF), BuildInfoClass::Get_Builder_Initials(), BuildInfoClass::Get_Build_Number_String(), BuildInfoClass::Get_Build_Date_String());
  182. Print("Console mode active\n");
  183. LastKeypressTime = 0;
  184. }
  185. }
  186. }
  187. /***********************************************************************************************
  188. * ConsoleModeClass::Get_Slave_Window_By_Title -- Look for a slave window *
  189. * *
  190. * *
  191. * *
  192. * INPUT: Login name of slave *
  193. * Settings file name of slave *
  194. * *
  195. * OUTPUT: HWND of slave window *
  196. * *
  197. * WARNINGS: None *
  198. * *
  199. * HISTORY: *
  200. * 2/4/2002 1:21PM ST : Created *
  201. *=============================================================================================*/
  202. HWND ConsoleModeClass::Get_Slave_Window_By_Title(char *name, char *settings)
  203. {
  204. StringClass title = Compose_Window_Title(name, settings, true);
  205. HWND window = FindWindow("ConsoleWindowClass", title.Peek_Buffer());
  206. return(window);
  207. }
  208. /***********************************************************************************************
  209. * ConsoleModeClass::Compose_Window_Title -- Build a window title string from name and settings*
  210. * *
  211. * *
  212. * *
  213. * INPUT: Login name *
  214. * Settings file name *
  215. * *
  216. * OUTPUT: StringClass containing full title bar string *
  217. * *
  218. * WARNINGS: None *
  219. * *
  220. * HISTORY: *
  221. * 2/4/2002 1:19PM ST : Created *
  222. *=============================================================================================*/
  223. StringClass ConsoleModeClass::Compose_Window_Title(char *name, char *settings, bool slave)
  224. {
  225. char title[256];
  226. if (!slave) {
  227. strcpy(title, MASTER_TITLE_BASE);
  228. } else {
  229. strcpy(title, SLAVE_TITLE_BASE);
  230. }
  231. if (name) {
  232. strcat(title, " - ");
  233. strcat(title, name);
  234. }
  235. if (settings) {
  236. strcat(title, " - ");
  237. strcat(title, settings);
  238. }
  239. return(StringClass(title));
  240. }
  241. /***********************************************************************************************
  242. * ConsoleModeClass::Set_Title -- Sets the text in the console title bar *
  243. * *
  244. * *
  245. * *
  246. * INPUT: Base text *
  247. * Name of settings file *
  248. * *
  249. * OUTPUT: Nothing *
  250. * *
  251. * WARNINGS: None *
  252. * *
  253. * HISTORY: *
  254. * 12/17/2001 5:03PM ST : Created *
  255. *=============================================================================================*/
  256. void ConsoleModeClass::Set_Title(char *name, char *settings)
  257. {
  258. if (ConsoleOutputHandle) {
  259. StringClass title = Compose_Window_Title(name, settings, SlaveMaster.Am_I_Slave());
  260. strcpy(Title, title.Peek_Buffer());
  261. SetConsoleTitle(Title);
  262. }
  263. }
  264. /***********************************************************************************************
  265. * ConsoleModeClass::Print -- Formatted print to console box *
  266. * *
  267. * *
  268. * *
  269. * INPUT: string *
  270. * format specifiers *
  271. * *
  272. * OUTPUT: Nothing *
  273. * *
  274. * WARNINGS: None *
  275. * *
  276. * HISTORY: *
  277. * 12/17/2001 5:04PM ST : Created *
  278. *=============================================================================================*/
  279. void ConsoleModeClass::Print(char const * string, ...)
  280. {
  281. if (ConsoleOutputHandle != INVALID_HANDLE_VALUE) {
  282. char buffer[8192];
  283. va_list va;
  284. va_start(va, string);
  285. vsprintf(&buffer[0], string, va);
  286. va_end(va);
  287. /*
  288. ** Have to use '%s' here or we end up doing the formatting twice.
  289. */
  290. cprintf("%s", buffer);
  291. Log_To_Disk(buffer);
  292. //WWDEBUG_SAY((buffer));
  293. Apply_Attributes();
  294. }
  295. }
  296. /***********************************************************************************************
  297. * ConsoleModeClass::Print_Maybe -- Formatted print to console box if not busy *
  298. * *
  299. * *
  300. * *
  301. * INPUT: string *
  302. * format specifiers *
  303. * *
  304. * OUTPUT: Nothing *
  305. * *
  306. * WARNINGS: None *
  307. * *
  308. * HISTORY: *
  309. * 12/17/2001 5:04PM ST : Created *
  310. *=============================================================================================*/
  311. void ConsoleModeClass::Print_Maybe(char const * string, ...)
  312. {
  313. if (string && !ProfileMode) {
  314. char buffer[8192];
  315. va_list va;
  316. va_start(va, string);
  317. vsprintf(&buffer[0], string, va);
  318. va_end(va);
  319. Log_To_Disk(buffer);
  320. if (Pos == 1 && (TIMEGETTIME() - LastKeypressTime > 5 * 1000) && ConsoleOutputHandle != INVALID_HANDLE_VALUE) {
  321. /*
  322. ** Have to use '%s' here or we end up doing the formatting twice.
  323. */
  324. cprintf("%s", buffer);
  325. //WWDEBUG_SAY((buffer));
  326. Apply_Attributes();
  327. }
  328. }
  329. }
  330. /***********************************************************************************************
  331. * ConsoleModeClass::Static_Print_Maybe -- Static version of Print_Maybe *
  332. * *
  333. * *
  334. * *
  335. * INPUT: String *
  336. * *
  337. * OUTPUT: Nothing *
  338. * *
  339. * WARNINGS: None *
  340. * *
  341. * HISTORY: *
  342. * 8/14/2002 11:59AM ST : Created *
  343. *=============================================================================================*/
  344. void ConsoleModeClass::Static_Print_Maybe(char const * string, ...)
  345. {
  346. ConsoleBox.Print_Maybe(string);
  347. }
  348. /***********************************************************************************************
  349. * ConsoleModeClass::cprintf -- let's get all the prints going through one place again *
  350. * *
  351. * *
  352. * *
  353. * INPUT: string *
  354. * format specifiers *
  355. * *
  356. * OUTPUT: Nothing *
  357. * *
  358. * WARNINGS: None *
  359. * *
  360. * HISTORY: *
  361. * 12/17/2001 5:04PM ST : Created *
  362. *=============================================================================================*/
  363. void ConsoleModeClass::cprintf(char const * string, ...)
  364. {
  365. if (string) {
  366. char buffer[8192];
  367. va_list va;
  368. buffer[sizeof(buffer)-1] = 0;
  369. va_start(va, string);
  370. _vsnprintf(&buffer[0], sizeof(buffer)-1, string, va);
  371. va_end(va);
  372. /*
  373. ** Have to use '%s' here or we end up doing the formatting twice.
  374. */
  375. ::cprintf("%s", buffer);
  376. GameSideServerControlClass::Print("%s", buffer);
  377. }
  378. }
  379. /***********************************************************************************************
  380. * ConsoleModeClass::Get_Log_File_Nmae -- Get name of log file *
  381. * *
  382. * *
  383. * *
  384. * INPUT: Nothing *
  385. * *
  386. * OUTPUT: Nothing *
  387. * *
  388. * WARNINGS: None *
  389. * *
  390. * HISTORY: *
  391. * 8/8/2002 1:07PM ST : Created *
  392. *=============================================================================================*/
  393. const char *ConsoleModeClass::Get_Log_File_Name(void)
  394. {
  395. static char _log_file_name[256];
  396. static int _last_day = -1;
  397. SYSTEMTIME time;
  398. GetLocalTime(&time);
  399. sprintf(_log_file_name, "renlog_%d-%d-%02d.txt", time.wMonth, time.wDay, time.wYear);
  400. if (_last_day != time.wDay && ServerSettingsClass::Get_Disk_Log_Size() != -1) {
  401. _last_day = time.wDay;
  402. FILETIME file_time;
  403. if (SystemTimeToFileTime(&time, &file_time)) {
  404. _int64 int_file_time;
  405. memcpy(&int_file_time, &file_time, sizeof(int_file_time));
  406. _int64 time_diff = ((_int64)10000000) * ((_int64)60*60*24*ServerSettingsClass::Get_Disk_Log_Size());
  407. int_file_time -= time_diff;
  408. memcpy(&file_time, &int_file_time, sizeof(file_time));
  409. /*
  410. ** Find all log files.
  411. */
  412. WIN32_FIND_DATA find_data;
  413. HANDLE find_handle = FindFirstFile("renlog_*.txt", &find_data);
  414. while (find_handle != INVALID_HANDLE_VALUE) {
  415. if (CompareFileTime(&find_data.ftLastWriteTime, &file_time) == -1) {
  416. DeleteFile(find_data.cFileName);
  417. }
  418. if (!FindNextFile(find_handle, &find_data)) {
  419. break;
  420. }
  421. }
  422. FindClose(find_handle);
  423. }
  424. }
  425. return(_log_file_name);
  426. }
  427. /***********************************************************************************************
  428. * ConsoleModeClass::Log_To_Disk -- Log console output to disk *
  429. * *
  430. * *
  431. * *
  432. * INPUT: String to log *
  433. * *
  434. * OUTPUT: Nothing *
  435. * *
  436. * WARNINGS: None *
  437. * *
  438. * HISTORY: *
  439. * 8/8/2002 12:47PM ST : Created *
  440. *=============================================================================================*/
  441. void ConsoleModeClass::Log_To_Disk(const char *string)
  442. {
  443. if (ConsoleOutputHandle != INVALID_HANDLE_VALUE) {
  444. if (ServerSettingsClass::Get_Disk_Log_Size() > 0) {
  445. FILE *log_file = fopen(Get_Log_File_Name(), "at");
  446. if (log_file != NULL) {
  447. char timestr[256] = "?";
  448. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, NULL, "'['HH':'mm':'ss'] '", timestr, 255);
  449. fwrite(timestr, 1, strlen(timestr), log_file);
  450. fwrite(string, 1, strlen(string), log_file);
  451. fclose(log_file);
  452. }
  453. }
  454. }
  455. }
  456. /***********************************************************************************************
  457. * ConsoleModeClass::Think -- Handles input to the console box *
  458. * *
  459. * *
  460. * *
  461. * INPUT: Nothing *
  462. * *
  463. * OUTPUT: Nothing *
  464. * *
  465. * WARNINGS: None *
  466. * *
  467. * HISTORY: *
  468. * 12/17/2001 5:04PM ST : Created *
  469. *=============================================================================================*/
  470. void ConsoleModeClass::Think(void)
  471. {
  472. static char string[256] = ">";
  473. char key = 0;
  474. static char suggestion[256] = "";
  475. static char last_suggestion[256] = "";
  476. static char help[256] = "";
  477. static char suggestion_stub[256];
  478. static unsigned long last_info_time = 0;
  479. static int num_players = -1; //eh?
  480. static int delay = 100;
  481. if (ConsoleInputHandle != INVALID_HANDLE_VALUE) {
  482. /*
  483. ** See if there is a key waiting in the queue.
  484. */
  485. if (_kbhit()) {
  486. /*
  487. ** Get the key from the queue.
  488. */
  489. key = _getche();
  490. if (key == 0 || key == 0xE0) {
  491. key = _getche();
  492. }
  493. /*
  494. ** Note the time of the last keypress.
  495. */
  496. LastKeypressTime = TIMEGETTIME();
  497. switch (key) {
  498. /*
  499. ** TAB key used to get command line suggestions.
  500. */
  501. case 9:
  502. {
  503. string[Pos] = 0;
  504. if (!strlen(last_suggestion)) {
  505. strcpy(suggestion_stub, string+1);
  506. }
  507. ConsoleFunctionManager::Get_Command_Suggestion(suggestion_stub, last_suggestion, suggestion, help, 256);
  508. strcpy(last_suggestion, suggestion);
  509. /*
  510. ** Save the cursor position.
  511. */
  512. CONSOLE_SCREEN_BUFFER_INFO info;
  513. int ok = GetConsoleScreenBufferInfo(ConsoleOutputHandle, &info);
  514. /*
  515. ** Clear out the two lines below.
  516. */
  517. cprintf("\r\n ");
  518. cprintf("\r\n ");
  519. /*
  520. ** Move the cursor back up one line to the current command prompt line.
  521. */
  522. if (ok) {
  523. COORD new_pos = info.dwCursorPosition;
  524. new_pos.X = 0;
  525. SetConsoleCursorPosition(ConsoleOutputHandle, new_pos);
  526. }
  527. /*
  528. ** Print the suggestion on the line below.
  529. */
  530. cprintf("\r\n%s\r", help);
  531. /*
  532. ** Move the cursor back up one line to the current command prompt line.
  533. */
  534. if (ok) {
  535. COORD new_pos = info.dwCursorPosition;
  536. new_pos.X = 0;
  537. SetConsoleCursorPosition(ConsoleOutputHandle, new_pos);
  538. }
  539. /*
  540. ** Clear out the command line and print the suggestion.
  541. */
  542. cprintf("\r \r>%s", suggestion);
  543. strcpy(string+1, suggestion);
  544. Pos = strlen(string);
  545. break;
  546. }
  547. /*
  548. ** Handle backspace.
  549. */
  550. case 8:
  551. if (Pos > 1) {
  552. Pos--;
  553. last_suggestion[0] = 0;
  554. cprintf(" \b");
  555. } else {
  556. /*
  557. ** Compensate for backspace going too far.
  558. */
  559. if (Pos == 1) {
  560. cprintf(">");
  561. }
  562. }
  563. break;
  564. /*
  565. ** Handle escape.
  566. */
  567. case 27:
  568. if (ProfileMode) {
  569. StatisticsDisplayManager::Set_Display("off");
  570. ProfileMode = false;
  571. Print("\n\n\n\n");
  572. Print("\n\n\n\n");
  573. Print("\n\n\n\n");
  574. Print("\n\n\n\n");
  575. }
  576. cprintf("\r \r>");
  577. Pos = 1;
  578. string[0] = '>';
  579. string[1] = 0;
  580. break;
  581. /*
  582. ** Anything else gets put into the command buffer.
  583. */
  584. default:
  585. if (ProfileMode) {
  586. Handle_Profile_Key(key);
  587. } else {
  588. if (key == 32 || isgraph(key)) {
  589. string[Pos++] = key;
  590. last_suggestion[0] = 0;
  591. }
  592. }
  593. break;
  594. }
  595. /*
  596. ** Handle user hitting enter (13).
  597. */
  598. if (Pos > 1 && key == 13 || Pos > 200) {
  599. string[Pos] = 0;
  600. cprintf("\r\n \r>");
  601. /*
  602. ** Pass the command string to the console parser.
  603. */
  604. ConsoleFunctionManager::Parse_Input(string+1);
  605. cprintf("\r\n>");
  606. Pos = 1;
  607. string[0] = '>';
  608. Apply_Attributes();
  609. }
  610. }
  611. /*
  612. ** Print up game info if console is idle.
  613. */
  614. delay--;
  615. if (delay <= 0) {
  616. delay = 100;
  617. unsigned long time = TIMEGETTIME();
  618. /*
  619. ** Handle timer reset.
  620. */
  621. if (time < last_info_time) {
  622. last_info_time = time;
  623. }
  624. /*
  625. ** Print if enough time has gone by.
  626. */
  627. if (Pos == 1 && time - LastKeypressTime > 30 * 1000) {
  628. if (time - last_info_time > 60 * 1000) {
  629. if (cNetwork::PServerConnection && cNetwork::PServerConnection->Get_Num_RHosts() != num_players) {
  630. num_players = cNetwork::PServerConnection->Get_Num_RHosts();
  631. ConsoleFunctionManager::Parse_Input("game_info");
  632. cprintf(">");
  633. last_info_time = time;
  634. Apply_Attributes();
  635. }
  636. }
  637. }
  638. }
  639. }
  640. }
  641. /***********************************************************************************************
  642. * ConsoleModeClass::Add_Message -- Print colored text to the console *
  643. * *
  644. * *
  645. * *
  646. * INPUT: Formatted wide string *
  647. * Color to print in *
  648. * Forced - set to true to print even if the user is currently typing at the console *
  649. * *
  650. * OUTPUT: Nothing *
  651. * *
  652. * WARNINGS: None *
  653. * *
  654. * HISTORY: *
  655. * 12/17/2001 5:06PM ST : Created *
  656. *=============================================================================================*/
  657. ConsoleModeClass::Add_Message(WideStringClass *formatted_text, Vector3 *text_color, bool forced)
  658. {
  659. if (!ProfileMode && formatted_text && text_color && (forced || (Pos == 1 && TIMEGETTIME() - LastKeypressTime > 3 * 1000))) {
  660. unsigned short color = 0;
  661. /*
  662. ** Convert the Vector3 RGB to text attribute colors.
  663. */
  664. if (text_color->X != 0.0f) {
  665. color |= FOREGROUND_RED;
  666. if (text_color->X > 0.4f) {
  667. color |= FOREGROUND_INTENSITY;
  668. }
  669. }
  670. if (text_color->Y != 0.0f) {
  671. color |= FOREGROUND_GREEN;
  672. if (text_color->Y > 0.4f) {
  673. color |= FOREGROUND_INTENSITY;
  674. }
  675. }
  676. if (text_color->Z != 0.0f) {
  677. color |= FOREGROUND_BLUE;
  678. if (text_color->Z > 0.4f) {
  679. color |= FOREGROUND_INTENSITY;
  680. }
  681. }
  682. if (!SlaveMaster.Am_I_Slave()) {
  683. SetConsoleTextAttribute(ConsoleOutputHandle, color | BACKGROUND_BLUE);
  684. } else {
  685. SetConsoleTextAttribute(ConsoleOutputHandle, color | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE);
  686. }
  687. StringClass string(128, true);
  688. formatted_text->Convert_To(string);
  689. cprintf("%s", string.Peek_Buffer());
  690. Log_To_Disk(string.Peek_Buffer());
  691. if (!SlaveMaster.Am_I_Slave()) {
  692. SetConsoleTextAttribute(ConsoleOutputHandle, MASTER_COLORS);
  693. } else {
  694. SetConsoleTextAttribute(ConsoleOutputHandle, SLAVE_COLORS);
  695. }
  696. /*
  697. ** Reprint the prompt.
  698. */
  699. //cprintf(">");
  700. Apply_Attributes();
  701. }
  702. }
  703. /***********************************************************************************************
  704. * ConsoleModeClass::Apply_Attributes -- Reapply the console colors. *
  705. * *
  706. * *
  707. * *
  708. * INPUT: Nothing *
  709. * *
  710. * OUTPUT: Nothing *
  711. * *
  712. * WARNINGS: None *
  713. * *
  714. * HISTORY: *
  715. * 12/24/2001 1:26PM ST : Created *
  716. *=============================================================================================*/
  717. void ConsoleModeClass::Apply_Attributes(void)
  718. {
  719. CONSOLE_SCREEN_BUFFER_INFO info;
  720. int ok = GetConsoleScreenBufferInfo(ConsoleOutputHandle, &info);
  721. if (ok) {
  722. COORD pos = info.dwCursorPosition;
  723. unsigned long written = 0;
  724. if (!SlaveMaster.Am_I_Slave()) {
  725. FillConsoleOutputAttribute(ConsoleOutputHandle, MASTER_COLORS, 5*80, pos, &written);
  726. } else {
  727. FillConsoleOutputAttribute(ConsoleOutputHandle, SLAVE_COLORS, 5*80, pos, &written);
  728. }
  729. }
  730. }
  731. // unrecognized character escape sequence
  732. #pragma warning(disable : 4129)
  733. /***********************************************************************************************
  734. * ConsoleModeClass::Update_Profile -- Print the profile text *
  735. * *
  736. * *
  737. * *
  738. * INPUT: Profile text *
  739. * *
  740. * OUTPUT: Nothing *
  741. * *
  742. * WARNINGS: None *
  743. * *
  744. * HISTORY: *
  745. * 1/13/2002 12:56PM ST : Created *
  746. *=============================================================================================*/
  747. void ConsoleModeClass::Update_Profile(StringClass profile_string)
  748. {
  749. if (profile_string.Get_Length() && ProfileMode && TIMEGETTIME() - LastProfilePrint > 1500) {
  750. LastProfilePrint = TIMEGETTIME();
  751. /*
  752. ** Get a checksum of the profile string.
  753. */
  754. unsigned long crc = CRC::Memory((unsigned char*)profile_string.Peek_Buffer(), profile_string.Get_Length());
  755. if (crc != LastProfileCRC) {
  756. /*
  757. ** Create a copy of the string and scan it for '%'.
  758. */
  759. int len = profile_string.Get_Length();
  760. char *str = (char*) alloca(len * 2);
  761. char *src = profile_string.Peek_Buffer();
  762. char *dst = str;
  763. char c;
  764. for (int i=0 ; i<len ; i++) {
  765. c = *src++;
  766. /*
  767. ** % = 37. Double up % sign so it prints literally.
  768. */
  769. if (c == 37) {
  770. *dst++ = 37;
  771. }
  772. *dst++ = c;
  773. }
  774. *dst = 0;
  775. /*
  776. ** Save the cursor position.
  777. */
  778. CONSOLE_SCREEN_BUFFER_INFO info;
  779. int ok = GetConsoleScreenBufferInfo(ConsoleOutputHandle, &info);
  780. COORD pos = info.dwCursorPosition;
  781. /*
  782. ** Fill the console with spaces.
  783. */
  784. if (ok) {
  785. unsigned long num_written = 0;
  786. FillConsoleOutputCharacter(ConsoleOutputHandle, ' ', 206*80, pos, &num_written);
  787. /*
  788. ** Fill the attributes too, the first time.
  789. */
  790. if (LastProfileCRC == 0) {
  791. if (!SlaveMaster.Am_I_Slave()) {
  792. FillConsoleOutputAttribute(ConsoleOutputHandle, MASTER_COLORS, 20*80, pos, &num_written);
  793. } else {
  794. FillConsoleOutputAttribute(ConsoleOutputHandle, SLAVE_COLORS, 20*80, pos, &num_written);
  795. }
  796. }
  797. }
  798. /*
  799. ** Print out the profile info.
  800. */
  801. Print(str);
  802. /*
  803. ** Move the cursor back up to the original position.
  804. */
  805. if (ok) {
  806. SetConsoleCursorPosition(ConsoleOutputHandle, pos);
  807. }
  808. LastProfileCRC = crc;
  809. }
  810. }
  811. }
  812. /***********************************************************************************************
  813. * ConsoleModeClass::Handle_Profile_Key -- Handle keyboard input in profile mode *
  814. * *
  815. * *
  816. * *
  817. * INPUT: Key pressed *
  818. * *
  819. * OUTPUT: Nothing *
  820. * *
  821. * WARNINGS: None *
  822. * *
  823. * HISTORY: *
  824. * 1/13/2002 1:09PM ST : Created *
  825. *=============================================================================================*/
  826. void ConsoleModeClass::Handle_Profile_Key(int key)
  827. {
  828. if (Get_Console()) {
  829. if (key >= '0' && key <= '9') {
  830. char profile_text[4];
  831. profile_text[0] = (char)key;
  832. profile_text[1] = 0;
  833. Get_Console()->Profile_Command(profile_text);
  834. cprintf("\r");
  835. LastProfilePrint = 0;
  836. } else {
  837. if (key >= 'a' && key <= 'z') {
  838. char profile_text[4];
  839. profile_text[0] = '1';
  840. profile_text[1] = (char)(key - 'a') + '0';
  841. profile_text[2] = 0;
  842. Get_Console()->Profile_Command(profile_text);
  843. cprintf("\r");
  844. LastProfilePrint = 0;
  845. } else {
  846. if (key == '.') {
  847. Get_Console()->Profile_Command("up");
  848. cprintf("\r");
  849. LastProfilePrint = 0;
  850. }
  851. }
  852. }
  853. }
  854. }
  855. /***********************************************************************************************
  856. * ConsoleModeClass::Wait_For_Keypress -- Wait for user to press a key *
  857. * *
  858. * *
  859. * *
  860. * INPUT: Nothing *
  861. * *
  862. * OUTPUT: Nothing *
  863. * *
  864. * WARNINGS: None *
  865. * *
  866. * HISTORY: *
  867. * 2/4/2002 11:10AM ST : Created *
  868. *=============================================================================================*/
  869. void ConsoleModeClass::Wait_For_Keypress(void)
  870. {
  871. if (Get_Console()) {
  872. if (ConsoleInputHandle != INVALID_HANDLE_VALUE) {
  873. Print("** Press any key to continue **\n");
  874. }
  875. _getch();
  876. }
  877. }