/* * 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 "globalincs/systemvars.h" #include "hud/hud.h" #include "network/multi.h" #include "pilotfile/pilotfile.h" #include "playerman/player.h" #include "stats/stats.h" static const scoring_struct *Player_stats; // coverity[GLOBAL_INIT_ORDER] -- safe; default-constructed, no cross-TU dependencies static scoring_struct All_time_ever_stats; void show_stats_init() { if (Game_mode & GM_MULTIPLAYER) { set_player_stats(MY_NET_PLAYER_NUM); } else { Player_stats = &Player->stats; } // multi only has current stats and all-time-ever stats, so this is only needed in single-player Pilot.export_stats(&All_time_ever_stats); } // write out the label for each stat void show_stats_label(StatsType type, int sx, int sy, int dy) { char text[NAME_LENGTH]; if (type == StatsType::MISSION_STATS) gr_printf_menu(sx, sy, "%s", XSTR("Mission Stats", 114)); else gr_printf_menu(sx, sy, "%s", XSTR("All Time Stats", 128)); sy += 2 * dy; gr_printf_menu(sx, sy, "%s", XSTR("Total kills", 115)); sy += 2 * dy; gr_printf_menu(sx, sy, "%s", XSTR("Primary weapon shots", 116)); sy += dy; gr_printf_menu(sx, sy, "%s", XSTR("Primary weapon hits", 117)); sy += dy; gr_printf_menu(sx, sy, "%s", XSTR("Primary friendly hits", 118)); sy += dy; strcpy_s(text, XSTR("Primary hit %", 119)); replace_one(text, "%%", "%", NAME_LENGTH - 1); gr_printf_menu(sx, sy, "%s", text); sy += dy; strcpy_s(text, XSTR("Primary friendly hit %", 120)); replace_one(text, "%%", "%", NAME_LENGTH - 1); gr_printf_menu(sx, sy, "%s", text); sy += 2 * dy; gr_printf_menu(sx, sy, "%s", XSTR("Secondary weapon shots", 121)); sy += dy; gr_printf_menu(sx, sy, "%s", XSTR("Secondary weapon hits", 122)); sy += dy; gr_printf_menu(sx, sy, "%s", XSTR("Secondary friendly hits", 123)); sy += dy; strcpy_s(text, XSTR("Secondary hit %", 124)); replace_one(text, "%%", "%", NAME_LENGTH - 1); gr_printf_menu(sx, sy, "%s", text); sy += dy; strcpy_s(text, XSTR("Secondary friendly hit %", 125)); replace_one(text, "%%", "%", NAME_LENGTH - 1); gr_printf_menu(sx, sy, "%s", text); sy += 2 * dy; gr_printf_menu(sx, sy, "%s", XSTR("Assists", 126)); sy += 2 * dy; if (Game_mode & GM_MULTIPLAYER) { if (type == StatsType::MISSION_STATS) { gr_printf_menu(sx, sy, "%s", XSTR("Player Deaths", 127)); sy += 2 * dy; } if (type == StatsType::MISSION_STATS) gr_printf_menu(sx, sy, "%s", XSTR("Mission score", 1526)); else gr_printf_menu(sx, sy, "%s", XSTR("Score", 1527)); } } void show_stats_numbers(StatsType type, int sx, int sy, int dy) { switch (type) { case StatsType::MISSION_STATS: show_stats_numbers(*Player_stats, true, sx, sy, dy); break; case StatsType::ALL_TIME_CAMPAIGN_STATS: Assertion(!(Game_mode & GM_MULTIPLAYER), "ALL_TIME_CAMPAIGN_STATS are not stored for multiplayer!"); show_stats_numbers(*Player_stats, false, sx, sy, dy); break; case StatsType::ALL_TIME_EVER_STATS: if (Game_mode & GM_MULTIPLAYER) show_stats_numbers(*Player_stats, false, sx, sy, dy); // in multiplayer, the all-time-ever stats are stored in the player else show_stats_numbers(All_time_ever_stats, false, sx, sy, dy); break; default: UNREACHABLE("Unhandled StatsType %d in show_stats_numbers()", static_cast(type)); } } int stats_get_kills(StatsType type, int ship_class) { switch (type) { case StatsType::MISSION_STATS: return stats_get_kills(*Player_stats, true, ship_class); case StatsType::ALL_TIME_CAMPAIGN_STATS: return stats_get_kills(*Player_stats, false, ship_class); case StatsType::ALL_TIME_EVER_STATS: if (Game_mode & GM_MULTIPLAYER) return stats_get_kills(*Player_stats, false, ship_class); // in multiplayer, the all-time-ever stats are stored in the player else return stats_get_kills(All_time_ever_stats, false, ship_class); default: UNREACHABLE("Unhandled StatsType %d in stats_get_kills()", static_cast(type)); return 0; } } void show_stats_numbers(const scoring_struct &stats, bool use_m_stats, int sx, int sy, int dy) { float pct; int kill_count_ok, p_shots_fired, p_shots_hit, p_bonehead_hits, s_shots_fired, s_shots_hit, s_bonehead_hits, assists, score; if (use_m_stats) { kill_count_ok = stats.m_kill_count_ok; p_shots_fired = stats.mp_shots_fired; p_shots_hit = stats.mp_shots_hit; p_bonehead_hits = stats.mp_bonehead_hits; s_shots_fired = stats.ms_shots_fired; s_shots_hit = stats.ms_shots_hit; s_bonehead_hits = stats.ms_bonehead_hits; assists = stats.m_assists; score = stats.m_score; } else { kill_count_ok = stats.kill_count_ok; p_shots_fired = stats.p_shots_fired; p_shots_hit = stats.p_shots_hit; p_bonehead_hits = stats.p_bonehead_hits; s_shots_fired = stats.s_shots_fired; s_shots_hit = stats.s_shots_hit; s_bonehead_hits = stats.s_bonehead_hits; assists = stats.assists; score = stats.score; } sy += 2 * dy; // kills stats gr_printf_menu(sx, sy, "%d", kill_count_ok); sy += 2 * dy; // primary weapon stats gr_printf_menu(sx, sy, "%u", p_shots_fired); sy += dy; gr_printf_menu(sx, sy, "%u", p_shots_hit); sy += dy; gr_printf_menu(sx, sy, "%u", p_bonehead_hits); sy += dy; if (p_shots_fired > 0) pct = 100.0f * i2fl(p_shots_hit) / i2fl(p_shots_fired); else pct = 0.0f; gr_printf_menu(sx, sy, "%d%%", fl2i(pct)); sy += dy; if (p_shots_fired > 0) pct = 100.0f * i2fl(p_bonehead_hits) / i2fl(p_shots_fired); else pct = 0.0f; gr_printf_menu(sx, sy, "%d%%", fl2i(pct)); sy += 2 * dy; // secondary weapon stats gr_printf_menu(sx, sy, "%u", s_shots_fired); sy += dy; gr_printf_menu(sx, sy, "%u", s_shots_hit); sy += dy; gr_printf_menu(sx, sy, "%u", s_bonehead_hits); sy += dy; if (s_shots_fired > 0) pct = 100.0f * i2fl(s_shots_hit) / i2fl(s_shots_fired); else pct = 0.0f; gr_printf_menu(sx, sy, "%d%%", fl2i(pct)); sy += dy; if (s_shots_fired > 0) pct = 100.0f * i2fl(s_bonehead_hits) / i2fl(s_shots_fired); else pct = 0.0f; gr_printf_menu(sx, sy, "%d%%", fl2i(pct)); sy += 2 * dy; // assists and player rescues (respawns) gr_printf_menu(sx, sy, "%d", assists); sy += 2 * dy; if (Game_mode & GM_MULTIPLAYER) { if (use_m_stats) { gr_printf_menu(sx, sy, "%d", stats.m_player_deaths); sy += 2 * dy; } // score gr_printf_menu(sx, sy, "%d", score); } } int stats_get_kills(const scoring_struct &stats, bool use_m_stats, int ship_class) { Assertion(stats.kills.in_bounds(ship_class), "ship_class is out of bounds!"); if (use_m_stats) return stats.m_okKills[ship_class]; else return stats.kills[ship_class]; } void show_stats_close() { } // initialize the statistics portion of the player structure for multiplayer. Only the host of // a netgame needs to be doing this (and if fact, only he *should* be doing this) void init_multiplayer_stats( ) { scoring_struct *ptr; for (int idx=0; idx < MAX_PLAYERS; idx++) { ptr = &Players[idx].stats; scoring_level_init( ptr ); } } void set_player_stats(int pid) { Player_stats = &Net_players[pid].m_player->stats; }