mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
1468 lines
46 KiB
C++
1468 lines
46 KiB
C++
/*
|
|
* Descent 3
|
|
* Copyright (C) 2024 Parallax Software
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
--- HISTORICAL COMMENTS FOLLOW ---
|
|
|
|
* $Logfile: /DescentIII/Main/Dmfc/dmfcstats.cpp $
|
|
* $Revision: 1.1.1.1 $
|
|
* $Date: 2003/08/26 03:57:21 $
|
|
* $Author: kevinb $
|
|
*
|
|
* Functions for in-game stats system
|
|
*
|
|
* $Log: dmfcstats.cpp,v $
|
|
* Revision 1.1.1.1 2003/08/26 03:57:21 kevinb
|
|
* initial 1.5 import
|
|
*
|
|
*
|
|
* 34 10/26/99 10:32a Jeff
|
|
* fixed COM interface bug
|
|
*
|
|
* 33 9/03/99 5:48p Jeff
|
|
* fixed crash if the stats is brought up before all player records are
|
|
* recieved
|
|
*
|
|
* 32 7/14/99 11:48a Jeff
|
|
* localized text for patch fixes
|
|
*
|
|
* 31 7/11/99 6:09p Jeff
|
|
* for team games (or where the divide up by teams flag is set), process
|
|
* everyone in the game and display them, before the disconnected people,
|
|
* so everyone is displayed.
|
|
*
|
|
* 30 7/09/99 6:17p Jeff
|
|
* fixed bugs when scrolling down in a dedicated server game
|
|
*
|
|
* 29 7/06/99 11:47p Jeff
|
|
* selected pilot when stats are enabled is yourself, not server
|
|
*
|
|
* 28 5/23/99 3:04a Jason
|
|
* fixed bug with player rankings not being updated correctly
|
|
*
|
|
* 27 5/22/99 1:12a Jeff
|
|
* correctly handle Viewer_object
|
|
*
|
|
* 26 5/19/99 5:26p Jeff
|
|
* fixed crash trying to view stats before getting player records from
|
|
* server
|
|
*
|
|
* 25 5/13/99 4:55p Ardussi
|
|
* changes for compiling on the Mac
|
|
*
|
|
* 24 5/03/99 12:07p Jeff
|
|
* safety precautions
|
|
*
|
|
* 23 3/29/99 7:20p Jeff
|
|
* added vis stuff for coop stat views
|
|
*
|
|
* 22 3/27/99 4:53p Jeff
|
|
* player rankings in multiplayer games implemented. Fixed join message
|
|
* so it doesn't get cut off
|
|
*
|
|
* 21 3/17/99 12:25p Jeff
|
|
* converted DMFC to be COM interface
|
|
*
|
|
* 20 3/05/99 1:30p Jeff
|
|
* fixed 99% of the high res issues
|
|
*
|
|
* 19 2/11/99 12:51a Jeff
|
|
* changed names of exported variables
|
|
*
|
|
* 18 2/08/99 7:49p Jeff
|
|
* removed calls to get frame parameters (function is dead..pending
|
|
* removal)
|
|
*
|
|
* 17 2/08/99 5:22p Jeff
|
|
* exported rend_SetZBuffer...fixed up small view of stats
|
|
*
|
|
* 16 2/08/99 12:06a Jeff
|
|
* some new flags for more configuration. Added an option to see from a
|
|
* player's view
|
|
*
|
|
* 15 2/06/99 6:59p Jeff
|
|
* created RenderHUDGetTextLineWidth and RenderHUDGetTextHeight
|
|
*
|
|
* 14 1/31/99 7:26p Matt
|
|
* Renamed a bunch of functions to have HUD capitalized
|
|
*
|
|
* 13 1/24/99 8:31p Jeff
|
|
* updated stat manager to show team information
|
|
*
|
|
* 12 1/20/99 8:07p Jeff
|
|
* disconnected players in color mode team show up as grey
|
|
*
|
|
* 11 1/19/99 3:55a Jeff
|
|
* all strings localized out
|
|
*
|
|
* 10 1/16/99 2:55p Jeff
|
|
* possibly fixed some stat manager bugs...needs testing
|
|
*
|
|
* 9 1/13/99 4:36p Jeff
|
|
* fixed scroll bug
|
|
*
|
|
* 8 1/07/99 5:01p Jeff
|
|
* added Int3's and updated all net games to use stats manager...correctly
|
|
* too
|
|
*
|
|
* 7 1/04/99 12:21p Jeff
|
|
* added support for hosts.allow/deny and updates stats manager a little
|
|
*
|
|
* 6 12/08/98 4:47p Jeff
|
|
* umm, various changes, fixed pilot pics so that they work for everyone
|
|
* now
|
|
*
|
|
* 5 12/08/98 3:29p Jeff
|
|
* updated the team control dialog so the server can determine if they
|
|
* want to make the clients wait
|
|
*
|
|
* 4 12/08/98 12:17p Jeff
|
|
* various changes that include an improved Team Control dialog (doesn't
|
|
* switch teams until exit..) and spew/respawn players that change teams
|
|
*
|
|
* 3 12/04/98 7:04p Jeff
|
|
* almost finished up dmfc stat manager
|
|
*
|
|
* 2 12/03/98 7:05p Jeff
|
|
* updated new stats
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "gamedll_header.h"
|
|
#include "DMFC.h"
|
|
#include "dmfcinternal.h"
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
extern DMFCBase *basethis;
|
|
extern player_record Player_records[MAX_PLAYER_RECORDS];
|
|
|
|
#define ROW_PIXEL_GAP 2
|
|
#define PAGE_DISP_TIME 2.0f
|
|
#define ALPHA_IN_TIME 0.4f
|
|
|
|
#define PLIST_WIN_W 400
|
|
#define PLIST_WIN_H 440
|
|
#define PLIST_WIN_X 10
|
|
#define PLIST_WIN_Y 20
|
|
#define DLIST_WIN_W 210
|
|
#define DLIST_WIN_H 440
|
|
#define DLIST_WIN_X PLIST_WIN_W + PLIST_WIN_X + 10
|
|
#define DLIST_WIN_Y 20
|
|
|
|
// constructor
|
|
CDmfcStats::CDmfcStats() {
|
|
m_cPtrs = 0;
|
|
m_init = false;
|
|
m_flags = 0;
|
|
m_SortedPRecs = NULL;
|
|
m_pMaxNumberDisplayed = NULL;
|
|
m_MaxCount = 0;
|
|
m_iPLColCount = 0;
|
|
m_iDColCount = 0;
|
|
m_PLColInfo = NULL;
|
|
m_DColInfo = NULL;
|
|
m_PLColCallback = NULL;
|
|
m_DColCallback = NULL;
|
|
m_PLColCallbackBMP = NULL;
|
|
m_DColCallbackBMP = NULL;
|
|
m_TeamCallback = NULL;
|
|
m_GameName = NULL;
|
|
m_top_index = 0;
|
|
m_selected_index = 0;
|
|
m_bottom_index = -1;
|
|
m_enabled = false;
|
|
m_font_height = 0;
|
|
m_y_start_plist = 0;
|
|
m_y_start_detail = 0;
|
|
m_x_start_plist = 0;
|
|
m_x_start_detail = 0;
|
|
m_selected_prec = 0;
|
|
m_highlight_bmp = BAD_BITMAP_HANDLE;
|
|
m_background_bmp = BAD_BITMAP_HANDLE;
|
|
m_page_index = 0;
|
|
m_can_fit_count = -1;
|
|
m_page_display_time = 0;
|
|
m_has_multiple_pages = false;
|
|
m_alpha = 0;
|
|
alpha_in_time = 0;
|
|
}
|
|
|
|
// destructor
|
|
CDmfcStats::~CDmfcStats() {
|
|
if (m_GameName) {
|
|
free(m_GameName);
|
|
}
|
|
if (m_PLColInfo) {
|
|
free(m_PLColInfo);
|
|
}
|
|
if (m_DColInfo) {
|
|
free(m_DColInfo);
|
|
}
|
|
|
|
if (m_highlight_bmp > BAD_BITMAP_HANDLE)
|
|
DLLbm_FreeBitmap(m_highlight_bmp);
|
|
|
|
if (m_background_bmp > BAD_BITMAP_HANDLE)
|
|
DLLbm_FreeBitmap(m_background_bmp);
|
|
}
|
|
|
|
// initialization member function
|
|
bool CDmfcStats::Initialize(tDmfcStatsInit *init_info) {
|
|
m_font_height = DLLgrfont_GetHeight(basethis->Game_fonts[HUD_FONT_INDEX]);
|
|
// m_font_height = DLLRenderHUDGetTextHeight("X");
|
|
m_flags = init_info->flags;
|
|
m_SortedPRecs = init_info->SortedPlayerRecords;
|
|
if (!m_SortedPRecs)
|
|
goto error_init;
|
|
m_pMaxNumberDisplayed = init_info->MaxNumberDisplayed;
|
|
if ((m_flags & DSIF_ONLY_X_PLAYERS_SHOWN) && (!m_pMaxNumberDisplayed))
|
|
goto error_init;
|
|
|
|
m_PLColCallback = init_info->clbPlayerColumn;
|
|
m_DColCallback = init_info->clbDetailedColumn;
|
|
m_PLColCallbackBMP = init_info->clbPlayerColumnBMP;
|
|
m_DColCallbackBMP = init_info->clbDetailedColumnBMP;
|
|
m_TeamCallback = init_info->clTeamLine;
|
|
|
|
m_iPLColCount = init_info->cColumnCountPlayerList;
|
|
m_iDColCount = init_info->cColumnCountDetailed;
|
|
|
|
if (m_iPLColCount > 0 && !init_info->PlayerListColumns)
|
|
goto error_init;
|
|
|
|
if (m_iDColCount > 0 && !init_info->DetailedColumns)
|
|
goto error_init;
|
|
|
|
if (m_iPLColCount > 0) {
|
|
m_PLColInfo = (tDmfcStatsColumnInfo *)malloc(sizeof(tDmfcStatsColumnInfo) * m_iPLColCount);
|
|
if (!m_PLColInfo)
|
|
goto error_init;
|
|
memcpy(m_PLColInfo, init_info->PlayerListColumns, sizeof(tDmfcStatsColumnInfo) * m_iPLColCount);
|
|
}
|
|
|
|
if (m_iDColCount > 0) {
|
|
m_DColInfo = (tDmfcStatsColumnInfo *)malloc(sizeof(tDmfcStatsColumnInfo) * m_iDColCount);
|
|
if (!m_DColInfo) {
|
|
goto error_init;
|
|
}
|
|
memcpy(m_DColInfo, init_info->DetailedColumns, sizeof(tDmfcStatsColumnInfo) * m_iDColCount);
|
|
}
|
|
|
|
if (init_info->GameName) {
|
|
m_GameName = strdup(init_info->GameName);
|
|
}
|
|
|
|
m_y_start_plist = PLIST_WIN_Y + 2 * (m_font_height + ROW_PIXEL_GAP);
|
|
m_y_start_detail = DLIST_WIN_Y + (m_font_height + ROW_PIXEL_GAP);
|
|
m_x_start_plist = PLIST_WIN_X;
|
|
m_x_start_detail = DLIST_WIN_X;
|
|
|
|
m_highlight_bmp = DLLbm_AllocBitmap(32, 32, 0);
|
|
m_background_bmp = DLLbm_AllocBitmap(32, 32, 0);
|
|
uint16_t *data;
|
|
|
|
if (m_highlight_bmp == -1)
|
|
m_highlight_bmp = BAD_BITMAP_HANDLE;
|
|
if (m_background_bmp == -1)
|
|
m_background_bmp = BAD_BITMAP_HANDLE;
|
|
|
|
if (m_highlight_bmp > BAD_BITMAP_HANDLE) {
|
|
data = DLLbm_data(m_highlight_bmp, 0);
|
|
for (int x = 0; x < 32 * 32; x++) {
|
|
data[x] = GR_RGB16(50, 50, 50) | OPAQUE_FLAG;
|
|
}
|
|
}
|
|
|
|
if (m_background_bmp > BAD_BITMAP_HANDLE) {
|
|
data = DLLbm_data(m_background_bmp, 0);
|
|
for (int x = 0; x < 32 * 32; x++) {
|
|
data[x] = GR_RGB16(0, 0, 0) | OPAQUE_FLAG;
|
|
}
|
|
}
|
|
|
|
m_init = true;
|
|
return true;
|
|
|
|
error_init:
|
|
if (m_GameName) {
|
|
free(m_GameName);
|
|
}
|
|
if (m_PLColInfo) {
|
|
free(m_PLColInfo);
|
|
}
|
|
if (m_DColInfo) {
|
|
free(m_DColInfo);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//=================================
|
|
|
|
// enables/disables the displaying of the stats screen
|
|
void CDmfcStats::Enable(bool enable) {
|
|
m_enabled = enable;
|
|
if (enable) {
|
|
player_record *pr = PRec_GetPRecordByPnum(basethis->GetPlayerNum());
|
|
if (pr && pr->state != STATE_EMPTY) {
|
|
m_selected_prec = pr - Player_records;
|
|
} else {
|
|
m_selected_prec = 0;
|
|
}
|
|
alpha_in_time = 0;
|
|
m_alpha = 0;
|
|
m_page_index = 0;
|
|
m_can_fit_count = -1;
|
|
m_page_display_time = 0;
|
|
m_has_multiple_pages = false;
|
|
|
|
basethis->Players[basethis->GetPlayerNum()].small_dll_obj = -1;
|
|
if (m_flags & DSIF_SHOWPLAYERVIEW) {
|
|
player_record *pr = basethis->GetPlayerRecord(m_selected_prec);
|
|
if (pr && pr->state == STATE_INGAME) {
|
|
basethis->Players[basethis->GetPlayerNum()].small_dll_obj = basethis->Players[pr->pnum].objnum;
|
|
}
|
|
}
|
|
} else {
|
|
basethis->Players[basethis->GetPlayerNum()].small_dll_obj = -1;
|
|
}
|
|
}
|
|
|
|
// returns the state of the stats manager
|
|
bool CDmfcStats::IsEnabled() { return m_enabled; }
|
|
|
|
// scrolls the player list down one
|
|
void CDmfcStats::ScrollDown() {
|
|
if (CanScrollDown()) {
|
|
|
|
if (m_flags & DSIF_SEPERATE_BY_TEAM) {
|
|
// we need to handle team stats a bit different
|
|
// we must state on connected people until no more
|
|
// connected people exist, then go through the list
|
|
// through disconnected people
|
|
player_record *pr = basethis->GetPlayerRecord(m_selected_prec);
|
|
if (!pr || pr->state == STATE_EMPTY) {
|
|
m_selected_index++;
|
|
m_selected_prec = m_translate[m_selected_index];
|
|
} else {
|
|
bool isingame = (pr->state == STATE_INGAME) ? true : false;
|
|
|
|
while (1) {
|
|
m_selected_index++;
|
|
if (m_selected_index == (m_MaxCount - 1)) {
|
|
// we hit the bottom
|
|
m_selected_prec = m_translate[m_selected_index];
|
|
|
|
if (!isingame)
|
|
break; // we have gotten to the bottom of everyone
|
|
|
|
pr = basethis->GetPlayerRecord(m_selected_prec);
|
|
|
|
// check to see if we want this player
|
|
if (pr->state == STATE_INGAME)
|
|
break;
|
|
|
|
// now go through the disconnected folk
|
|
isingame = false;
|
|
m_selected_index = -1; // set to -1, since it will be incremented right away
|
|
continue;
|
|
}
|
|
|
|
m_selected_prec = m_translate[m_selected_index];
|
|
pr = basethis->GetPlayerRecord(m_selected_prec);
|
|
|
|
if (!pr || pr->state == STATE_EMPTY)
|
|
continue;
|
|
|
|
// should we use this player?
|
|
if (isingame) {
|
|
if (pr->state != STATE_INGAME)
|
|
continue; // move to the next
|
|
} else {
|
|
if (pr->state != STATE_DISCONNECTED)
|
|
continue; // move to the next
|
|
}
|
|
|
|
// all matches up if we haven't continue by here
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
m_selected_index++;
|
|
m_selected_prec = m_translate[m_selected_index];
|
|
}
|
|
|
|
m_page_index = 0;
|
|
m_can_fit_count = -1;
|
|
m_page_display_time = 0;
|
|
m_has_multiple_pages = false;
|
|
|
|
basethis->Players[basethis->GetPlayerNum()].small_dll_obj = -1;
|
|
if (m_flags & DSIF_SHOWPLAYERVIEW) {
|
|
player_record *pr = basethis->GetPlayerRecord(m_selected_prec);
|
|
if (pr && pr->state == STATE_INGAME) {
|
|
basethis->Players[basethis->GetPlayerNum()].small_dll_obj = basethis->Players[pr->pnum].objnum;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// scrolls the player list up one
|
|
void CDmfcStats::ScrollUp() {
|
|
if (CanScrollUp()) {
|
|
if (m_flags & DSIF_SEPERATE_BY_TEAM) {
|
|
// we need to handle team stats a bit different
|
|
// we must state on connected people until no more
|
|
// connected people exist, then go through the list
|
|
// through disconnected people
|
|
player_record *pr = basethis->GetPlayerRecord(m_selected_prec);
|
|
if (!pr || pr->state == STATE_EMPTY) {
|
|
m_selected_index--;
|
|
m_selected_prec = m_translate[m_selected_index];
|
|
} else {
|
|
bool isingame = (pr->state == STATE_INGAME) ? true : false;
|
|
|
|
while (1) {
|
|
m_selected_index--;
|
|
if (m_selected_index == 0) {
|
|
// we hit the top
|
|
m_selected_prec = m_translate[m_selected_index];
|
|
|
|
if (isingame)
|
|
break; // we have gotten to the top of everyone
|
|
|
|
pr = basethis->GetPlayerRecord(m_selected_prec);
|
|
|
|
// check to see if we want this player
|
|
if (pr->state == STATE_DISCONNECTED)
|
|
break;
|
|
|
|
// now go through the connected folk
|
|
isingame = true;
|
|
m_selected_index = m_MaxCount; // set to m_MaxCount, since it will be incremented right away
|
|
continue;
|
|
}
|
|
|
|
m_selected_prec = m_translate[m_selected_index];
|
|
pr = basethis->GetPlayerRecord(m_selected_prec);
|
|
|
|
if (!pr || pr->state == STATE_EMPTY)
|
|
continue;
|
|
|
|
// should we use this player?
|
|
if (isingame) {
|
|
if (pr->state != STATE_INGAME)
|
|
continue; // move to the next
|
|
} else {
|
|
if (pr->state != STATE_DISCONNECTED)
|
|
continue; // move to the next
|
|
}
|
|
|
|
// all matches up if we haven't continue by here
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
m_selected_index--;
|
|
m_selected_prec = m_translate[m_selected_index];
|
|
}
|
|
|
|
m_page_index = 0;
|
|
m_can_fit_count = -1;
|
|
m_page_display_time = 0;
|
|
m_has_multiple_pages = false;
|
|
|
|
basethis->Players[basethis->GetPlayerNum()].small_dll_obj = -1;
|
|
if (m_flags & DSIF_SHOWPLAYERVIEW) {
|
|
player_record *pr = basethis->GetPlayerRecord(m_selected_prec);
|
|
if (pr && pr->state == STATE_INGAME) {
|
|
basethis->Players[basethis->GetPlayerNum()].small_dll_obj = basethis->Players[pr->pnum].objnum;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// returns true if the player list can scroll down any more
|
|
bool CDmfcStats::CanScrollDown() { return (m_selected_index < (m_MaxCount - 1)) ? true : false; }
|
|
|
|
// returns true if the player list can scroll up any more
|
|
bool CDmfcStats::CanScrollUp() { return (bool)(m_selected_index > 0); }
|
|
|
|
void drawline(int lx, int rx, int y, float perc) {
|
|
int width = ((float)(rx - lx)) * perc;
|
|
int center = lx + (rx - lx) / 2;
|
|
|
|
width = width / 2;
|
|
lx = center - width;
|
|
rx = center + width;
|
|
|
|
/*
|
|
rx = lx + width;
|
|
*/
|
|
|
|
int ny = y;
|
|
basethis->ConvertHUDCoord(lx, y, &lx, &y);
|
|
basethis->ConvertHUDCoord(rx, ny, &rx, &ny);
|
|
DLLrend_DrawLine(lx, y, rx, ny);
|
|
}
|
|
|
|
// renders the stats screen
|
|
void CDmfcStats::Render() {
|
|
int i, c, curr_x, curr_y;
|
|
player_record *pr;
|
|
char buffer[256];
|
|
DLLrend_SetFlatColor(GR_WHITE);
|
|
float perc_done = (alpha_in_time < ALPHA_IN_TIME) ? (alpha_in_time / ALPHA_IN_TIME) : 1.0f;
|
|
bool need_to_display_observer_icon;
|
|
bool is_dedicated_server;
|
|
int last_team = -1;
|
|
int teams_displayed = 0;
|
|
bool team_disp[DLLMAX_TEAMS];
|
|
|
|
for (i = 0; i < DLLMAX_TEAMS; i++) {
|
|
team_disp[i] = false;
|
|
}
|
|
|
|
// render all the player list columns
|
|
curr_x = m_x_start_plist;
|
|
curr_y = PLIST_WIN_Y + 1;
|
|
|
|
// render window and headings
|
|
DLLRenderHUDQuad(PLIST_WIN_X, PLIST_WIN_Y, PLIST_WIN_W, PLIST_WIN_H, 0, 0, 1, 1, m_background_bmp, perc_done * 200.0f,
|
|
0);
|
|
|
|
DLLgrtext_SetFont(basethis->Game_fonts[HUD_FONT_INDEX]);
|
|
int l_width = DLLRenderHUDGetTextLineWidth(m_GameName);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, (PLIST_WIN_W / 2) - (l_width / 2), curr_y, m_GameName);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
for (c = 0; c < m_iPLColCount; c++) {
|
|
strcpy(buffer, m_PLColInfo[c].title);
|
|
basethis->ClipString(m_PLColInfo[c].width, buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, curr_x, curr_y, buffer);
|
|
curr_x += m_PLColInfo[c].width;
|
|
}
|
|
curr_y += (m_font_height + (ROW_PIXEL_GAP) / 2);
|
|
if (m_iPLColCount > 0)
|
|
drawline(PLIST_WIN_X, PLIST_WIN_X + PLIST_WIN_W - 1, curr_y, perc_done);
|
|
|
|
curr_x = m_x_start_plist;
|
|
curr_y = m_y_start_plist + 4;
|
|
|
|
bool displaying_in_game_players = true;
|
|
bool not_overflowing = true;
|
|
bool update_bottom_index = true;
|
|
|
|
redisplay_list:
|
|
|
|
for (i = m_top_index; i < m_MaxCount; i++) {
|
|
pr = PRec_GetPRecord(m_translate[i]);
|
|
|
|
if (!pr || pr->state == STATE_EMPTY)
|
|
continue;
|
|
|
|
if (m_flags & DSIF_SEPERATE_BY_TEAM) {
|
|
// for team games we seperate disconnected and ingame people
|
|
if (displaying_in_game_players) {
|
|
// filter out non-ingame players
|
|
if (pr->state != STATE_INGAME)
|
|
continue;
|
|
} else {
|
|
// filter out non-disconnected players
|
|
if (pr->state != STATE_DISCONNECTED)
|
|
continue;
|
|
}
|
|
}
|
|
|
|
is_dedicated_server = basethis->IsPlayerDedicatedServer(pr);
|
|
|
|
if ((m_flags & DSIF_SEPERATE_BY_TEAM) && (last_team != pr->team) && !is_dedicated_server) {
|
|
i--; // this line doesn't count
|
|
last_team = pr->team;
|
|
buffer[0] = '\0';
|
|
|
|
if (!team_disp[last_team]) {
|
|
teams_displayed++;
|
|
team_disp[last_team] = true;
|
|
}
|
|
|
|
if (m_TeamCallback) {
|
|
snprintf(buffer, sizeof(buffer), DTXT_TEAMLABEL, basethis->GetTeamString(pr->team));
|
|
int length = strlen(buffer);
|
|
buffer[length] = ' '; // lose the \0
|
|
|
|
(*m_TeamCallback)(pr->team, &buffer[length], sizeof(buffer) - length - 1);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
|
|
int width = (PLIST_WIN_X + PLIST_WIN_W - curr_x - 5);
|
|
float ratio = DEFAULT_HUD_WIDTH / ((float)*basethis->Game_window_w);
|
|
|
|
// clip the string to the width
|
|
basethis->ClipString(width, buffer, false);
|
|
|
|
int l = ratio * ((float)DLLRenderHUDGetTextLineWidth(buffer));
|
|
int x = (width / 2) - (l / 2);
|
|
|
|
DLLRenderHUDText(basethis->GetTeamColor(pr->team), m_alpha, 0, x, curr_y, buffer);
|
|
}
|
|
|
|
goto skip_line; // don't process this line
|
|
}
|
|
|
|
// draw the highlight bar if selected bitmap
|
|
if (m_selected_index == i) {
|
|
DLLRenderHUDQuad(m_x_start_plist, curr_y, PLIST_WIN_W, m_font_height, 0, 0, 1, 1, m_highlight_bmp,
|
|
perc_done * 128.0f, 0);
|
|
}
|
|
|
|
need_to_display_observer_icon =
|
|
(pr->state == STATE_INGAME) ? (basethis->IsPlayerObserver(pr->pnum) ? true : false) : false;
|
|
|
|
for (c = 0; c < m_iPLColCount; c++) {
|
|
buffer[0] = '\0';
|
|
|
|
if (!is_dedicated_server || m_PLColInfo[c].type == DSCOL_PILOT_NAME || m_PLColInfo[c].type == DSCOL_BLANK) {
|
|
switch (m_PLColInfo[c].type) {
|
|
case DSCOL_BMP:
|
|
break;
|
|
case DSCOL_KILLS_LEVEL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.kills[DSTAT_LEVEL]);
|
|
break;
|
|
case DSCOL_KILLS_OVERALL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.kills[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_KILLS_BOTH:
|
|
snprintf(buffer, sizeof(buffer), "%d[%d]", pr->dstats.kills[DSTAT_LEVEL], pr->dstats.kills[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_DEATHS_LEVEL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.deaths[DSTAT_LEVEL]);
|
|
break;
|
|
case DSCOL_DEATHS_OVERALL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.deaths[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_DEATHS_BOTH:
|
|
snprintf(buffer, sizeof(buffer), "%d[%d]", pr->dstats.deaths[DSTAT_LEVEL], pr->dstats.deaths[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_SUICIDES_LEVEL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.suicides[DSTAT_LEVEL]);
|
|
break;
|
|
case DSCOL_SUICIDES_OVERALL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.suicides[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_SUICIDES_BOTH:
|
|
snprintf(buffer, sizeof(buffer), "%d[%d]", pr->dstats.suicides[DSTAT_LEVEL],
|
|
pr->dstats.suicides[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_PILOT_NAME:
|
|
strcpy(buffer, pr->callsign);
|
|
break;
|
|
case DSCOL_PILOT_TEAM:
|
|
snprintf(buffer, sizeof(buffer), "%s", basethis->GetTeamString(pr->team));
|
|
break;
|
|
case DSCOL_PING:
|
|
if (pr->state == STATE_INGAME)
|
|
snprintf(buffer, sizeof(buffer), "%.0f", basethis->NetPlayers[pr->pnum].ping_time * 1000.0f);
|
|
else
|
|
strcpy(buffer, "N/A");
|
|
break;
|
|
case DSCOL_CUSTOM:
|
|
if (m_PLColCallback)
|
|
(*m_PLColCallback)(m_translate[i], c, buffer, sizeof(buffer));
|
|
break;
|
|
case DSCOL_BLANK:
|
|
buffer[0] = '\0';
|
|
break;
|
|
}
|
|
} else {
|
|
strcpy(buffer, "N/A");
|
|
}
|
|
|
|
int width_to_use = m_PLColInfo[c].width;
|
|
|
|
if (m_PLColInfo[c].type != DSCOL_BMP) {
|
|
|
|
if (need_to_display_observer_icon) {
|
|
if (m_flags & DSIF_SHOW_OBSERVERICON && m_PLColInfo[c].type == DSCOL_PILOT_NAME) {
|
|
need_to_display_observer_icon = false;
|
|
DLLRenderHUDQuad(curr_x, curr_y, m_font_height, m_font_height, 0, 0, 1, 1, basethis->hBitmapObserver,
|
|
m_alpha, 0);
|
|
curr_x += m_font_height + 1;
|
|
width_to_use -= (m_font_height + 1);
|
|
}
|
|
}
|
|
|
|
// clip the string to the width
|
|
basethis->ClipString(std::min(width_to_use, (PLIST_WIN_X + PLIST_WIN_W - curr_x - 5)), buffer, false);
|
|
|
|
// print out string
|
|
ddgr_color color;
|
|
switch (m_PLColInfo[c].color_type) {
|
|
case DSCOLOR_NORMAL:
|
|
color = (pr->state == STATE_INGAME) ? GR_GREEN : GR_GREY;
|
|
break;
|
|
case DSCOLOR_TEAM:
|
|
color = (m_PLColInfo[c].type == DSCOL_PILOT_NAME)
|
|
? (basethis->GetTeamColor(pr->team))
|
|
: ((pr->state == STATE_INGAME) ? (basethis->GetTeamColor(pr->team)) : (GR_GREY));
|
|
break;
|
|
case DSCOLOR_SHIPCOLOR:
|
|
color = (pr->state == STATE_INGAME) ? basethis->Player_colors[pr->pnum] : GR_GREY;
|
|
break;
|
|
case DSCOLOR_CUSTOM:
|
|
color = m_PLColInfo[c].color;
|
|
break;
|
|
default:
|
|
color = (pr->state == STATE_INGAME) ? GR_GREEN : GR_GREY;
|
|
break;
|
|
};
|
|
|
|
DLLRenderHUDText(color, m_alpha, 0, curr_x, curr_y, buffer);
|
|
} else {
|
|
|
|
// we need to draw a custom bitmap
|
|
(*m_PLColCallbackBMP)(m_translate[i], c, curr_x, curr_y, m_PLColInfo[c].width, m_font_height + ROW_PIXEL_GAP,
|
|
m_alpha);
|
|
}
|
|
|
|
curr_x += width_to_use;
|
|
|
|
if (curr_x > PLIST_WIN_W + PLIST_WIN_X)
|
|
break; // we can't fit anymore columns
|
|
}
|
|
|
|
// update the bottom index
|
|
if (update_bottom_index || i > m_bottom_index) {
|
|
m_bottom_index = i;
|
|
update_bottom_index = false; // we force an update the first time through
|
|
}
|
|
skip_line:
|
|
curr_x = m_x_start_plist;
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
|
|
if ((curr_y + m_font_height + ROW_PIXEL_GAP) > PLIST_WIN_H + PLIST_WIN_Y) {
|
|
not_overflowing = false;
|
|
break; // we are done here
|
|
}
|
|
}
|
|
|
|
if ((m_flags & DSIF_SEPERATE_BY_TEAM) && displaying_in_game_players && not_overflowing) {
|
|
// we can continue displaying, but just the disconnected people now
|
|
last_team = -1; // so we redraw the team names
|
|
displaying_in_game_players = false;
|
|
|
|
// display the disconnected people
|
|
goto redisplay_list;
|
|
}
|
|
|
|
// Display the remaining teams
|
|
if ((m_flags & DSIF_SEPERATE_BY_TEAM) && (teams_displayed < DLLMAX_TEAMS) &&
|
|
((curr_y + m_font_height + ROW_PIXEL_GAP) < PLIST_WIN_H + PLIST_WIN_Y)) {
|
|
int tcount = basethis->GetNumTeams();
|
|
for (i = 0; i < tcount; i++) {
|
|
if (team_disp[i])
|
|
continue;
|
|
|
|
team_disp[i] = true;
|
|
last_team = i;
|
|
buffer[0] = '\0';
|
|
teams_displayed++;
|
|
|
|
if (m_TeamCallback) {
|
|
snprintf(buffer, sizeof(buffer), DTXT_TEAMLABEL, basethis->GetTeamString(i));
|
|
int length = strlen(buffer);
|
|
buffer[length] = ' '; // lose the \0
|
|
|
|
(*m_TeamCallback)(i, &buffer[length], sizeof(buffer) - length - 1);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
|
|
int width = (PLIST_WIN_X + PLIST_WIN_W - curr_x - 5);
|
|
float ratio = DEFAULT_HUD_WIDTH / ((float)*basethis->Game_window_w);
|
|
|
|
// clip the string to the width
|
|
basethis->ClipString(width, buffer, false);
|
|
|
|
int l = ratio * ((float)DLLRenderHUDGetTextLineWidth(buffer));
|
|
int x = (width / 2) - (l / 2);
|
|
|
|
DLLRenderHUDText(basethis->GetTeamColor(i), m_alpha, 0, x, curr_y, buffer);
|
|
}
|
|
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
|
|
if ((curr_y + m_font_height + ROW_PIXEL_GAP) > PLIST_WIN_H + PLIST_WIN_Y) {
|
|
break; // we are done here
|
|
}
|
|
}
|
|
}
|
|
|
|
// render the detailed menu
|
|
curr_x = m_x_start_detail;
|
|
curr_y = DLIST_WIN_Y + 1;
|
|
|
|
DLLRenderHUDQuad(DLIST_WIN_X, DLIST_WIN_Y, DLIST_WIN_W, DLIST_WIN_H, 0, 0, 1, 1, m_background_bmp, perc_done * 200.0f,
|
|
0);
|
|
pr = PRec_GetPRecord(m_selected_prec);
|
|
if (!pr || pr->state == STATE_EMPTY || pr->pinfo == NULL)
|
|
return;
|
|
|
|
is_dedicated_server = basethis->IsPlayerDedicatedServer(pr);
|
|
|
|
// display the heading for the player
|
|
strcpy(buffer, pr->callsign);
|
|
basethis->ClipString(DLIST_WIN_W, buffer, false);
|
|
l_width = DLLRenderHUDGetTextLineWidth(buffer);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, DLIST_WIN_X + (DLIST_WIN_W / 2) - (l_width / 2), curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
|
|
if (m_flags & DSIF_SHOW_PIC && pr->state == STATE_INGAME && !is_dedicated_server) {
|
|
|
|
if (basethis->PilotPicBmpHandles[pr->pnum] > BAD_BITMAP_HANDLE) {
|
|
// display the pilot picture
|
|
DLLRenderHUDQuad(DLIST_WIN_X + (DLIST_WIN_W / 2) - 32, curr_y, 64, 64, 0, 0, 1, 1,
|
|
basethis->PilotPicBmpHandles[pr->pnum], m_alpha, 0);
|
|
curr_y += 70;
|
|
} else if (basethis->AreLogosEnabled()) { // only show logo's if enabled
|
|
bool animated;
|
|
int bmp_to_disp = BAD_BITMAP_HANDLE;
|
|
int logo_handle = basethis->GetPlayerLogoBmp(pr->pnum, &animated);
|
|
if (logo_handle != -1) {
|
|
if (animated) {
|
|
// display a vclip
|
|
|
|
vclip *vc = &basethis->GameVClips[logo_handle];
|
|
float interval = 1.0f / 10.0f;
|
|
int frames_elapsed = (int)(alpha_in_time / interval);
|
|
|
|
int frame = frames_elapsed % vc->num_frames;
|
|
bmp_to_disp = vc->frames[frame];
|
|
|
|
} else {
|
|
bmp_to_disp = logo_handle;
|
|
}
|
|
DLLRenderHUDQuad(DLIST_WIN_X + (DLIST_WIN_W / 2) - 32, curr_y, 64, 64, 0, 0, 1, 1, bmp_to_disp, m_alpha, 0);
|
|
curr_y += 70;
|
|
}
|
|
}
|
|
}
|
|
|
|
int old_y = curr_y;
|
|
int max_w = 0;
|
|
int x_to_use = curr_x + 5;
|
|
PInfo *pi;
|
|
tPExtraInfo *ei;
|
|
pi = (PInfo *)pr->pinfo;
|
|
ei = pi->GetExtraInfo();
|
|
|
|
// drawline(DLIST_WIN_X,DLIST_WIN_X+DLIST_WIN_W-1,curr_y,perc_done); curr_y += 3;
|
|
|
|
// game status
|
|
strcpy(buffer, DTXT_STAT_STATUS);
|
|
// l_width = (DLLgrtext_GetTextLineWidth(buffer)*(*basethis->Hud_aspect_x));
|
|
l_width = DLLRenderHUDGetTextLineWidth(buffer);
|
|
max_w = l_width;
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
|
|
// ranking (if available)
|
|
int player_rank;
|
|
char player_rank_buffer[64];
|
|
player_rank =
|
|
(pr->state == STATE_INGAME && !is_dedicated_server) ? GetPlayerRankIndex(pr->pnum, player_rank_buffer) : -1;
|
|
|
|
if (player_rank != -1) {
|
|
strcpy(buffer, DTXT_RANK);
|
|
l_width = DLLRenderHUDGetTextLineWidth(buffer);
|
|
if (l_width > max_w)
|
|
max_w = l_width;
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
|
|
// team (if available)
|
|
if (basethis->GetNumTeams() > 1 && !is_dedicated_server) {
|
|
strcpy(buffer, DTXT_STAT_TEAM);
|
|
l_width = DLLRenderHUDGetTextLineWidth(buffer);
|
|
if (l_width > max_w)
|
|
max_w = l_width;
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
|
|
// time in game
|
|
strcpy(buffer, DTXT_STAT_PLAYTIME);
|
|
l_width = DLLRenderHUDGetTextLineWidth(buffer);
|
|
if (l_width > max_w)
|
|
max_w = l_width;
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
|
|
uint8_t streak_type = 0;
|
|
|
|
if (!is_dedicated_server) {
|
|
// none of this should be displayed for a dedicated server
|
|
|
|
if (ei->kills_in_a_row)
|
|
streak_type = 1;
|
|
else if (ei->deaths_in_a_row)
|
|
streak_type = 2;
|
|
|
|
// kills/deaths in a row
|
|
if (streak_type > 0) {
|
|
strcpy(buffer, DTXT_STAT_STREAK);
|
|
l_width = DLLRenderHUDGetTextLineWidth(buffer);
|
|
if (l_width > max_w)
|
|
max_w = l_width;
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
|
|
// last player you killed
|
|
if (!(m_flags & DSIF_NOLASTVICTIM)) {
|
|
strcpy(buffer, DTXT_STAT_LASTVICTIM);
|
|
l_width = DLLRenderHUDGetTextLineWidth(buffer);
|
|
if (l_width > max_w)
|
|
max_w = l_width;
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
|
|
// last player to kill you
|
|
if (!(m_flags & DSIF_NOLASTKILLER)) {
|
|
strcpy(buffer, DTXT_STAT_LASTKILLER);
|
|
l_width = DLLRenderHUDGetTextLineWidth(buffer);
|
|
if (l_width > max_w)
|
|
max_w = l_width;
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
}
|
|
|
|
curr_y = old_y;
|
|
x_to_use += (max_w + 5);
|
|
int width_to_clip;
|
|
|
|
width_to_clip = DLIST_WIN_X + DLIST_WIN_W - x_to_use - 5;
|
|
|
|
// game status
|
|
if (pr->state == STATE_INGAME) {
|
|
if (basethis->IsPlayerDedicatedServer(pr)) {
|
|
strcpy(buffer, DTXT_STAT_SERVER);
|
|
} else {
|
|
if (basethis->IsPlayerObserver(pr->pnum)) {
|
|
strcpy(buffer, DTXT_STAT_OBSERVER);
|
|
} else {
|
|
strcpy(buffer, DTXT_STAT_PLAYING);
|
|
}
|
|
}
|
|
} else {
|
|
strcpy(buffer, DTXT_STAT_DISCONNECTED);
|
|
}
|
|
basethis->ClipString(width_to_clip, buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
|
|
// player ranking (if available)
|
|
if (player_rank != -1) {
|
|
basethis->ClipString(width_to_clip, player_rank_buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, player_rank_buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
|
|
// team (if available)
|
|
if (basethis->GetNumTeams() > 1 && !is_dedicated_server) {
|
|
strcpy(buffer, basethis->GetTeamString(pr->team));
|
|
basethis->ClipString(width_to_clip, buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
|
|
// time in game
|
|
strcpy(buffer, basethis->GetTimeString(basethis->GetTimeInGame(m_selected_prec)));
|
|
basethis->ClipString(width_to_clip, buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
|
|
if (!is_dedicated_server) {
|
|
switch (streak_type) {
|
|
case 1: // kills in a row
|
|
snprintf(buffer, sizeof(buffer), "%d %s", ei->kills_in_a_row,
|
|
(ei->kills_in_a_row == 1) ? DTXT_STAT_KILL : DTXT_STAT_KILLS);
|
|
basethis->ClipString(width_to_clip, buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
break;
|
|
case 2: // deaths in a row
|
|
snprintf(buffer, sizeof(buffer), "%d %s", ei->deaths_in_a_row,
|
|
(ei->deaths_in_a_row == 1) ? DTXT_STAT_DEATH : DTXT_STAT_DEATHS);
|
|
basethis->ClipString(width_to_clip, buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
player_record *tpr;
|
|
// last player you killed
|
|
if (ei->last_kill_num != -1) {
|
|
tpr = PRec_GetPRecord(ei->last_kill_num);
|
|
if (tpr && tpr->state != STATE_EMPTY) {
|
|
strcpy(buffer, tpr->callsign);
|
|
} else {
|
|
buffer[0] = '\0';
|
|
}
|
|
} else {
|
|
buffer[0] = '\0';
|
|
}
|
|
if (!(m_flags & DSIF_NOLASTVICTIM)) {
|
|
basethis->ClipString(width_to_clip, buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
|
|
// last player to kill you
|
|
if (ei->last_death_num != -1) {
|
|
tpr = PRec_GetPRecord(ei->last_death_num);
|
|
if (tpr && tpr->state != STATE_EMPTY) {
|
|
strcpy(buffer, tpr->callsign);
|
|
} else {
|
|
buffer[0] = '\0';
|
|
}
|
|
} else {
|
|
buffer[0] = '\0';
|
|
}
|
|
if (!(m_flags & DSIF_NOLASTKILLER)) {
|
|
basethis->ClipString(width_to_clip, buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, x_to_use, curr_y, buffer);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
}
|
|
|
|
// drawline(DLIST_WIN_X,DLIST_WIN_X+DLIST_WIN_W-1,curr_y,perc_done); curr_y += 10;
|
|
|
|
curr_x = m_x_start_detail;
|
|
|
|
// now do the detail columns (if any for this player)
|
|
for (c = 0; c < m_iDColCount; c++) {
|
|
strcpy(buffer, m_DColInfo[c].title);
|
|
basethis->ClipString(m_DColInfo[c].width, buffer, false);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, curr_x, curr_y, buffer);
|
|
curr_x += m_DColInfo[c].width;
|
|
}
|
|
|
|
if (m_iDColCount > 0)
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
curr_x = m_x_start_detail;
|
|
|
|
if (m_iDColCount > 0)
|
|
drawline(DLIST_WIN_X, DLIST_WIN_X + DLIST_WIN_W - 1, curr_y, perc_done);
|
|
curr_y += 3;
|
|
|
|
for (c = 0; c < m_iDColCount; c++) {
|
|
buffer[0] = '\0';
|
|
if (!is_dedicated_server || m_DColInfo[c].type == DSCOL_PILOT_NAME || m_DColInfo[c].type == DSCOL_BLANK) {
|
|
switch (m_DColInfo[c].type) {
|
|
case DSCOL_BMP:
|
|
break;
|
|
case DSCOL_KILLS_LEVEL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.kills[DSTAT_LEVEL]);
|
|
break;
|
|
case DSCOL_KILLS_OVERALL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.kills[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_KILLS_BOTH:
|
|
snprintf(buffer, sizeof(buffer), "%d[%d]", pr->dstats.kills[DSTAT_LEVEL], pr->dstats.kills[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_DEATHS_LEVEL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.deaths[DSTAT_LEVEL]);
|
|
break;
|
|
case DSCOL_DEATHS_OVERALL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.deaths[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_DEATHS_BOTH:
|
|
snprintf(buffer, sizeof(buffer), "%d[%d]", pr->dstats.deaths[DSTAT_LEVEL], pr->dstats.deaths[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_SUICIDES_LEVEL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.suicides[DSTAT_LEVEL]);
|
|
break;
|
|
case DSCOL_SUICIDES_OVERALL:
|
|
snprintf(buffer, sizeof(buffer), "%d", pr->dstats.suicides[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_SUICIDES_BOTH:
|
|
snprintf(buffer, sizeof(buffer), "%d[%d]", pr->dstats.suicides[DSTAT_LEVEL],
|
|
pr->dstats.suicides[DSTAT_OVERALL]);
|
|
break;
|
|
case DSCOL_PILOT_NAME:
|
|
strcpy(buffer, pr->callsign);
|
|
break;
|
|
case DSCOL_PILOT_TEAM:
|
|
snprintf(buffer, sizeof(buffer), "%s", basethis->GetTeamString(pr->team));
|
|
break;
|
|
case DSCOL_PING:
|
|
if (pr->state == STATE_INGAME)
|
|
snprintf(buffer, sizeof(buffer), "%.0f", basethis->NetPlayers[pr->pnum].ping_time * 1000.0f);
|
|
else
|
|
strcpy(buffer, "---");
|
|
break;
|
|
case DSCOL_CUSTOM:
|
|
if (m_DColCallback)
|
|
(*m_DColCallback)(m_selected_prec, c, buffer, sizeof(buffer));
|
|
break;
|
|
case DSCOL_BLANK:
|
|
buffer[0] = '\0';
|
|
break;
|
|
}
|
|
} else {
|
|
strcpy(buffer, "N/A");
|
|
}
|
|
|
|
if (m_DColInfo[c].type != DSCOL_BMP) {
|
|
|
|
// clip the string to the width
|
|
basethis->ClipString(std::min(m_DColInfo[c].width, (DLIST_WIN_X + DLIST_WIN_W - curr_x - 5)), buffer, false);
|
|
|
|
// print out string
|
|
ddgr_color color;
|
|
switch (m_DColInfo[c].color_type) {
|
|
case DSCOLOR_NORMAL:
|
|
color = (pr->state == STATE_INGAME) ? GR_GREEN : GR_GREY;
|
|
break;
|
|
case DSCOLOR_TEAM:
|
|
color = basethis->GetTeamColor(pr->team);
|
|
break;
|
|
case DSCOLOR_SHIPCOLOR:
|
|
color = (pr->state == STATE_INGAME) ? basethis->Player_colors[pr->pnum] : GR_GREY;
|
|
break;
|
|
case DSCOLOR_CUSTOM:
|
|
color = m_DColInfo[c].color;
|
|
break;
|
|
default:
|
|
color = (pr->state == STATE_INGAME) ? GR_GREEN : GR_GREY;
|
|
break;
|
|
};
|
|
|
|
DLLRenderHUDText(color, m_alpha, 0, curr_x, curr_y, buffer);
|
|
|
|
} else {
|
|
// we need to draw a custom bitmap
|
|
(*m_DColCallbackBMP)(m_selected_prec, c, curr_x, curr_y, m_DColInfo[c].width, m_font_height + ROW_PIXEL_GAP,
|
|
m_alpha);
|
|
}
|
|
|
|
curr_x += m_DColInfo[c].width;
|
|
|
|
if (curr_x > DLIST_WIN_W + DLIST_WIN_X)
|
|
break; // we can't fit anymore columns
|
|
}
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
|
|
// finally do the who-killed-who stats for the player
|
|
int col_callsign, col_kills, col_deaths;
|
|
col_callsign = m_x_start_detail + 5;
|
|
col_kills = col_callsign + 100;
|
|
col_deaths = col_kills + 50;
|
|
int colw_callsign, colw_kills, colw_deaths;
|
|
colw_callsign = col_kills - col_callsign;
|
|
colw_kills = col_deaths - col_kills;
|
|
colw_deaths = DLIST_WIN_X + DLIST_WIN_W - col_deaths;
|
|
|
|
if (!(m_flags & DSIF_NODETAILEDINFO)) {
|
|
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, col_callsign, curr_y, DTXT_STAT_PILOTNAMELABEL);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, col_kills, curr_y, DTXT_STAT_KILLS);
|
|
DLLRenderHUDText(GR_WHITE, m_alpha, 0, col_deaths, curr_y, DTXT_STAT_DEATHS);
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
drawline(DLIST_WIN_X, DLIST_WIN_X + DLIST_WIN_W - 1, curr_y, perc_done);
|
|
curr_y += 3;
|
|
|
|
if (m_can_fit_count == -1) {
|
|
// we need to recalculate the how-many-items-can-fit-on-this-page value
|
|
int count = 0;
|
|
int y = curr_y;
|
|
|
|
while (y + (m_font_height + ROW_PIXEL_GAP) < DLIST_WIN_H + DLIST_WIN_Y) {
|
|
count++;
|
|
y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
m_can_fit_count = count;
|
|
}
|
|
|
|
tPInfoStat stat;
|
|
player_record *dpr;
|
|
int stats_displayed = 0;
|
|
bool clean_exit = true;
|
|
int start_index = (m_page_index * m_can_fit_count);
|
|
bool team_game = (basethis->GetNumTeams() > 1) ? true : false;
|
|
|
|
if (basethis->FindPInfoStatFirst(m_selected_prec, &stat)) {
|
|
if (stat.slot != m_selected_prec) {
|
|
dpr = basethis->GetPlayerRecord(stat.slot);
|
|
stats_displayed++;
|
|
|
|
ASSERT(dpr != NULL);
|
|
if (dpr && start_index < stats_displayed) {
|
|
ddgr_color color;
|
|
color = (dpr->state == STATE_INGAME)
|
|
? ((team_game) ? basethis->GetTeamColor(dpr->team) : basethis->Player_colors[dpr->pnum])
|
|
: GR_GREY;
|
|
|
|
strcpy(buffer, dpr->callsign);
|
|
basethis->ClipString(colw_callsign - 5, buffer, false);
|
|
DLLRenderHUDText(color, m_alpha, 0, col_callsign, curr_y, buffer);
|
|
|
|
snprintf(buffer, sizeof(buffer), "%d", stat.kills);
|
|
basethis->ClipString(colw_kills - 5, buffer, false);
|
|
DLLRenderHUDText(color, m_alpha, 0, col_kills, curr_y, buffer);
|
|
|
|
snprintf(buffer, sizeof(buffer), "%d", stat.deaths);
|
|
basethis->ClipString(colw_deaths - 5, buffer, false);
|
|
DLLRenderHUDText(color, m_alpha, 0, col_deaths, curr_y, buffer);
|
|
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
}
|
|
|
|
while (basethis->FindPInfoStatNext(&stat)) {
|
|
if (stat.slot != m_selected_prec) {
|
|
dpr = basethis->GetPlayerRecord(stat.slot);
|
|
stats_displayed++;
|
|
|
|
ASSERT(dpr != NULL);
|
|
if (dpr && start_index < stats_displayed) {
|
|
ddgr_color color;
|
|
color = (dpr->state == STATE_INGAME)
|
|
? ((team_game) ? basethis->GetTeamColor(dpr->team) : basethis->Player_colors[dpr->pnum])
|
|
: GR_GREY;
|
|
|
|
strcpy(buffer, dpr->callsign);
|
|
basethis->ClipString(colw_callsign - 5, buffer, false);
|
|
DLLRenderHUDText(color, m_alpha, 0, col_callsign, curr_y, buffer);
|
|
|
|
snprintf(buffer, sizeof(buffer), "%d", stat.kills);
|
|
basethis->ClipString(colw_kills - 5, buffer, false);
|
|
DLLRenderHUDText(color, m_alpha, 0, col_kills, curr_y, buffer);
|
|
|
|
snprintf(buffer, sizeof(buffer), "%d", stat.deaths);
|
|
basethis->ClipString(colw_deaths - 5, buffer, false);
|
|
DLLRenderHUDText(color, m_alpha, 0, col_deaths, curr_y, buffer);
|
|
|
|
curr_y += (m_font_height + ROW_PIXEL_GAP);
|
|
}
|
|
}
|
|
|
|
if (curr_y + (m_font_height + ROW_PIXEL_GAP) > DLIST_WIN_H + DLIST_WIN_Y) {
|
|
|
|
if (basethis->FindPInfoStatNext(&stat)) {
|
|
clean_exit = false; // there are more stats
|
|
m_has_multiple_pages = true;
|
|
}
|
|
|
|
break; // can't fit anymore
|
|
}
|
|
}
|
|
}
|
|
basethis->FindPInfoStatClose();
|
|
|
|
m_page_display_time += *basethis->Frametime;
|
|
if ((m_page_display_time >= PAGE_DISP_TIME) && m_has_multiple_pages) {
|
|
if (!clean_exit)
|
|
m_page_index++;
|
|
else
|
|
m_page_index = 0; // if there was a clean exit, that means we were on the last page,
|
|
// go back to the beginning
|
|
m_page_display_time = 0;
|
|
}
|
|
}
|
|
|
|
if (m_flags & DSIF_SHOWPLAYERVIEW && m_flags & DSIF_NODETAILEDINFO && pr->state == STATE_INGAME) {
|
|
DLLgrtext_Flush();
|
|
|
|
float x, y, w, h;
|
|
x = (float)DLIST_WIN_X + 2;
|
|
y = (float)curr_y;
|
|
h = w = (float)std::min(DLIST_WIN_W - 4, (DLIST_WIN_Y + DLIST_WIN_H - curr_y) - 4);
|
|
object *obj_view = &basethis->Objects[basethis->Players[pr->pnum].objnum];
|
|
|
|
x *= *basethis->Hud_aspect_x;
|
|
y *= *basethis->Hud_aspect_y;
|
|
w *= *basethis->Hud_aspect_x;
|
|
h *= *basethis->Hud_aspect_y;
|
|
x += *basethis->Game_window_x;
|
|
y += *basethis->Game_window_y;
|
|
|
|
if (obj_view->type == OBJ_PLAYER) {
|
|
DisplayPlayerView((int)x, (int)y, (int)w, (int)h, obj_view);
|
|
}
|
|
}
|
|
|
|
alpha_in_time += *basethis->Frametime;
|
|
m_alpha = (perc_done * 255.0f);
|
|
}
|
|
|
|
// validates all the variables
|
|
void CDmfcStats::ValidateInfo() {
|
|
// change index to match the last selected prec num so it doesn't move around
|
|
int new_idx = -1;
|
|
for (int p = 0; p < m_MaxCount; p++) {
|
|
if (m_translate[p] == m_selected_prec) {
|
|
// found it, update the index
|
|
new_idx = p;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (new_idx == -1) {
|
|
// the old prec wasn't found
|
|
m_selected_index = 0;
|
|
} else {
|
|
m_selected_index = new_idx;
|
|
}
|
|
|
|
// make sure selected index is in view
|
|
while (m_selected_index < m_top_index) {
|
|
m_top_index--;
|
|
}
|
|
if (m_bottom_index != -1) { // make sure it has been set in a frame
|
|
while (m_selected_index > m_bottom_index) {
|
|
m_top_index++;
|
|
m_bottom_index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// the do-it-all function, call once per frame
|
|
void CDmfcStats::DoFrame() {
|
|
if (!m_enabled)
|
|
return;
|
|
|
|
int high_count;
|
|
int count;
|
|
int index;
|
|
static slot_state last_state = STATE_EMPTY;
|
|
player_record *pr;
|
|
|
|
if (m_flags & DSIF_ONLY_X_PLAYERS_SHOWN)
|
|
high_count = *m_pMaxNumberDisplayed;
|
|
else
|
|
high_count = MAX_PLAYER_RECORDS;
|
|
|
|
// count the number of players in the game/disconnected
|
|
// build translation table
|
|
count = 0;
|
|
index = 0;
|
|
|
|
if (m_SortedPRecs[0] != 0) {
|
|
count = 0;
|
|
index = 0;
|
|
}
|
|
|
|
for (int p = 0; p < MAX_PLAYER_RECORDS; p++) {
|
|
|
|
// increase count to see how many at most there are to display
|
|
pr = PRec_GetPRecord(p);
|
|
if (pr && pr->state != STATE_EMPTY && !basethis->IsPlayerDedicatedServer(pr))
|
|
count++;
|
|
|
|
// update translation table
|
|
pr = PRec_GetPRecord(m_SortedPRecs[p]);
|
|
if (pr && pr->state != STATE_EMPTY && !basethis->IsPlayerDedicatedServer(pr)) {
|
|
m_translate[index] = m_SortedPRecs[p];
|
|
index++;
|
|
}
|
|
}
|
|
|
|
if (m_flags & DSIF_SEPERATE_BY_TEAM) {
|
|
// Seperate by teams
|
|
int team_index;
|
|
int real_index = 0;
|
|
int num_teams = basethis->GetNumTeams();
|
|
int temp_array[MAX_PLAYER_RECORDS];
|
|
int prec, p;
|
|
|
|
bool getting_ingame_people = true;
|
|
|
|
get_disconnected_people:
|
|
|
|
for (team_index = 0; team_index < num_teams; team_index++) {
|
|
for (p = 0; p < index; p++) {
|
|
prec = m_translate[p];
|
|
pr = PRec_GetPRecord(prec);
|
|
if (pr->state != STATE_EMPTY && pr->team == team_index) {
|
|
|
|
// we must make sure to move all disconnected people to the
|
|
// bottom
|
|
if ((getting_ingame_people && pr->state == STATE_INGAME) ||
|
|
(!getting_ingame_people && pr->state == STATE_DISCONNECTED)) {
|
|
temp_array[real_index] = prec;
|
|
real_index++;
|
|
}
|
|
}
|
|
}
|
|
// next team
|
|
}
|
|
|
|
if (getting_ingame_people) {
|
|
getting_ingame_people = false;
|
|
goto get_disconnected_people;
|
|
}
|
|
|
|
memcpy(m_translate, temp_array, sizeof(int) * MAX_PLAYER_RECORDS);
|
|
}
|
|
|
|
m_MaxCount = std::min({high_count, count, index});
|
|
|
|
pr = PRec_GetPRecord(m_selected_prec);
|
|
if (!pr || pr->state != last_state) {
|
|
m_can_fit_count = -1; // we need to recalc this
|
|
m_page_index = 0;
|
|
m_has_multiple_pages = false;
|
|
if (pr)
|
|
last_state = pr->state;
|
|
}
|
|
|
|
ValidateInfo();
|
|
|
|
Render();
|
|
|
|
// save the last selected prec num for the next frame
|
|
m_selected_prec = m_translate[m_selected_index];
|
|
}
|
|
|
|
void CDmfcStats::DisplayPlayerView(int x, int y, int w, int h, object *viewer) {
|
|
object *save_viewer_object = *basethis->Viewer_object;
|
|
|
|
DLLrend_SetZBufferState(1);
|
|
|
|
// Set up for rendering
|
|
DLLStartFrame(x, y, x + w, y + h, true);
|
|
|
|
// Reset facings for mine stuff
|
|
DLLResetFacings();
|
|
|
|
// Set the viewer for this render
|
|
*basethis->Viewer_object = viewer;
|
|
|
|
// Render the world
|
|
DLLGameRenderWorld(viewer, &viewer->pos, viewer->roomnum, &viewer->orient, *basethis->Render_zoom, false);
|
|
|
|
// Restore the viewre
|
|
*basethis->Viewer_object = save_viewer_object;
|
|
|
|
// Done rendering
|
|
DLLEndFrame();
|
|
}
|