2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/MissionUI/Chatbox.cpp $
15 * C module to handle all code for multiplayer chat windows
18 * Revision 1.5 2004/09/20 01:31:44 theoddone33
21 * Revision 1.4 2003/05/25 02:30:43 taylor
24 * Revision 1.3 2002/06/09 04:41:22 relnev
25 * added copyright header
27 * Revision 1.2 2002/05/07 03:16:46 theoddone33
28 * The Great Newline Fix
30 * Revision 1.1.1.1 2002/05/03 03:28:10 root
34 * 12 8/05/99 4:05p Jefff
35 * fixed pause chatbox display coords
37 * 11 7/29/99 10:47p Dave
38 * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
40 * 10 5/22/99 5:35p Dave
41 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
43 * 9 2/24/99 2:25p Dave
44 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
45 * bug for dogfight more.
47 * 8 2/23/99 8:11p Dave
48 * Tidied up dogfight mode. Fixed TvT ship type problems for alpha wing.
49 * Small pass over todolist items.
51 * 7 2/11/99 3:08p Dave
52 * PXO refresh button. Very preliminary squad war support.
54 * 6 2/01/99 5:55p Dave
55 * Removed the idea of explicit bitmaps for buttons. Fixed text
56 * highlighting for disabled gadgets.
58 * 5 1/29/99 2:08a Dave
59 * Fixed beam weapon collisions with players. Reduced size of scoring
60 * struct for multiplayer. Disabled PXO.
62 * 4 1/28/99 7:09p Neilk
63 * Modified chatbox to use new interface graphics (only 640)
65 * 3 10/13/98 9:28a Dave
66 * Started neatening up freespace.h. Many variables renamed and
67 * reorganized. Added AlphaColors.[h,cpp]
69 * 2 10/07/98 10:53a Dave
72 * 1 10/07/98 10:49a Dave
74 * 57 9/17/98 3:08p Dave
75 * PXO to non-pxo game warning popup. Player icon stuff in create and join
76 * game screens. Upped server count refresh time in PXO to 35 secs (from
79 * 56 9/11/98 5:08p Dave
80 * More tweaks to kick notification system.
82 * 55 9/11/98 4:14p Dave
83 * Fixed file checksumming of < file_size. Put in more verbose kicking and
84 * PXO stats store reporting.
86 * 54 6/09/98 5:15p Lawrance
87 * French/German localization
89 * 53 6/09/98 10:31a Hoffoss
90 * Created index numbers for all xstr() references. Any new xstr() stuff
91 * added from here on out should be added to the end if the list. The
92 * current list count can be found in FreeSpace.cpp (search for
95 * 52 6/01/98 11:43a John
96 * JAS & MK: Classified all strings for localization.
98 * 51 5/22/98 9:35p Dave
99 * Put in channel based support for PXO. Put in "shutdown" button for
100 * standalone. UI tweaks for TvT
102 * 50 5/17/98 6:32p Dave
103 * Make sure clients/servers aren't kicked out of the debriefing when team
104 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
105 * xfer/pilot info popup stuff.
107 * 49 5/17/98 1:43a Dave
108 * Eradicated chatbox problems. Remove speed match for observers. Put in
109 * help screens for PXO. Fix messaging and end mission privelges. Fixed
110 * team select screen bugs. Misc UI fixes.
112 * 48 5/15/98 9:52p Dave
113 * Added new stats for freespace. Put in artwork for viewing stats on PXO.
115 * 47 5/15/98 5:15p Dave
116 * Fix a standalone resetting bug.Tweaked PXO interface. Display captaincy
117 * status for team vs. team. Put in asserts to check for invalid team vs.
120 * 46 5/08/98 7:08p Dave
121 * Lots of UI tweaking.
123 * 45 5/07/98 6:26p Dave
124 * Fix strange boundary conditions which arise when players die/respawn
125 * while the game is being ended. Spiff up the chatbox doskey thing a bit.
127 * 44 5/04/98 10:39p Dave
128 * Put in endgame sequencing. Need to check campaign situations.
129 * Realigned ship info on team select screen.
131 * 43 5/02/98 5:38p Dave
132 * Put in new tracker API code. Put in ship information on mp team select
133 * screen. Make standalone server name permanent. Fixed standalone server
136 * 42 4/29/98 6:00p Dave
137 * Fixed chatbox font colors. Made observer offscreen indicators work.
138 * Numerous small UI fixes. Fix rank limitations for mp games.
140 * 41 4/25/98 3:14p Dave
141 * Fixed chatbox clipping problem.
143 * 40 4/16/98 6:34p Dave
144 * Fixed reversed team vs. team colors.
146 * 39 4/14/98 5:06p Dave
147 * Don't load or send invalid pilot pics. Fixed chatbox graphic errors.
148 * Made chatbox display team icons in a team vs. team game. Fixed up pause
149 * and endgame sequencing issues.
151 * 38 4/13/98 7:48p Dave
152 * Fixed chatbox overrun errors. Put in line recall function (4 deep).
154 * 37 4/12/98 2:09p Dave
155 * Make main hall door text less stupid. Make sure inputbox focus in the
156 * multi host options screen is managed more intelligently.
158 * 36 4/01/98 11:19p Dave
159 * Put in auto-loading of xferred pilot pic files. Grey out background
160 * behind pinfo popup. Put a chatbox message in when players are kicked.
161 * Moved mission title down in briefing. Other ui fixes.
163 * 35 3/31/98 4:42p Allender
164 * mission objective support for team v. team mode. Chatbox changes to
165 * make input box be correct length when typing
167 * 34 3/29/98 1:24p Dave
168 * Make chatbox not clear between multiplayer screens. Select player ship
169 * as default in mp team select and weapons select screens. Made create
170 * game mission list use 2 fixed size columns.
172 * 33 3/19/98 5:05p Dave
173 * Put in support for targeted multiplayer text and voice messaging (all,
174 * friendly, hostile, individual).
176 * 32 3/18/98 12:03p John
177 * Marked all the new strings as externalized or not.
179 * 31 3/17/98 12:30a Dave
180 * Put in hud support for rtvoice. Several ui interface changes.
182 * 30 3/10/98 10:59p Dave
183 * Fixed single player pause screen. Put in temporary fix for multiplayer
184 * version. Fixed several chatbox display and text string bugs.
186 * 29 2/27/98 9:41a Dave
187 * Made "up/down" arrows flip direction when toggling chatbox sizes.
189 * 28 2/26/98 4:21p Dave
190 * More robust multiplayer voice.
192 * 27 2/22/98 4:17p John
193 * More string externalization classification... 190 left to go!
195 * 26 2/22/98 12:19p John
196 * Externalized some strings
198 * 25 2/13/98 3:46p Dave
199 * Put in dynamic chatbox sizing. Made multiplayer file lookups use cfile
202 * 24 2/04/98 10:50p Allender
203 * zero out chat line before storing text
205 * 23 1/29/98 5:23p Dave
206 * Made ingame join handle bad packets gracefully.
208 * 22 1/23/98 5:43p Dave
209 * Finished bringing standalone up to speed. Coded in new host options
212 * 21 1/17/98 5:51p Dave
213 * Bug fixes for bugs generated by multiplayer testing.
215 * 20 1/16/98 5:23p Allender
216 * more chatbox changes
218 * 19 1/16/98 4:28p Allender
219 * automatically send line when close to end of chatbox.
221 * 18 1/16/98 2:34p Dave
222 * Made pause screen work properly (multiplayer). Changed how chat packets
225 * 17 1/15/98 6:12p Dave
226 * Fixed weapons loadout bugs with multiplayer respawning. Added
227 * multiplayer start screen. Fixed a few chatbox bugs.
229 * 16 1/15/98 5:10p Allender
230 * ton of interface changes. chatbox in multiplayer now behaves
231 * differently than before. It's always active in any screen that uses
232 * it. Only non-printatble characters will get passed back out from
235 * 15 1/12/98 5:17p Dave
236 * Put in a bunch of multiplayer sequencing code. Made weapon/ship select
237 * work through the standalone.
239 * 14 1/07/98 5:20p Dave
240 * Put in support for multiplayer campaigns with the new interface
243 * 13 1/05/98 5:06p Dave
244 * Fixed a chat packet bug. Fixed a few state save/restore bugs. Updated a
245 * few things for multiplayer server transfer.
247 * 12 12/29/97 3:15p Dave
248 * Put in auto-indenting for multiplayer chatbox. Tweaked some multiplayer
251 * 11 12/22/97 9:13p Allender
252 * fixed up a few minor issues with chatbox
254 * 10 12/19/97 7:08p Jasen
255 * Updated coords for new ChatBox (small)
257 * 9 12/18/97 8:59p Dave
258 * Finished putting in basic support for weapon select and ship select in
261 * 8 12/06/97 4:27p Dave
262 * Another load of interface and multiplayer bug fixes.
264 * 7 12/03/97 4:16p Hoffoss
265 * Changed sound stuff used in interface screens for interface purposes.
267 * 6 11/12/97 4:40p Dave
268 * Put in multiplayer campaign support parsing, loading and saving. Made
269 * command-line variables better named. Changed some things on the initial
270 * pilot select screen.
272 * 5 10/24/97 10:59p Hoffoss
273 * Added in create pilot popup window and barracks screen.
275 * 4 10/08/97 5:08p Lawrance
276 * use mask region for chat box inputbox, so getting focus is easier
278 * 3 10/01/97 4:47p Lawrance
279 * move some #defines out of header file into .cpp file
281 * 2 10/01/97 4:39p Lawrance
282 * move chat code into Chatbox.cpp, simplify interface
284 * 1 10/01/97 10:54a Lawrance
291 #include "freespace.h"
293 #include "missionscreencommon.h"
294 #include "multimsgs.h"
301 #include "multi_pmsg.h"
302 #include "alphacolors.h"
304 ///////////////////////////////////////////////////////////
306 ///////////////////////////////////////////////////////////
308 // a little extra spacing for the team vs. team icons
309 #define CHATBOX_TEAM_ICON_SPACE 18
311 // SMALL CHATBOX ----------------------------------------------------------------------------------
314 const char* Chatbox_small_bitmap_fname[GR_NUM_RESOLUTIONS] = {
316 "2_Chatbox" // GR_1024
320 const char* Chatbox_small_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
321 "Chatbox-m", // GR_640
322 "2_Chatbox-m" // GR_1024
326 int Chatbox_small_coords[GR_NUM_RESOLUTIONS][2] = {
339 // display area coods
340 int Chatbox_small_display_coords[GR_NUM_RESOLUTIONS][4] = {
343 214 + CHATBOX_TEAM_ICON_SPACE, 16, 380 - CHATBOX_TEAM_ICON_SPACE, 56
345 196 + CHATBOX_TEAM_ICON_SPACE, 13, 410 - CHATBOX_TEAM_ICON_SPACE, 74
349 315 + CHATBOX_TEAM_ICON_SPACE, 22, 654 - CHATBOX_TEAM_ICON_SPACE, 116
354 int Chatbox_small_input_coords[GR_NUM_RESOLUTIONS][4] = {
368 int Chatbox_small_max_lines[GR_NUM_RESOLUTIONS] = {
377 // BIG CHATBOX ----------------------------------------------------------------------------------
380 const char* Chatbox_big_bitmap_fname[GR_NUM_RESOLUTIONS] = {
381 "ChatboxBig", // GR_640
382 "2_ChatboxBig" // GR_1024
386 const char* Chatbox_big_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
387 "Chatbox-m", // GR_640
388 "2_Chatbox-m" // GR_1024
392 int Chatbox_big_coords[GR_NUM_RESOLUTIONS][2] = {
405 // display area coords
406 int Chatbox_big_display_coords[GR_NUM_RESOLUTIONS][4] = {
409 214 + CHATBOX_TEAM_ICON_SPACE, 16, 410 - CHATBOX_TEAM_ICON_SPACE, 326
411 196 + CHATBOX_TEAM_ICON_SPACE, 13, 410 - CHATBOX_TEAM_ICON_SPACE, 326
415 315 + CHATBOX_TEAM_ICON_SPACE, 22, 654 - CHATBOX_TEAM_ICON_SPACE, 519
420 int Chatbox_big_input_coords[GR_NUM_RESOLUTIONS][4] = {
434 int Chatbox_big_max_lines[GR_NUM_RESOLUTIONS] = {
443 // PAUSED CHATBOX ----------------------------------------------------------------------------------
446 const char* Chatbox_p_bitmap_fname[GR_NUM_RESOLUTIONS] = {
448 "2_MPPause" // GR_1024
452 const char* Chatbox_p_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
453 "MPPause-m", // GR_640
454 "2_MPPause-m" // GR_1024
458 int Chatbox_p_coords[GR_NUM_RESOLUTIONS][2] = {
467 // display area coords
468 int Chatbox_p_display_coords[GR_NUM_RESOLUTIONS][4] = {
470 103 + CHATBOX_TEAM_ICON_SPACE, 149, 380 - CHATBOX_TEAM_ICON_SPACE, 143
473 165 + CHATBOX_TEAM_ICON_SPACE, 244, 654 - CHATBOX_TEAM_ICON_SPACE, 263
478 int Chatbox_p_input_coords[GR_NUM_RESOLUTIONS][4] = {
488 int Chatbox_p_max_lines[GR_NUM_RESOLUTIONS] = {
493 // defines for location and other info of chat box MULTI_PAUSED
495 #define CHATBOX_MP_FNAME NOX("MPPause")
496 #define CHATBOX_MP_MASK NOX("MPPause-m")
497 #define CHATBOX_MP_X1 112
498 #define CHATBOX_MP_Y1 198
499 #define CHATBOX_MP_X2 477
500 #define CHATBOX_MP_Y2 308
501 #define CHATBOX_MP_ICON_X (CHATBOX_MP_X1)
502 #define CHATBOX_MP_W (CHATBOX_MP_X2 - CHATBOX_MP_X1 + 1)
503 #define CHATBOX_MP_H (CHATBOX_MP_Y2 - CHATBOX_MP_Y1 + 1)
504 #define CHATBOX_MP_BEGIN_X (CHATBOX_MP_X1 + 3 + CHATBOX_TEAM_ICON_SPACE)
505 #define CHATBOX_MP_BEGIN_Y CHATBOX_MP_Y1
506 #define CHATBOX_MP_DISP_W 365
507 #define CHATBOX_MP_MAX_LINES 11
508 #define CHATBOX_MP_INPUTBOX_X (CHATBOX_MP_X1 + 3)
509 #define CHATBOX_MP_INPUTBOX_W (CHATBOX_MP_W)
510 #define CHATBOX_MP_TEXTENTER_Y 329
513 // CHATBOX ----------------------------------------------------------------------------------
515 // the settings being used for this instance
516 char Chatbox_mask[50];
525 int Chatbox_max_lines;
526 int Chatbox_inputbox_x;
527 int Chatbox_inputbox_w;
528 int Chatbox_textenter_y;
529 int Chat_scroll_up_coord[2];
530 int Chat_scroll_down_coord[2];
532 // how many pixels to indent succesive lines of text from a given player
533 #define CHAT_LINE_INDENT 20
535 // what chars other than letters and number's we'll toss
536 #define CHATBOX_INVALID_CHARS NOX("~`") // this is primarily so that we don't interfere with the voice recording keys
538 // common defines and data
539 #define CHATBOX_STRING_LEN (CALLSIGN_LEN + CHATBOX_MAX_LEN + 32)
540 UI_WINDOW Chat_window;
541 UI_INPUTBOX Chat_inputbox;
542 UI_BUTTON Chat_enter_text;
545 #define CHATBOX_NUM_BUTTONS 3
546 #define CHATBOX_SCROLL_UP 0
547 #define CHATBOX_SCROLL_DOWN 1
548 #define CHATBOX_TOGGLE_SIZE 2 // used for both big and small
550 // coordinate indicies
551 #define CHATBOX_X_COORD 0
552 #define CHATBOX_Y_COORD 1
553 #define CHATBOX_W_COORD 2
554 #define CHATBOX_H_COORD 3
557 ui_button_info Chatbox_buttons[GR_NUM_RESOLUTIONS][CHATBOX_NUM_BUTTONS+1] = {
560 ui_button_info("CHB_00b", 616, 8, -1, -1, 0),
561 ui_button_info("CHB_01b", 616, 47, -1, -1, 1),
562 ui_button_info("CHB_02a", 595, 69, -1, -1, 2),
563 ui_button_info("CHB_02b", 595, 69, -1, -1, 2),
565 ui_button_info("CHB_00", 613, 3, -1, -1, 0),
566 ui_button_info("CHB_01", 613, 41, -1, -1, 1),
567 ui_button_info("CHB_02a", 607, 74, -1, -1, 2),
568 ui_button_info("CHB_02b", 607, 74, -1, -1, 2),
572 ui_button_info("2_CHB_00", 981, 5, -1, -1, 0),
573 ui_button_info("2_CHB_01", 981, 67, -1, -1, 1),
574 ui_button_info("2_CHB_02a", 971, 119, -1, -1, 2),
575 ui_button_info("2_CHB_02b", 971, 119, -1, -1, 2),
579 int Chatbox_mode_flags = 0;
581 int Chatbox_bitmap = -1;
582 int Chatbox_big_bitmap = -1;
583 int Chatbox_small_bitmap = -1;
584 int Chatbox_mp_bitmap = -1;
585 int Chatbox_created = 0;
587 ///////////////////////////////////////////////////////////
589 ///////////////////////////////////////////////////////////
590 #define MAX_BRIEF_CHAT_LINES 60 // how many lines we can store in the scrollback buffer
591 #define BRIEF_DISPLAY_SPACING 2 // pixel spacing between chat lines
593 // the first byte of the text string will be the net player id of the
594 char Brief_chat_lines[MAX_BRIEF_CHAT_LINES][CHATBOX_STRING_LEN];
595 int Brief_chat_indents[MAX_BRIEF_CHAT_LINES];
597 int Brief_chat_next_index[MAX_BRIEF_CHAT_LINES];
598 int Brief_chat_prev_index[MAX_BRIEF_CHAT_LINES];
599 int Num_brief_chat_lines;
600 int Brief_current_add_line;
601 int Brief_start_display_index;
603 // chatbox line recall data
604 #define CHATBOX_MAX_RECALL_LINES 10
605 int Chatbox_recall_count = 0;
606 int Chatbox_recall_index = 0;
607 int Chatbox_recall_last = -1;
608 char Chatbox_recall_lines[CHATBOX_MAX_RECALL_LINES][CHATBOX_MAX_LEN+2];
610 ///////////////////////////////////////////////////////////
611 // forward declarations
612 ///////////////////////////////////////////////////////////
613 void chatbox_chat_init();
614 void chatbox_render_chat_lines();
615 void chatbox_set_mode(int mode_flags);
616 void chatbox_toggle_size();
617 void chatbox_toggle_size_adjust_lines();
618 void chat_autosplit_line(char *msg,char *remainder);
619 int chatbox_num_displayed_lines();
620 void chatbox_recall_add(char *string);
621 void chatbox_recall_up();
622 void chatbox_recall_down();
624 // set the chatbox mode without checking for any previous modes which may need to be handled specially
625 void chatbox_set_mode(int mode_flags)
629 // set the stored mode
630 Chatbox_mode_flags = mode_flags;
632 // small pregame chatbox
633 if(Chatbox_mode_flags & CHATBOX_FLAG_SMALL){
636 // big pregame chatbox
637 else if(Chatbox_mode_flags & CHATBOX_FLAG_BIG){
640 // multiplayer paused
645 // set up the display/init variables based upon what mode we chode
648 strcpy(Chatbox_mask, Chatbox_small_bitmap_mask_fname[gr_screen.res]);
649 Chatbox_x1 = Chatbox_small_coords[gr_screen.res][CHATBOX_X_COORD];
650 Chatbox_y1 = Chatbox_small_coords[gr_screen.res][CHATBOX_Y_COORD];
651 Chatbox_icon_x = Chatbox_small_display_coords[gr_screen.res][CHATBOX_X_COORD] - CHATBOX_TEAM_ICON_SPACE;
652 Chatbox_w = Chatbox_small_display_coords[gr_screen.res][CHATBOX_W_COORD];
653 Chatbox_h = Chatbox_small_display_coords[gr_screen.res][CHATBOX_H_COORD];
654 Chatbox_begin_x = Chatbox_small_display_coords[gr_screen.res][CHATBOX_X_COORD];
655 Chatbox_begin_y = Chatbox_small_display_coords[gr_screen.res][CHATBOX_Y_COORD];
656 Chatbox_disp_w = Chatbox_small_display_coords[gr_screen.res][CHATBOX_W_COORD];
657 Chatbox_max_lines = Chatbox_small_max_lines[gr_screen.res];
658 Chatbox_inputbox_x = Chatbox_small_input_coords[gr_screen.res][CHATBOX_X_COORD];
659 Chatbox_inputbox_w = Chatbox_small_input_coords[gr_screen.res][CHATBOX_W_COORD];
660 Chatbox_textenter_y = Chatbox_small_input_coords[gr_screen.res][CHATBOX_Y_COORD];
664 strcpy(Chatbox_mask, Chatbox_big_bitmap_mask_fname[gr_screen.res]);
665 Chatbox_x1 = Chatbox_big_coords[gr_screen.res][CHATBOX_X_COORD];
666 Chatbox_y1 = Chatbox_big_coords[gr_screen.res][CHATBOX_Y_COORD];
667 Chatbox_icon_x = Chatbox_big_display_coords[gr_screen.res][CHATBOX_X_COORD] - CHATBOX_TEAM_ICON_SPACE;
668 Chatbox_w = Chatbox_big_display_coords[gr_screen.res][CHATBOX_W_COORD];
669 Chatbox_h = Chatbox_big_display_coords[gr_screen.res][CHATBOX_H_COORD];
670 Chatbox_begin_x = Chatbox_big_display_coords[gr_screen.res][CHATBOX_X_COORD];
671 Chatbox_begin_y = Chatbox_big_display_coords[gr_screen.res][CHATBOX_Y_COORD];
672 Chatbox_disp_w = Chatbox_big_display_coords[gr_screen.res][CHATBOX_W_COORD];
673 Chatbox_max_lines = Chatbox_big_max_lines[gr_screen.res];
674 Chatbox_inputbox_x = Chatbox_big_input_coords[gr_screen.res][CHATBOX_X_COORD];
675 Chatbox_inputbox_w = Chatbox_big_input_coords[gr_screen.res][CHATBOX_W_COORD];
676 Chatbox_textenter_y = Chatbox_big_input_coords[gr_screen.res][CHATBOX_Y_COORD];
680 Chatbox_x1 = Chatbox_p_coords[gr_screen.res][CHATBOX_X_COORD];
681 Chatbox_y1 = Chatbox_p_coords[gr_screen.res][CHATBOX_Y_COORD];
682 Chatbox_icon_x = Chatbox_p_display_coords[gr_screen.res][CHATBOX_X_COORD] - CHATBOX_TEAM_ICON_SPACE;
683 Chatbox_w = Chatbox_p_display_coords[gr_screen.res][CHATBOX_W_COORD];
684 Chatbox_h = Chatbox_p_display_coords[gr_screen.res][CHATBOX_H_COORD];
685 Chatbox_begin_x = Chatbox_p_display_coords[gr_screen.res][CHATBOX_X_COORD];
686 Chatbox_begin_y = Chatbox_p_display_coords[gr_screen.res][CHATBOX_Y_COORD];
687 Chatbox_disp_w = Chatbox_p_display_coords[gr_screen.res][CHATBOX_W_COORD];
688 Chatbox_max_lines = Chatbox_p_max_lines[gr_screen.res];
689 Chatbox_inputbox_x = Chatbox_p_input_coords[gr_screen.res][CHATBOX_X_COORD];
690 Chatbox_inputbox_w = Chatbox_p_input_coords[gr_screen.res][CHATBOX_W_COORD];
691 Chatbox_textenter_y = Chatbox_p_input_coords[gr_screen.res][CHATBOX_Y_COORD];
696 // automatically split up any input text, send it, and leave the remainder
697 void chatbox_autosplit_line()
699 char *remainder = NULL, msg[150];
702 // if the chat line is getting too long, fire off the message, putting the last
703 // word on the next input line.
705 Chat_inputbox.get_text(msg);
707 // determine if the width of the string in pixels is > than the inputbox width -- if so,
708 // then send the message
709 gr_get_string_size(&msg_pixel_width, NULL, msg);
710 // if ( msg_pixel_width >= (Chatbox_inputbox_w - Player->short_callsign_width) ) {
711 if ( msg_pixel_width >= (Chatbox_inputbox_w - 25)) {
712 remainder = strrchr(msg, ' ');
718 // if I'm the server, then broadcast the packet
719 chatbox_recall_add(msg);
720 send_game_chat_packet(Net_player, msg, MULTI_MSG_ALL,NULL);
721 chatbox_add_line(msg, MY_NET_PLAYER_NUM);
724 // display any remainder of text on the next line
725 Chat_inputbox.set_text(remainder);
727 } else if((Chat_inputbox.pressed() && (strlen(msg) > 0)) || (strlen(msg) >= CHATBOX_MAX_LEN)) {
728 // tack on the null terminator in the boundary case
730 if(x >= CHATBOX_MAX_LEN){
731 msg[CHATBOX_MAX_LEN-1] = '\0';
733 // if I'm the server, then broadcast the packet
734 chatbox_recall_add(msg);
735 send_game_chat_packet(Net_player, msg, MULTI_MSG_ALL,NULL);
736 chatbox_add_line(msg, MY_NET_PLAYER_NUM);
740 // initialize all chatbox details with the given mode flags
741 int chatbox_create(int mode_flags)
745 // don't do anything if the chatbox is already initialized
746 if (Chatbox_created){
750 // probably shouldn't be using the chatbox in single player mode
751 SDL_assert(Game_mode & GM_MULTIPLAYER);
753 // setup all data to correspond to our mode flags
754 chatbox_set_mode(mode_flags);
756 // initialize all low-level details related to chatting
759 // attempt to load in the chatbox background bitmap
760 if(Chatbox_mode_flags & CHATBOX_FLAG_DRAW_BOX){
761 Chatbox_big_bitmap = bm_load(Chatbox_big_bitmap_fname[gr_screen.res]);
762 Chatbox_small_bitmap = bm_load(Chatbox_small_bitmap_fname[gr_screen.res]);
763 Chatbox_mp_bitmap = bm_load(Chatbox_p_bitmap_fname[gr_screen.res]);
765 if(Chatbox_mode_flags & CHATBOX_FLAG_SMALL){
766 Chatbox_bitmap = Chatbox_small_bitmap;
767 } else if(Chatbox_mode_flags & CHATBOX_FLAG_BIG){
768 Chatbox_bitmap = Chatbox_big_bitmap;
770 Chatbox_bitmap = Chatbox_mp_bitmap;
773 if((Chatbox_bitmap == -1) || (Chatbox_small_bitmap == -1) || (Chatbox_big_bitmap == -1) || (Chatbox_mp_bitmap == -1)){
778 // attempt to create the ui window for the chatbox and assign the mask
779 Chat_window.create( 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );
780 Chat_window.set_mask_bmap(Chatbox_mask);
782 // create the chat text enter input area
783 Chat_inputbox.create( &Chat_window, Chatbox_inputbox_x, Chatbox_textenter_y, Chatbox_inputbox_w, CHATBOX_MAX_LEN, "", UI_INPUTBOX_FLAG_INVIS | UI_INPUTBOX_FLAG_ESC_CLR | UI_INPUTBOX_FLAG_KEYTHRU | UI_INPUTBOX_FLAG_EAT_USED, Chatbox_w, Color_netplayer[MY_NET_PLAYER_NUM]);
784 Chat_inputbox.set_focus();
785 Chat_inputbox.set_invalid_chars(CHATBOX_INVALID_CHARS);
787 // if we're supposed to supply and check for out own buttons
788 if((Chatbox_mode_flags & CHATBOX_FLAG_BUTTONS) && (Chatbox_mode_flags & CHATBOX_FLAG_DRAW_BOX)){
789 for(idx=0; idx<CHATBOX_NUM_BUTTONS; idx++){
791 Chatbox_buttons[gr_screen.res][idx].button.create(&Chat_window, "", Chatbox_buttons[gr_screen.res][idx].x, Chatbox_buttons[gr_screen.res][idx].y, 60, 30, (idx == CHATBOX_TOGGLE_SIZE) ? 0 : 1);
793 // set the highlight action
794 Chatbox_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
797 Chatbox_buttons[gr_screen.res][idx].button.set_bmaps(Chatbox_buttons[gr_screen.res][idx].filename);
800 Chatbox_buttons[gr_screen.res][idx].button.link_hotspot(Chatbox_buttons[gr_screen.res][idx].hotspot);
803 // now create the toggle size button with the appropriate button
804 if(Chatbox_mode_flags & CHATBOX_FLAG_SMALL){
805 Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].button.set_bmaps(Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].filename);
807 Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].button.set_bmaps(Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE+1].filename);
811 // an invisible button that will set focus to input box when clicked on
812 Chat_enter_text.create( &Chat_window, "", 0, 0, 60, 30, 0);
813 Chat_enter_text.hide(); // button doesn't show up
814 Chat_enter_text.link_hotspot(50);
820 // process this frame for the chatbox
821 int chatbox_process(int key_in)
827 // if the chatbox hasn't explicitly been created, we can't do any processing
828 if(!Chatbox_created){
832 // process the incoming key appropriately
834 key_out = Chat_window.process();
836 key_out = Chat_window.process(key_in);
839 // look for special keypresses
841 // line recall up one
847 // line recall down one
849 chatbox_recall_down();
854 // if we're supposed to be checking our own scroll buttons
855 if((Chatbox_mode_flags & CHATBOX_FLAG_BUTTONS) && (Chatbox_mode_flags & CHATBOX_FLAG_DRAW_BOX)){
856 if ( Chatbox_buttons[gr_screen.res][CHATBOX_SCROLL_UP].button.pressed() ) {
860 if ( Chatbox_buttons[gr_screen.res][CHATBOX_SCROLL_DOWN].button.pressed() ) {
861 chatbox_scroll_down();
864 if ( Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].button.pressed() ){
865 chatbox_toggle_size();
869 // check to see if the enter text button has been pressed
870 if ( Chat_enter_text.pressed() ) {
871 Chat_inputbox.set_focus();
874 // check to see if the current input text needs to be split up and sent automaticall
875 chatbox_autosplit_line();
882 // destory the UI window
883 Chat_window.destroy();
885 // unload any bitmaps
886 if(Chatbox_small_bitmap != -1){
887 bm_unload(Chatbox_small_bitmap);
889 if(Chatbox_big_bitmap != -1){
890 bm_unload(Chatbox_big_bitmap);
892 if(Chatbox_mp_bitmap != -1){
893 bm_unload(Chatbox_mp_bitmap);
896 // clear all the text lines in the
901 // shutdown all chatbox functionality
904 // only do this if we have valid data
906 // clear all chat data
907 memset(Brief_chat_lines,0,(MAX_BRIEF_CHAT_LINES * (CHATBOX_MAX_LEN + 2)));
908 Brief_start_display_index=0;
909 Num_brief_chat_lines=0;
910 Brief_current_add_line=0;
912 // clear all line recall data
913 Chatbox_recall_count = 0;
914 Chatbox_recall_index = 0;
915 Chatbox_recall_last = -1;
916 memset(Chatbox_recall_lines,0,CHATBOX_MAX_RECALL_LINES * (CHATBOX_MAX_LEN + 2));
920 // render the chatbox for this frame
921 void chatbox_render()
923 if (!Chatbox_created){
927 // clear the multiplayer chat window
928 // gr_set_clip(Chatbox_x1, Chatbox_y1, Chatbox_w, Chatbox_h);
932 // draw the background bitmap if we're supposed to
933 if ( (Chatbox_bitmap != -1) && (Chatbox_mode_flags & CHATBOX_FLAG_DRAW_BOX)) {
934 gr_set_bitmap( Chatbox_bitmap , GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
935 gr_bitmap(Chatbox_x1, Chatbox_y1);
938 // render the chat lines
939 chatbox_render_chat_lines();
941 // render any UI window stuff
945 // try and scroll the chatbox up. return 0 or 1 on fail or success
946 int chatbox_scroll_up()
948 if(Num_brief_chat_lines > Chatbox_max_lines){
949 int prev = Brief_chat_prev_index[Brief_start_display_index];
951 // check to make sure we won't be going "up" above the "beginning" of the text array
952 if(Brief_chat_prev_index[Brief_current_add_line] != prev && !(Num_brief_chat_lines < MAX_BRIEF_CHAT_LINES && Brief_start_display_index==0)){
953 Brief_start_display_index = prev;
961 // try and scroll the chatbox down, return 0 or 1 on fail or success
962 int chatbox_scroll_down()
967 if(Num_brief_chat_lines > Chatbox_max_lines){
968 // yuck. There's got to be a better way to do this.
969 next = Brief_chat_next_index[Brief_start_display_index];
970 for(idx = 1;idx <= Chatbox_max_lines; idx++){
971 next = Brief_chat_next_index[next];
974 // check to make sure we won't be going "down" below the "bottom" of the text array
975 if(Brief_chat_next_index[Brief_current_add_line] != next){
976 Brief_start_display_index = Brief_chat_next_index[Brief_start_display_index];
983 // quick explanation as to how the scrolling works :
984 // Brief_chat_next_index is an array A of size n, where A[i] = i+1 and A[n] = 0
985 // Brief_chat_prev_index is an array A of size n, where A[i] = i-1 and A[0] = n
986 // in other words, if you increment an integer i = A[i], you get the next index (or the prev)
987 // with wrapping. In this way, as chat lines are entered, they are continuously wrapped
988 // around the Brief_chat_lines array so we can keep it at a fixed size. These arrays are used
989 // for both entering new chat strings as well as moving the Brief_start_display_index
990 // integer, which is self-explanatory
992 void chatbox_chat_init()
998 // setup the wraparound arrays
999 for(idx=0;idx<MAX_BRIEF_CHAT_LINES;idx++){
1000 Brief_chat_next_index[idx] = idx+1;
1002 Brief_chat_next_index[MAX_BRIEF_CHAT_LINES-1]=0;
1004 for(idx=MAX_BRIEF_CHAT_LINES-1; idx > 0 ; idx--){
1005 Brief_chat_prev_index[idx] = idx - 1;
1007 Brief_chat_prev_index[0] = MAX_BRIEF_CHAT_LINES-1;
1009 // initialize the line recall data
1010 Chatbox_recall_count = 0;
1011 Chatbox_recall_index = 0;
1012 Chatbox_recall_last = -1;
1013 memset(Chatbox_recall_lines,0,CHATBOX_MAX_RECALL_LINES * (CHATBOX_MAX_LEN + 2));
1016 // int Test_color = 0;
1017 void chatbox_add_line(const char *msg, int pid, int add_id)
1022 char *p_str[3]; // for the initial line (unindented)
1023 char msg_extra[CHATBOX_STRING_LEN];
1025 if(!Chatbox_created){
1029 // maybe stick on who sent the message
1031 if(MULTI_STANDALONE(Net_players[pid])){
1032 sprintf(msg_extra, NOX("%s %s"), NOX("<SERVER>"), msg );
1034 sprintf(msg_extra, NOX("%s: %s"), Net_players[pid].player->short_callsign, msg );
1037 strcpy(msg_extra,msg);
1039 SDL_assert(strlen(msg_extra) < (CHATBOX_STRING_LEN - 2));
1041 // split the text up into as many lines as necessary
1042 n_lines = split_str(msg_extra, Chatbox_disp_w, n_chars, p_str, 3);
1043 SDL_assert(n_lines != -1);
1045 // setup the first line -- be sure to clear out the line
1046 memset( Brief_chat_lines[Brief_current_add_line], 0, CHATBOX_STRING_LEN );
1048 // add the player id #
1049 Brief_chat_lines[Brief_current_add_line][0] = (char)(pid % 16);
1050 // Brief_chat_lines[Brief_current_add_line][0] = (char)Test_color;
1051 // Test_color = (Test_color == MAX_PLAYERS - 1) ? 0 : Test_color++;
1053 // set the indent to 0
1054 Brief_chat_indents[Brief_current_add_line] = 0;
1056 // copy in the chars
1057 strncpy(&Brief_chat_lines[Brief_current_add_line][1],p_str[0],CHATBOX_STRING_LEN - 1);
1058 if(n_chars[0] >= CHATBOX_STRING_LEN){
1059 Brief_chat_lines[Brief_current_add_line][CHATBOX_STRING_LEN - 1] = '\0';
1061 Brief_chat_lines[Brief_current_add_line][n_chars[0] + 1] = '\0';
1064 // increment the total line count if we haven't reached the max already
1065 if(Num_brief_chat_lines<MAX_BRIEF_CHAT_LINES){
1066 Num_brief_chat_lines++;
1069 // get the index of the next string to add text to
1070 Brief_current_add_line = Brief_chat_next_index[Brief_current_add_line];
1072 // if we have more than 1 line, re-split everything so that the rest are indented
1074 // split up the string after the first break-marker
1075 n_lines = split_str(msg_extra + n_chars[0],Chatbox_disp_w - CHAT_LINE_INDENT,n_chars,p_str,3);
1076 SDL_assert(n_lines != -1);
1078 // setup these remaining lines
1079 for(idx=0;idx<n_lines;idx++){
1080 // add the player id#
1081 Brief_chat_lines[Brief_current_add_line][0] = (char)(pid % 16);
1083 // add the proper indent
1084 Brief_chat_indents[Brief_current_add_line] = CHAT_LINE_INDENT;
1086 // copy in the line text itself
1087 strncpy(&Brief_chat_lines[Brief_current_add_line][1],p_str[idx],CHATBOX_STRING_LEN-1);
1088 if(n_chars[idx] >= CHATBOX_STRING_LEN){
1089 Brief_chat_lines[Brief_current_add_line][CHATBOX_STRING_LEN - 1] = '\0';
1091 Brief_chat_lines[Brief_current_add_line][n_chars[idx] + 1] = '\0';
1094 // increment the total line count if we haven't reached the max already
1095 if(Num_brief_chat_lines<MAX_BRIEF_CHAT_LINES){
1096 Num_brief_chat_lines++;
1099 // get the index of the next line to add text to
1100 Brief_current_add_line = Brief_chat_next_index[Brief_current_add_line];
1104 // COMMAND LINE OPTION
1105 if(Cmdline_multi_stream_chat_to_file && Multi_chat_stream!=NULL && strlen(msg)>0){ // stream to the file if we're supposed to
1106 cfwrite_string(msg,Multi_chat_stream);
1107 cfwrite_char('\n',Multi_chat_stream);
1110 // if this line of text is from the player himself, automatically go to the bottom of
1112 if(pid == MY_NET_PLAYER_NUM){
1113 if(Num_brief_chat_lines > Chatbox_max_lines){
1114 Brief_start_display_index = Brief_current_add_line;
1115 for(backup = 1;backup <= Chatbox_max_lines;backup++){
1116 Brief_start_display_index = Brief_chat_prev_index[Brief_start_display_index];
1120 // if we have enough lines of text to require scrolling, scroll down by one.
1122 chatbox_scroll_down();
1126 void chatbox_render_chat_lines()
1128 int started_at,player_num,count,ly;
1130 started_at = Brief_start_display_index;
1132 ly = Chatbox_begin_y;
1133 while((count < Chatbox_max_lines) && (count < Num_brief_chat_lines)){
1134 // determine what player this chat line came from, and set the appropriate text color
1135 player_num = Brief_chat_lines[started_at][0];
1137 // print the line out
1138 gr_set_color_fast(Color_netplayer[player_num]);
1140 // draw the first line (no indent)
1141 gr_string(Chatbox_begin_x + Brief_chat_indents[started_at],ly,&Brief_chat_lines[started_at][1]);
1143 // if we're in a team vs. team game, blit the player color icon
1144 if(Netgame.type_flags & NG_TYPE_TEAM){
1145 switch(Net_players[player_num].p_info.team){
1147 // if he's a team captain
1148 if(Net_players[player_num].flags & NETINFO_FLAG_TEAM_CAPTAIN){
1149 if(Multi_common_icons[MICON_TEAM0_SELECT] != -1){
1150 gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1151 gr_bitmap(Chatbox_icon_x,ly-2);
1154 // just you're average peon
1156 if(Multi_common_icons[MICON_TEAM0] != -1){
1157 gr_set_bitmap(Multi_common_icons[MICON_TEAM0], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1158 gr_bitmap(Chatbox_icon_x,ly-2);
1163 // if he's a team captain
1164 if(Net_players[player_num].flags & NETINFO_FLAG_TEAM_CAPTAIN){
1165 if(Multi_common_icons[MICON_TEAM1_SELECT] != -1){
1166 gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1167 gr_bitmap(Chatbox_icon_x,ly-2);
1170 // just your average peon
1172 if(Multi_common_icons[MICON_TEAM1] != -1){
1173 gr_set_bitmap(Multi_common_icons[MICON_TEAM1], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1174 gr_bitmap(Chatbox_icon_x,ly-2);
1181 // increment the count and line position
1185 // increment the started at index
1186 started_at = Brief_chat_next_index[started_at];
1190 void chatbox_toggle_size()
1192 // if we're in "small" mode
1193 if(Chatbox_mode_flags & CHATBOX_FLAG_SMALL){
1194 chatbox_force_big();
1197 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1199 // if we're in "big" mode
1200 else if(Chatbox_mode_flags & CHATBOX_FLAG_BIG){
1201 chatbox_force_small();
1204 gamesnd_play_iface(SND_IFACE_MOUSE_CLICK);
1208 void chatbox_toggle_size_adjust_lines()
1212 // if the chatbox is now big, move the starting display index _up_ as far as possible
1213 if(Chatbox_mode_flags & CHATBOX_FLAG_BIG){
1214 // if we've wrapped around or we have more chatlines then we can display, move back as far as we can
1215 if((Num_brief_chat_lines > MAX_BRIEF_CHAT_LINES) || (Num_brief_chat_lines > Chatbox_max_lines)){
1216 count_diff = Chatbox_max_lines - chatbox_num_displayed_lines();
1217 while(count_diff > 0){
1218 Brief_start_display_index = Brief_chat_prev_index[Brief_start_display_index];
1222 // otherwise start displaying from position 0
1224 Brief_start_display_index = 0;
1227 // if the chatbox is now small, move the starting display index down as far as we need
1228 else if(Chatbox_mode_flags & CHATBOX_FLAG_SMALL){
1229 count_diff = chatbox_num_displayed_lines();
1230 // if we were displaying more lines than we can now
1231 if(count_diff > Chatbox_max_lines){
1232 count_diff -= Chatbox_max_lines;
1233 while(count_diff > 0){
1234 Brief_start_display_index = Brief_chat_next_index[Brief_start_display_index];
1241 int chatbox_num_displayed_lines()
1243 int idx = Brief_start_display_index;
1246 // count the lines up
1248 while(idx != Brief_current_add_line){
1249 idx = Brief_chat_next_index[idx];
1256 // force the chatbox to go into small mode (if its in large mode) - will not wotk if in multi paused chatbox mode
1257 void chatbox_force_small()
1261 // don't do anything unless we're currently in "big" mode
1262 if(!(Chatbox_mode_flags & CHATBOX_FLAG_BIG)){
1266 new_mode_flags = Chatbox_mode_flags;
1268 // switch to the appropriate mode
1269 new_mode_flags &= ~(CHATBOX_FLAG_SMALL | CHATBOX_FLAG_BIG);
1270 new_mode_flags |= CHATBOX_FLAG_SMALL;
1271 Chatbox_bitmap = Chatbox_small_bitmap;
1273 // flip the up/down arrow
1274 Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].button.set_bmaps(Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].filename);
1276 // call this to set everything up correctly
1277 chatbox_set_mode(new_mode_flags);
1279 // change the location of the input box
1280 Chat_inputbox.update_dimensions(Chatbox_inputbox_x, Chatbox_textenter_y, Chatbox_inputbox_w,15);
1281 Chat_inputbox.set_focus();
1283 // adjust what line we start displaying from based upon the new size of the window
1284 chatbox_toggle_size_adjust_lines();
1287 // force the chatbox to go into big mode (if its in small mode) - will not work if in multi paused chatbox mode
1288 void chatbox_force_big()
1292 // don't do anything unless we're currently in "small" mode
1293 if(!(Chatbox_mode_flags & CHATBOX_FLAG_SMALL)){
1297 new_mode_flags = Chatbox_mode_flags;
1299 // switch to the appropriate mode
1300 new_mode_flags &= ~(CHATBOX_FLAG_SMALL | CHATBOX_FLAG_BIG);
1301 new_mode_flags |= CHATBOX_FLAG_BIG;
1302 Chatbox_bitmap = Chatbox_big_bitmap;
1304 // flip the up/down arrow
1305 Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].button.set_bmaps(Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE+1].filename);
1307 // call this to set everything up correctly
1308 chatbox_set_mode(new_mode_flags);
1310 // change the location of the input box
1311 Chat_inputbox.update_dimensions(Chatbox_inputbox_x, Chatbox_textenter_y, Chatbox_inputbox_w,15);
1312 Chat_inputbox.set_focus();
1314 // adjust what line we start displaying from based upon the new size of the window
1315 chatbox_toggle_size_adjust_lines();
1318 // "lose" the focus on the chatbox inputbox
1319 void chatbox_lose_focus()
1321 if(!Chatbox_created){
1325 // clear the focus on the inputbox
1326 Chat_inputbox.clear_focus();
1329 // return if the inputbox for the chatbox currently has focus
1330 int chatbox_has_focus()
1332 return Chat_inputbox.has_focus();
1335 // grab the focus for the chatbox inputbox
1336 void chatbox_set_focus()
1338 Chat_inputbox.set_focus();
1341 // return if the inputbox was pressed - "clicked on"
1342 int chatbox_pressed()
1344 return Chat_inputbox.pressed();
1347 // add the string to the line recall list
1348 void chatbox_recall_add(char *string)
1352 // aleays reset the recall index when adding
1353 Chatbox_recall_index = 0;
1354 Chatbox_recall_last = -1;
1356 // if this string matches the last string we entered, don't add it again
1357 if(!strcmp(string,Chatbox_recall_lines[0])){
1361 // move all items up (this works fine for small #'s of recall lines
1362 for(idx=CHATBOX_MAX_RECALL_LINES-1;idx > 0;idx--){
1363 memcpy(&Chatbox_recall_lines[idx],&Chatbox_recall_lines[idx-1],CHATBOX_MAX_LEN+2);
1366 // copy the new item into spot 0
1367 strcpy(Chatbox_recall_lines[0],string);
1369 // increment the recall count if necessary
1370 if(Chatbox_recall_count < CHATBOX_MAX_RECALL_LINES){
1371 Chatbox_recall_count++;
1375 // user has pressed the "up" key
1376 void chatbox_recall_up()
1378 // if we've got no recall lines, do nothing
1379 if(Chatbox_recall_count <= 0){
1383 // if we can increment up
1384 if(Chatbox_recall_index < (Chatbox_recall_count - 1)){
1385 // if this is the last line we recalled, pre-increment
1386 if(Chatbox_recall_last == Chatbox_recall_index){
1387 Chat_inputbox.set_text(Chatbox_recall_lines[++Chatbox_recall_index]);
1388 Chatbox_recall_last = Chatbox_recall_index;
1390 // otherwise, post increment
1392 Chat_inputbox.set_text(Chatbox_recall_lines[Chatbox_recall_index++]);
1393 Chatbox_recall_last = Chatbox_recall_index - 1;
1396 // if we can't increment up
1398 Chat_inputbox.set_text(Chatbox_recall_lines[Chatbox_recall_index]);
1399 Chatbox_recall_last = Chatbox_recall_index;
1403 // user has pressed the "down" key
1404 void chatbox_recall_down()
1406 // if we've got no recall lines, do nothing
1407 if(Chatbox_recall_count <= 0){
1411 // if we can decrement down
1412 if(Chatbox_recall_index > 0){
1413 // if this is the last line we recalled, pre-decrement
1414 if(Chatbox_recall_last == Chatbox_recall_index){
1415 Chat_inputbox.set_text(Chatbox_recall_lines[--Chatbox_recall_index]);
1416 Chatbox_recall_last = Chatbox_recall_index;
1418 // otherwise post,decrement
1420 Chat_inputbox.set_text(Chatbox_recall_lines[Chatbox_recall_index--]);
1421 Chatbox_recall_last = Chatbox_recall_index + 1;
1424 // if we can't decrement down
1426 Chat_inputbox.set_text("");
1427 Chatbox_recall_last = -1;
1431 // reset all timestamps associated with the chatbox
1432 void chatbox_reset_timestamps()
1436 // if there is no chatbox created, do nothing
1437 if(!Chatbox_created){
1441 // otherwise clear all timestamps on all the buttons
1442 for(idx=0; idx<CHATBOX_NUM_BUTTONS+1; idx++){
1443 Chatbox_buttons[gr_screen.res][idx].button.reset_timestamps();