MSGLIST.CPP 56 KB

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