// process an entered line of text and maybe perform a command on it (return 1 if an action was performed, 0 if not) int multi_msg_check_command(char *str) { int idx; char *prefix = NULL, *predicate = NULL, param[MULTI_MSG_MAX_TEXT_LEN+1]; char temp_str[MULTI_MSG_MAX_TEXT_LEN+1]; // look for a colon if(strstr(str,":") == NULL){ return 0; } // we don't want to modify the original string, which strtok() does strcpy_s(temp_str, str); // try and find a command prefix prefix = strtok(temp_str, ":"); if (prefix == NULL) return 0; // get all the text after the message predicate = strtok(NULL, NOX("\n\0")); if (predicate == NULL) return 0; // store the text as the actual parameter strcpy_s(param, predicate); drop_leading_white_space(param); // go through all existing commands and see what we can do for(idx=0;idx<MULTI_MSG_CMD_COUNT;idx++){ if(!stricmp(prefix,Multi_msg_commands[idx])){ // perform the command multi_msg_perform_command(idx,param); // return true return 1; } } // apply the results as a general expression, if we're in message all mode if(Multi_msg_mode == MULTI_MSG_ALL){ strcpy_s(Multi_msg_text,param); // send the chat packet send_game_chat_packet(Net_player, Multi_msg_text, MULTI_MSG_EXPR,NULL, prefix); // echo the message locally multi_msg_display_mission_text(Multi_msg_text, MY_NET_PLAYER_NUM); // return true return 1; } // no commands performed return 0; }
// automatically split up any input text, send it, and leave the remainder void chatbox_autosplit_line() { char *remainder,msg[150]; int msg_pixel_width; // if the chat line is getting too long, fire off the message, putting the last // word on the next input line. memset(msg,0,150); Chat_inputbox.get_text(msg); remainder = ""; // determine if the width of the string in pixels is > than the inputbox width -- if so, // then send the message gr_get_string_size(&msg_pixel_width, NULL, msg); // if ( msg_pixel_width >= (Chatbox_inputbox_w - Player->short_callsign_width) ) { if ( msg_pixel_width >= (Chatbox_inputbox_w - 25)) { remainder = strrchr(msg, ' '); if ( remainder ) { *remainder = '\0'; remainder++; } else { remainder = ""; } // if I'm the server, then broadcast the packet chatbox_recall_add(msg); send_game_chat_packet(Net_player, msg, MULTI_MSG_ALL,NULL); chatbox_add_line(msg, MY_NET_PLAYER_NUM); // display any remainder of text on the next line Chat_inputbox.set_text(remainder); } else if((Chat_inputbox.pressed() && (strlen(msg) > 0)) || (strlen(msg) >= CHATBOX_MAX_LEN)) { // tack on the null terminator in the boundary case int 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); send_game_chat_packet(Net_player, msg, MULTI_MSG_ALL,NULL); chatbox_add_line(msg, MY_NET_PLAYER_NUM); // display any remainder of text on the next line Chat_inputbox.set_text(remainder); } }
// process a text string entered by the local player void multi_msg_eval_text_msg() { int player_index; // if its a 0 length string, don't do anything if(strlen(Multi_msg_text) <= 0){ return; } // evaluate any special commands here if(multi_msg_check_command(Multi_msg_text)){ return; } // get the player if in MSG_TARGET mode if(Multi_msg_mode == MULTI_MSG_TARGET){ if(Player_ai->target_objnum != -1){ player_index = multi_find_player_by_object(&Objects[Player_ai->target_objnum]); if(player_index != -1){ // send the chat packet send_game_chat_packet(Net_player, Multi_msg_text, Multi_msg_mode, &Net_players[player_index]); // echo the message locally multi_msg_display_mission_text(Multi_msg_text, MY_NET_PLAYER_NUM); } } } // all other modes else { // send the chat packet send_game_chat_packet(Net_player, Multi_msg_text, Multi_msg_mode, NULL); // echo the message locally multi_msg_display_mission_text(Multi_msg_text, MY_NET_PLAYER_NUM); } }
// automatically split up any input text, send it, and leave the remainder void chatbox_autosplit_line() { char *remainder,msg[150]; char temp[150]; int msg_pixel_width; int target, target_length = -1; // if the chat line is getting too long, fire off the message, putting the last // word on the next input line. memset(msg,0,150); Chat_inputbox.get_text(msg); remainder = ""; // check if this message is supposed to have a recipient target = chatbox_get_msg_target_type(msg); target_length = chatbox_get_msg_target_length(msg); // determine if the width of the string in pixels is > than the inputbox width -- if so, // then send the message gr_get_string_size(&msg_pixel_width, NULL, msg); // if ( msg_pixel_width >= (Chatbox_inputbox_w - Player->short_callsign_width) ) { if ( msg_pixel_width >= (Chatbox_inputbox_w - 25)) { remainder = strrchr(msg, ' '); if ( remainder ) { *remainder = '\0'; remainder++; } else { remainder = ""; } // 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 strncpy(temp, msg+1, target_length-2); temp[target_length-2] = '\0'; send_game_chat_packet(Net_player, msg, target, NULL, temp); } chatbox_add_line(msg, MY_NET_PLAYER_NUM); if (target != MULTI_MSG_ALL) { // we need to add the target the message is going to before we add the rest of the string 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)) { // tack on the null terminator in the boundary case int 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 strncpy(temp, msg+1, target_length-2); temp[target_length-2] = '\0'; send_game_chat_packet(Net_player, msg, target, NULL, temp); } chatbox_add_line(msg, MY_NET_PLAYER_NUM); // display any remainder of text on the next line Chat_inputbox.set_text(remainder); } }
//evaluate a kill on a weapon, right now this is only called on bombs. -Halleck int scoring_eval_kill_on_weapon(object *weapon_obj, object *other_obj) { float max_damage_pct; // the pct% of total damage the max damage object did int max_damage_index; // the index into the dying ship's damage_ship[] array corresponding the greatest amount of damage int killer_sig; // signature of the guy getting credit for the kill (or -1 if none) int idx,net_player_num; player *plr; // pointer to a player struct if it was a player who got the kill net_player *net_plr = NULL; net_player *dead_plr = NULL; float scoring_scale_by_damage = 1; // percentage to scale the killer's score by if we score based on the amount of damage caused int kill_score; weapon *dead_wp; // the weapon that was killed weapon_info *dead_wip; // info on the weapon that was killed if((weapon_obj->instance < 0) || (weapon_obj->instance >= MAX_WEAPONS)){ return -1; } dead_wp = &Weapons[weapon_obj->instance]; //assign the dead weapon dead_wip = &Weapon_info[dead_wp->weapon_info_index]; // multiplayer clients bail here if(MULTIPLAYER_CLIENT){ return -1; } // we don't evaluate kills on anything except weapons if(weapon_obj->type != OBJ_WEAPON){ return -1; } // we don't evaluate kills on anything except bombs, currently. -Halleck if(!(dead_wip->wi_flags & WIF_BOMB)) { return -1; } // clear out invalid damager ships for(idx=0; idx<MAX_DAMAGE_SLOTS; idx++){ if((dead_wp->damage_ship_id[idx] >= 0) && (ship_get_by_signature(dead_wp->damage_ship_id[idx]) < 0)){ dead_wp->damage_ship[idx] = 0.0f; dead_wp->damage_ship_id[idx] = -1; } } // determine which object did the most damage to the dying object, and how much damage that was max_damage_index = -1; for(idx=0;idx<MAX_DAMAGE_SLOTS;idx++){ // bogus ship if(dead_wp->damage_ship_id[idx] < 0){ continue; } // if this slot did more damage then the next highest slot if((max_damage_index == -1) || (dead_wp->damage_ship[idx] > dead_wp->damage_ship[max_damage_index])){ max_damage_index = idx; } } // doh if((max_damage_index < 0) || (max_damage_index >= MAX_DAMAGE_SLOTS)){ return -1; } // the pct of total damage applied to this ship max_damage_pct = dead_wp->damage_ship[max_damage_index] / dead_wp->total_damage_received; CLAMP(max_damage_pct, 0.0f, 1.0f); // only evaluate if the max damage % is high enough to record a kill and it was done by a valid object if((max_damage_pct >= Kill_percentage) && (dead_wp->damage_ship_id[max_damage_index] >= 0)){ // set killer_sig for this ship to the signature of the guy who gets credit for the kill killer_sig = dead_wp->damage_ship_id[max_damage_index]; // set the scale value if we only award 100% score for 100% damage if (The_mission.ai_profile->flags & AIPF_KILL_SCORING_SCALES_WITH_DAMAGE) { scoring_scale_by_damage = max_damage_pct; } // null this out for now plr = NULL; net_plr = NULL; // get the player (whether single or multiplayer) net_player_num = -1; if(Game_mode & GM_MULTIPLAYER){ net_player_num = multi_find_player_by_signature(killer_sig); if(net_player_num != -1){ plr = Net_players[net_player_num].m_player; net_plr = &Net_players[net_player_num]; } } else { if(Objects[Player->objnum].signature == killer_sig){ plr = Player; } } // if we found a valid player, evaluate some kill details if(plr != NULL){ //int si_index; // bogus if((plr->objnum < 0) || (plr->objnum >= MAX_OBJECTS)){ return -1; } // get the ship info index of the ship type of this kill. we need to take ship // copies into account here. //si_index = dead_wp->weapon_info_index; // if he killed a guy on his own team increment his bonehead kills if((Ships[Objects[plr->objnum].instance].team == dead_wp->team) && !MULTI_DOGFIGHT ){ if (!(The_mission.flags & MISSION_FLAG_NO_TRAITOR)) { plr->stats.m_bonehead_kills++; kill_score = -(int)(dead_wip->score * scoring_get_scale_factor()); plr->stats.m_score += kill_score; if(net_plr != NULL ) { multi_team_maybe_add_score(-(dead_wip->score), net_plr->p_info.team); } } } // otherwise increment his valid kill count and score else { // dogfight mode if(MULTI_DOGFIGHT && (multi_find_player_by_object(weapon_obj) < 0)){ // don't add a kill for dogfight kills on non-players } else { // bombs don't scale with difficulty at the moment. If we change this we want to *scoring_get_scale_factor() too kill_score = (int)(dead_wip->score * scoring_scale_by_damage); plr->stats.m_score += kill_score; hud_gauge_popup_start(HUD_KILLS_GAUGE); #ifdef SCORING_DEBUG char kill_score_text[1024] = ""; sprintf(kill_score_text, "SCORING : %s killed a ship worth %i points and gets %i pts for the kill", plr->callsign, dead_wip->score, kill_score); if (MULTIPLAYER_MASTER) { send_game_chat_packet(Net_player, kill_score_text, MULTI_MSG_ALL); } HUD_printf(kill_score_text); mprintf((kill_score_text)); #endif // multiplayer if(net_plr != NULL){ multi_team_maybe_add_score(dead_wip->score , net_plr->p_info.team); // award teammates % of score value for big ship kills // not in dogfight tho // and not if there is no assist threshold (as otherwise assists could get higher scores than kills) /* Below is N/A. -Halleck if (!(Netgame.type_flags & NG_TYPE_DOGFIGHT) && (Ship_info[dead_wp->ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP))) { for (idx=0; idx<MAX_PLAYERS; idx++) { if (MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].p_info.team == net_plr->p_info.team) && (&Net_players[idx] != net_plr)) { assist_score = (int)(dead_wip->score * The_mission.ai_profile->assist_award_percentage_scale[Game_skill_level]); Net_players[idx].m_player->stats.m_score += assist_score; #ifdef SCORING_DEBUG // DEBUG CODE TO TEST NEW SCORING char score_text[1024] = ""; sprintf(score_text, "SCORING : All team mates get %d pts for helping kill the capship", assist_score); send_game_chat_packet(Net_player, score_text, MULTI_MSG_ALL); HUD_printf(score_text); mprintf((score_text)); #endif } } } */ // death message if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (net_plr != NULL) && (dead_plr != NULL) && (net_plr->m_player != NULL) && (dead_plr->m_player != NULL)){ char dead_text[1024] = ""; sprintf(dead_text, "%s gets the kill for %s", net_plr->m_player->callsign, dead_plr->m_player->callsign); send_game_chat_packet(Net_player, dead_text, MULTI_MSG_ALL, NULL, NULL, 2); HUD_printf(dead_text); } } } } // increment his all-encompassing kills /*Not really a kill. -Halleck plr->stats.m_kills[si_index]++; plr->stats.m_kill_count++; // update everyone on this guy's kills if this is multiplayer if(MULTIPLAYER_MASTER && (net_player_num != -1)){ // send appropriate stats if(Netgame.type_flags & NG_TYPE_DOGFIGHT){ // evaluate dogfight kills multi_df_eval_kill(&Net_players[net_player_num], weapon_obj); // update stats send_player_stats_block_packet(&Net_players[net_player_num], STATS_DOGFIGHT_KILLS); } else { send_player_stats_block_packet(&Net_players[net_player_num], STATS_MISSION_KILLS); } } */ } } else { // set killer_sig for this ship to -1, indicating no one got the kill for it killer_sig = -1; } // pass in the guy who got the credit for the kill (if any), so that he doesn't also // get credit for an assist /* TODO: ADD ASSIST CALC BACK IN. -Halleck scoring_eval_assists(dead_wp,killer_sig, is_enemy_player); */ #ifdef SCORING_DEBUG if (Game_mode & GM_MULTIPLAYER) { char buf[256]; sprintf(Scoring_debug_text, "SCORING : %s killed.\nDamage by ship:\n\n", dead_wip->name); // show damage done by player for (int i=0; i<MAX_DAMAGE_SLOTS; i++) { int net_player_num = multi_find_player_by_signature(dead_wp->damage_ship_id[i]); if (net_player_num != -1) { plr = Net_players[net_player_num].m_player; sprintf(buf, "%s: %f", plr->callsign, dead_wp->damage_ship[i]); if (dead_wp->damage_ship_id[i] == killer_sig ) { strcat_s(buf, " KILLER\n"); } else { strcat_s(buf, "\n"); } strcat_s(Scoring_debug_text, buf); } } mprintf ((Scoring_debug_text)); } #endif return max_damage_index; }
// kill_id is the object signature of the guy who got the credit for the kill (may be -1, if no one got it) // this is to ensure that you don't also get an assist if you get the kill. void scoring_eval_assists(ship *sp,int killer_sig, bool is_enemy_player) { int idx; player *plr; float scoring_scale_by_damage = 1; // percentage to scale the score by if we score based on the amount of damage caused int assist_score; int net_player_num; float scoring_scale_factor; // multiplayer clients bail here if(MULTIPLAYER_CLIENT){ return; } // evaluate each damage slot to see if it did enough to give the assis for(idx=0;idx<MAX_DAMAGE_SLOTS;idx++){ // if this slot did enough damage to get an assist if(((sp->damage_ship[idx]/sp->total_damage_received) >= Assist_percentage) || (The_mission.ai_profile->flags & AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE)){ // get the player which did this damage (if any) plr = NULL; // multiplayer if(Game_mode & GM_MULTIPLAYER){ net_player_num = multi_find_player_by_signature(sp->damage_ship_id[idx]); if(net_player_num != -1){ plr = Net_players[net_player_num].m_player; } } // single player else { if(Objects[Player->objnum].signature == sp->damage_ship_id[idx]){ plr = Player; } } // if we found a player, give him the assist if he attacks it if ((plr != NULL) && (iff_x_attacks_y(Ships[Objects[plr->objnum].instance].team, sp->team)) && (killer_sig != Objects[plr->objnum].signature)) { // player has to equal the threshold to get an assist if ((sp->damage_ship[idx]/sp->total_damage_received) >= Assist_percentage) { plr->stats.m_assists++; nprintf(("Network","-==============GAVE PLAYER %s AN ASSIST=====================-\n",plr->callsign)); } // Don't scale in TvT and dogfight if (is_enemy_player) { Assert(Game_mode & GM_MULTIPLAYER); scoring_scale_factor = 1.0f; } else { scoring_scale_factor = scoring_get_scale_factor(); } // maybe award assist points based on damage if (The_mission.ai_profile->flags & AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE) { scoring_scale_by_damage = (sp->damage_ship[idx]/sp->total_damage_received); assist_score = (int)(sp->score * scoring_scale_factor * scoring_scale_by_damage); plr->stats.m_score += assist_score; } // otherwise give the points based on the percentage in the mission file else { assist_score = (int)(sp->score * sp->assist_score_pct * scoring_scale_factor ); plr->stats.m_score += assist_score; } #ifdef SCORING_DEBUG // DEBUG CODE TO TEST NEW SCORING char score_text[1024] = ""; sprintf(score_text, "SCORING : %s gets %d pts for getting an assist\n", plr->callsign, assist_score); if (MULTIPLAYER_MASTER) { send_game_chat_packet(Net_player, score_text, MULTI_MSG_ALL); } HUD_printf(score_text); mprintf ((score_text)); #endif } } } }
//evaluate a kill on a weapon, right now this is only called on bombs. -Halleck int scoring_eval_kill_on_weapon(object *weapon_obj, object *other_obj) { int killer_sig; // signature of the guy getting credit for the kill (or -1 if none) int net_player_num; player *plr; // pointer to a player struct if it was a player who got the kill net_player *net_plr = NULL; int kill_score; // multiplayer clients bail here if(MULTIPLAYER_CLIENT){ return -1; } // we don't evaluate kills on anything except weapons // also make sure there was a killer, and that it was a ship if((weapon_obj->type != OBJ_WEAPON) || (weapon_obj->instance < 0) || (weapon_obj->instance >= MAX_WEAPONS) || (other_obj == nullptr) || (other_obj->type != OBJ_WEAPON) || (other_obj->instance < 0) || (other_obj->instance >= MAX_WEAPONS) || (other_obj->parent == -1) || (Objects[other_obj->parent].type != OBJ_SHIP)) { return -1; } weapon *dead_wp = &Weapons[weapon_obj->instance]; // the weapon that was killed weapon_info *dead_wip = &Weapon_info[dead_wp->weapon_info_index]; // info on the weapon that was killed // we don't evaluate kills on anything except bombs, currently. -Halleck if(!(dead_wip->wi_flags & WIF_BOMB)) { return -1; } // set killer_sig for this weapon to the signature of the guy who gets credit for the kill killer_sig = Objects[other_obj->parent].signature; // only evaluate if the kill was done by a valid object if(killer_sig >= 0) { // null this out for now plr = NULL; net_plr = NULL; // get the player (whether single or multiplayer) net_player_num = -1; if(Game_mode & GM_MULTIPLAYER){ net_player_num = multi_find_player_by_signature(killer_sig); if(net_player_num != -1){ plr = Net_players[net_player_num].m_player; net_plr = &Net_players[net_player_num]; } } else { if(Objects[Player->objnum].signature == killer_sig){ plr = Player; } } // if we found a valid player, evaluate some kill details if(plr != NULL){ // bogus if((plr->objnum < 0) || (plr->objnum >= MAX_OBJECTS)){ return -1; } // if he killed a bomb on his own team increment his bonehead kills if((Ships[Objects[plr->objnum].instance].team == dead_wp->team) && !MULTI_DOGFIGHT ){ if (!(The_mission.flags & MISSION_FLAG_NO_TRAITOR)) { plr->stats.m_bonehead_kills++; kill_score = -(int)(dead_wip->score * scoring_get_scale_factor()); plr->stats.m_score += kill_score; if(net_plr != NULL ) { multi_team_maybe_add_score(-(dead_wip->score), net_plr->p_info.team); } } } // otherwise increment his valid kill count and score else { // dogfight mode if(MULTI_DOGFIGHT && (multi_find_player_by_object(weapon_obj) < 0)){ // don't add a kill for dogfight kills on non-players } else { // bombs don't scale with difficulty at the moment. If we change this we want to *scoring_get_scale_factor() kill_score = dead_wip->score; plr->stats.m_score += kill_score; hud_gauge_popup_start(HUD_KILLS_GAUGE); #ifdef SCORING_DEBUG char kill_score_text[1024] = ""; sprintf(kill_score_text, "SCORING : %s killed a bomb worth %i points and gets %i pts for the kill", plr->callsign, dead_wip->score, kill_score); if (MULTIPLAYER_MASTER) { send_game_chat_packet(Net_player, kill_score_text, MULTI_MSG_ALL); } HUD_printf(kill_score_text); mprintf((kill_score_text)); #endif // multiplayer if(net_plr != NULL){ multi_team_maybe_add_score(dead_wip->score , net_plr->p_info.team); } } } } } #ifdef SCORING_DEBUG if (Game_mode & GM_MULTIPLAYER) { sprintf(Scoring_debug_text, "SCORING : %s killed.\nKilled by player:\n", dead_wip->name); int net_player_num = multi_find_player_by_signature(killer_sig); if (net_player_num != -1) { plr = Net_players[net_player_num].m_player; char buf[256]; sprintf(buf, " %s\n", plr->callsign); strcat_s(Scoring_debug_text, buf); } mprintf ((Scoring_debug_text)); } #endif return killer_sig; }