MSGLIST.CPP 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399
  1. /*
  2. ** Command & Conquer Red Alert(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. /* $Header: /CounterStrike/MSGLIST.CPP 2 3/04/97 2:52p Joe_bostic $ */
  19. /***************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * File Name : MSGLIST.CPP *
  25. * *
  26. * Programmer : Bill R. Randolph *
  27. * *
  28. * Start Date : 05/22/95 *
  29. * *
  30. * Last Update : March 4, 1997 [JLB] *
  31. * *
  32. *-------------------------------------------------------------------------*
  33. * Functions: *
  34. * MessageListClass::MessageListClass -- constructor *
  35. * MessageListClass::~MessageListClass -- destructor *
  36. * MessageListClass::Init -- Inits message system, sets options *
  37. * MessageListClass::Add_Message -- displays the given message *
  38. * MessageListClass::Get_Message -- retrieves given message *
  39. * MessageListClass::Get_Label -- retrieves given text label *
  40. * MessageListClass::Concat_Message -- concats the given message *
  41. * MessageListClass::Add_Edit -- Adds editable string to message list *
  42. * MessageListClass::Remove_Edit -- removes the edit field *
  43. * MessageListClass::Get_Edit_Buf -- gets edit buffer *
  44. * MessageListClass::Set_Edit_Color -- sets color of edit gizmo *
  45. * MessageListClass::Manage -- Manages multiplayer messages *
  46. * MessageListClass::Input -- Handles input for sending messages *
  47. * MessageListClass::Draw -- Draws the messages *
  48. * MessageListClass::Num_Messages -- returns # messages in the list *
  49. * MessageListClass::Set_Width -- sets allowable width of messages *
  50. * MessageListClass::Trim_Message -- trims chars off start of message *
  51. * MessageListClass::Compute_Y -- recomputes y-coord for all messages *
  52. * MessageListClass::Reset -- Reset so no messages are visible. *
  53. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  54. #include "function.h"
  55. /**************************** Globals **************************************/
  56. /***************************************************************************
  57. * MessageListClass::MessageListClass -- constructor *
  58. * *
  59. * INPUT: *
  60. * x,y coord of upper-left of top message *
  61. * max_msg max messages allowed, including edit message *
  62. * *
  63. * OUTPUT: *
  64. * none. *
  65. * *
  66. * WARNINGS: *
  67. * none. *
  68. * *
  69. * HISTORY: *
  70. * 05/21/1995 BRR : Created. *
  71. *=========================================================================*/
  72. MessageListClass::MessageListClass(void)
  73. {
  74. int i;
  75. //------------------------------------------------------------------------
  76. // Init all data members
  77. //------------------------------------------------------------------------
  78. MessageList = 0;
  79. MessageX = 0;
  80. MessageY = 0;
  81. MaxMessages = 0;
  82. MaxChars = 0;
  83. Height = 0;
  84. EnableOverflow = 0;
  85. AdjustEdit = 0;
  86. IsEdit = 0;
  87. EditX = 0;
  88. EditY = 0;
  89. EditLabel = 0;
  90. EditBuf[0] = 0;
  91. OverflowBuf[0] = 0;
  92. EditCurPos = 0;
  93. EditInitPos = 0;
  94. CursorChar = 0;
  95. OverflowStart = 0;
  96. OverflowEnd = 0;
  97. for (i = 0; i < MAX_NUM_MESSAGES; i++) {
  98. BufferAvail[i] = 1;
  99. }
  100. } // end of MessageListClass
  101. /***************************************************************************
  102. * MessageListClass::~MessageListClass -- destructor *
  103. * *
  104. * INPUT: *
  105. * x,y coord of upper-left of top message *
  106. * max_msg max messages allowed, including edit message *
  107. * *
  108. * OUTPUT: *
  109. * none. *
  110. * *
  111. * WARNINGS: *
  112. * none. *
  113. * *
  114. * HISTORY: *
  115. * 05/21/1995 BRR : Created. *
  116. *=========================================================================*/
  117. MessageListClass::~MessageListClass()
  118. {
  119. Init(0,0,0,0,0,0,0,0,0,0);
  120. } // end of ~MessageListClass
  121. /***************************************************************************
  122. * MessageListClass::Init -- Inits message system, sets options *
  123. * *
  124. * INPUT: *
  125. * x,y coord of upper-left of top message *
  126. * max_msg max messages allowed, NOT including edit message *
  127. * maxchars max # characters allowed per message *
  128. * height pixel height of a line of text *
  129. * edit_x x-coord of edit field; -1 = put at the top of the *
  130. * other messages *
  131. * edit_y y-coord of edit field; -1 = put at the top of the *
  132. * other messages *
  133. * overflow_on true = enable the overflow typing feature *
  134. * over_start start index for overflow processing *
  135. * over_end end index for overflow processing *
  136. * width pixel width of message buffer *
  137. * *
  138. * OUTPUT: *
  139. * none. *
  140. * *
  141. * WARNINGS: *
  142. * none. *
  143. * *
  144. * HISTORY: *
  145. * 05/21/1995 BRR : Created. *
  146. *=========================================================================*/
  147. void MessageListClass::Init(int x, int y, int max_msg, int maxchars,
  148. int height, int edit_x, int edit_y, int overflow_on, int over_start,
  149. int over_end, int width)
  150. {
  151. TextLabelClass * txtlabel;
  152. int i;
  153. Width = width;
  154. //------------------------------------------------------------------------
  155. // Remove every entry in the list
  156. //------------------------------------------------------------------------
  157. txtlabel = MessageList;
  158. while (txtlabel) {
  159. MessageList = (TextLabelClass *)txtlabel->Remove();
  160. delete txtlabel;
  161. txtlabel = MessageList;
  162. }
  163. //------------------------------------------------------------------------
  164. // Mark all buffers as available
  165. //------------------------------------------------------------------------
  166. for (i = 0; i < MAX_NUM_MESSAGES; i++) {
  167. BufferAvail[i] = 1;
  168. }
  169. //------------------------------------------------------------------------
  170. // Remove the editable message
  171. //------------------------------------------------------------------------
  172. if (IsEdit) {
  173. delete EditLabel;
  174. EditLabel = 0;
  175. }
  176. //------------------------------------------------------------------------
  177. // Init variables
  178. //------------------------------------------------------------------------
  179. MessageList = 0;
  180. MessageX = x;
  181. MessageY = y;
  182. MaxMessages = max_msg;
  183. if (MaxMessages > MAX_NUM_MESSAGES)
  184. MaxMessages = MAX_NUM_MESSAGES;
  185. MaxChars = maxchars;
  186. if (MaxChars > MAX_MESSAGE_LENGTH)
  187. MaxChars = MAX_MESSAGE_LENGTH;
  188. Height = height;
  189. //------------------------------------------------------------------------
  190. // Init the edit field variables. If edit_x or edit_y is -1, place the
  191. // edit field above the other messages; otherwise, place it at the desired
  192. // coords.
  193. //------------------------------------------------------------------------
  194. EnableOverflow = overflow_on;
  195. IsEdit = 0;
  196. if (edit_x == -1 || edit_y == -1) {
  197. AdjustEdit = 1;
  198. EditX = x;
  199. EditY = y;
  200. }
  201. else {
  202. AdjustEdit = 0;
  203. EditX = edit_x;
  204. EditY = edit_y;
  205. }
  206. EditLabel = 0;
  207. EditBuf[0] = 0;
  208. OverflowBuf[0] = 0;
  209. EditCurPos = 0;
  210. EditInitPos = 0;
  211. CursorChar = 0;
  212. //------------------------------------------------------------------------
  213. // Init the overflow processing indices
  214. //------------------------------------------------------------------------
  215. OverflowStart = over_start;
  216. OverflowEnd = over_end;
  217. if (OverflowEnd >= MaxChars) {
  218. OverflowEnd = MaxChars - 1;
  219. }
  220. if (OverflowStart >= OverflowEnd) {
  221. OverflowStart = OverflowEnd - 1;
  222. }
  223. } // end of Init
  224. /***********************************************************************************************
  225. * MessageListClass::Reset -- Reset so no messages are visible. *
  226. * *
  227. * This routine will reset the message list tracker so that any displayed messages are *
  228. * cleared. *
  229. * *
  230. * INPUT: none *
  231. * *
  232. * OUTPUT: none *
  233. * *
  234. * WARNINGS: none *
  235. * *
  236. * HISTORY: *
  237. * 03/04/1997 JLB : Created. *
  238. *=============================================================================================*/
  239. void MessageListClass::Reset(void)
  240. {
  241. //------------------------------------------------------------------------
  242. // Remove every entry in the list
  243. //------------------------------------------------------------------------
  244. TextLabelClass * txtlabel = MessageList;
  245. while (txtlabel) {
  246. MessageList = (TextLabelClass *)txtlabel->Remove();
  247. delete txtlabel;
  248. txtlabel = MessageList;
  249. }
  250. //------------------------------------------------------------------------
  251. // Mark all buffers as available
  252. //------------------------------------------------------------------------
  253. for (int index = 0; index < MAX_NUM_MESSAGES; index++) {
  254. BufferAvail[index] = 1;
  255. }
  256. //------------------------------------------------------------------------
  257. // Remove the editable message
  258. //------------------------------------------------------------------------
  259. if (IsEdit) {
  260. delete EditLabel;
  261. EditLabel = 0;
  262. }
  263. //------------------------------------------------------------------------
  264. // Init variables
  265. //------------------------------------------------------------------------
  266. MessageList = 0;
  267. EditLabel = 0;
  268. IsEdit = 0;
  269. }
  270. /***************************************************************************
  271. * MessageListClass::Add_Message -- displays the given message *
  272. * *
  273. * INPUT: *
  274. * name name of sender, NULL = none *
  275. * id numerical ID for this message *
  276. * txt text to display *
  277. * color color to draw text in *
  278. * style style to use *
  279. * timeout # of ticks the thing is supposed to last (-1 = forever) *
  280. * *
  281. * OUTPUT: *
  282. * ptr to new TextLabelClass object. *
  283. * *
  284. * WARNINGS: *
  285. * none. *
  286. * *
  287. * HISTORY: *
  288. * 05/05/1995 BRR : Created. *
  289. * 10/16/1996 JLB : Audio feedback added. *
  290. *=========================================================================*/
  291. TextLabelClass * MessageListClass::Add_Message(char const * name, int id, char const * txt,
  292. PlayerColorType color, TextPrintType style, int timeout)
  293. {
  294. TextLabelClass * txtlabel;
  295. int i;
  296. int found;
  297. char message[MAX_MESSAGE_LENGTH + 30];
  298. char temp[MAX_MESSAGE_LENGTH + 30];
  299. int print_this_pass;
  300. char save = 0;
  301. int mess_start;
  302. //------------------------------------------------------------------------
  303. // Combine the name & message text, if there's a name given
  304. //------------------------------------------------------------------------
  305. if (name) {
  306. sprintf(message, "%s:%s", name, txt);
  307. } else {
  308. strcpy(message, txt);
  309. }
  310. //------------------------------------------------------------------------
  311. // Check that printing this wont overrun the width of the print area on screen
  312. //------------------------------------------------------------------------
  313. print_this_pass = 0;
  314. Fancy_Text_Print(TXT_NONE, 0, 0, &ColorRemaps[color], TBLACK, style);
  315. int wid = String_Pixel_Width(message);
  316. if (wid >= Width-8) {
  317. //------------------------------------------------------------------------
  318. // Bugger. Its too long. Loop through and find out how many chars we can print
  319. //------------------------------------------------------------------------
  320. if (name) {
  321. sprintf (temp, "%s:", name);
  322. mess_start = strlen (name)+1;
  323. } else {
  324. mess_start = 0;
  325. }
  326. for (int i=1 ; i<strlen(txt) ; i++) {
  327. strncpy (&temp[mess_start], txt, i);
  328. temp [mess_start + i] = 0;
  329. wid = String_Pixel_Width(temp);
  330. if (wid >= Width-8) {
  331. print_this_pass = mess_start + i-1;
  332. break;
  333. }
  334. }
  335. //------------------------------------------------------------------------
  336. // Prematurely terminate the string so it doesn't all print.
  337. // We will re-enter at the end to print the rest.
  338. //------------------------------------------------------------------------
  339. if (print_this_pass) {
  340. save = message [print_this_pass];
  341. message [print_this_pass] = 0;
  342. }
  343. }
  344. //------------------------------------------------------------------------
  345. // Remove the top-most message if we're about to exceed the max allowed
  346. //------------------------------------------------------------------------
  347. if ( (MaxMessages > 0) && ((Num_Messages() + 1) > MaxMessages)) {
  348. txtlabel = MessageList;
  349. if (txtlabel==NULL)
  350. return(NULL);
  351. //.....................................................................
  352. // Remove this message from the list; mark its buffer as being available.
  353. //.....................................................................
  354. MessageList = (TextLabelClass *)txtlabel->Remove();
  355. for (i = 0; i < MAX_NUM_MESSAGES; i++) {
  356. if (txtlabel->Text == MessageBuffers[i])
  357. BufferAvail[i] = 1;
  358. }
  359. delete txtlabel;
  360. }
  361. //------------------------------------------------------------------------
  362. // Create the message
  363. //------------------------------------------------------------------------
  364. txtlabel = new TextLabelClass (message, MessageX, MessageY,
  365. &ColorRemaps[color], style);
  366. if (timeout==-1) {
  367. txtlabel->UserData1 = 0;
  368. }
  369. else {
  370. txtlabel->UserData1 = TickCount + timeout;
  371. }
  372. txtlabel->UserData2 = id;
  373. //------------------------------------------------------------------------
  374. // Find a buffer to store our message in; if there are none, don't add the
  375. // message.
  376. //------------------------------------------------------------------------
  377. found = 0;
  378. for (i = 0; i < MAX_NUM_MESSAGES; i++) {
  379. if (BufferAvail[i]) {
  380. BufferAvail[i] = 0;
  381. memset (MessageBuffers[i],0,MAX_MESSAGE_LENGTH + 30);
  382. strcpy (MessageBuffers[i],message);
  383. txtlabel->Text = MessageBuffers[i];
  384. found = 1;
  385. break;
  386. }
  387. }
  388. if (!found) {
  389. delete txtlabel;
  390. return (NULL);
  391. }
  392. Sound_Effect(VOC_INCOMING_MESSAGE);
  393. //------------------------------------------------------------------------
  394. // Attach the message to our list
  395. //------------------------------------------------------------------------
  396. if (MessageList) {
  397. txtlabel->Add_Tail (*MessageList);
  398. }
  399. else {
  400. MessageList = txtlabel;
  401. }
  402. //------------------------------------------------------------------------
  403. // Recompute all messages' y-coordinate values
  404. //------------------------------------------------------------------------
  405. Compute_Y();
  406. //------------------------------------------------------------------------
  407. // If we terminated the string before the end then we need to reenter to
  408. // add a new message with the rest of the string.
  409. //------------------------------------------------------------------------
  410. if (save) {
  411. message [print_this_pass] = save;
  412. Add_Message (name, id, &message [print_this_pass], color, style, timeout);
  413. }
  414. return(txtlabel);
  415. } // end of Add_Message
  416. /***************************************************************************
  417. * MessageListClass::Get_Message -- retrieves given message *
  418. * *
  419. * INPUT: *
  420. * id ID of message to get *
  421. * *
  422. * OUTPUT: *
  423. * ptr to message text, NULL if not found *
  424. * *
  425. * WARNINGS: *
  426. * none. *
  427. * *
  428. * HISTORY: *
  429. * 11/07/1995 BRR : Created. *
  430. *=========================================================================*/
  431. char * MessageListClass::Get_Message(int id)
  432. {
  433. TextLabelClass * gadg;
  434. //------------------------------------------------------------------------
  435. // Scan the message list, searching for the given ID
  436. //------------------------------------------------------------------------
  437. if (MessageList) {
  438. gadg = MessageList;
  439. while (gadg) {
  440. if (gadg->UserData2 == id) {
  441. return (gadg->Text);
  442. }
  443. gadg = (TextLabelClass *)gadg->Get_Next();
  444. }
  445. }
  446. return (NULL);
  447. } // end of Get_Message
  448. /***************************************************************************
  449. * MessageListClass::Get_Label -- retrieves given text label *
  450. * *
  451. * INPUT: *
  452. * id ID of message to get *
  453. * *
  454. * OUTPUT: *
  455. * ptr to message text, NULL if not found *
  456. * *
  457. * WARNINGS: *
  458. * none. *
  459. * *
  460. * HISTORY: *
  461. * 11/07/1995 BRR : Created. *
  462. *=========================================================================*/
  463. TextLabelClass * MessageListClass::Get_Label(int id)
  464. {
  465. TextLabelClass * gadg;
  466. //------------------------------------------------------------------------
  467. // Scan the message list, searching for the given ID
  468. //------------------------------------------------------------------------
  469. if (MessageList) {
  470. gadg = MessageList;
  471. while (gadg) {
  472. if (gadg->UserData2 == id) {
  473. return (gadg);
  474. }
  475. gadg = (TextLabelClass *)gadg->Get_Next();
  476. }
  477. }
  478. return (NULL);
  479. } // end of Get_Label
  480. /***************************************************************************
  481. * MessageListClass::Concat_Message -- concats the given message *
  482. * *
  483. * INPUT: *
  484. * name name of sender; NULL = none *
  485. * id ID of message to concatenate to *
  486. * txt text to concatenate onto existing message *
  487. * timeout new timeout for message *
  488. * *
  489. * OUTPUT: *
  490. * 1 = OK, 0 = error (id or name not found) *
  491. * *
  492. * WARNINGS: *
  493. * If the required message doesn't exist, this routine does nothing. *
  494. * *
  495. * HISTORY: *
  496. * 11/07/1995 BRR : Created. *
  497. *=========================================================================*/
  498. int MessageListClass::Concat_Message(char const * name, int id, char const * txt, int timeout)
  499. {
  500. int min_chars;
  501. int max_chars;
  502. char * msg;
  503. TextLabelClass * tlabel;
  504. int found;
  505. //------------------------------------------------------------------------
  506. // If no name is given, or the concatenation feature is turned off,
  507. // don't concatenate the message
  508. //------------------------------------------------------------------------
  509. if (!name || !EnableOverflow) {
  510. return (0);
  511. }
  512. //------------------------------------------------------------------------
  513. // Scan through all active messages, searching for one with a matching
  514. // name & ID
  515. //------------------------------------------------------------------------
  516. found = 0;
  517. if (MessageList) {
  518. tlabel = MessageList;
  519. while (tlabel) {
  520. if (tlabel->UserData2 == id &&
  521. !memcmp(tlabel->Text,name,strlen(name))) {
  522. found = 1;
  523. break;
  524. }
  525. tlabel = (TextLabelClass *)tlabel->Get_Next();
  526. }
  527. }
  528. //------------------------------------------------------------------------
  529. // name and ID not found; return
  530. //------------------------------------------------------------------------
  531. if (!found) {
  532. return (0);
  533. }
  534. //------------------------------------------------------------------------
  535. // set a pointer to the text string, plus the name and colon
  536. //------------------------------------------------------------------------
  537. msg = tlabel->Text + strlen(name) + 1;
  538. //------------------------------------------------------------------------
  539. // If there's room enough in the message, just add the given string
  540. //------------------------------------------------------------------------
  541. if ( (strlen(msg) + strlen(txt)) < MaxChars) {
  542. //---------------------------------------------------------------------
  543. // We need to trim the message if there is no room to draw it
  544. //---------------------------------------------------------------------
  545. char *concat_test = new char [MaxChars+1];
  546. Fancy_Text_Print(TXT_NONE, 0, 0, tlabel->Color, TBLACK, tlabel->Style);
  547. int name_width = String_Pixel_Width(tlabel->Text) - String_Pixel_Width(msg);
  548. int width;
  549. strcpy (concat_test, msg);
  550. strcat (concat_test, txt);
  551. width = String_Pixel_Width(concat_test) + name_width;
  552. min_chars = 10;
  553. while (width >= Width-8){
  554. max_chars = strlen (msg);
  555. if (max_chars < min_chars) {
  556. max_chars = min_chars;
  557. }
  558. Trim_Message (NULL, msg, min_chars, max_chars, 0);
  559. strcpy (concat_test, msg);
  560. strcat (concat_test, txt);
  561. width = String_Pixel_Width(concat_test) + name_width;
  562. };
  563. delete [] concat_test;
  564. strcat (msg,txt);
  565. }
  566. //------------------------------------------------------------------------
  567. // Otherwise, trim off some characters from the beginning of the
  568. // message. Trim off at least enough to leave room for the new text.
  569. // Trim from left to right to remove the minimum required text.
  570. //------------------------------------------------------------------------
  571. else {
  572. min_chars = (strlen(msg) + strlen(txt)) - MaxChars;
  573. max_chars = strlen(msg);
  574. if (max_chars < min_chars) {
  575. max_chars = min_chars;
  576. }
  577. Trim_Message (NULL, msg, min_chars, max_chars, 0);
  578. strcat (msg, txt);
  579. }
  580. //------------------------------------------------------------------------
  581. // Set the new timeout value for the message
  582. //------------------------------------------------------------------------
  583. if (timeout==-1) {
  584. tlabel->UserData1 = 0;
  585. }
  586. else {
  587. tlabel->UserData1 = TickCount + timeout;
  588. }
  589. return (1);
  590. } // end of Concat_Message
  591. /***********************************************************************************************
  592. * MessageListClass::Set_Edit_Focus -- Give the gadget system focus to the edit box *
  593. * *
  594. * *
  595. * *
  596. * INPUT: Nothing *
  597. * *
  598. * OUTPUT: Nothing *
  599. * *
  600. * WARNINGS: None *
  601. * *
  602. * HISTORY: *
  603. * 10/19/96 4:41PM ST : Created *
  604. *=============================================================================================*/
  605. void MessageListClass::Set_Edit_Focus (void)
  606. {
  607. if (IsEdit) EditLabel->Set_Focus();
  608. }
  609. /***********************************************************************************************
  610. * MessageListClass::Has_Edit_Focus -- Find out if the edit box has the input focus *
  611. * *
  612. * *
  613. * *
  614. * INPUT: Nothing *
  615. * *
  616. * OUTPUT: Nothing *
  617. * *
  618. * WARNINGS: None *
  619. * *
  620. * HISTORY: *
  621. * 10/19/96 4:41PM ST : Created *
  622. *=============================================================================================*/
  623. bool MessageListClass::Has_Edit_Focus (void)
  624. {
  625. if (IsEdit){
  626. return (EditLabel->Has_Focus());
  627. }else{
  628. return(false);
  629. }
  630. }
  631. /***************************************************************************
  632. * MessageListClass::Add_Edit -- Adds editable string to message list *
  633. * *
  634. * INPUT: *
  635. * color color of edit message *
  636. * style style of edit message *
  637. * to string: who to send to; NULL = none *
  638. * cursor character to use as a cursor; 0 = none *
  639. * *
  640. * OUTPUT: *
  641. * ptr to new TextLabelClass *
  642. * *
  643. * WARNINGS: *
  644. * none. *
  645. * *
  646. * HISTORY: *
  647. * 05/22/1995 BRR : Created. *
  648. *=========================================================================*/
  649. TextLabelClass * MessageListClass::Add_Edit(PlayerColorType color,
  650. TextPrintType style, char * to, char cursor, int width)
  651. {
  652. int i;
  653. TextLabelClass * txtlabel;
  654. //------------------------------------------------------------------------
  655. // Do nothing if we're already in "edit" mode
  656. //------------------------------------------------------------------------
  657. if (IsEdit) {
  658. EditLabel->Set_Focus();
  659. return(NULL);
  660. }
  661. //------------------------------------------------------------------------
  662. // Remove the top-most message if we're about to exceed the max allowed
  663. //------------------------------------------------------------------------
  664. if (AdjustEdit && ((Num_Messages() + 1) > MaxMessages)) {
  665. txtlabel = MessageList;
  666. MessageList = (TextLabelClass *)txtlabel->Remove();
  667. for (i = 0; i < MAX_NUM_MESSAGES; i++) {
  668. if (txtlabel->Text == MessageBuffers[i])
  669. BufferAvail[i] = 1;
  670. }
  671. delete txtlabel;
  672. }
  673. //------------------------------------------------------------------------
  674. // If no 'to' field was passed in, ignore it
  675. //------------------------------------------------------------------------
  676. if (!to) {
  677. to = "";
  678. }
  679. //------------------------------------------------------------------------
  680. // Set the cursor character
  681. //------------------------------------------------------------------------
  682. CursorChar = cursor;
  683. //------------------------------------------------------------------------
  684. // Initialize the buffer positions; create a new text label object
  685. //------------------------------------------------------------------------
  686. memset (EditBuf, 0, sizeof(EditBuf));
  687. strcpy (EditBuf, to);
  688. OverflowBuf[0] = 0;
  689. EditCurPos = EditInitPos = strlen(to);
  690. EditLabel = new TextLabelClass (EditBuf, EditX, EditY,
  691. &ColorRemaps[color], style);
  692. Width = width;
  693. if (EditLabel) {
  694. IsEdit = 1;
  695. EditLabel->Set_Focus();
  696. }
  697. else {
  698. IsEdit = 0;
  699. }
  700. //------------------------------------------------------------------------
  701. // If the edit field appears over the message list, recompute the y-value
  702. // for all messages. Also, adjust MaxMessages down by one, since there
  703. // is now one less slot available.
  704. //------------------------------------------------------------------------
  705. if (AdjustEdit) {
  706. Compute_Y();
  707. MaxMessages--;
  708. }
  709. return(EditLabel);
  710. } // end of Add_Edit
  711. /***************************************************************************
  712. * MessageListClass::Remove_Edit -- removes the edit field *
  713. * *
  714. * INPUT: *
  715. * none. *
  716. * *
  717. * OUTPUT: *
  718. * none. *
  719. * *
  720. * WARNINGS: *
  721. * none. *
  722. * *
  723. * HISTORY: *
  724. * 11/06/1995 BRR : Created. *
  725. *=========================================================================*/
  726. void MessageListClass::Remove_Edit(void)
  727. {
  728. //------------------------------------------------------------------------
  729. // If the edit field is active, delete it
  730. //------------------------------------------------------------------------
  731. if (IsEdit) {
  732. IsEdit = 0;
  733. delete EditLabel;
  734. //.....................................................................
  735. // If the edit field appears over the message list, recompute the
  736. // y-value for all messages. Adjust MaxMessages back up, since there
  737. // is now a new available slot.
  738. //.....................................................................
  739. if (AdjustEdit) {
  740. Compute_Y();
  741. MaxMessages++;
  742. }
  743. }
  744. } // end if Remove_Edit
  745. /***************************************************************************
  746. * MessageListClass::Get_Edit_Buf -- gets edit buffer *
  747. * *
  748. * INPUT: *
  749. * none. *
  750. * *
  751. * OUTPUT: *
  752. * ptr to edit buffer, minus the "To:" header *
  753. * *
  754. * WARNINGS: *
  755. * none. *
  756. * *
  757. * HISTORY: *
  758. * 05/21/1995 BRR : Created. *
  759. *=========================================================================*/
  760. char * MessageListClass::Get_Edit_Buf(void)
  761. {
  762. return(EditBuf + EditInitPos);
  763. } // end of Get_Edit_Buf
  764. /***************************************************************************
  765. * MessageListClass::Set_Edit_Color -- sets color of edit gizmo *
  766. * *
  767. * INPUT: *
  768. * color color to set edit label to *
  769. * *
  770. * OUTPUT: *
  771. * none. *
  772. * *
  773. * WARNINGS: *
  774. * none. *
  775. * *
  776. * HISTORY: *
  777. * 12/08/1995 BRR : Created. *
  778. *=========================================================================*/
  779. void MessageListClass::Set_Edit_Color(PlayerColorType color)
  780. {
  781. if (IsEdit) {
  782. EditLabel->Color = &ColorRemaps[color];
  783. }
  784. } // end of Set_Edit_Color
  785. /***************************************************************************
  786. * MessageListClass::Manage -- Manages multiplayer messages *
  787. * *
  788. * If this routine returns TRUE, the caller should update the display. *
  789. * *
  790. * INPUT: *
  791. * none. *
  792. * *
  793. * OUTPUT: *
  794. * none. *
  795. * *
  796. * WARNINGS: *
  797. * 0 = no change has occurred, 1 = changed *
  798. * *
  799. * HISTORY: *
  800. * 05/05/1995 BRR : Created. *
  801. *=========================================================================*/
  802. int MessageListClass::Manage (void)
  803. {
  804. TextLabelClass * txtlabel;
  805. TextLabelClass * next;
  806. int changed = 0;
  807. int i;
  808. //------------------------------------------------------------------------
  809. // Loop through all messages
  810. //------------------------------------------------------------------------
  811. txtlabel = MessageList;
  812. while (txtlabel) {
  813. //.....................................................................
  814. // If this message's time is up, remove it from the list
  815. //.....................................................................
  816. if (txtlabel->UserData1 != 0 && TickCount > txtlabel->UserData1) {
  817. //..................................................................
  818. // Save the next ptr in the list; remove this entry
  819. //..................................................................
  820. next = (TextLabelClass *)txtlabel->Get_Next();
  821. MessageList = (TextLabelClass *)txtlabel->Remove();
  822. for (i = 0; i < MAX_NUM_MESSAGES; i++) {
  823. if (txtlabel->Text == MessageBuffers[i]) {
  824. BufferAvail[i] = 1;
  825. }
  826. }
  827. delete txtlabel;
  828. changed = 1;
  829. txtlabel = next;
  830. }
  831. else {
  832. txtlabel = (TextLabelClass *)txtlabel->Get_Next();
  833. }
  834. }
  835. //------------------------------------------------------------------------
  836. // If a changed has been made, recompute the y-coord of all messages
  837. //------------------------------------------------------------------------
  838. if (changed) {
  839. Compute_Y();
  840. }
  841. return(changed);
  842. } // end of Manage
  843. /***************************************************************************
  844. * MessageListClass::Input -- Handles input for sending messages *
  845. * *
  846. * INPUT: *
  847. * input key value to process *
  848. * *
  849. * OUTPUT: *
  850. * 1 = caller should redraw the message list (no need to complete *
  851. * refresh, though) *
  852. * 2 = caller should completely refresh the display. *
  853. * 3 = caller should send the edit message. *
  854. * (sets 'input' to 0 if it processes it.) *
  855. * 4 = caller should send the Overflow buffer *
  856. * *
  857. * WARNINGS: *
  858. * none. *
  859. * *
  860. * HISTORY: *
  861. * 05/05/1995 BRR : Created. *
  862. *=========================================================================*/
  863. int MessageListClass::Input(KeyNumType &input)
  864. {
  865. KeyASCIIType ascii;
  866. int retcode = 0;
  867. int numchars;
  868. //------------------------------------------------------------------------
  869. // Do nothing if nothing to do.
  870. //------------------------------------------------------------------------
  871. if (input == KN_NONE) {
  872. return(0);
  873. }
  874. //------------------------------------------------------------------------
  875. // Leave mouse events alone.
  876. //------------------------------------------------------------------------
  877. if ( (input & (~KN_RLSE_BIT))==KN_LMOUSE ||
  878. (input & (~KN_RLSE_BIT))==KN_RMOUSE) {
  879. return(0);
  880. }
  881. //------------------------------------------------------------------------
  882. // If we're in 'edit mode', handle keys
  883. //------------------------------------------------------------------------
  884. if (IsEdit) {
  885. ascii = (KeyASCIIType)(Keyboard->To_ASCII(input) & 0x00ff);
  886. #ifdef WIN32
  887. /*
  888. ** Allow numeric keypad presses to map to ascii numbers
  889. */
  890. if ((input & WWKEY_VK_BIT) && ascii >='0' && ascii <= '9') {
  891. input = (KeyNumType)(input & ~WWKEY_VK_BIT);
  892. } else {
  893. /*
  894. ** Filter out all special keys except return, escape and backspace
  895. */
  896. if ((!(input & WWKEY_VK_BIT) && !(input & KN_BUTTON)
  897. && ascii >= ' ' && ascii <= 127)
  898. || (input & 0xff)== (KN_RETURN & 0xff)
  899. || (input & 0xff)== (KN_BACKSPACE & 0xff)
  900. || (input & 0xff)== (KN_ESC & 0xff) ) {
  901. //ascii = (KeyASCIIType)(Keyboard->To_ASCII(input));
  902. } else {
  903. input = KN_NONE;
  904. return (0);
  905. }
  906. }
  907. #endif //WIN32
  908. switch (ascii) {
  909. //..................................................................
  910. // ESC = abort message
  911. //..................................................................
  912. case KA_ESC & 0xff:
  913. Remove_Edit();
  914. retcode = 2;
  915. input = KN_NONE;
  916. break;
  917. //..................................................................
  918. // RETURN = send the message.
  919. // Add a space to the end, in case another message gets concatenated
  920. // onto this one after we send it; then, they won't be mushed
  921. // together.
  922. //..................................................................
  923. case KA_RETURN & 0xff:
  924. if (EditCurPos == EditInitPos) {
  925. retcode = 0;
  926. input = KN_NONE;
  927. break;
  928. }
  929. if ( (EditCurPos - EditInitPos) < (MaxChars - 1) ) {
  930. EditBuf[EditCurPos] = ' ';
  931. EditCurPos++;
  932. EditBuf[EditCurPos] = 0;
  933. }
  934. Remove_Edit();
  935. retcode = 3;
  936. input = KN_NONE;
  937. break;
  938. //..................................................................
  939. // BACKSPACE = remove a character
  940. //..................................................................
  941. case KA_BACKSPACE & 0xff:
  942. if (EditCurPos > EditInitPos) {
  943. EditCurPos--;
  944. EditBuf[EditCurPos] = 0;
  945. retcode = 2;
  946. }
  947. input = KN_NONE;
  948. EditLabel->Set_Focus();
  949. break;
  950. //..................................................................
  951. // default: add a character. Reserve the last buffer position for
  952. // null. (EditCurPos - EditInitPos) is the buffer index # of the
  953. // next character, after the "To:" prefix.
  954. //..................................................................
  955. default:
  956. EditLabel->Set_Focus();
  957. bool overflowed = false;
  958. if (ascii >= ' ' && ascii <= 127) {
  959. if ( (EditCurPos - EditInitPos) < (MaxChars - 1) ) {
  960. EditBuf[EditCurPos] = ascii;
  961. EditCurPos++;
  962. EditBuf[EditCurPos] = 0;
  963. retcode = 1;
  964. /*
  965. ** Verify that the additional character would not overrun the on screen edit box.
  966. */
  967. Fancy_Text_Print(TXT_NONE, 0, 0, EditLabel->Color, TBLACK, EditLabel->Style);
  968. int width = String_Pixel_Width(EditBuf);
  969. if (width >= Width-10) {
  970. overflowed = true;
  971. EditCurPos--;
  972. EditBuf[EditCurPos] = 0;
  973. retcode = 0;
  974. }
  975. } else {
  976. //............................................................
  977. // If there's no room in the buffer, and overflow is enabled,
  978. // trim the extra characters off (from right to left, to
  979. // remove the max possible characters), and then add the new
  980. // character in.
  981. //............................................................
  982. overflowed = true;
  983. }
  984. if (/*BGEnableOverflow &&*/ overflowed) {
  985. numchars = Trim_Message (OverflowBuf, EditBuf + EditInitPos,
  986. OverflowStart,OverflowEnd, 1);
  987. EditCurPos -= numchars;
  988. EditBuf[EditCurPos] = ascii;
  989. EditCurPos++;
  990. EditBuf[EditCurPos] = 0;
  991. retcode = 4;
  992. }
  993. }
  994. input = KN_NONE;
  995. break;
  996. }
  997. }
  998. return(retcode);
  999. } // end of Input
  1000. /***************************************************************************
  1001. * MessageListClass::Draw -- draws messages *
  1002. * *
  1003. * INPUT: *
  1004. * none *
  1005. * *
  1006. * OUTPUT: *
  1007. * none. *
  1008. * *
  1009. * WARNINGS: *
  1010. * none. *
  1011. * *
  1012. * HISTORY: *
  1013. * 05/22/1995 BRR : Created. *
  1014. *=========================================================================*/
  1015. void MessageListClass::Draw(void)
  1016. {
  1017. char txt[2] = {0,0};
  1018. if (IsEdit) {
  1019. if (LogicPage == &SeenBuff) {
  1020. Hide_Mouse();
  1021. }
  1022. EditLabel->Draw_Me(true);
  1023. if (CursorChar && (EditCurPos - EditInitPos) < (MaxChars - 1) && EditLabel->Has_Focus()) {
  1024. txt[0] = CursorChar;
  1025. Fancy_Text_Print(txt,
  1026. EditLabel->X + String_Pixel_Width(EditLabel->Text),
  1027. EditLabel->Y,
  1028. EditLabel->Color,
  1029. TBLACK,
  1030. EditLabel->Style);
  1031. }
  1032. if (LogicPage == &SeenBuff) {
  1033. Show_Mouse();
  1034. }
  1035. }
  1036. if (MessageList) {
  1037. if (LogicPage == &SeenBuff) {
  1038. Hide_Mouse();
  1039. }
  1040. MessageList->Draw_All();
  1041. if (LogicPage == &SeenBuff) {
  1042. Show_Mouse();
  1043. }
  1044. }
  1045. } // end of Draw
  1046. /***************************************************************************
  1047. * MessageListClass::Num_Messages -- returns # messages in the list *
  1048. * *
  1049. * INPUT: *
  1050. * none. *
  1051. * *
  1052. * OUTPUT: *
  1053. * # of messages, including the edit field if it's above the messages *
  1054. * *
  1055. * WARNINGS: *
  1056. * none. *
  1057. * *
  1058. * HISTORY: *
  1059. * 06/26/1995 BRR : Created. *
  1060. *=========================================================================*/
  1061. int MessageListClass::Num_Messages(void)
  1062. {
  1063. GadgetClass * gadg;
  1064. int num;
  1065. num = 0;
  1066. if (MessageList) {
  1067. gadg = MessageList;
  1068. while (gadg) {
  1069. num++;
  1070. gadg = gadg->Get_Next();
  1071. }
  1072. }
  1073. if (IsEdit && AdjustEdit) {
  1074. num++;
  1075. }
  1076. return (num);
  1077. } // end of Num_Messages
  1078. /***************************************************************************
  1079. * MessageListClass::Set_Width -- sets allowable width of messages *
  1080. * *
  1081. * INPUT: *
  1082. * width pixel width *
  1083. * *
  1084. * OUTPUT: *
  1085. * none. *
  1086. * *
  1087. * WARNINGS: *
  1088. * none. *
  1089. * *
  1090. * HISTORY: *
  1091. * 06/26/1995 BRR : Created. *
  1092. *=========================================================================*/
  1093. void MessageListClass::Set_Width(int width)
  1094. {
  1095. GadgetClass * gadg;
  1096. if (MessageList) {
  1097. gadg = MessageList;
  1098. while (gadg) {
  1099. ((TextLabelClass *)gadg)->PixWidth = width;
  1100. gadg = gadg->Get_Next();
  1101. }
  1102. }
  1103. if (IsEdit) {
  1104. EditLabel->PixWidth = width;
  1105. }
  1106. } // end of Set_Width
  1107. /***************************************************************************
  1108. * MessageListClass::Trim_Message -- trims chars off start of message *
  1109. * *
  1110. * INPUT: *
  1111. * dest buffer to store removed characters in; NULL = none *
  1112. * src text buffer to trim *
  1113. * min_chars min # chars that must be trimmed off *
  1114. * max_chars max # chars allowed to trim *
  1115. * scandir 0 = left-to-right, 1 = right-to-left *
  1116. * *
  1117. * OUTPUT: *
  1118. * # characters removed *
  1119. * *
  1120. * WARNINGS: *
  1121. * none. *
  1122. * *
  1123. * HISTORY: *
  1124. * 11/07/1995 BRR : Created. *
  1125. *=========================================================================*/
  1126. int MessageListClass::Trim_Message(char * dest, char * src, int min_chars,
  1127. int max_chars, int scandir)
  1128. {
  1129. int i;
  1130. int len;
  1131. int found;
  1132. //------------------------------------------------------------------------
  1133. // validate parameters
  1134. //------------------------------------------------------------------------
  1135. if (min_chars <= 0) {
  1136. return(0);
  1137. }
  1138. len = strlen (src);
  1139. if (max_chars > len) {
  1140. max_chars = len;
  1141. }
  1142. //------------------------------------------------------------------------
  1143. // find 1st available white space; if there is none, just trim off
  1144. // 'min_chars' characters. 'i' will be the number of chars to trim.
  1145. // The chars removed will include the white space.
  1146. //------------------------------------------------------------------------
  1147. found = 0;
  1148. //........................................................................
  1149. // scan from left to right
  1150. //........................................................................
  1151. if (scandir == 0) {
  1152. for (i = min_chars; i <= max_chars; i++) {
  1153. if (isspace(src[i - 1])) {
  1154. found = 1;
  1155. break;
  1156. }
  1157. }
  1158. }
  1159. //........................................................................
  1160. // scan from right to left
  1161. //........................................................................
  1162. else {
  1163. for (i = max_chars; i >= min_chars; i--) {
  1164. if (isspace(src[i - 1])) {
  1165. found = 1;
  1166. break;
  1167. }
  1168. }
  1169. }
  1170. //........................................................................
  1171. // If no whitespace was found, just set 'i' to the min # characters
  1172. //........................................................................
  1173. if (!found) {
  1174. i = min_chars;
  1175. }
  1176. //------------------------------------------------------------------------
  1177. // Save trimmed characters in the dest buffer, if there is one
  1178. //------------------------------------------------------------------------
  1179. if (dest) {
  1180. memcpy (dest, src, i);
  1181. dest[i] ='\0';
  1182. }
  1183. //------------------------------------------------------------------------
  1184. // Shift characters over in the source buffer
  1185. //------------------------------------------------------------------------
  1186. memmove (src, src + i, len - i + 1);
  1187. return (i);
  1188. } // end of Trim_Message
  1189. /***************************************************************************
  1190. * MessageListClass::Compute_Y -- recomputes y-coord for all messages *
  1191. * *
  1192. * INPUT: *
  1193. * none. *
  1194. * *
  1195. * OUTPUT: *
  1196. * none. *
  1197. * *
  1198. * WARNINGS: *
  1199. * none. *
  1200. * *
  1201. * HISTORY: *
  1202. * 11/07/1995 BRR : Created. *
  1203. *=========================================================================*/
  1204. void MessageListClass::Compute_Y(void)
  1205. {
  1206. GadgetClass * gadg;
  1207. int y;
  1208. //------------------------------------------------------------------------
  1209. // If the editable message is attached to the message list, 'AdjustEdit'
  1210. // will be set; so, adjust all y-values downward one line. Otherwise,
  1211. // the editable message has its own screen coordinates.
  1212. //------------------------------------------------------------------------
  1213. if (IsEdit && AdjustEdit) {
  1214. y = MessageY + Height;
  1215. }
  1216. else {
  1217. y = MessageY;
  1218. }
  1219. if (MessageList) {
  1220. gadg = MessageList;
  1221. while (gadg) {
  1222. gadg->Y = y;
  1223. gadg = gadg->Get_Next();
  1224. y += Height;
  1225. }
  1226. }
  1227. } // end of Compute_Y
  1228. /*************************** end of msglist.cpp ****************************/