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