mirror of
https://github.com/kevinbentley/Descent3.git
synced 2026-04-05 05:00:06 -04:00
1095 lines
28 KiB
C++
1095 lines
28 KiB
C++
/*
|
|
* $Logfile: /DescentIII/Main/tanarchy/tanarchy.cpp $
|
|
* $Revision: 1.1.1.1 $
|
|
* $Date: 2003-08-26 03:59:14 $
|
|
* $Author: kevinb $
|
|
*
|
|
* <insert description of file here>
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
*
|
|
* 74 10/03/01 1:05p Matt
|
|
* Made team_name buffer large enough to hold the team number *plus* the
|
|
* number of players on the team.
|
|
*
|
|
* 73 9/24/01 2:28p Matt
|
|
* Allowed room for longer team name on results screen.
|
|
*
|
|
* 72 9/18/01 6:54p Matt
|
|
* Show results for NUM_TEAMS, not MAX_TEAMS.
|
|
* Removed some unused code.
|
|
*
|
|
* 71 9/13/01 5:31p Matt
|
|
* Added a team member list to the stats display.
|
|
* Fixed a non-terminated string bug.
|
|
*
|
|
* 70 10/21/99 3:28p Kevin
|
|
* Mac merge!
|
|
*
|
|
* 69 7/15/99 1:18a Jeff
|
|
* added $scores
|
|
*
|
|
* 68 7/12/99 2:27p Jeff
|
|
* fixed PLR to only display the team label for the disconnected list if
|
|
* there are people in the list
|
|
*
|
|
* 67 7/12/99 1:22p Jeff
|
|
* updated for new netflags
|
|
*
|
|
* 66 7/11/99 6:55p Jeff
|
|
* fixed PLR so it doesn't go off the screen on long lists and active
|
|
* players in the game are shown first
|
|
*
|
|
* 65 5/23/99 5:54p Jeff
|
|
* fixed HUD display
|
|
*
|
|
* 64 5/23/99 3:04a Jason
|
|
* fixed bug with player rankings not being updated correctly
|
|
*
|
|
* 63 5/12/99 11:04p Jeff
|
|
* dmfc and multiplayer games now have endian friendly packets (*whew*)
|
|
*
|
|
* 62 5/12/99 11:28a Jeff
|
|
* added sourcesafe comment block
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "gamedll_header.h"
|
|
#include <string.h>
|
|
#include "idmfc.h"
|
|
#include "tanDMFC.h"
|
|
#include "tanarchystr.h"
|
|
IDMFC *DMFCBase = NULL;
|
|
IDmfcStats *dstat = NULL;
|
|
player *dPlayers;
|
|
|
|
#define SPID_NEWPLAYER 0
|
|
#define NUM_TEAMS 2
|
|
|
|
int SortedPLRPlayers[MAX_TEAMS][MAX_PLAYER_RECORDS];
|
|
int TeamScore[NUM_TEAMS];
|
|
int SortedTeams[NUM_TEAMS];
|
|
int SortedPlayers[MAX_PLAYER_RECORDS];
|
|
bool DisplayScoreScreen;
|
|
bool display_my_welcome = false;
|
|
|
|
void GetGameStartPacket(ubyte *data);
|
|
void SendGameStartPacket(int pnum);
|
|
void DisplayScores(void);
|
|
void DisplayHUDScores(struct tHUDItem *hitem);
|
|
void DisplayWelcomeMessage(int player_num);
|
|
void SortTeamScores(int *sortedindex,int *scores);
|
|
void OnSaveStatsToFile(void);
|
|
void OnLevelEndSaveStatsToFile(void);
|
|
void OnDisconnectSaveStatsToFile(void);
|
|
void OnPrintScores(int level);
|
|
|
|
int Highlight_bmp = -1;
|
|
|
|
///////////////////////////////////////////////
|
|
//localization info
|
|
char **StringTable;
|
|
int StringTableSize = 0;
|
|
char *_ErrorString = "Missing String";
|
|
char *GetStringFromTable(int d){if( (d<0) || (d>=StringTableSize) ) return _ErrorString; else return StringTable[d];}
|
|
///////////////////////////////////////////////
|
|
|
|
void DetermineScore(int precord_num,int column_num,char *buffer,int buffer_size)
|
|
{
|
|
player_record *pr = DMFCBase->GetPlayerRecord(precord_num);
|
|
if(!pr || pr->state==STATE_EMPTY){
|
|
buffer[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
sprintf(buffer,"%d[%d]", pr->dstats.kills[DSTAT_LEVEL]-pr->dstats.suicides[DSTAT_LEVEL],
|
|
pr->dstats.kills[DSTAT_OVERALL]-pr->dstats.suicides[DSTAT_OVERALL]);
|
|
}
|
|
|
|
void TeamScoreCallback(int team,char *buffer,int buffer_size)
|
|
{
|
|
ASSERT(team>=0 && team<DLLMAX_TEAMS);
|
|
|
|
sprintf(buffer," %d",TeamScore[team]);
|
|
}
|
|
|
|
#ifdef MACINTOSH
|
|
#pragma export on
|
|
#endif
|
|
|
|
// This function gets called by the game when it wants to learn some info about the game
|
|
void DLLFUNCCALL DLLGetGameInfo (tDLLOptions *options)
|
|
{
|
|
options->flags = DOF_MAXTEAMS|DOF_MINTEAMS;
|
|
options->max_teams = 2;
|
|
options->min_teams = 2;
|
|
strcpy(options->game_name,TXT_GAMENAME);
|
|
strcpy(options->requirements,"");
|
|
}
|
|
|
|
// Initializes the game function pointers
|
|
void DLLFUNCCALL DLLGameInit (int *api_func,ubyte *all_ok,int num_teams_to_use)
|
|
{
|
|
*all_ok = 1;
|
|
DMFCBase = CreateDMFC();
|
|
if(!DMFCBase)
|
|
{
|
|
*all_ok = 0;
|
|
return;
|
|
}
|
|
|
|
dstat = CreateDmfcStats();
|
|
if(!dstat)
|
|
{
|
|
*all_ok = 0;
|
|
return;
|
|
}
|
|
DMFCBase->LoadFunctions(api_func);
|
|
DMFCBase->Set_OnGameStateRequest(OnGameStateRequest);
|
|
DMFCBase->Set_OnClientPlayerKilled(OnClientPlayerKilled);
|
|
DMFCBase->Set_OnServerGameCreated(OnServerGameCreated);
|
|
DMFCBase->Set_OnClientLevelStart(OnClientLevelStart);
|
|
DMFCBase->Set_OnClientLevelEnd(OnClientLevelEnd);
|
|
DMFCBase->Set_OnClientPlayerEntersGame(OnClientPlayerEntersGame);
|
|
DMFCBase->Set_OnInterval(OnInterval);
|
|
DMFCBase->Set_OnHUDInterval(OnHUDInterval);
|
|
DMFCBase->Set_OnKeypress(OnKeypress);
|
|
DMFCBase->Set_OnPLRInterval(OnPLRInterval);
|
|
DMFCBase->Set_OnPLRInit(OnPLRInit);
|
|
DMFCBase->Set_OnSaveStatsToFile(OnSaveStatsToFile);
|
|
DMFCBase->Set_OnLevelEndSaveStatsToFile(OnLevelEndSaveStatsToFile);
|
|
DMFCBase->Set_OnDisconnectSaveStatsToFile(OnDisconnectSaveStatsToFile);
|
|
DMFCBase->Set_OnPrintScores(OnPrintScores);
|
|
|
|
dPlayers = DMFCBase->GetPlayers();
|
|
|
|
DMFCBase->GameInit(NUM_TEAMS);
|
|
DLLCreateStringTable("tanarchy.str",&StringTable,&StringTableSize);
|
|
DLLmprintf((0,"%d strings loaded from string table\n",StringTableSize));
|
|
if(!StringTableSize){
|
|
*all_ok = 0;
|
|
return;
|
|
}
|
|
|
|
netgame_info *Netgame = DMFCBase->GetNetgameInfo();
|
|
Netgame->flags |= (NF_TRACK_RANK);
|
|
|
|
//add the death and suicide messages
|
|
DMFCBase->AddDeathMessage(TXT_DEATH1,true);
|
|
DMFCBase->AddDeathMessage(TXT_DEATH2,true);
|
|
DMFCBase->AddDeathMessage(TXT_DEATH3,false);
|
|
DMFCBase->AddDeathMessage(TXT_DEATH4,false);
|
|
DMFCBase->AddDeathMessage(TXT_DEATH5,true);
|
|
DMFCBase->AddDeathMessage(TXT_DEATH6,true);
|
|
DMFCBase->AddDeathMessage(TXT_DEATH7,false);
|
|
DMFCBase->AddDeathMessage(TXT_DEATH8,true);
|
|
DMFCBase->AddDeathMessage(TXT_DEATH9,true);
|
|
DMFCBase->AddDeathMessage(TXT_DEATH10,true);
|
|
|
|
DMFCBase->AddSuicideMessage(TXT_SUICIDE1);
|
|
DMFCBase->AddSuicideMessage(TXT_SUICIDE2);
|
|
DMFCBase->AddSuicideMessage(TXT_SUICIDE3);
|
|
DMFCBase->AddSuicideMessage(TXT_SUICIDE4);
|
|
DMFCBase->AddSuicideMessage(TXT_SUICIDE5);
|
|
DMFCBase->AddSuicideMessage(TXT_SUICIDE6);
|
|
|
|
//register special packet receivers
|
|
DMFCBase->RegisterPacketReceiver(SPID_NEWPLAYER,GetGameStartPacket);
|
|
|
|
DMFCBase->SetNumberOfTeams(NUM_TEAMS);
|
|
|
|
DMFCBase->AddHUDItemCallback(HI_TEXT,DisplayHUDScores);
|
|
|
|
DisplayScoreScreen = false;
|
|
|
|
Highlight_bmp = DLLbm_AllocBitmap(32,32,0);
|
|
if(Highlight_bmp>BAD_BITMAP_HANDLE){
|
|
ushort *data = DLLbm_data(Highlight_bmp,0);
|
|
if(!data){
|
|
//bail on out of here
|
|
*all_ok = 0;
|
|
return;
|
|
}
|
|
for(int x=0;x<32*32;x++){
|
|
data[x] = GR_RGB16(50,50,50)|OPAQUE_FLAG;
|
|
}
|
|
}
|
|
|
|
// Initialize the Stats Manager
|
|
// ----------------------------
|
|
|
|
tDmfcStatsInit tsi;
|
|
tDmfcStatsColumnInfo pl_col[6];
|
|
char gname[20];
|
|
strcpy(gname,TXT_STATSGAMENAME);
|
|
|
|
tsi.flags = DSIF_SHOW_PIC|DSIF_SHOW_OBSERVERICON|DSIF_SEPERATE_BY_TEAM;
|
|
tsi.cColumnCountDetailed = 0;
|
|
tsi.cColumnCountPlayerList = 6;
|
|
tsi.clbDetailedColumnBMP = NULL;
|
|
tsi.clbDetailedColumn = NULL;
|
|
tsi.clbPlayerColumn = DetermineScore;
|
|
tsi.clbPlayerColumnBMP = NULL;
|
|
tsi.DetailedColumns = NULL;
|
|
tsi.GameName = gname;
|
|
tsi.MaxNumberDisplayed = NULL;
|
|
tsi.PlayerListColumns = pl_col;
|
|
tsi.SortedPlayerRecords = SortedPlayers;
|
|
tsi.clTeamLine = TeamScoreCallback;
|
|
|
|
pl_col[0].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[0].title,TXT_PILOT);
|
|
pl_col[0].type = DSCOL_PILOT_NAME;
|
|
pl_col[0].width = 120;
|
|
|
|
pl_col[1].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[1].title,TXT_SCORE);
|
|
pl_col[1].type = DSCOL_CUSTOM;
|
|
pl_col[1].width = 47;
|
|
|
|
pl_col[2].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[2].title,TXT_KILLS);
|
|
pl_col[2].type = DSCOL_KILLS_LEVEL;
|
|
pl_col[2].width = 47;
|
|
|
|
pl_col[3].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[3].title,TXT_DEATHS);
|
|
pl_col[3].type = DSCOL_DEATHS_LEVEL;
|
|
pl_col[3].width = 57;
|
|
|
|
pl_col[4].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[4].title,TXT_SUICIDES);
|
|
pl_col[4].type = DSCOL_SUICIDES_LEVEL;
|
|
pl_col[4].width = 67;
|
|
|
|
pl_col[5].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[5].title,TXT_PING);
|
|
pl_col[5].type = DSCOL_PING;
|
|
pl_col[5].width = 40;
|
|
|
|
dstat->Initialize(&tsi);
|
|
}
|
|
// Called when the DLL is shutdown
|
|
void DLLFUNCCALL DLLGameClose ()
|
|
{
|
|
if(Highlight_bmp>BAD_BITMAP_HANDLE)
|
|
DLLbm_FreeBitmap(Highlight_bmp);
|
|
|
|
DLLDestroyStringTable(StringTable,StringTableSize);
|
|
|
|
if(dstat)
|
|
{
|
|
dstat->DestroyPointer();
|
|
dstat = NULL;
|
|
}
|
|
|
|
if(DMFCBase)
|
|
{
|
|
DMFCBase->GameClose();
|
|
DMFCBase->DestroyPointer();
|
|
DMFCBase = NULL;
|
|
}
|
|
}
|
|
|
|
// The server has just started, so clear out all the stats and game info
|
|
void OnServerGameCreated(void)
|
|
{
|
|
DMFCBase->OnServerGameCreated();
|
|
|
|
for(int i=0;i<NUM_TEAMS;i++)
|
|
{
|
|
TeamScore[i] = 0;
|
|
}
|
|
}
|
|
|
|
// The server has started a new level, so clear out level scores
|
|
void OnClientLevelStart(void)
|
|
{
|
|
DMFCBase->OnClientLevelStart();
|
|
for(int i=0;i<NUM_TEAMS;i++)
|
|
{
|
|
TeamScore[i] = 0;
|
|
}
|
|
DMFCBase->RequestGameState();
|
|
}
|
|
|
|
void OnClientLevelEnd(void)
|
|
{
|
|
DMFCBase->OnClientLevelEnd();
|
|
}
|
|
|
|
|
|
// A New Player has entered the game, so we want to send him a game status packet that
|
|
// has information about the game
|
|
void OnGameStateRequest(int player_num)
|
|
{
|
|
SendGameStartPacket(player_num);
|
|
DMFCBase->OnGameStateRequest(player_num);
|
|
}
|
|
|
|
// A new player has entered the game, zero there stats out
|
|
void OnClientPlayerEntersGame(int player_num)
|
|
{
|
|
DMFCBase->OnClientPlayerEntersGame(player_num);
|
|
|
|
if(player_num!=DMFCBase->GetPlayerNum())
|
|
DisplayWelcomeMessage(player_num);
|
|
else
|
|
display_my_welcome = true;
|
|
}
|
|
|
|
// We need to adjust the scores
|
|
void OnClientPlayerKilled(object *killer_obj,int victim_pnum)
|
|
{
|
|
int kpnum;
|
|
|
|
if(killer_obj){
|
|
if((killer_obj->type==OBJ_PLAYER)||(killer_obj->type==OBJ_GHOST))
|
|
kpnum = killer_obj->id;
|
|
else if(killer_obj->type==OBJ_ROBOT || (killer_obj->type == OBJ_BUILDING && killer_obj->ai_info)){
|
|
//countermeasure kill
|
|
kpnum = DMFCBase->GetCounterMeasureOwner(killer_obj);
|
|
}else{
|
|
kpnum = -1;
|
|
}
|
|
}else
|
|
kpnum = -1;
|
|
|
|
if(DMFCBase->IsPlayerDedicatedServer(victim_pnum))
|
|
return;//dedicated server
|
|
|
|
if(kpnum==victim_pnum && victim_pnum!=-1)
|
|
//subtract from the team score
|
|
TeamScore[dPlayers[victim_pnum].team]--;
|
|
else
|
|
if((kpnum!=-1)&&(dPlayers[kpnum].team!=-1))
|
|
TeamScore[dPlayers[kpnum].team]++;
|
|
|
|
DMFCBase->OnClientPlayerKilled(killer_obj,victim_pnum);
|
|
}
|
|
|
|
void OnHUDInterval(void)
|
|
{
|
|
dstat->DoFrame();
|
|
|
|
DMFCBase->DisplayOutrageLogo();
|
|
|
|
DMFCBase->OnHUDInterval();
|
|
}
|
|
|
|
void OnInterval(void)
|
|
{
|
|
SortTeamScores(SortedTeams,TeamScore);
|
|
DMFCBase->GetSortedPlayerSlots(SortedPlayers,MAX_PLAYER_RECORDS);
|
|
|
|
//do killgoal check
|
|
int goal;
|
|
if(DMFCBase->GetScoreLimit(&goal))
|
|
{
|
|
for(int i=0;i<NUM_TEAMS;i++)
|
|
{
|
|
if(TeamScore[i]>=goal)
|
|
DMFCBase->EndLevel();
|
|
}
|
|
}
|
|
DMFCBase->OnInterval();
|
|
}
|
|
|
|
void OnKeypress(int key)
|
|
{
|
|
dllinfo *Data = DMFCBase->GetDLLInfoCallData();
|
|
switch(key){
|
|
case K_F7:
|
|
DisplayScoreScreen = !DisplayScoreScreen;
|
|
DMFCBase->EnableOnScreenMenu(false);
|
|
dstat->Enable(DisplayScoreScreen);
|
|
break;
|
|
case K_PAGEDOWN:
|
|
if(DisplayScoreScreen){
|
|
dstat->ScrollDown();
|
|
Data->iRet = 1;
|
|
}
|
|
break;
|
|
case K_PAGEUP:
|
|
if(DisplayScoreScreen){
|
|
dstat->ScrollUp();
|
|
Data->iRet = 1;
|
|
}
|
|
break;
|
|
case K_F6:
|
|
DisplayScoreScreen = false;
|
|
dstat->Enable(false);
|
|
break;
|
|
case K_ESC:
|
|
if(DisplayScoreScreen){
|
|
dstat->Enable(false);
|
|
DisplayScoreScreen = false;
|
|
Data->iRet = 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
DMFCBase->OnKeypress(key);
|
|
}
|
|
|
|
bool compare_slots(int a,int b)
|
|
{
|
|
int ascore,bscore;
|
|
player_record *apr,*bpr;
|
|
apr = DMFCBase->GetPlayerRecord(a);
|
|
bpr = DMFCBase->GetPlayerRecord(b);
|
|
if( !apr )
|
|
return true;
|
|
if( !bpr )
|
|
return false;
|
|
if( apr->state==STATE_EMPTY )
|
|
return true;
|
|
if( bpr->state==STATE_EMPTY )
|
|
return false;
|
|
if( (apr->state==STATE_INGAME) && (bpr->state==STATE_INGAME) ){
|
|
//both players were in the game
|
|
ascore = apr->dstats.kills[DSTAT_LEVEL] - apr->dstats.suicides[DSTAT_LEVEL];
|
|
bscore = bpr->dstats.kills[DSTAT_LEVEL] - bpr->dstats.suicides[DSTAT_LEVEL];
|
|
return (ascore<bscore);
|
|
}
|
|
if( (apr->state==STATE_INGAME) && (bpr->state==STATE_DISCONNECTED) ){
|
|
//apr gets priority since he was in the game on exit
|
|
return false;
|
|
}
|
|
if( (apr->state==STATE_DISCONNECTED) && (bpr->state==STATE_INGAME) ){
|
|
//bpr gets priority since he was in the game on exit
|
|
return true;
|
|
}
|
|
//if we got here then both players were disconnected
|
|
ascore = apr->dstats.kills[DSTAT_LEVEL] - apr->dstats.suicides[DSTAT_LEVEL];
|
|
bscore = bpr->dstats.kills[DSTAT_LEVEL] - bpr->dstats.suicides[DSTAT_LEVEL];
|
|
return (ascore<bscore);
|
|
}
|
|
|
|
void OnPLRInit(void)
|
|
{
|
|
int i,t,j;
|
|
|
|
for(i=0;i<MAX_PLAYER_RECORDS;i++){
|
|
SortedPlayers[i] = i;
|
|
}
|
|
|
|
for(i=1;i<=MAX_PLAYER_RECORDS-1;i++){
|
|
t=SortedPlayers[i];
|
|
// Shift elements down until
|
|
// insertion point found.
|
|
for(j=i-1;j>=0 && compare_slots(SortedPlayers[j],t); j--){
|
|
SortedPlayers[j+1] = SortedPlayers[j];
|
|
}
|
|
// insert
|
|
SortedPlayers[j+1] = t;
|
|
}
|
|
|
|
//Now fill in the final structure of sorted names
|
|
int TeamCount[MAX_TEAMS];
|
|
int team;
|
|
for(i=0;i<MAX_TEAMS;i++)
|
|
TeamCount[i] = 0;
|
|
for(i=0;i<MAX_PLAYER_RECORDS;i++){
|
|
int slot = SortedPlayers[i];
|
|
player_record *pr = DMFCBase->GetPlayerRecord(slot);
|
|
if(pr && pr->state!=STATE_EMPTY){
|
|
|
|
if(DMFCBase->IsPlayerDedicatedServer(pr))
|
|
continue;//dedicated server
|
|
|
|
team = (pr->state==STATE_INGAME)?dPlayers[pr->pnum].team:pr->team;
|
|
SortedPLRPlayers[team][TeamCount[team]] = slot;
|
|
TeamCount[team]++;
|
|
}
|
|
}
|
|
for(i=0;i<MAX_TEAMS;i++){
|
|
if(TeamCount[i]<MAX_PLAYER_RECORDS)
|
|
SortedPLRPlayers[i][TeamCount[i]] = -1;
|
|
}
|
|
|
|
DMFCBase->OnPLRInit();
|
|
}
|
|
|
|
void OnPLRInterval(void)
|
|
{
|
|
DMFCBase->OnPLRInterval();
|
|
|
|
int TeamCol = 35;
|
|
int NameCol = 190;
|
|
int KillsCol = 330;
|
|
int DeathsCol = 380;
|
|
int SuicidesCol = 430;
|
|
int y = 40;
|
|
int slot;
|
|
player_record *pr;
|
|
|
|
DLLgrtext_SetFont((DMFCBase->GetGameFontTranslateArray())[SMALL_UI_FONT_INDEX]);
|
|
int height = DLLgrfont_GetHeight((DMFCBase->GetGameFontTranslateArray())[SMALL_UI_FONT_INDEX]) + 1;
|
|
|
|
//print out header
|
|
DLLgrtext_SetColor(GR_RGB(255,255,150));
|
|
DLLgrtext_Printf(NameCol,y,TXT_PILOT);
|
|
DLLgrtext_Printf(KillsCol,y,TXT_KILLS);
|
|
DLLgrtext_Printf(DeathsCol,y,TXT_DEATHS);
|
|
DLLgrtext_Printf(SuicidesCol,y,TXT_SUICIDES);
|
|
y+=height;
|
|
bool has_members;
|
|
bool doing_connected = true;
|
|
|
|
do_disconnected_folk:
|
|
|
|
|
|
for(int team=0;team<NUM_TEAMS;team++){
|
|
//process this team
|
|
bool show_team_label;
|
|
show_team_label = false;
|
|
|
|
if(!doing_connected)
|
|
{
|
|
int temp_idx;
|
|
temp_idx = 0;
|
|
|
|
while(SortedPLRPlayers[team][temp_idx]!=-1)
|
|
{
|
|
int pnum=DMFCBase->WasPlayerInGameAtLevelEnd(SortedPLRPlayers[team][temp_idx]);
|
|
if(pnum==-1)
|
|
{
|
|
show_team_label = true;
|
|
break;
|
|
}
|
|
temp_idx++;
|
|
}
|
|
}else
|
|
{
|
|
show_team_label = true;
|
|
}
|
|
|
|
if(show_team_label){
|
|
//is there anyone on this team?
|
|
DLLgrtext_SetColor(DMFCBase->GetTeamColor(team));
|
|
DLLgrtext_Printf(TeamCol,y,TXT_TEAMSCORE,DMFCBase->GetTeamString(team),TeamScore[team]);
|
|
}
|
|
has_members = false;
|
|
|
|
for(int index=0;index<MAX_PLAYER_RECORDS;index++){
|
|
//get the player num
|
|
slot = SortedPLRPlayers[team][index];
|
|
if(slot==-1)//we are done with this team
|
|
break;
|
|
pr = DMFCBase->GetPlayerRecord(slot);
|
|
if(pr && pr->state!=STATE_EMPTY){
|
|
|
|
if(DMFCBase->IsPlayerDedicatedServer(pr))
|
|
continue;//dedicated server
|
|
|
|
int pnum=DMFCBase->WasPlayerInGameAtLevelEnd(slot);
|
|
|
|
if( (doing_connected && pnum==-1) ||
|
|
(!doing_connected && pnum!=-1) )
|
|
continue;//we're not handling them right now
|
|
|
|
if(pnum!=-1)
|
|
{
|
|
DLLgrtext_SetColor(DMFCBase->GetTeamColor(team));
|
|
}else
|
|
{
|
|
DLLgrtext_SetColor(GR_RGB(128,128,128));
|
|
}
|
|
|
|
//valid player
|
|
DLLgrtext_Printf(NameCol,y,"%s %d[%d]",pr->callsign,pr->dstats.kills[DSTAT_LEVEL]-pr->dstats.suicides[DSTAT_LEVEL],pr->dstats.kills[DSTAT_OVERALL]-pr->dstats.suicides[DSTAT_OVERALL]);
|
|
DLLgrtext_Printf(KillsCol,y,"%d[%d]",pr->dstats.kills[DSTAT_LEVEL],pr->dstats.kills[DSTAT_OVERALL]);
|
|
DLLgrtext_Printf(DeathsCol,y,"%d[%d]",pr->dstats.deaths[DSTAT_LEVEL],pr->dstats.deaths[DSTAT_OVERALL]);
|
|
DLLgrtext_Printf(SuicidesCol,y,"%d[%d]",pr->dstats.suicides[DSTAT_LEVEL],pr->dstats.suicides[DSTAT_OVERALL]);
|
|
y+=height;
|
|
has_members = true;
|
|
|
|
if(y>=440)
|
|
goto quick_exit;
|
|
}
|
|
}//end for
|
|
//on to the next team
|
|
if(!has_members)
|
|
y+=height;
|
|
|
|
if(y>=440)
|
|
goto quick_exit;
|
|
|
|
}//end for
|
|
|
|
if(doing_connected)
|
|
{
|
|
doing_connected = false;
|
|
goto do_disconnected_folk;
|
|
}
|
|
|
|
quick_exit:;
|
|
|
|
}
|
|
|
|
void SaveStatsToFile(char *filename)
|
|
{
|
|
CFILE *file;
|
|
DLLOpenCFILE(&file,filename,"wt");
|
|
if(!file){
|
|
DLLmprintf((0,"Unable to open output file\n"));
|
|
return;
|
|
}
|
|
|
|
//write out game stats
|
|
#define BUFSIZE 150
|
|
char buffer[BUFSIZE];
|
|
char tempbuffer[25];
|
|
int sortedslots[MAX_PLAYER_RECORDS];
|
|
player_record *pr,*dpr;
|
|
tPInfoStat stat;
|
|
int count,length,p;
|
|
|
|
//sort the stats
|
|
DMFCBase->GetSortedPlayerSlots(sortedslots,MAX_PLAYER_RECORDS);
|
|
count = 1;
|
|
|
|
sprintf(buffer,TXT_SAVESTATSA,(DMFCBase->GetNetgameInfo())->name,(DMFCBase->GetCurrentMission())->cur_level);
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
for(p=0;p<NUM_TEAMS;p++){
|
|
int team_i = SortedTeams[p];
|
|
memset(buffer,' ',BUFSIZE);
|
|
sprintf(tempbuffer,TXT_TEAM,DMFCBase->GetTeamString(team_i));
|
|
memcpy(&buffer[0],tempbuffer,strlen(tempbuffer));
|
|
sprintf(tempbuffer,"[%d]",TeamScore[team_i]);
|
|
memcpy(&buffer[20],tempbuffer,strlen(tempbuffer));
|
|
buffer[20 + strlen(tempbuffer)] = '\0';
|
|
DLLcf_WriteString(file,buffer);
|
|
}
|
|
|
|
//Write team members
|
|
DLLcf_WriteString(file,""); //blank line
|
|
for(int t=0;t<NUM_TEAMS;t++){
|
|
int team_i = SortedTeams[t];
|
|
|
|
sprintf(buffer,TXT_TEAM,DMFCBase->GetTeamString(team_i));
|
|
strcat(buffer,":");
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
for(p=0;p<MAX_PLAYER_RECORDS;p++){
|
|
pr = DMFCBase->GetPlayerRecord(sortedslots[p]);
|
|
if( pr && pr->state!=STATE_EMPTY) {
|
|
|
|
if(DMFCBase->IsPlayerDedicatedServer(pr))
|
|
continue;//skip dedicated server
|
|
|
|
if (pr->team == team_i) { //Check if current team
|
|
sprintf(buffer," %s",pr->callsign);
|
|
DLLcf_WriteString(file,buffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DLLcf_WriteString(file,""); //blank line
|
|
|
|
sprintf(buffer,TXT_SAVESTATSB);
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
sprintf(buffer,TXT_SAVESTATSC);
|
|
DLLcf_WriteString(file,buffer);
|
|
sprintf(buffer,"-----------------------------------------------------------------------------");
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
|
|
for(p=0;p<MAX_PLAYER_RECORDS;p++){
|
|
pr = DMFCBase->GetPlayerRecord(sortedslots[p]);
|
|
if( pr && pr->state!=STATE_EMPTY) {
|
|
|
|
if(DMFCBase->IsPlayerDedicatedServer(pr))
|
|
continue;//skip dedicated server
|
|
|
|
memset(buffer,' ',BUFSIZE);
|
|
|
|
sprintf(tempbuffer,"%d)",count);
|
|
memcpy(&buffer[0],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%s%s",(pr->state==STATE_INGAME)?"":"*",pr->callsign);
|
|
memcpy(&buffer[5],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d[%d]",pr->dstats.kills[DSTAT_LEVEL]-pr->dstats.suicides[DSTAT_LEVEL],pr->dstats.kills[DSTAT_OVERALL]-pr->dstats.suicides[DSTAT_OVERALL]);
|
|
memcpy(&buffer[34],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d[%d]",pr->dstats.kills[DSTAT_LEVEL],pr->dstats.kills[DSTAT_OVERALL]);
|
|
memcpy(&buffer[46],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d[%d]",pr->dstats.deaths[DSTAT_LEVEL],pr->dstats.deaths[DSTAT_OVERALL]);
|
|
memcpy(&buffer[58],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d[%d]",pr->dstats.suicides[DSTAT_LEVEL],pr->dstats.suicides[DSTAT_OVERALL]);
|
|
memcpy(&buffer[69],tempbuffer,strlen(tempbuffer));
|
|
|
|
int pos;
|
|
pos = 69 + strlen(tempbuffer) + 1;
|
|
if(pos<BUFSIZE)
|
|
buffer[pos] = '\0';
|
|
|
|
buffer[BUFSIZE-1] = '\0';
|
|
DLLcf_WriteString(file,buffer);
|
|
count++;
|
|
}
|
|
}
|
|
|
|
DLLcf_WriteString(file,TXT_SAVESTATSD);
|
|
|
|
count =1;
|
|
for(p=0;p<MAX_PLAYER_RECORDS;p++){
|
|
pr = DMFCBase->GetPlayerRecord(p);
|
|
if( pr && pr->state!=STATE_EMPTY) {
|
|
|
|
if(DMFCBase->IsPlayerDedicatedServer(pr))
|
|
continue;//skip dedicated server
|
|
|
|
//Write out header
|
|
sprintf(buffer,"%d) %s%s",count,(pr->state==STATE_INGAME)?"":"*",pr->callsign);
|
|
DLLcf_WriteString(file,buffer);
|
|
length = strlen(buffer);
|
|
memset(buffer,'=',length);
|
|
buffer[length] = '\0';
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
//time in game
|
|
sprintf(buffer,TXT_TIMEINGAME,DMFCBase->GetTimeString(DMFCBase->GetTimeInGame(p)));
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
if(DMFCBase->FindPInfoStatFirst(p,&stat)){
|
|
sprintf(buffer,TXT_SAVESTATSE);
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
if(stat.slot!=p){
|
|
memset(buffer,' ',BUFSIZE);
|
|
dpr = DMFCBase->GetPlayerRecord(stat.slot);
|
|
int pos;
|
|
|
|
if(dpr)
|
|
{
|
|
sprintf(tempbuffer,"%s",dpr->callsign);
|
|
memcpy(buffer,tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d",stat.kills);
|
|
memcpy(&buffer[30],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d",stat.deaths);
|
|
memcpy(&buffer[40],tempbuffer,strlen(tempbuffer));
|
|
|
|
pos = 40 + strlen(tempbuffer) + 1;
|
|
if(pos<BUFSIZE)
|
|
buffer[pos] = '\0';
|
|
|
|
buffer[BUFSIZE-1] = '\0';
|
|
DLLcf_WriteString(file,buffer);
|
|
}
|
|
}
|
|
|
|
|
|
while(DMFCBase->FindPInfoStatNext(&stat)){
|
|
if(stat.slot!=p){
|
|
int pos;
|
|
memset(buffer,' ',BUFSIZE);
|
|
dpr = DMFCBase->GetPlayerRecord(stat.slot);
|
|
|
|
if(dpr)
|
|
{
|
|
sprintf(tempbuffer,"%s",dpr->callsign);
|
|
memcpy(buffer,tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d",stat.kills);
|
|
memcpy(&buffer[30],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d",stat.deaths);
|
|
memcpy(&buffer[40],tempbuffer,strlen(tempbuffer));
|
|
|
|
pos = 40 + strlen(tempbuffer) + 1;
|
|
if(pos<BUFSIZE)
|
|
buffer[pos] = '\0';
|
|
|
|
buffer[BUFSIZE-1] = '\0';
|
|
DLLcf_WriteString(file,buffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DMFCBase->FindPInfoStatClose();
|
|
DLLcf_WriteString(file,""); //skip a line
|
|
count++;
|
|
}
|
|
}
|
|
|
|
//done writing stats
|
|
DLLcfclose(file);
|
|
DLLAddHUDMessage(TXT_STATSSAVED);
|
|
}
|
|
|
|
#define ROOTFILENAME "Team Anarchy"
|
|
void OnSaveStatsToFile(void)
|
|
{
|
|
char filename[256];
|
|
DMFCBase->GenerateStatFilename(filename,ROOTFILENAME,false);
|
|
SaveStatsToFile(filename);
|
|
}
|
|
|
|
void OnLevelEndSaveStatsToFile(void)
|
|
{
|
|
char filename[256];
|
|
DMFCBase->GenerateStatFilename(filename,ROOTFILENAME,true);
|
|
SaveStatsToFile(filename);
|
|
}
|
|
|
|
void OnDisconnectSaveStatsToFile(void)
|
|
{
|
|
char filename[256];
|
|
DMFCBase->GenerateStatFilename(filename,ROOTFILENAME,false);
|
|
SaveStatsToFile(filename);
|
|
}
|
|
|
|
//Handles when we get a new player packet
|
|
void GetGameStartPacket(ubyte *data)
|
|
{
|
|
//get the team scores
|
|
DLLmprintf((0,"Receiving Team Scores from server\n"));
|
|
int count = 0,i;
|
|
for(i=0;i<NUM_TEAMS;i++)
|
|
{
|
|
TeamScore[i] = MultiGetInt(data,&count);
|
|
}
|
|
}
|
|
|
|
//Handles sending a new player packet
|
|
void SendGameStartPacket(int pnum)
|
|
{
|
|
int count = 0;
|
|
ubyte data[MAX_GAME_DATA_SIZE];
|
|
|
|
DMFCBase->StartPacket(data,SPID_NEWPLAYER,&count);
|
|
|
|
//add the team scores
|
|
int i;
|
|
for(i=0;i<NUM_TEAMS;i++)
|
|
{
|
|
MultiAddInt(TeamScore[i],data,&count);
|
|
}
|
|
|
|
//we're done
|
|
DLLmprintf((0,"Sending Team Scores to %s\n",dPlayers[pnum].callsign));
|
|
DMFCBase->SendPacket(data,count,pnum);
|
|
}
|
|
|
|
void DisplayHUDScores(struct tHUDItem *hitem)
|
|
{
|
|
if(display_my_welcome)
|
|
{
|
|
DisplayWelcomeMessage(DMFCBase->GetPlayerNum());
|
|
display_my_welcome = false;
|
|
}
|
|
|
|
if(DisplayScoreScreen)
|
|
return;
|
|
|
|
int height = DLLgrfont_GetHeight((DMFCBase->GetGameFontTranslateArray())[HUD_FONT_INDEX]) + 3;
|
|
int y = (DMFCBase->GetGameWindowH()/2) - ((height*NUM_TEAMS)/2);
|
|
int x = 520;
|
|
ubyte alpha = DMFCBase->ConvertHUDAlpha((ubyte)((DisplayScoreScreen)?128:255));
|
|
int team;
|
|
|
|
// char name[30];
|
|
|
|
//determine coordinates to use here
|
|
//we'll use a virtual width of 85 pixels on a 640x480 screen
|
|
//so first determine the new width
|
|
int name_width = 100.0f * DMFCBase->GetHudAspectX();
|
|
int score_width = DLLgrtext_GetTextLineWidth("888");
|
|
int name_x = DMFCBase->GetGameWindowW() - name_width - score_width - 10;
|
|
int score_x = DMFCBase->GetGameWindowW() - score_width - 5;
|
|
|
|
team = DMFCBase->GetMyTeam();
|
|
DLLRenderHUDText(DMFCBase->GetTeamColor(team),255,0,x,0,TXT_TEAM,DMFCBase->GetTeamString(team));
|
|
int num_players = 0;
|
|
|
|
for(int i=0;i<NUM_TEAMS;i++){
|
|
team = SortedTeams[i];
|
|
num_players = 0;
|
|
|
|
for(int q=0;q<DLLMAX_PLAYERS;q++)
|
|
{
|
|
if(DMFCBase->CheckPlayerNum(q) && dPlayers[q].team==team && !DMFCBase->IsPlayerDedicatedServer(q))
|
|
num_players++;
|
|
}
|
|
|
|
if(team==DMFCBase->GetMyTeam())
|
|
{
|
|
if(Highlight_bmp>BAD_BITMAP_HANDLE){
|
|
//draw the highlite bar in the background
|
|
DLLrend_SetAlphaValue(alpha*0.50f);
|
|
DLLrend_SetAlphaValue(alpha);
|
|
DLLrend_SetZBufferState (0);
|
|
DLLrend_SetTextureType (TT_LINEAR);
|
|
DLLrend_SetLighting (LS_NONE);
|
|
DLLrend_SetAlphaType (AT_CONSTANT_TEXTURE);
|
|
|
|
DLLrend_DrawScaledBitmap(name_x-2,y-2,score_x+score_width+2,y+height-1,Highlight_bmp,0,0,1,1,1.0);
|
|
DLLrend_SetZBufferState (1);
|
|
}
|
|
}
|
|
|
|
char team_name[MAX_TEAMNAME_LEN+5];
|
|
sprintf(team_name,"[%d]%s",num_players,DMFCBase->GetTeamString(team));
|
|
DMFCBase->ClipString(name_width,team_name,true);
|
|
|
|
DLLgrtext_SetAlpha(alpha);
|
|
DLLgrtext_SetColor(DMFCBase->GetTeamColor(team));
|
|
DLLgrtext_Printf(name_x,y,team_name);
|
|
DLLgrtext_Printf(score_x,y,"%d",TeamScore[team]);
|
|
|
|
// sprintf(name,TXT_TEAMSCORE,DMFCBase->GetTeamString(team));
|
|
// DMFCBase->ClipString(name_width,name,true);
|
|
|
|
y+=height;
|
|
}
|
|
}
|
|
|
|
|
|
// insert sort
|
|
#define compGT(a,b) (a < b)
|
|
void SortTeamScores(int *sortedindex,int *scores)
|
|
{
|
|
int t;
|
|
int i, j;
|
|
|
|
//copy scores into scoreinfo array
|
|
for(i=0;i<NUM_TEAMS;i++)
|
|
{
|
|
sortedindex[i] = i;
|
|
}
|
|
|
|
for(i=1;i<=NUM_TEAMS-1;i++)
|
|
{
|
|
t=sortedindex[i];
|
|
|
|
/* Shift elements down until */
|
|
/* insertion point found. */
|
|
for(j=i-1;j>=0 && compGT(scores[sortedindex[j]],scores[t]); j--)
|
|
{
|
|
sortedindex[j+1] = sortedindex[j];
|
|
}
|
|
|
|
/* insert */
|
|
sortedindex[j+1] = t;
|
|
}
|
|
}
|
|
|
|
void DisplayWelcomeMessage(int player_num)
|
|
{
|
|
char name_buffer[64];
|
|
strcpy(name_buffer,(DMFCBase->GetPlayers())[player_num].callsign);
|
|
|
|
if(player_num==DMFCBase->GetPlayerNum())
|
|
{
|
|
int team = DMFCBase->GetMyTeam();
|
|
if(team==-1)
|
|
return;
|
|
|
|
DLLAddHUDMessage(TXT_WELCOME,name_buffer);
|
|
DLLAddColoredHUDMessage(DMFCBase->GetTeamColor(team),TXT_TEAMJOINMSG,DMFCBase->GetTeamString(team));
|
|
}
|
|
else
|
|
{
|
|
int team = dPlayers[player_num].team;
|
|
if(team==-1)
|
|
return;
|
|
|
|
DLLAddColoredHUDMessage(DMFCBase->GetTeamColor(team),TXT_JOINED,name_buffer,DMFCBase->GetTeamString(team));
|
|
}
|
|
}
|
|
|
|
void OnPrintScores(int level)
|
|
{
|
|
char buffer[256];
|
|
char name[70];
|
|
int t,i;
|
|
int pos[6];
|
|
int len[6];
|
|
|
|
for(i=0;i<NUM_TEAMS;i++)
|
|
{
|
|
sprintf(buffer,"%s:%d\n",DMFCBase->GetTeamString(i),TeamScore[i]);
|
|
DPrintf(buffer);
|
|
}
|
|
|
|
memset(buffer,' ',256);
|
|
pos[0] = 0; t = len[0] = 30; //give ample room for pilot name
|
|
pos[1] = pos[0] + t + 1; t = len[1] = strlen(TXT_POINTS);
|
|
pos[2] = pos[1] + t + 1; t = len[2] = strlen(TXT_KILLS_SHORT);
|
|
pos[3] = pos[2] + t + 1; t = len[3] = strlen(TXT_DEATHS_SHORT);
|
|
pos[4] = pos[3] + t + 1; t = len[4] = strlen(TXT_SUICIDES_SHORT);
|
|
pos[5] = pos[4] + t + 1; t = len[5] = strlen(TXT_PING);
|
|
|
|
memcpy(&buffer[pos[0]],TXT_PILOT,strlen(TXT_PILOT));
|
|
memcpy(&buffer[pos[1]],TXT_POINTS,len[1]);
|
|
memcpy(&buffer[pos[2]],TXT_KILLS_SHORT,len[2]);
|
|
memcpy(&buffer[pos[3]],TXT_DEATHS_SHORT,len[3]);
|
|
memcpy(&buffer[pos[4]],TXT_SUICIDES_SHORT,len[4]);
|
|
memcpy(&buffer[pos[5]],TXT_PING,len[5]);
|
|
buffer[pos[5]+len[5]+1] = '\n';
|
|
buffer[pos[5]+len[5]+2] = '\0';
|
|
DPrintf(buffer);
|
|
|
|
int slot;
|
|
player_record *pr;
|
|
int pcount;
|
|
|
|
if(level<0 || level>=MAX_PLAYER_RECORDS)
|
|
pcount = MAX_PLAYER_RECORDS;
|
|
else
|
|
pcount = level;
|
|
|
|
netplayer *dNetPlayers = DMFCBase->GetNetPlayers();
|
|
|
|
int sortedplayers[MAX_PLAYER_RECORDS];
|
|
DMFCBase->GetSortedPlayerSlots(sortedplayers,MAX_PLAYER_RECORDS);
|
|
|
|
for(i=0;i<pcount;i++){
|
|
slot = sortedplayers[i];
|
|
pr = DMFCBase->GetPlayerRecord(slot);
|
|
if((pr)&&(pr->state!=STATE_EMPTY)){
|
|
|
|
if(DMFCBase->IsPlayerDedicatedServer(pr))
|
|
continue; //skip dedicated server
|
|
|
|
sprintf(name,"%s%s: %.8s",(pr->state==STATE_DISCONNECTED)?"*":"",pr->callsign,DMFCBase->GetTeamString(pr->team));
|
|
name[29] = '\0';
|
|
|
|
memset(buffer,' ',256);
|
|
t = strlen(name); memcpy(&buffer[pos[0]],name,(t<len[0])?t:len[0]);
|
|
sprintf(name,"%d",pr->dstats.kills[DSTAT_LEVEL]-pr->dstats.suicides[DSTAT_LEVEL]);
|
|
t = strlen(name); memcpy(&buffer[pos[1]],name,(t<len[1])?t:len[1]);
|
|
sprintf(name,"%d",pr->dstats.kills[DSTAT_LEVEL]);
|
|
t = strlen(name); memcpy(&buffer[pos[2]],name,(t<len[2])?t:len[2]);
|
|
sprintf(name,"%d",pr->dstats.deaths[DSTAT_LEVEL]);
|
|
t = strlen(name); memcpy(&buffer[pos[3]],name,(t<len[3])?t:len[3]);
|
|
sprintf(name,"%d",pr->dstats.suicides[DSTAT_LEVEL]);
|
|
t = strlen(name); memcpy(&buffer[pos[4]],name,(t<len[4])?t:len[4]);
|
|
|
|
if(pr->state==STATE_INGAME)
|
|
sprintf(name,"%.0f",dNetPlayers[pr->pnum].ping_time*1000.0f);
|
|
else
|
|
strcpy(name,"---");
|
|
t = strlen(name); memcpy(&buffer[pos[5]],name,(t<len[5])?t:len[5]);
|
|
buffer[pos[5]+len[5]+1] = '\n';
|
|
buffer[pos[5]+len[5]+2] = '\0';
|
|
DPrintf(buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef MACINTOSH
|
|
#pragma export off
|
|
#endif
|
|
|