/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ #include "cfile/cfile.h" #include "cmdline/cmdline.h" #include "gamesnd/gamesnd.h" #include "globalincs/alphacolors.h" #include "io/key.h" #include "missionui/chatbox.h" #include "network/multi.h" #include "network/multi_pmsg.h" #include "network/multimsgs.h" #include "network/multiui.h" #include "parse/parselo.h" #include "playerman/player.h" #include "ui/ui.h" /////////////////////////////////////////////////////////// // Chat window UI /////////////////////////////////////////////////////////// // a little extra spacing for the team vs. team icons #define CHATBOX_TEAM_ICON_SPACE 18 // SMALL CHATBOX ---------------------------------------------------------------------------------- // background bitmap const char* Chatbox_small_bitmap_fname[GR_NUM_RESOLUTIONS] = { "Chatbox", // GR_640 "2_Chatbox" // GR_1024 }; // background mask const char* Chatbox_small_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = { "Chatbox-m", // GR_640 "2_Chatbox-m" // GR_1024 }; // chatbox coords int Chatbox_small_coords[GR_NUM_RESOLUTIONS][2] = { { // GR_640 192, 0 }, { // GR_1024 308, 0 // ? } }; // display area coods int Chatbox_small_display_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 196 + CHATBOX_TEAM_ICON_SPACE, 13, 410 - CHATBOX_TEAM_ICON_SPACE, 74 }, { // GR_1024 315 + CHATBOX_TEAM_ICON_SPACE, 22, 654 - CHATBOX_TEAM_ICON_SPACE, 116 } }; // input box coords int Chatbox_small_input_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 204, 100, 371, 22 }, { // GR_1024 328, 163, 591, 34 } }; // max # of lines int Chatbox_small_max_lines[GR_NUM_RESOLUTIONS] = { 7, // GR_640 12 // GR_1024 }; // BIG CHATBOX ---------------------------------------------------------------------------------- // background bitmap const char* Chatbox_big_bitmap_fname[GR_NUM_RESOLUTIONS] = { "ChatboxBig", // GR_640 "2_ChatboxBig" // GR_1024 }; // mask const char* Chatbox_big_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = { "Chatbox-m", // GR_640 "2_Chatbox-m" // GR_1024 }; // chatbox coords int Chatbox_big_coords[GR_NUM_RESOLUTIONS][2] = { { // GR_640 192, 0 }, { // GR_1024 307, 0 } }; // display area coords int Chatbox_big_display_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 196 + CHATBOX_TEAM_ICON_SPACE, 13, 410 - CHATBOX_TEAM_ICON_SPACE, 326 }, { // GR_1024 315 + CHATBOX_TEAM_ICON_SPACE, 22, 654 - CHATBOX_TEAM_ICON_SPACE, 519 } }; // input box coords int Chatbox_big_input_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 204, 352, 371, 22 }, { // GR_1024 328, 565, 591, 34 } }; // max # of lines int Chatbox_big_max_lines[GR_NUM_RESOLUTIONS] = { 32, // GR_640 51 // GR_1024 }; // PAUSED CHATBOX ---------------------------------------------------------------------------------- // mask const char* Chatbox_p_bitmap_fname[GR_NUM_RESOLUTIONS] = { "MPPause", // GR_640 "2_MPPause" // GR_1024 }; // mask const char* Chatbox_p_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = { "MPPause-m", // GR_640 "2_MPPause-m" // GR_1024 }; // chatbox coords int Chatbox_p_coords[GR_NUM_RESOLUTIONS][2] = { { // GR_640 // 192, 0 0, 0 }, { // GR_1024 // 307, 0 0, 0 } }; // display area coords int Chatbox_p_display_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 103 + CHATBOX_TEAM_ICON_SPACE, 149, 380 - CHATBOX_TEAM_ICON_SPACE, 143 }, { // GR_1024 165 + CHATBOX_TEAM_ICON_SPACE, 244, 654 - CHATBOX_TEAM_ICON_SPACE, 263 } }; // input box coords int Chatbox_p_input_coords[GR_NUM_RESOLUTIONS][4] = { { // GR_640 106, 328, 379, 17 }, { // GR_1024 165, 525, 607, 27 } }; // max # of lines int Chatbox_p_max_lines[GR_NUM_RESOLUTIONS] = { 17, // GR_640 26 // GR_1024 }; // defines for location and other info of chat box MULTI_PAUSED /* #define CHATBOX_MP_FNAME NOX("MPPause") #define CHATBOX_MP_MASK NOX("MPPause-m") #define CHATBOX_MP_X1 112 #define CHATBOX_MP_Y1 198 #define CHATBOX_MP_X2 477 #define CHATBOX_MP_Y2 308 #define CHATBOX_MP_ICON_X (CHATBOX_MP_X1) #define CHATBOX_MP_W (CHATBOX_MP_X2 - CHATBOX_MP_X1 + 1) #define CHATBOX_MP_H (CHATBOX_MP_Y2 - CHATBOX_MP_Y1 + 1) #define CHATBOX_MP_BEGIN_X (CHATBOX_MP_X1 + 3 + CHATBOX_TEAM_ICON_SPACE) #define CHATBOX_MP_BEGIN_Y CHATBOX_MP_Y1 #define CHATBOX_MP_DISP_W 365 #define CHATBOX_MP_MAX_LINES 11 #define CHATBOX_MP_INPUTBOX_X (CHATBOX_MP_X1 + 3) #define CHATBOX_MP_INPUTBOX_W (CHATBOX_MP_W) #define CHATBOX_MP_TEXTENTER_Y 329 */ // CHATBOX ---------------------------------------------------------------------------------- // the settings being used for this instance char Chatbox_mask[50]; int Chatbox_x1; int Chatbox_y1; int Chatbox_icon_x; int Chatbox_w; int Chatbox_h; int Chatbox_begin_x; int Chatbox_begin_y; int Chatbox_disp_w; int Chatbox_max_lines; int Chatbox_inputbox_x; int Chatbox_inputbox_w; int Chatbox_textenter_y; int Chat_scroll_up_coord[2]; int Chat_scroll_down_coord[2]; // how many pixels to indent succesive lines of text from a given player #define CHAT_LINE_INDENT 20 // what chars other than letters and number's we'll toss #define CHATBOX_INVALID_CHARS NOX("~`") // this is primarily so that we don't interfere with the voice recording keys // common defines and UI_WINDOW Chat_window; UI_INPUTBOX Chat_inputbox; UI_BUTTON Chat_enter_text; // button controls #define CHATBOX_NUM_BUTTONS 3 #define CHATBOX_SCROLL_UP 0 #define CHATBOX_SCROLL_DOWN 1 #define CHATBOX_TOGGLE_SIZE 2 // used for both big and small // coordinate indicies #define CHATBOX_X_COORD 0 #define CHATBOX_Y_COORD 1 #define CHATBOX_W_COORD 2 #define CHATBOX_H_COORD 3 // chatbox buttons ui_button_info Chatbox_buttons[GR_NUM_RESOLUTIONS][CHATBOX_NUM_BUTTONS+1] = { { // GR_640 ui_button_info("CHB_00", 613, 3, -1, -1, 0), ui_button_info("CHB_01", 613, 41, -1, -1, 1), ui_button_info("CHB_02a", 607, 74, -1, -1, 2), ui_button_info("CHB_02b", 607, 74, -1, -1, 2), }, { // GR_1024 ui_button_info("2_CHB_00", 981, 5, -1, -1, 0), ui_button_info("2_CHB_01", 981, 67, -1, -1, 1), ui_button_info("2_CHB_02a", 971, 119, -1, -1, 2), ui_button_info("2_CHB_02b", 971, 119, -1, -1, 2), } }; int Chatbox_mode_flags = 0; int Chatbox_bitmap = -1; int Chatbox_big_bitmap = -1; int Chatbox_small_bitmap = -1; int Chatbox_mp_bitmap = -1; int Chatbox_created = 0; /////////////////////////////////////////////////////////// // Chat window text /////////////////////////////////////////////////////////// #define BRIEF_DISPLAY_SPACING 2 // pixel spacing between chat lines // the first byte of the text string will be the net player id of the SCP_list Brief_chat; // the index of the chat line we will start rendering at int Brief_start_display_index; // chatbox line recall data #define CHATBOX_MAX_RECALL_LINES 10 int Chatbox_recall_count = 0; int Chatbox_recall_index = 0; int Chatbox_recall_last = -1; char Chatbox_recall_lines[CHATBOX_MAX_RECALL_LINES][CHATBOX_MAX_LEN+2]; /////////////////////////////////////////////////////////// // forward declarations /////////////////////////////////////////////////////////// void chatbox_chat_init(); void chatbox_render_chat_lines(); void chatbox_set_mode(int mode_flags); void chatbox_toggle_size(); void chatbox_toggle_size_adjust_lines(); void chat_autosplit_line(char *msg,char *remainder); void chatbox_recall_add(char *string); void chatbox_recall_up(); void chatbox_recall_down(); // set the chatbox mode without checking for any previous modes which may need to be handled specially void chatbox_set_mode(int mode_flags) { int size; // set the stored mode Chatbox_mode_flags = mode_flags; // small pregame chatbox if(Chatbox_mode_flags & CHATBOX_FLAG_SMALL){ size = 0; } // big pregame chatbox else if(Chatbox_mode_flags & CHATBOX_FLAG_BIG){ size = 1; } // multiplayer paused else { size = 2; } // set up the display/init variables based upon what mode we chode switch(size){ case 0: strcpy_s(Chatbox_mask, Chatbox_small_bitmap_mask_fname[gr_screen.res]); Chatbox_x1 = Chatbox_small_coords[gr_screen.res][CHATBOX_X_COORD]; Chatbox_y1 = Chatbox_small_coords[gr_screen.res][CHATBOX_Y_COORD]; Chatbox_icon_x = Chatbox_small_display_coords[gr_screen.res][CHATBOX_X_COORD] - CHATBOX_TEAM_ICON_SPACE; Chatbox_w = Chatbox_small_display_coords[gr_screen.res][CHATBOX_W_COORD]; Chatbox_h = Chatbox_small_display_coords[gr_screen.res][CHATBOX_H_COORD]; Chatbox_begin_x = Chatbox_small_display_coords[gr_screen.res][CHATBOX_X_COORD]; Chatbox_begin_y = Chatbox_small_display_coords[gr_screen.res][CHATBOX_Y_COORD]; Chatbox_disp_w = Chatbox_small_display_coords[gr_screen.res][CHATBOX_W_COORD]; Chatbox_max_lines = gr_get_dynamic_font_lines(Chatbox_small_max_lines[gr_screen.res]); Chatbox_inputbox_x = Chatbox_small_input_coords[gr_screen.res][CHATBOX_X_COORD]; Chatbox_inputbox_w = Chatbox_small_input_coords[gr_screen.res][CHATBOX_W_COORD]; Chatbox_textenter_y = Chatbox_small_input_coords[gr_screen.res][CHATBOX_Y_COORD]; break; case 1: strcpy_s(Chatbox_mask, Chatbox_big_bitmap_mask_fname[gr_screen.res]); Chatbox_x1 = Chatbox_big_coords[gr_screen.res][CHATBOX_X_COORD]; Chatbox_y1 = Chatbox_big_coords[gr_screen.res][CHATBOX_Y_COORD]; Chatbox_icon_x = Chatbox_big_display_coords[gr_screen.res][CHATBOX_X_COORD] - CHATBOX_TEAM_ICON_SPACE; Chatbox_w = Chatbox_big_display_coords[gr_screen.res][CHATBOX_W_COORD]; Chatbox_h = Chatbox_big_display_coords[gr_screen.res][CHATBOX_H_COORD]; Chatbox_begin_x = Chatbox_big_display_coords[gr_screen.res][CHATBOX_X_COORD]; Chatbox_begin_y = Chatbox_big_display_coords[gr_screen.res][CHATBOX_Y_COORD]; Chatbox_disp_w = Chatbox_big_display_coords[gr_screen.res][CHATBOX_W_COORD]; Chatbox_max_lines = gr_get_dynamic_font_lines(Chatbox_big_max_lines[gr_screen.res]); Chatbox_inputbox_x = Chatbox_big_input_coords[gr_screen.res][CHATBOX_X_COORD]; Chatbox_inputbox_w = Chatbox_big_input_coords[gr_screen.res][CHATBOX_W_COORD]; Chatbox_textenter_y = Chatbox_big_input_coords[gr_screen.res][CHATBOX_Y_COORD]; break; case 2: Chatbox_x1 = Chatbox_p_coords[gr_screen.res][CHATBOX_X_COORD]; Chatbox_y1 = Chatbox_p_coords[gr_screen.res][CHATBOX_Y_COORD]; Chatbox_icon_x = Chatbox_p_display_coords[gr_screen.res][CHATBOX_X_COORD] - CHATBOX_TEAM_ICON_SPACE; Chatbox_w = Chatbox_p_display_coords[gr_screen.res][CHATBOX_W_COORD]; Chatbox_h = Chatbox_p_display_coords[gr_screen.res][CHATBOX_H_COORD]; Chatbox_begin_x = Chatbox_p_display_coords[gr_screen.res][CHATBOX_X_COORD]; Chatbox_begin_y = Chatbox_p_display_coords[gr_screen.res][CHATBOX_Y_COORD]; Chatbox_disp_w = Chatbox_p_display_coords[gr_screen.res][CHATBOX_W_COORD]; Chatbox_max_lines = gr_get_dynamic_font_lines(Chatbox_p_max_lines[gr_screen.res]); Chatbox_inputbox_x = Chatbox_p_input_coords[gr_screen.res][CHATBOX_X_COORD]; Chatbox_inputbox_w = Chatbox_p_input_coords[gr_screen.res][CHATBOX_W_COORD]; Chatbox_textenter_y = Chatbox_p_input_coords[gr_screen.res][CHATBOX_Y_COORD]; break; } } int chatbox_get_msg_target_type(char *msg ) { if (msg[0] != '/') { return MULTI_MSG_ALL; } if (!strnicmp (msg, "/f:", 3)) { return MULTI_MSG_FRIENDLY; } if (!strnicmp (msg, "/h:", 3)) { return MULTI_MSG_HOSTILE; } return MULTI_MSG_EXPR; } size_t chatbox_get_msg_target_length(char *msg) { if ((msg[0] != '/') && (strchr(msg, ':') != NULL) ) { return 0; } // find the first space return strcspn(msg, ":") + 1 ; } // send a msg to the game chat void chatbox_send_msg(char* msg) { // check if this message is supposed to have a recipient int target = chatbox_get_msg_target_type(msg); // tack on the null terminator in the boundary case size_t x = strlen(msg); if (x >= CHATBOX_MAX_LEN) { msg[CHATBOX_MAX_LEN - 1] = '\0'; } // if I'm the server, then broadcast the packet chatbox_recall_add(msg); if (target != MULTI_MSG_EXPR) { send_game_chat_packet(Net_player, msg, target); } else { // copy the name of the player the message is being sent to char temp[CHATBOX_MAX_LEN]; size_t target_length = chatbox_get_msg_target_length(msg); strncpy(temp, msg + 1, target_length - 2); temp[target_length - 2] = '\0'; send_game_chat_packet(Net_player, msg, target, nullptr, temp); } chatbox_add_line(msg, MY_NET_PLAYER_NUM); } // automatically split up any input text, send it, and leave the remainder void chatbox_autosplit_line() { char msg[CHATBOX_MAX_LEN]; // if the chat line is getting too long, fire off the message, putting the last // word on the next input line. memset(msg, 0, CHATBOX_MAX_LEN); Chat_inputbox.get_text(msg); const char* remainder = ""; // determine if the width of the string in pixels is > than the inputbox width -- if so, // then send the message int msg_pixel_width; gr_get_string_size(&msg_pixel_width, nullptr, msg); // if ( msg_pixel_width >= (Chatbox_inputbox_w - Player->short_callsign_width) ) { if ( msg_pixel_width >= (Chatbox_inputbox_w - 25)) { auto last_space = strrchr(msg, ' '); if ( last_space ) { *last_space = '\0'; remainder = last_space + 1; } else { remainder = ""; } chatbox_send_msg(msg); // check if this message is supposed to have a recipient int target = chatbox_get_msg_target_type(msg); if (target != MULTI_MSG_ALL) { // we need to add the target the message is going to before we add the rest of the string char temp[CHATBOX_MAX_LEN]; size_t target_length = chatbox_get_msg_target_length(msg); strncpy(temp, msg, target_length); temp[target_length] = ' '; temp[target_length+1] = '\0'; strcat_s(temp, remainder); Chat_inputbox.set_text(temp); } else { // display any remainder of text on the next line Chat_inputbox.set_text(remainder); } } else if((Chat_inputbox.pressed() && (msg[0] != '\0')) || (strlen(msg) >= CHATBOX_MAX_LEN)) { chatbox_send_msg(msg); // display any remainder of text on the next line Chat_inputbox.set_text(remainder); } } // initialize all chatbox details with the given mode flags int chatbox_create(int mode_flags) { int idx; // don't do anything if the chatbox is already initialized if (Chatbox_created){ return -1; } // probably shouldn't be using the chatbox in single player mode Assert(Game_mode & GM_MULTIPLAYER); // setup all data to correspond to our mode flags chatbox_set_mode(mode_flags); // initialize all low-level details related to chatting chatbox_chat_init(); // attempt to load in the chatbox background bitmap if(Chatbox_mode_flags & CHATBOX_FLAG_DRAW_BOX){ Chatbox_big_bitmap = bm_load(Chatbox_big_bitmap_fname[gr_screen.res]); Chatbox_small_bitmap = bm_load(Chatbox_small_bitmap_fname[gr_screen.res]); Chatbox_mp_bitmap = bm_load(Chatbox_p_bitmap_fname[gr_screen.res]); if(Chatbox_mode_flags & CHATBOX_FLAG_SMALL){ Chatbox_bitmap = Chatbox_small_bitmap; } else if(Chatbox_mode_flags & CHATBOX_FLAG_BIG){ Chatbox_bitmap = Chatbox_big_bitmap; } else { Chatbox_bitmap = Chatbox_mp_bitmap; } if((Chatbox_bitmap == -1) || (Chatbox_small_bitmap == -1) || (Chatbox_big_bitmap == -1) || (Chatbox_mp_bitmap == -1)){ return -1; } } // attempt to create the ui window for the chatbox and assign the mask Chat_window.create( 0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0 ); Chat_window.set_mask_bmap(Chatbox_mask); // create the chat text enter input area 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]); Chat_inputbox.set_focus(); Chat_inputbox.set_invalid_chars(CHATBOX_INVALID_CHARS); // if we're supposed to supply and check for out own buttons if((Chatbox_mode_flags & CHATBOX_FLAG_BUTTONS) && (Chatbox_mode_flags & CHATBOX_FLAG_DRAW_BOX)){ for(idx=0; idx(Brief_chat.size()) > Chatbox_max_lines) { if (Brief_start_display_index > 0) { Brief_start_display_index--; return 1; } } return 0; } // try and scroll the chatbox down, return 0 or 1 on fail or success int chatbox_scroll_down() { if (static_cast(Brief_chat.size()) > Chatbox_max_lines) { if (Brief_start_display_index < (static_cast(Brief_chat.size()) - Chatbox_max_lines)) { Brief_start_display_index++; return 1; } } return 0; } void chatbox_chat_init() { chatbox_clear(); // initialize the line recall data Chatbox_recall_count = 0; Chatbox_recall_index = 0; Chatbox_recall_last = -1; memset(Chatbox_recall_lines,0,CHATBOX_MAX_RECALL_LINES * (CHATBOX_MAX_LEN + 2)); } void chat_box_add_chat_to_list(brief_chat& chat) { if (Brief_chat.size() >= MAX_BRIEF_CHAT_LINES) { Brief_chat.erase(Brief_chat.begin()); } Brief_chat.push_back(chat); } // int Test_color = 0; void chatbox_add_line(const char *msg, int pid, int add_id) { if(!Chatbox_created){ return; } brief_chat chat; chat.indent = false; chat.player_id = pid; // maybe stick on who sent the message if(add_id){ if(MULTI_STANDALONE(Net_players[pid])){ strcpy_s(chat.callsign, ""); } else { strcpy_s(chat.callsign, Net_players[pid].m_player->short_callsign); } } else { chat.callsign[0] = '\0'; } // split the text up into as many lines as necessary int n_chars[3]; const char* p_str[3]; // for the initial line (unindented) int n_lines = split_str(msg, Chatbox_disp_w, n_chars, p_str, 3, CHATBOX_STRING_LEN); Assertion(n_lines != -1, "Chat split string returned an invalid number of lines, please report!"); // will happen if msg is all whitespace, in which case we should ignore it if (n_lines == 0) { return; } // copy in the chars strcpy_s(chat.text, p_str[0]); chat_box_add_chat_to_list(chat); // if we have more than 1 line, re-split everything so that the rest are indented if(n_lines > 1){ // split up the string after the first break-marker char msg_extra[CHATBOX_STRING_LEN]; n_lines = split_str(msg_extra + n_chars[0],Chatbox_disp_w - CHAT_LINE_INDENT,n_chars,p_str,3, CHATBOX_STRING_LEN); Assertion(n_lines != -1, "Chat split string returned an invalid number of lines, please report!"); // setup these remaining lines for(int idx=0;idx(Brief_chat.size()) > Chatbox_max_lines) { Brief_start_display_index = (static_cast(Brief_chat.size()) - Chatbox_max_lines); } } // if we have enough lines of text to require scrolling, scroll down by one. else { chatbox_scroll_down(); } } void chatbox_render_chat_lines() { int count = 0; int ly = Chatbox_begin_y; int line_height = gr_get_font_height() + 1; if (Brief_chat.empty()) { return; } Assertion(Brief_start_display_index >= 0 && Brief_start_display_index < static_cast(Brief_chat.size()), "Chat display index is invalid, please report!"); auto chat = Brief_chat.begin(); std::advance(chat, Brief_start_display_index); while (chat != Brief_chat.end() && count < Chatbox_max_lines) { char msg[CHATBOX_STRING_LEN]; // add the player callsign sprintf(msg, "%s %s", chat->callsign, chat->text); Assertion(strlen(msg) < (CHATBOX_STRING_LEN - 2), "Chat string is too long, please report!"); // print the line out gr_set_color_fast(Color_netplayer[chat->player_id]); // draw the first line (no indent) int indent = 0; if (chat->indent) { indent = CHAT_LINE_INDENT; } gr_string(Chatbox_begin_x + indent, ly, msg, GR_RESIZE_MENU); // if we're in a team vs. team game, blit the player color icon if (Netgame.type_flags & NG_TYPE_TEAM) { switch (Net_players[chat->player_id].p_info.team) { case 0: // if he's a team captain if (Net_players[chat->player_id].flags & NETINFO_FLAG_TEAM_CAPTAIN) { if (Multi_common_icons[MICON_TEAM0_SELECT] != -1) { gr_set_bitmap(Multi_common_icons[MICON_TEAM0_SELECT]); gr_bitmap(Chatbox_icon_x, ly - 2, GR_RESIZE_MENU); } } // just you're average peon else { if (Multi_common_icons[MICON_TEAM0] != -1) { gr_set_bitmap(Multi_common_icons[MICON_TEAM0]); gr_bitmap(Chatbox_icon_x, ly - 2, GR_RESIZE_MENU); } } break; case 1: // if he's a team captain if (Net_players[chat->player_id].flags & NETINFO_FLAG_TEAM_CAPTAIN) { if (Multi_common_icons[MICON_TEAM1_SELECT] != -1) { gr_set_bitmap(Multi_common_icons[MICON_TEAM1_SELECT]); gr_bitmap(Chatbox_icon_x, ly - 2, GR_RESIZE_MENU); } } // just your average peon else { if (Multi_common_icons[MICON_TEAM1] != -1) { gr_set_bitmap(Multi_common_icons[MICON_TEAM1]); gr_bitmap(Chatbox_icon_x, ly - 2, GR_RESIZE_MENU); } } break; } } // increment the count and line position count++; ++chat; ly += line_height; } } void chatbox_toggle_size() { // if we're in "small" mode if(Chatbox_mode_flags & CHATBOX_FLAG_SMALL){ chatbox_force_big(); // play a sound gamesnd_play_iface(InterfaceSounds::IFACE_MOUSE_CLICK); } // if we're in "big" mode else if(Chatbox_mode_flags & CHATBOX_FLAG_BIG){ chatbox_force_small(); // play a sound gamesnd_play_iface(InterfaceSounds::IFACE_MOUSE_CLICK); } } void chatbox_toggle_size_adjust_lines() { if ((static_cast(Brief_chat.size()) > Chatbox_max_lines)) { Brief_start_display_index = (static_cast(Brief_chat.size()) - Chatbox_max_lines); } else { Brief_start_display_index = 0; } } // force the chatbox to go into small mode (if its in large mode) - will not wotk if in multi paused chatbox mode void chatbox_force_small() { int new_mode_flags; // don't do anything unless we're currently in "big" mode if(!(Chatbox_mode_flags & CHATBOX_FLAG_BIG)){ return; } new_mode_flags = Chatbox_mode_flags; // switch to the appropriate mode new_mode_flags &= ~(CHATBOX_FLAG_SMALL | CHATBOX_FLAG_BIG); new_mode_flags |= CHATBOX_FLAG_SMALL; Chatbox_bitmap = Chatbox_small_bitmap; // flip the up/down arrow Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].button.set_bmaps(Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].filename); // call this to set everything up correctly chatbox_set_mode(new_mode_flags); // change the location of the input box Chat_inputbox.update_dimensions(Chatbox_inputbox_x, Chatbox_textenter_y, Chatbox_inputbox_w,15); Chat_inputbox.set_focus(); // adjust what line we start displaying from based upon the new size of the window chatbox_toggle_size_adjust_lines(); } // force the chatbox to go into big mode (if its in small mode) - will not work if in multi paused chatbox mode void chatbox_force_big() { int new_mode_flags; // don't do anything unless we're currently in "small" mode if(!(Chatbox_mode_flags & CHATBOX_FLAG_SMALL)){ return; } new_mode_flags = Chatbox_mode_flags; // switch to the appropriate mode new_mode_flags &= ~(CHATBOX_FLAG_SMALL | CHATBOX_FLAG_BIG); new_mode_flags |= CHATBOX_FLAG_BIG; Chatbox_bitmap = Chatbox_big_bitmap; // flip the up/down arrow Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE].button.set_bmaps(Chatbox_buttons[gr_screen.res][CHATBOX_TOGGLE_SIZE+1].filename); // call this to set everything up correctly chatbox_set_mode(new_mode_flags); // change the location of the input box Chat_inputbox.update_dimensions(Chatbox_inputbox_x, Chatbox_textenter_y, Chatbox_inputbox_w,15); Chat_inputbox.set_focus(); // adjust what line we start displaying from based upon the new size of the window chatbox_toggle_size_adjust_lines(); } // "lose" the focus on the chatbox inputbox void chatbox_lose_focus() { if(!Chatbox_created){ return; } // clear the focus on the inputbox Chat_inputbox.clear_focus(); } // return if the inputbox for the chatbox currently has focus int chatbox_has_focus() { return Chat_inputbox.has_focus(); } // grab the focus for the chatbox inputbox void chatbox_set_focus() { Chat_inputbox.set_focus(); } // return if the inputbox was pressed - "clicked on" int chatbox_pressed() { return Chat_inputbox.pressed(); } // add the string to the line recall list void chatbox_recall_add(char *string) { int idx; // aleays reset the recall index when adding Chatbox_recall_index = 0; Chatbox_recall_last = -1; // if this string matches the last string we entered, don't add it again if(!strcmp(string,Chatbox_recall_lines[0])){ return; } // move all items up (this works fine for small #'s of recall lines for(idx=CHATBOX_MAX_RECALL_LINES-1;idx > 0;idx--){ memcpy(&Chatbox_recall_lines[idx],&Chatbox_recall_lines[idx-1],CHATBOX_MAX_LEN+2); } // copy the new item into spot 0 strcpy_s(Chatbox_recall_lines[0],string); // increment the recall count if necessary if(Chatbox_recall_count < CHATBOX_MAX_RECALL_LINES){ Chatbox_recall_count++; } } // user has pressed the "up" key void chatbox_recall_up() { // if we've got no recall lines, do nothing if(Chatbox_recall_count <= 0){ return; } // if we can increment up if(Chatbox_recall_index < (Chatbox_recall_count - 1)){ // if this is the last line we recalled, pre-increment if(Chatbox_recall_last == Chatbox_recall_index){ Chat_inputbox.set_text(Chatbox_recall_lines[++Chatbox_recall_index]); Chatbox_recall_last = Chatbox_recall_index; } // otherwise, post increment else { Chat_inputbox.set_text(Chatbox_recall_lines[Chatbox_recall_index++]); Chatbox_recall_last = Chatbox_recall_index - 1; } } // if we can't increment up else { Chat_inputbox.set_text(Chatbox_recall_lines[Chatbox_recall_index]); Chatbox_recall_last = Chatbox_recall_index; } } // user has pressed the "down" key void chatbox_recall_down() { // if we've got no recall lines, do nothing if(Chatbox_recall_count <= 0){ return; } // if we can decrement down if(Chatbox_recall_index > 0){ // if this is the last line we recalled, pre-decrement if(Chatbox_recall_last == Chatbox_recall_index){ Chat_inputbox.set_text(Chatbox_recall_lines[--Chatbox_recall_index]); Chatbox_recall_last = Chatbox_recall_index; } // otherwise post,decrement else { Chat_inputbox.set_text(Chatbox_recall_lines[Chatbox_recall_index--]); Chatbox_recall_last = Chatbox_recall_index + 1; } } // if we can't decrement down else { Chat_inputbox.set_text(""); Chatbox_recall_last = -1; } } // reset all timestamps associated with the chatbox void chatbox_reset_timestamps() { int idx; // if there is no chatbox created, do nothing if(!Chatbox_created){ return; } // otherwise clear all timestamps on all the buttons for(idx=0; idx