mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-23 03:58:59 +00:00
2838 lines
79 KiB
C++
2838 lines
79 KiB
C++
/*
|
|
* $Logfile: /DescentIII/Main/ctf/ctf.cpp $
|
|
* $Revision: 1.1.1.1 $
|
|
* $Date: 2003/08/26 03:56:47 $
|
|
* $Author: kevinb $
|
|
*
|
|
* <insert description of file here>
|
|
*
|
|
* $Log: ctf.cpp,v $
|
|
* Revision 1.1.1.1 2003/08/26 03:56:47 kevinb
|
|
* initial 1.5 import
|
|
*
|
|
*
|
|
* 140 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.
|
|
*
|
|
* 139 9/24/01 2:28p Matt
|
|
* Allowed room for longer team name on results screen.
|
|
*
|
|
* 138 9/20/01 12:58p Matt
|
|
* Added a team member list to the stats file.
|
|
*
|
|
* 137 10/21/99 9:27p Jeff
|
|
* B.A. Macintosh code merge
|
|
*
|
|
* 136 9/03/99 5:30p Jeff
|
|
* use the flag's roomnumber instead of the player's roomnum when checking
|
|
* for a score (in case of a really thin room that the flag is in)
|
|
*
|
|
* 135 8/17/99 5:53p Jeff
|
|
* track ranks on PXO
|
|
*
|
|
* 134 7/15/99 1:17a Jeff
|
|
* fixed up $scores
|
|
*
|
|
* 133 7/13/99 12:10p Jeff
|
|
* added some specific text taunt token decoding
|
|
*
|
|
* 132 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
|
|
*
|
|
* 131 7/11/99 6:54p Jeff
|
|
* fixed PLR so it doesn't go off the screen on long lists and active
|
|
* players in the game are shown first
|
|
*
|
|
* 130 6/10/99 5:21p Jeff
|
|
* fixed crash in french version, due to local array being to small
|
|
*
|
|
* 129 5/26/99 4:38a Jeff
|
|
* fixed ctf bad scoring bugs
|
|
*
|
|
* 128 5/23/99 3:04a Jason
|
|
* fixed bug with player rankings not being updated correctly
|
|
*
|
|
* 127 5/20/99 7:54p 3dsmax
|
|
* changed number of attach points
|
|
*
|
|
* 126 5/12/99 11:04p Jeff
|
|
* dmfc and multiplayer games now have endian friendly packets (*whew*)
|
|
*
|
|
* 125 5/12/99 11:28a Jeff
|
|
* added sourcesafe comment block
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
|
|
|
|
#include "gamedll_header.h"
|
|
#include <string.h>
|
|
|
|
#include "idmfc.h"
|
|
#include "ctf.h"
|
|
#include "CTFstr.h"
|
|
|
|
IDMFC *DMFCBase;
|
|
IDmfcStats *dstat;
|
|
|
|
object *dObjects;
|
|
player *dPlayers;
|
|
room *dRooms;
|
|
netplayer *dNetPlayers;
|
|
|
|
#define SPID_GAMESTATE 0x01
|
|
#define SPID_ADDDELFLAG 0x02
|
|
#define SPID_COLLIDE 0x03
|
|
|
|
//Inventory flags
|
|
#define FLAGMASK_REDTEAM 0x01
|
|
#define FLAGMASK_BLUETEAM 0x02
|
|
#define FLAGMASK_GREENTEAM 0x04
|
|
#define FLAGMASK_YELLOWTEAM 0x08
|
|
|
|
//athome masks
|
|
#define REDAH 0x001
|
|
#define BLUEAH 0x002
|
|
#define GREENAH 0x004
|
|
#define YELLOWAH 0x008
|
|
|
|
#define FLAG_TIMEOUT_VALUE 120
|
|
//Sound name defines
|
|
#define SOUND_PICKUPFLAG_OWNTEAM "CTFPickupFlag1"
|
|
#define SOUND_PICKUPFLAG_OTHERTEAM "CTFPickupFlag1"
|
|
#define SOUND_SCORE_OWNTEAM "CTFScore1"
|
|
#define SOUND_SCORE_OTHERTEAM "CTFScore1"
|
|
#define SOUND_LOSEFLAG_OWNTEAM "CTFLostFlag1"
|
|
#define SOUND_LOSEFLAG_OTHERTEAM "CTFLostFlag1"
|
|
#define SOUND_FLAGRETURNED_OWNTEAM "CTFReturnedFlag1"
|
|
#define SOUND_FLAGRETURNED_OTHERTEAM "CTFReturnedFlag1"
|
|
#define SOUND_HATTRICK_FIRST "CTFHatTrick"
|
|
#define SOUND_HATTRICK_REGULAR "CTFHatTrick"
|
|
/*
|
|
$$TABLE_SOUND "CTFPickupFlag1"
|
|
$$TABLE_SOUND "CTFPickupFlag1"
|
|
$$TABLE_SOUND "CTFScore1"
|
|
$$TABLE_SOUND "CTFScore1"
|
|
$$TABLE_SOUND "CTFLostFlag1"
|
|
$$TABLE_SOUND "CTFLostFlag1"
|
|
$$TABLE_SOUND "CTFReturnedFlag1"
|
|
$$TABLE_SOUND "CTFReturnedFlag1"
|
|
$$TABLE_SOUND "CTFHatTrick"
|
|
$$TABLE_SOUND "CTFHatTrick"
|
|
*/
|
|
int snd_return_ownteam = -1;
|
|
int snd_return_otherteam = -1;
|
|
int snd_pickedup_otherteam = -1;
|
|
int snd_pickedup_ownteam = -1;
|
|
int snd_score_ownteam = -1;
|
|
int snd_score_otherteam = -1;
|
|
int snd_lose_ownteam = -1;
|
|
int snd_lose_otherteam = -1;
|
|
int snd_hattrick_first = -1;
|
|
int snd_hattrick_reg = -1;
|
|
|
|
typedef struct
|
|
{
|
|
int Score[2];
|
|
}tPlayerStat; //Overall scores (throughout the game)
|
|
int pack_pstat(tPlayerStat *user_info,ubyte *data)
|
|
{
|
|
int count = 0;
|
|
MultiAddInt(user_info->Score[0],data,&count);
|
|
MultiAddInt(user_info->Score[1],data,&count);
|
|
return count;
|
|
}
|
|
|
|
int unpack_pstat(tPlayerStat *user_info,ubyte *data)
|
|
{
|
|
int count = 0;
|
|
user_info->Score[0] = MultiGetInt(data,&count);
|
|
user_info->Score[1] = MultiGetInt(data,&count);
|
|
return count;
|
|
}
|
|
|
|
int SortedPlayers[MAX_PLAYER_RECORDS]; //sorted player nums
|
|
int SortedPLRPlayers[DLLMAX_TEAMS][MAX_PLAYER_RECORDS];
|
|
|
|
int TeamScores[DLLMAX_TEAMS]; //teams scores
|
|
int OverallTeamScores[DLLMAX_TEAMS]; //overall scores per team
|
|
int SortedTeams[DLLMAX_TEAMS]; //sorted team scores
|
|
int Highlight_bmp = -1;
|
|
bool DisplayScoreScreen;
|
|
bool Someone_has_hattrick = false; //this is false if no one has had a hattrick this level
|
|
bool First_game_frame = false;
|
|
|
|
int FlagIDs[DLLMAX_TEAMS]; //Flag Object ID's
|
|
int AFlagIDs[DLLMAX_TEAMS]; //Attached Flag Object ID's
|
|
int GoalRooms[DLLMAX_TEAMS]; //Goal Rooms for Teams
|
|
int FlagBmp[DLLMAX_TEAMS]; //Flag Bitmap handles
|
|
int FlagAHBmp[DLLMAX_TEAMS]; //Flag At Home Bitmap handles
|
|
int DimFlagAHBmp[DLLMAX_TEAMS]; //Dimmed versions of the Flag At Home Bitmaps
|
|
bool FlagAtHome[DLLMAX_TEAMS]; //Flag At Home bools
|
|
int HasFlag[DLLMAX_TEAMS]; //List of Playernums of who has what flag, -1 if no one does
|
|
bool DisplayFlagBlink=true,DisplayScoreBlink=true;
|
|
int WhoJustFlagged=-1,WhoJustFlaggedTimer=-1;
|
|
int WhoJustScored=-1,WhoJustScoredTimer=-1;
|
|
int CTFNumOfTeams = 2;
|
|
int ChildFlags[DLLMAX_TEAMS]; //Object handles of attached flags as a player has em
|
|
|
|
float Flag_timeout_timers[DLLMAX_TEAMS];
|
|
bool display_my_welcome = false;
|
|
|
|
void OnTimerScoreKill(void); //timer callback: when a score flash timer ends
|
|
void OnTimerScore(void); //timer callback: on a score flash interval
|
|
void OnTimer(void); //timer callback: when a flag taken flash timer ends
|
|
void OnTimerKill(void); //timer callback: on a flag taken flash interval
|
|
void DisplayWelcomeMessage(int player_num); //displays a welcome message to the player when he joins
|
|
void SortTeamScores(int *sortedindex,int *scores); //sorts an array of team scores, filling in the sorted index numbers
|
|
void DisplayHUDScores(struct tHUDItem *hitem); //callback when the HUD info is to be drawn
|
|
void ReceiveGameState(ubyte *data); //callback when a gamestate packet is received from the server
|
|
void SendGameState(int playernum); //called when the server is to send gamestate packet to a client
|
|
void SetColoredBalls(int playernum,bool reset=false);//sets the colored balls around a player (determined by what is in their inventory)
|
|
void ChangeNumberOfTeams(int newsize); //called when the number of teams in the game is changed or to be changed
|
|
void DoFlagReturnedHome(int team); //called to handle any events when a flag is returned home for a team
|
|
void DoLoseFlag(int team); //called to handle any events when a team loses their flag
|
|
void TellClientsToAddorDelFlag(int pnum,int team,int objnum,bool add);
|
|
void ServerIsTellingMeToAddorDelAFlag(ubyte *data);
|
|
void OnGetTokenString(char *src,char *dest,int dest_size);
|
|
// returns the number of flags a player has, 0 if none, or an invalid pnum
|
|
int GetFlagCountForPlayer(int pnum);
|
|
// returns the mask of which flags this player currently has
|
|
ubyte GetFlagMaskForPlayer(int pnum);
|
|
// adds a flag to a player, as a precaution, it will go through all the players and makes sure that no one
|
|
// has the flag that is being added. If they are adding the flag, than remove that flag from whoever we thought had it
|
|
// it will return false if it had to remove a flag from a player
|
|
bool GivePlayerFlag(int pnum,ubyte team);
|
|
//this function takes a flag away from the player, useful for when he scores, spews, disconnects, or observer modes
|
|
void LoseFlagForPlayer(int pnum,ubyte team,bool remove_from_inven=true);
|
|
|
|
///////////////////////////////////////////////
|
|
//localization info/functions
|
|
char **StringTable;
|
|
int StringTableSize = 0;
|
|
char *_ErrorString = "Missing String";
|
|
char *GetString(int d){if( (d<0) || (d>=StringTableSize) ) return _ErrorString; else return StringTable[d];}
|
|
void SaveStatsToFile(char *filename);
|
|
|
|
#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 = 4;
|
|
options->min_teams = 2;
|
|
strcpy(options->game_name,TXT_CTF);
|
|
strcpy(options->requirements,"MINGOALS2,GOALPERTEAM");
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
tPlayerStat *stat = (tPlayerStat *)pr->user_info;
|
|
sprintf(buffer,"%d",(stat)?stat->Score[DSTAT_LEVEL]:0);
|
|
}
|
|
|
|
void TeamScoreCallback(int team,char *buffer,int buffer_size)
|
|
{
|
|
ASSERT(team>=0 && team<DLLMAX_TEAMS);
|
|
|
|
sprintf(buffer," %d",TeamScores[team]);
|
|
}
|
|
|
|
void ShowStatBitmap(int precord_num,int column_num,int x,int y,int w,int h,ubyte alpha_to_use)
|
|
{
|
|
player_record *pr = DMFCBase->GetPlayerRecord(precord_num);
|
|
int flagcount,flagmask;
|
|
|
|
if(pr && pr->state==STATE_INGAME ){
|
|
|
|
flagcount = GetFlagCountForPlayer(pr->pnum);
|
|
|
|
if(!flagcount)
|
|
return;
|
|
|
|
flagmask = GetFlagMaskForPlayer(pr->pnum);
|
|
|
|
//Display the flags that this player has
|
|
x = x + w - (11*flagcount);
|
|
for(int q=0;q<CTFNumOfTeams;q++){
|
|
//draw all the flags the player has in his inventory
|
|
if(flagmask&0x01){
|
|
//player has this flag
|
|
DLLRenderHUDQuad(x,y,10,10,0,0,1,1,FlagBmp[q],alpha_to_use,0);
|
|
x += 11;
|
|
}
|
|
|
|
//rotate 1 bit for next flag
|
|
flagmask = flagmask>>1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
// 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);
|
|
|
|
// Setup event handlers
|
|
DMFCBase->Set_OnInterval(OnInterval);
|
|
DMFCBase->Set_OnHUDInterval(OnHUDInterval);
|
|
DMFCBase->Set_OnKeypress(OnKeypress);
|
|
DMFCBase->Set_OnServerGameCreated(OnServerGameCreated);
|
|
DMFCBase->Set_OnClientLevelStart(OnClientLevelStart);
|
|
DMFCBase->Set_OnClientLevelEnd(OnClientLevelEnd);
|
|
DMFCBase->Set_OnGameStateRequest(OnGameStateRequest);
|
|
DMFCBase->Set_OnPlayerConnect(OnPlayerConnect);
|
|
DMFCBase->Set_OnClientPlayerKilled(OnClientPlayerKilled);
|
|
DMFCBase->Set_OnServerCollide(OnServerCollide);
|
|
//DMFCBase->Set_OnClientCollide(OnClientCollide);
|
|
DMFCBase->Set_OnPLRInterval(OnPLRInterval);
|
|
DMFCBase->Set_OnPLRInit(OnPLRInit);
|
|
DMFCBase->Set_OnCanChangeTeam(OnCanChangeTeam);
|
|
DMFCBase->Set_OnSaveStatsToFile(OnSaveStatsToFile);
|
|
DMFCBase->Set_OnLevelEndSaveStatsToFile(OnLevelEndSaveStatsToFile);
|
|
DMFCBase->Set_OnDisconnectSaveStatsToFile(OnDisconnectSaveStatsToFile);
|
|
DMFCBase->Set_OnPrintScores(OnPrintScores);
|
|
DMFCBase->Set_OnPlayerEntersObserver(OnPlayerEntersObserver);
|
|
DMFCBase->Set_OnClientPlayerDisconnect(OnClientPlayerDisconnect);
|
|
DMFCBase->Set_OnPlayerChangeTeam(OnPlayerChangeTeam);
|
|
DMFCBase->Set_OnGetTokenString(OnGetTokenString);
|
|
|
|
// Setup arrays for easier to read code
|
|
dObjects = DMFCBase->GetObjects();
|
|
dPlayers = DMFCBase->GetPlayers();
|
|
dRooms = DMFCBase->GetRooms();
|
|
dNetPlayers = DMFCBase->GetNetPlayers();
|
|
|
|
netgame_info *Netgame = DMFCBase->GetNetgameInfo();
|
|
Netgame->flags |= (NF_TRACK_RANK);
|
|
|
|
CTFNumOfTeams = num_teams_to_use;
|
|
|
|
DMFCBase->GameInit(CTFNumOfTeams);
|
|
DLLCreateStringTable("CTF.str",&StringTable,&StringTableSize);
|
|
DLLmprintf((0,"%d strings loaded from string table\n",StringTableSize));
|
|
if(!StringTableSize){
|
|
*all_ok = 0;
|
|
return;
|
|
}
|
|
|
|
ChangeNumberOfTeams(CTFNumOfTeams);
|
|
|
|
//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);
|
|
|
|
//setup the Playerstats struct so DMFC can handle it automatically when a new player enters the game
|
|
DMFCBase->SetupPlayerRecord(sizeof(tPlayerStat),(int (*)(void *,ubyte *))pack_pstat,(int (*)(void *,ubyte *))unpack_pstat);
|
|
|
|
DMFCBase->AddHUDItemCallback(HI_TEXT,DisplayHUDScores);
|
|
|
|
DMFCBase->RegisterPacketReceiver(SPID_GAMESTATE,ReceiveGameState);
|
|
DMFCBase->RegisterPacketReceiver(SPID_ADDDELFLAG,ServerIsTellingMeToAddorDelAFlag);
|
|
DMFCBase->RegisterPacketReceiver(SPID_COLLIDE,OnClientCollide);
|
|
|
|
//Load all the bitmaps
|
|
FlagBmp[RED_TEAM] = DLLbm_AllocLoadFileBitmap("RedFlagIcon.ogf",0,BITMAP_FORMAT_1555);
|
|
FlagBmp[BLUE_TEAM] = DLLbm_AllocLoadFileBitmap("BlueFlagIcon.ogf",0,BITMAP_FORMAT_1555);
|
|
FlagBmp[GREEN_TEAM] = DLLbm_AllocLoadFileBitmap("GreenFlagIcon.ogf",0,BITMAP_FORMAT_1555);
|
|
FlagBmp[YELLOW_TEAM] = DLLbm_AllocLoadFileBitmap("YellowFlagIcon.ogf",0,BITMAP_FORMAT_1555);
|
|
//athome bitmaps
|
|
FlagAHBmp[RED_TEAM] = DLLbm_AllocLoadFileBitmap("RedFlagIcon.ogf",0,BITMAP_FORMAT_1555);
|
|
FlagAHBmp[BLUE_TEAM] = DLLbm_AllocLoadFileBitmap("BlueFlagIcon.ogf",0,BITMAP_FORMAT_1555);
|
|
FlagAHBmp[GREEN_TEAM] = DLLbm_AllocLoadFileBitmap("GreenFlagIcon.ogf",0,BITMAP_FORMAT_1555);
|
|
FlagAHBmp[YELLOW_TEAM] = DLLbm_AllocLoadFileBitmap("YellowFlagIcon.ogf",0,BITMAP_FORMAT_1555);
|
|
DimFlagAHBmp[RED_TEAM] = DLLbm_AllocLoadFileBitmap("RedFlagIconDim.ogf",0,BITMAP_FORMAT_1555);
|
|
DimFlagAHBmp[BLUE_TEAM] = DLLbm_AllocLoadFileBitmap("BlueFlagIconDim.ogf",0,BITMAP_FORMAT_1555);
|
|
DimFlagAHBmp[GREEN_TEAM] = DLLbm_AllocLoadFileBitmap("GreenFlagIconDim.ogf",0,BITMAP_FORMAT_1555);
|
|
DimFlagAHBmp[YELLOW_TEAM] = DLLbm_AllocLoadFileBitmap("YellowFlagIconDim.ogf",0,BITMAP_FORMAT_1555);
|
|
//fill in the IDs
|
|
|
|
|
|
FlagIDs[RED_TEAM] = DLLFindObjectIDName("FlagRed");
|
|
FlagIDs[BLUE_TEAM] = DLLFindObjectIDName("Flagblue");
|
|
FlagIDs[GREEN_TEAM] = DLLFindObjectIDName("FlagGreen");
|
|
FlagIDs[YELLOW_TEAM] = DLLFindObjectIDName("FlagYellow");
|
|
AFlagIDs[RED_TEAM] = DLLFindObjectIDName("ShipRedFlag");
|
|
AFlagIDs[BLUE_TEAM] = DLLFindObjectIDName("ShipBlueFlag");
|
|
AFlagIDs[GREEN_TEAM] = DLLFindObjectIDName("ShipGreenFlag");
|
|
AFlagIDs[YELLOW_TEAM] = DLLFindObjectIDName("ShipYellowFlag");
|
|
|
|
//give initial values for the at home so they're set
|
|
FlagAtHome[RED_TEAM] = FlagAtHome[BLUE_TEAM] =
|
|
FlagAtHome[GREEN_TEAM] = FlagAtHome[YELLOW_TEAM] = false;
|
|
|
|
//make sure all was init ok
|
|
for(int i=0;i<DLLMAX_TEAMS;i++){
|
|
if((FlagBmp[i]<=BAD_BITMAP_HANDLE)||(FlagAHBmp[i]<=BAD_BITMAP_HANDLE)||
|
|
(DimFlagAHBmp[i]<=BAD_BITMAP_HANDLE)||(FlagIDs[i]<0)||(AFlagIDs[i]<0)){
|
|
*all_ok = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
//Load in and touch all the sounds so they're ready to rock
|
|
snd_score_ownteam = DLLFindSoundName(IGNORE_TABLE(SOUND_SCORE_OWNTEAM));
|
|
if(snd_score_ownteam!=-1)
|
|
DLLTouchSound(snd_score_ownteam);
|
|
snd_score_otherteam = DLLFindSoundName(IGNORE_TABLE(SOUND_SCORE_OTHERTEAM));
|
|
if(snd_score_otherteam!=-1)
|
|
DLLTouchSound(snd_score_otherteam);
|
|
snd_pickedup_otherteam =DLLFindSoundName(IGNORE_TABLE(SOUND_PICKUPFLAG_OWNTEAM));
|
|
if(snd_pickedup_otherteam!=-1)
|
|
DLLTouchSound(snd_pickedup_otherteam);
|
|
snd_pickedup_ownteam =DLLFindSoundName(IGNORE_TABLE(SOUND_PICKUPFLAG_OTHERTEAM));
|
|
if(snd_pickedup_ownteam!=-1)
|
|
DLLTouchSound(snd_pickedup_ownteam);
|
|
snd_return_ownteam = DLLFindSoundName(IGNORE_TABLE(SOUND_FLAGRETURNED_OWNTEAM));
|
|
if(snd_return_ownteam!=-1)
|
|
DLLTouchSound(snd_return_ownteam);
|
|
snd_return_otherteam = DLLFindSoundName(IGNORE_TABLE(SOUND_FLAGRETURNED_OTHERTEAM));
|
|
if(snd_return_otherteam!=-1)
|
|
DLLTouchSound(snd_return_otherteam);
|
|
snd_lose_ownteam = DLLFindSoundName(IGNORE_TABLE(SOUND_LOSEFLAG_OWNTEAM));
|
|
if(snd_lose_ownteam!=-1)
|
|
DLLTouchSound(snd_lose_ownteam);
|
|
snd_lose_otherteam = DLLFindSoundName(IGNORE_TABLE(SOUND_LOSEFLAG_OTHERTEAM));
|
|
if(snd_lose_otherteam!=-1)
|
|
DLLTouchSound(snd_lose_otherteam);
|
|
snd_hattrick_first = DLLFindSoundName(IGNORE_TABLE(SOUND_HATTRICK_FIRST));
|
|
if(snd_hattrick_first!=-1)
|
|
DLLTouchSound(snd_hattrick_first);
|
|
snd_hattrick_reg = DLLFindSoundName(IGNORE_TABLE(SOUND_HATTRICK_REGULAR));
|
|
if(snd_hattrick_reg!=-1)
|
|
DLLTouchSound(snd_hattrick_reg);
|
|
|
|
DisplayScoreScreen = false;
|
|
|
|
|
|
// Initialize the Stats Manager
|
|
// ----------------------------
|
|
|
|
tDmfcStatsInit tsi;
|
|
tDmfcStatsColumnInfo pl_col[7];
|
|
char gname[32];
|
|
strcpy(gname,TXT_CTF);
|
|
|
|
tsi.flags = DSIF_SHOW_PIC|DSIF_SHOW_OBSERVERICON|DSIF_SEPERATE_BY_TEAM;
|
|
tsi.cColumnCountDetailed = 0;
|
|
tsi.cColumnCountPlayerList = 7;
|
|
tsi.clbDetailedColumnBMP = NULL;
|
|
tsi.clbDetailedColumn = NULL;
|
|
tsi.clbPlayerColumn = DetermineScore;
|
|
tsi.clbPlayerColumnBMP = ShowStatBitmap;
|
|
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;
|
|
pl_col[0].title[0] = '\0';
|
|
pl_col[0].type = DSCOL_BMP;
|
|
pl_col[0].width = 33;
|
|
|
|
pl_col[1].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[1].title,TXT_PILOT);
|
|
pl_col[1].type = DSCOL_PILOT_NAME;
|
|
pl_col[1].width = 120;
|
|
|
|
pl_col[2].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[2].title,TXT_POINTS);
|
|
pl_col[2].type = DSCOL_CUSTOM;
|
|
pl_col[2].width = 52;
|
|
|
|
pl_col[3].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[3].title,TXT_KILLS_SHORT);
|
|
pl_col[3].type = DSCOL_KILLS_LEVEL;
|
|
pl_col[3].width = 47;
|
|
|
|
pl_col[4].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[4].title,TXT_DEATHS_SHORT);
|
|
pl_col[4].type = DSCOL_DEATHS_LEVEL;
|
|
pl_col[4].width = 47;
|
|
|
|
pl_col[5].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[5].title,TXT_SUICIDES_SHORT);
|
|
pl_col[5].type = DSCOL_SUICIDES_LEVEL;
|
|
pl_col[5].width = 47;
|
|
|
|
pl_col[6].color_type = DSCOLOR_TEAM;
|
|
strcpy(pl_col[6].title,TXT_PING);
|
|
pl_col[6].type = DSCOL_PING;
|
|
pl_col[6].width = 40;
|
|
|
|
dstat->Initialize(&tsi);
|
|
}
|
|
// Called when the DLL is shutdown
|
|
void DLLFUNCCALL DLLGameClose ()
|
|
{
|
|
//@@SaveConfig();
|
|
//@@DMFCBase->CFGClose();
|
|
|
|
//Free all the bitmaps
|
|
DLLbm_FreeBitmap(FlagBmp[RED_TEAM]);
|
|
DLLbm_FreeBitmap(FlagBmp[BLUE_TEAM]);
|
|
DLLbm_FreeBitmap(FlagBmp[GREEN_TEAM]);
|
|
DLLbm_FreeBitmap(FlagBmp[YELLOW_TEAM]);
|
|
DLLbm_FreeBitmap(DimFlagAHBmp[RED_TEAM]);
|
|
DLLbm_FreeBitmap(DimFlagAHBmp[BLUE_TEAM]);
|
|
DLLbm_FreeBitmap(DimFlagAHBmp[GREEN_TEAM]);
|
|
DLLbm_FreeBitmap(DimFlagAHBmp[YELLOW_TEAM]);
|
|
DLLbm_FreeBitmap(FlagAHBmp[RED_TEAM]);
|
|
DLLbm_FreeBitmap(FlagAHBmp[BLUE_TEAM]);
|
|
DLLbm_FreeBitmap(FlagAHBmp[GREEN_TEAM]);
|
|
DLLbm_FreeBitmap(FlagAHBmp[YELLOW_TEAM]);
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
//DMFC Overrides
|
|
|
|
//OnHUDInterval
|
|
void OnHUDInterval(void)
|
|
{
|
|
dstat->DoFrame();
|
|
|
|
DMFCBase->DisplayOutrageLogo();
|
|
|
|
DMFCBase->OnHUDInterval();
|
|
}
|
|
|
|
//OnInterval
|
|
void OnInterval(void)
|
|
{
|
|
DMFCBase->GetSortedPlayerSlots(SortedPlayers,MAX_PLAYER_RECORDS);
|
|
|
|
SortTeamScores(SortedTeams,TeamScores);
|
|
|
|
//Determine if a flag has timed out yet
|
|
for(int i=0;i<CTFNumOfTeams;i++){
|
|
if((HasFlag[i]==-1)&&(!FlagAtHome[i])){
|
|
//check the time out values
|
|
if(DMFCBase->GetGametime()>=Flag_timeout_timers[i]){
|
|
//the timeout has expired, move home!
|
|
vector home_pos;
|
|
int home,objnum;
|
|
|
|
Flag_timeout_timers[i] = 0;
|
|
FlagAtHome[i] = true;
|
|
HasFlag[i] = -1;
|
|
home = GoalRooms[i];
|
|
objnum = -1;
|
|
|
|
//find the flag objnum
|
|
for(int o=0;o<MAX_OBJECTS;o++){
|
|
if(dObjects[o].type==OBJ_POWERUP && dObjects[o].id==FlagIDs[i]){
|
|
//found it
|
|
objnum = o;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(objnum==-1){
|
|
//hmm couldn't find the flag
|
|
//this is messed up...will create the flag on the server and all will be happy
|
|
if(DMFCBase->GetLocalRole()==LR_SERVER){
|
|
int flagid = FlagIDs[i];
|
|
if( (flagid!=-1) && (home>=0) && (home<=DMFCBase->GetHighestRoomIndex()) && (!ROOMNUM_OUTSIDE(home)) && (dRooms[home].used) ){
|
|
//Safe to create the flag
|
|
DLLComputeRoomCenter(&home_pos,&dRooms[home]);
|
|
objnum = DLLObjCreate(OBJ_POWERUP,flagid,home,&home_pos,NULL,OBJECT_HANDLE_NONE);
|
|
DLLMultiSendObject(&dObjects[objnum],0,true);
|
|
}
|
|
}
|
|
}else{
|
|
if( (home>=0) && (home<=DMFCBase->GetHighestRoomIndex()) && (!ROOMNUM_OUTSIDE(home)) && (dRooms[home].used) ){
|
|
DLLComputeRoomCenter(&home_pos,&dRooms[home]);
|
|
DLLObjSetPos(&dObjects[objnum],&home_pos,home,NULL,false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DMFCBase->OnInterval();
|
|
|
|
First_game_frame = true;
|
|
}
|
|
|
|
//OnKeypress
|
|
// What it needs to do:
|
|
// 1) Test for F7 keypress
|
|
void OnKeypress(int key)
|
|
{
|
|
dllinfo *Data;
|
|
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);
|
|
}
|
|
|
|
//OnServerGameCreated
|
|
// What it needs to do:
|
|
// 1) Zero out all the stats for every player
|
|
// 2) Zero out team scores
|
|
// 3) Display welcome message to server
|
|
void OnServerGameCreated(void)
|
|
{
|
|
DMFCBase->OnServerGameCreated();
|
|
tPlayerStat *stat;
|
|
player_record *pr;
|
|
int i;
|
|
|
|
for(i=0;i<MAX_PLAYER_RECORDS;i++)
|
|
{
|
|
pr = DMFCBase->GetPlayerRecord(i);
|
|
if(pr){
|
|
stat = (tPlayerStat *)pr->user_info;
|
|
if(stat){
|
|
stat->Score[DSTAT_LEVEL] = 0;
|
|
stat->Score[DSTAT_OVERALL] = 0;
|
|
}
|
|
}
|
|
}
|
|
for(i=0;i<CTFNumOfTeams;i++){
|
|
TeamScores[i] = 0;
|
|
OverallTeamScores[i] = 0;
|
|
}
|
|
}
|
|
|
|
//OnClientLevelStart
|
|
// What it needs to do:
|
|
// 1) Zero out level scores for everyone
|
|
// 2) Reset colored balls
|
|
// 3) Zero out team scores
|
|
// 4) Set number of teams
|
|
// 5) If we are the server, create the flags and send them to the clients
|
|
void OnClientLevelStart(void)
|
|
{
|
|
int i;
|
|
|
|
DMFCBase->OnClientLevelStart();
|
|
|
|
First_game_frame = false;
|
|
|
|
for(i=0;i<MAX_PLAYER_RECORDS;i++){
|
|
SortedPlayers[i] = -1;
|
|
}
|
|
for(i=0;i<DLLMAX_TEAMS;i++){
|
|
|
|
SortedTeams[i] = -1;
|
|
Flag_timeout_timers[i] = 0;
|
|
ChildFlags[i] = OBJECT_HANDLE_NONE;
|
|
}
|
|
|
|
Someone_has_hattrick = false;
|
|
|
|
tPlayerStat *stat;
|
|
player_record *pr;
|
|
for(i=0;i<MAX_PLAYER_RECORDS;i++)
|
|
{
|
|
pr = DMFCBase->GetPlayerRecord(i);
|
|
if(pr){
|
|
stat = (tPlayerStat *)pr->user_info;
|
|
if(stat){
|
|
stat->Score[DSTAT_LEVEL] = 0;
|
|
}
|
|
}
|
|
}
|
|
for(i=0;i<DLLMAX_PLAYERS;i++)
|
|
{
|
|
SetColoredBalls(i,true);
|
|
}
|
|
|
|
//fill in the goal room #'s
|
|
for(i=0;i<DLLMAX_TEAMS;i++){
|
|
GoalRooms[i] = DLLGetGoalRoomForTeam(i);
|
|
FlagAtHome[i] = true;
|
|
HasFlag[i] = -1;
|
|
TeamScores[i] = 0;
|
|
}
|
|
|
|
DMFCBase->SetNumberOfTeams(CTFNumOfTeams);
|
|
DLLMultiPaintGoalRooms(NULL);
|
|
|
|
//Bash the inventory since it doesn't get reset for the server
|
|
DLLInvReset(DMFCBase->GetPlayerNum(),true);
|
|
|
|
//Display our welcome message
|
|
display_my_welcome = true;
|
|
|
|
//If we are the server create the flags
|
|
if(DMFCBase->GetLocalRole()!=LR_SERVER){
|
|
//Get the game state
|
|
DMFCBase->RequestGameState();
|
|
return;
|
|
}
|
|
|
|
vector vpos;
|
|
int objnum;
|
|
int flagid,goalroom;
|
|
|
|
for(i=0;i<CTFNumOfTeams;i++){
|
|
flagid = FlagIDs[i];
|
|
goalroom = GoalRooms[i];
|
|
if( (flagid!=-1) && (goalroom>=0) && (goalroom<=DMFCBase->GetHighestRoomIndex()) && (!ROOMNUM_OUTSIDE(goalroom)) && (dRooms[goalroom].used) ){
|
|
//Safe to create the flag
|
|
DLLmprintf((0,"Creating %s Flag\n",DMFCBase->GetTeamString(i)));
|
|
DLLComputeRoomCenter(&vpos,&dRooms[goalroom]);
|
|
objnum = DLLObjCreate(OBJ_POWERUP,flagid,goalroom,&vpos,NULL,OBJECT_HANDLE_NONE);
|
|
DLLMultiSendObject(&dObjects[objnum],0,true);
|
|
}
|
|
}
|
|
}
|
|
|
|
//OnServerCollide
|
|
// What it needs to do:
|
|
// 1) See if the player has collided with a flag, if so pass to clients
|
|
void OnServerCollide(object *me_obj,object *it_obj)
|
|
{
|
|
//see if we need to send this event to the clients
|
|
//only if me==player it==flag powerup
|
|
if(!me_obj || !it_obj)
|
|
return;
|
|
if( (me_obj->type==OBJ_PLAYER||me_obj->type==OBJ_GHOST) && (it_obj->type==OBJ_POWERUP) )
|
|
if( (it_obj->id==FlagIDs[RED_TEAM]) ||
|
|
(it_obj->id==FlagIDs[BLUE_TEAM]) ||
|
|
(it_obj->id==FlagIDs[GREEN_TEAM]) ||
|
|
(it_obj->id==FlagIDs[YELLOW_TEAM]) ){
|
|
|
|
//Start a packet for the collide
|
|
ubyte data[MAX_GAME_DATA_SIZE];
|
|
int count = 0;
|
|
DMFCBase->StartPacket(data,SPID_COLLIDE,&count);
|
|
int start = count;
|
|
|
|
//we need me, it and me roomnum
|
|
MultiAddUshort((me_obj-dObjects),data,&count);
|
|
MultiAddUshort((it_obj-dObjects),data,&count);
|
|
MultiAddInt(it_obj->roomnum,data,&count);
|
|
|
|
DMFCBase->SendPacket(data,count,SP_ALL);
|
|
OnClientCollide(&data[start]);
|
|
}
|
|
}
|
|
|
|
//OnClientCollide
|
|
// What it needs to do:
|
|
// 1) See if Player collided with own flag
|
|
// 1.1) Check to see if in home goal
|
|
// 1.1.1) Reset colored balls
|
|
// 1.1.2) Remove all the flags from the inventory, send them back to their home goal
|
|
// 1.1.3) Add scores
|
|
// 1.1.4) Print out score
|
|
// 1.1.5) Do Kill Goal check
|
|
// 1,2) Move home flag to center of base
|
|
// 2) else collide with another team's flag
|
|
// 2.1) Add flag to inventory
|
|
// 2.2) Set rotating balls
|
|
// 2.3) Print out message
|
|
void OnClientCollide(ubyte *data)
|
|
{
|
|
object *me_obj,*it_obj;
|
|
int me_roomnum;
|
|
int count = 0;
|
|
int me_serv_objnum,it_serv_objnum,me_client_objnum,it_client_objnum;
|
|
|
|
me_serv_objnum = MultiGetUshort(data,&count);
|
|
it_serv_objnum = MultiGetUshort(data,&count);
|
|
me_roomnum = MultiGetInt(data,&count);
|
|
|
|
me_client_objnum = DMFCBase->ConvertServerToLocalObjnum(me_serv_objnum);
|
|
it_client_objnum = DMFCBase->ConvertServerToLocalObjnum(it_serv_objnum);
|
|
|
|
if(me_client_objnum==-1 || it_client_objnum==-1)
|
|
{
|
|
Int3();
|
|
return;
|
|
}
|
|
|
|
me_obj = &dObjects[me_client_objnum];
|
|
it_obj = &dObjects[it_client_objnum];
|
|
|
|
// now process the collide
|
|
|
|
int fteam=-1; //flags team
|
|
int pnum = me_obj->id; //player number
|
|
int pteam=DMFCBase->GetPlayerTeam(pnum); //player's team
|
|
int i;
|
|
bool play_return_home_msg = false;
|
|
|
|
for(i=0;i<CTFNumOfTeams;i++){
|
|
if(it_obj->id==FlagIDs[i])
|
|
fteam = i;
|
|
}
|
|
|
|
if(fteam==-1){
|
|
return; //something wrong, as none of the IDs are one of the flag's IDs
|
|
}
|
|
|
|
// Reset the timer for this flag since it's guaranteed someone owns it now
|
|
// or it has been sent home.
|
|
Flag_timeout_timers[fteam] = 0;
|
|
|
|
//Did player collide with his own team's flag?
|
|
if(fteam==pteam)
|
|
{
|
|
short flag_count = 0;
|
|
vector fpos;
|
|
int groom;
|
|
int flagcount;
|
|
int flagmask;
|
|
|
|
bool captured_flags[DLLMAX_TEAMS];
|
|
for(i=0;i<DLLMAX_TEAMS;i++){
|
|
captured_flags[i] = false;
|
|
}
|
|
|
|
//Check what room the player is in, if they're not in home base, then it's no score
|
|
if(GoalRooms[fteam]==me_roomnum){
|
|
//ok so he is in his home base, now find out how many flags he has, score for each and return them home
|
|
flagcount = GetFlagCountForPlayer(pnum);
|
|
flagmask = GetFlagMaskForPlayer(pnum);
|
|
|
|
//now loop through the flags, check to see if we have them and handle it
|
|
for(i=0;i<CTFNumOfTeams;i++){
|
|
if(flagmask&0x01){
|
|
//we have the flag we're currently working on
|
|
captured_flags[i] = true;
|
|
groom = GoalRooms[i];
|
|
if( (groom>=0) && (groom<=DMFCBase->GetHighestRoomIndex()) && (!ROOMNUM_OUTSIDE(groom)) && (dRooms[groom].used)){
|
|
//the room is valid, so move it back to home
|
|
|
|
LoseFlagForPlayer(pnum,i);
|
|
|
|
if(DMFCBase->GetLocalRole()==LR_SERVER){
|
|
//if we are the server create the object and send it on it's way to the player's
|
|
DLLComputeRoomCenter(&fpos,&dRooms[groom]);
|
|
int objnum = DLLObjCreate(OBJ_POWERUP,FlagIDs[i],groom,&fpos,NULL,OBJECT_HANDLE_NONE);
|
|
DLLMultiSendObject(&dObjects[objnum],1,true);
|
|
}//end server create
|
|
}//end room ok
|
|
|
|
//set it's at home flag
|
|
FlagAtHome[i] = true;
|
|
}//end flag check
|
|
//rotate the flagmask over one to check for the next flag
|
|
flagmask = flagmask >> 1;
|
|
}//end for loop
|
|
|
|
//remove any rotating balls
|
|
SetColoredBalls(pnum,true);
|
|
|
|
//Now handle any scoring
|
|
int score = 0;
|
|
switch(flagcount)
|
|
{
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
score = 1;
|
|
break;
|
|
case 2:
|
|
score = 3;
|
|
break;
|
|
case 3:
|
|
score = 9;
|
|
break;
|
|
}
|
|
|
|
//print out the message and add to the scores
|
|
|
|
if(score)
|
|
{
|
|
tPlayerStat *stat = (tPlayerStat *)DMFCBase->GetPlayerRecordData(pnum);
|
|
if(stat){
|
|
stat->Score[DSTAT_LEVEL] +=score;
|
|
stat->Score[DSTAT_OVERALL] +=score;
|
|
|
|
if(stat->Score[DSTAT_LEVEL]==3){
|
|
if(Someone_has_hattrick){
|
|
DLLAddHUDMessage(TXT_HATTRICK,dPlayers[pnum].callsign);
|
|
if(snd_hattrick_reg!=-1)
|
|
DLLPlay2dSound(snd_hattrick_reg,MAX_GAME_VOLUME/2);
|
|
}else{
|
|
DLLAddHUDMessage(TXT_HATTRICKFIRST,dPlayers[pnum].callsign);
|
|
if(snd_hattrick_first!=-1)
|
|
DLLPlay2dSound(snd_hattrick_first,MAX_GAME_VOLUME/2);
|
|
Someone_has_hattrick = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
TeamScores[pteam]+=score;
|
|
OverallTeamScores[pteam]+=score;
|
|
int newscore=TeamScores[pteam];
|
|
|
|
switch(flagcount){
|
|
case 1:
|
|
{
|
|
char t[20];
|
|
t[0] = '\0';
|
|
for(int c=0;c<DLLMAX_TEAMS;c++){
|
|
if(captured_flags[c]){
|
|
strcpy(t,DMFCBase->GetTeamString(c));
|
|
break;
|
|
}
|
|
}
|
|
DLLAddHUDMessage(TXT_CAPTURE,dPlayers[pnum].callsign,DMFCBase->GetTeamString(pteam),t);
|
|
}break;
|
|
case 2:
|
|
{
|
|
char t[2][20];
|
|
t[0][0] = '\0';
|
|
t[1][0] = '\0';
|
|
int index = 0;
|
|
for(int c=0;c<DLLMAX_TEAMS;c++){
|
|
if(captured_flags[c]){
|
|
strcpy(t[index],DMFCBase->GetTeamString(c));
|
|
index++;
|
|
if(index==2)
|
|
break;
|
|
}
|
|
}
|
|
DLLAddHUDMessage(TXT_CAPTURETWO,dPlayers[pnum].callsign,
|
|
DMFCBase->GetTeamString(pteam),t[0],t[1]);
|
|
}break;
|
|
case 3:
|
|
{
|
|
char t[3][20];
|
|
t[0][0] = '\0';
|
|
t[1][0] = '\0';
|
|
t[2][0] = '\0';
|
|
|
|
int index = 0;
|
|
for(int c=0;c<DLLMAX_TEAMS;c++){
|
|
if(captured_flags[c]){
|
|
strcpy(t[index],DMFCBase->GetTeamString(c));
|
|
index++;
|
|
if(index==3)
|
|
break;
|
|
}
|
|
}
|
|
DLLAddHUDMessage(TXT_CAPTURETHREE,dPlayers[pnum].callsign,
|
|
DMFCBase->GetTeamString(pteam),t[0],t[1],t[2]);
|
|
}
|
|
}
|
|
|
|
if(dPlayers[DMFCBase->GetPlayerNum()].team==pteam){
|
|
if(snd_score_ownteam!=-1)
|
|
DLLPlay2dSound(snd_score_ownteam,MAX_GAME_VOLUME/2);
|
|
}else{
|
|
if(snd_score_otherteam!=-1)
|
|
DLLPlay2dSound(snd_score_otherteam,MAX_GAME_VOLUME/2);
|
|
}
|
|
|
|
//Set a Timer to display
|
|
if(WhoJustScoredTimer!=-1)
|
|
DMFCBase->KillTimer(WhoJustScoredTimer);
|
|
WhoJustScoredTimer = DMFCBase->SetTimerInterval(OnTimerScore,0.5f,5.0f,OnTimerScoreKill);
|
|
WhoJustScored = pteam;
|
|
}
|
|
//do the killgoal check
|
|
int killgoal;
|
|
if(DMFCBase->GetScoreLimit(&killgoal)){
|
|
if(TeamScores[pteam]>=killgoal){
|
|
//That's all she wrote for this level
|
|
DLLmprintf((0,"OnClientCollide:Kill Goal Reached!\n"));
|
|
DMFCBase->EndLevel();
|
|
}
|
|
}
|
|
}else{
|
|
DoFlagReturnedHome(pteam);
|
|
if(DMFCBase->CheckPlayerNum(pnum)){
|
|
char parm1[20],parm2[20];
|
|
strcpy(parm1,DMFCBase->GetTeamString(pteam));
|
|
strcpy(parm2,DMFCBase->GetTeamString(fteam));
|
|
DLLAddHUDMessage(TXT_RETURN,dPlayers[pnum].callsign,parm1,parm2);
|
|
}
|
|
}
|
|
|
|
//since the player collided with his own team's flag we need to move the flag back home
|
|
FlagAtHome[pteam] = true;
|
|
HasFlag[pteam] = -1;
|
|
vector home_pos;
|
|
int home = GoalRooms[pteam];
|
|
|
|
if( (home>=0) && (home<=DMFCBase->GetHighestRoomIndex()) && (!ROOMNUM_OUTSIDE(home)) && (dRooms[home].used) )
|
|
{
|
|
DLLComputeRoomCenter(&home_pos,&dRooms[home]);
|
|
DLLObjSetPos(it_obj,&home_pos,home,NULL,false);
|
|
}
|
|
|
|
}//end Player Collides with own team's flag
|
|
else{
|
|
//The Player collide with another team's flag
|
|
FlagAtHome[fteam] = false;
|
|
|
|
//add the flag to the player
|
|
GivePlayerFlag(pnum,fteam);
|
|
|
|
if(dPlayers[DMFCBase->GetPlayerNum()].team==dPlayers[pnum].team){
|
|
if(snd_pickedup_ownteam!=-1)
|
|
DLLPlay2dSound(snd_pickedup_ownteam,MAX_GAME_VOLUME/2);
|
|
}else{
|
|
if(snd_pickedup_otherteam!=-1)
|
|
DLLPlay2dSound(snd_pickedup_otherteam,MAX_GAME_VOLUME/2);
|
|
}
|
|
|
|
//Set a Timer to display
|
|
if(WhoJustFlaggedTimer!=-1)
|
|
DMFCBase->KillTimer(WhoJustFlaggedTimer);
|
|
WhoJustFlaggedTimer = DMFCBase->SetTimerInterval(OnTimer,0.5f,5.0f,OnTimerKill);
|
|
WhoJustFlagged = fteam;
|
|
|
|
char parm1[20],parm2[20];
|
|
strcpy(parm1,DMFCBase->GetTeamString(pteam));
|
|
strcpy(parm2,DMFCBase->GetTeamString(fteam));
|
|
if(dObjects[dPlayers[pnum].objnum].roomnum==GoalRooms[fteam]){
|
|
DLLAddHUDMessage(TXT_PICKUPFLAG,dPlayers[pnum].callsign,parm1,parm2);
|
|
}else{
|
|
DLLAddHUDMessage(TXT_PICKUPFLAGSPEW,dPlayers[pnum].callsign,parm1,parm2);
|
|
}
|
|
|
|
//remove the flag from the world
|
|
if(DMFCBase->GetLocalRole()==LR_SERVER){
|
|
//tell the clients to remove this flag
|
|
DLLSetObjectDeadFlag(it_obj,true,false);
|
|
}
|
|
}
|
|
}
|
|
|
|
//OnGameStateRequest
|
|
// 1) Send game state to new player
|
|
void OnGameStateRequest(int player_num)
|
|
{
|
|
SendGameState(player_num);
|
|
DMFCBase->OnGameStateRequest(player_num);
|
|
}
|
|
|
|
void OnPlayerConnect(int player_num)
|
|
{
|
|
DMFCBase->OnPlayerConnect(player_num);
|
|
|
|
tPlayerStat *stat;
|
|
stat = (tPlayerStat *)DMFCBase->GetPlayerRecordData(player_num);
|
|
if(stat){
|
|
stat->Score[DSTAT_LEVEL] = 0;
|
|
stat->Score[DSTAT_OVERALL] = 0;
|
|
}
|
|
|
|
if(player_num!=DMFCBase->GetPlayerNum())
|
|
{
|
|
//announce the arrival of the player
|
|
DisplayWelcomeMessage(player_num);
|
|
}
|
|
}
|
|
|
|
void OnClientLevelEnd(void)
|
|
{
|
|
DMFCBase->OnClientLevelEnd();
|
|
}
|
|
|
|
void OnPlayerChangeTeam(int player_num,int newteam,bool announce,bool spew_onrespawn)
|
|
{
|
|
DMFCBase->OnPlayerChangeTeam(player_num,newteam,announce,spew_onrespawn);
|
|
player_record *pr = DMFCBase->GetPlayerRecordByPnum(player_num);
|
|
}
|
|
|
|
//OnClientPlayerKilled
|
|
// 1) If suicide add to suicides
|
|
// 2) Else add to killer's kill, add to victim's deaths
|
|
// 3) Reset colored balls
|
|
// 4) If killed in a flag's home goal than put it in the center of the room
|
|
void OnClientPlayerKilled(object *killer_obj,int victim_pnum)
|
|
{
|
|
int kpnum = -1;
|
|
|
|
if(killer_obj){
|
|
if((killer_obj->type==OBJ_PLAYER)||(killer_obj->type==OBJ_GHOST)||(killer_obj->type==OBJ_OBSERVER))
|
|
kpnum = killer_obj->id;
|
|
else if(killer_obj->type==OBJ_ROBOT || killer_obj->type == OBJ_BUILDING){
|
|
//countermeasure kill
|
|
kpnum = DMFCBase->GetCounterMeasureOwner(killer_obj);
|
|
}else{
|
|
kpnum = -1;
|
|
}
|
|
}
|
|
|
|
HandlePlayerSpew(victim_pnum);
|
|
DMFCBase->OnClientPlayerKilled(killer_obj,victim_pnum);
|
|
}
|
|
|
|
void OnClientPlayerDisconnect(int player_num)
|
|
{
|
|
HandlePlayerSpew(player_num);
|
|
DMFCBase->OnClientPlayerDisconnect(player_num);
|
|
}
|
|
|
|
void OnPlayerEntersObserver(int pnum,object *piggy)
|
|
{
|
|
HandlePlayerSpew(pnum);
|
|
DMFCBase->OnPlayerEntersObserver(pnum,piggy);
|
|
}
|
|
|
|
bool OnCanChangeTeam(int pnum,int newteam)
|
|
{
|
|
if(!DMFCBase->OnCanChangeTeam(pnum,newteam))
|
|
return false;
|
|
|
|
if(GetFlagCountForPlayer(pnum)){
|
|
DMFCBase->AnnounceTeamChangeDeny(pnum);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool compare_slots(int a,int b)
|
|
{
|
|
int ascore,bscore;
|
|
player_record *apr,*bpr;
|
|
tPlayerStat *astat,*bstat;
|
|
|
|
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;
|
|
astat = (tPlayerStat *)apr->user_info;
|
|
bstat = (tPlayerStat *)bpr->user_info;
|
|
|
|
if( (apr->state==STATE_INGAME) && (bpr->state==STATE_INGAME) ){
|
|
//both players were in the game
|
|
ascore = (astat)?astat->Score[DSTAT_LEVEL]:0;
|
|
bscore = (bstat)?bstat->Score[DSTAT_LEVEL]:0;
|
|
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 = (astat)?astat->Score[DSTAT_LEVEL]:0;
|
|
bscore = (bstat)?bstat->Score[DSTAT_LEVEL]:0;
|
|
return (ascore<bscore);
|
|
}
|
|
|
|
void OnPLRInit(void)
|
|
{
|
|
int tempsort[MAX_PLAYER_RECORDS];
|
|
int i,t,j;
|
|
|
|
for(i=0;i<MAX_PLAYER_RECORDS;i++){
|
|
tempsort[i] = i;
|
|
}
|
|
|
|
for(i=1;i<=MAX_PLAYER_RECORDS-1;i++){
|
|
t=tempsort[i];
|
|
// Shift elements down until
|
|
// insertion point found.
|
|
for(j=i-1;j>=0 && compare_slots(tempsort[j],t); j--){
|
|
tempsort[j+1] = tempsort[j];
|
|
}
|
|
// insert
|
|
tempsort[j+1] = t;
|
|
}
|
|
|
|
//copy the array over
|
|
memcpy(SortedPlayers,tempsort,MAX_PLAYER_RECORDS*sizeof(int));
|
|
|
|
//Now fill in the final structure of sorted names
|
|
int TeamCount[DLLMAX_TEAMS];
|
|
int team;
|
|
for(i=0;i<DLLMAX_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; //skip dedicated server
|
|
|
|
team = (pr->state==STATE_INGAME)?dPlayers[pr->pnum].team:pr->team;
|
|
|
|
if(team>=CTFNumOfTeams)
|
|
team = 0;
|
|
|
|
SortedPLRPlayers[team][TeamCount[team]] = slot;
|
|
|
|
TeamCount[team]++;
|
|
}
|
|
}
|
|
for(i=0;i<DLLMAX_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 = 180;
|
|
int PointsCol = 320;
|
|
int KillsCol = 370;
|
|
int DeathsCol = 410;
|
|
int SuicidesCol = 450;
|
|
int y = 40;
|
|
int slot;
|
|
bool had_members;
|
|
player_record *pr;
|
|
tPlayerStat *stat;
|
|
|
|
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(PointsCol,y,TXT_POINTS);
|
|
DLLgrtext_Printf(NameCol,y,TXT_PILOT);
|
|
DLLgrtext_Printf(KillsCol,y,TXT_KILLS_SHORT);
|
|
DLLgrtext_Printf(DeathsCol,y,TXT_DEATHS_SHORT);
|
|
DLLgrtext_Printf(SuicidesCol,y,TXT_SUICIDES_SHORT);
|
|
y+=height;
|
|
|
|
bool doing_connected = true;
|
|
|
|
do_disconnected_folk:
|
|
|
|
for(int team=0;team<CTFNumOfTeams;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_TEAMSCOREFORM,DMFCBase->GetTeamString(team),TeamScores[team],OverallTeamScores[team]);
|
|
}
|
|
had_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)
|
|
continue;
|
|
|
|
if(DMFCBase->IsPlayerDedicatedServer(pr))
|
|
continue;
|
|
|
|
if( (doing_connected && DMFCBase->WasPlayerInGameAtLevelEnd(slot)==-1) ||
|
|
(!doing_connected && DMFCBase->WasPlayerInGameAtLevelEnd(slot)!=-1) )
|
|
continue;//we're not handling them right now
|
|
|
|
stat = (tPlayerStat *)pr->user_info;
|
|
|
|
int pnum=DMFCBase->WasPlayerInGameAtLevelEnd(slot);
|
|
if(pnum!=-1)
|
|
{
|
|
DLLgrtext_SetColor(DMFCBase->GetTeamColor(team));
|
|
}else
|
|
{
|
|
DLLgrtext_SetColor(GR_RGB(128,128,128));
|
|
}
|
|
|
|
//valid player
|
|
char temp[120];
|
|
sprintf(temp,"%s",pr->callsign);
|
|
DMFCBase->ClipString(PointsCol - NameCol - 10,temp,true);
|
|
|
|
DLLgrtext_Printf(NameCol,y,"%s",temp);
|
|
DLLgrtext_Printf(PointsCol,y,"%d",(stat)?stat->Score[DSTAT_LEVEL]:0);
|
|
DLLgrtext_Printf(KillsCol,y,"%d",pr->dstats.kills[DSTAT_LEVEL]);
|
|
DLLgrtext_Printf(DeathsCol,y,"%d",pr->dstats.deaths[DSTAT_LEVEL]);
|
|
DLLgrtext_Printf(SuicidesCol,y,"%d",pr->dstats.suicides[DSTAT_LEVEL]);
|
|
y+=height;
|
|
|
|
if(y>=440)
|
|
goto quick_exit;
|
|
|
|
had_members = true;
|
|
|
|
}//end for
|
|
|
|
if(!had_members)
|
|
{
|
|
//skip a line
|
|
y+=height;
|
|
|
|
if(y>=440)
|
|
goto quick_exit;
|
|
}
|
|
//on to the next team
|
|
}//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;
|
|
tPlayerStat *ps;
|
|
int count,length,p;
|
|
int team;
|
|
|
|
//sort the stats
|
|
DMFCBase->GetSortedPlayerSlots(sortedslots,MAX_PLAYER_RECORDS);
|
|
|
|
int i,t,j;
|
|
|
|
for(i=0;i<MAX_PLAYER_RECORDS;i++){
|
|
sortedslots[i] = i;
|
|
}
|
|
|
|
for(i=1;i<=MAX_PLAYER_RECORDS-1;i++){
|
|
t=sortedslots[i];
|
|
// Shift elements down until
|
|
// insertion point found.
|
|
for(j=i-1;j>=0 && compare_slots(sortedslots[j],t); j--){
|
|
sortedslots[j+1] = sortedslots[j];
|
|
}
|
|
// insert
|
|
sortedslots[j+1] = t;
|
|
}
|
|
|
|
count = 1;
|
|
|
|
sprintf(buffer,TXT_STAT_HEADING,(DMFCBase->GetNetgameInfo())->name,(DMFCBase->GetCurrentMission())->cur_level);
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
for(i=0;i<DMFCBase->GetNumTeams();i++){
|
|
int team = SortedTeams[i];
|
|
|
|
sprintf(buffer,"%s: %d[%d]",DMFCBase->GetTeamString(team),TeamScores[team],OverallTeamScores[team]);
|
|
DLLcf_WriteString(file,buffer);
|
|
}
|
|
strcpy(buffer,"\r\n");
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
//Write team members
|
|
DLLcf_WriteString(file,""); //blank line
|
|
for(t=0;t<DMFCBase->GetNumTeams();t++){
|
|
int team_i = SortedTeams[t];
|
|
|
|
sprintf(buffer,"%s:",DMFCBase->GetTeamString(team_i));
|
|
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_STAT_HEADINGA);
|
|
DLLcf_WriteString(file,buffer);
|
|
sprintf(buffer,"--------------------------------------------------------------------------------------------------");
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
for(int pslot=0;pslot<MAX_PLAYER_RECORDS;pslot++){
|
|
int real_slot = sortedslots[pslot];
|
|
pr = DMFCBase->GetPlayerRecord(real_slot);
|
|
if( pr && pr->state!=STATE_EMPTY){
|
|
|
|
if(DMFCBase->IsPlayerDedicatedServer(pr))
|
|
continue;//skip dedicated server
|
|
|
|
//we have a valid play
|
|
ps = (tPlayerStat *)pr->user_info;
|
|
memset(buffer,' ',BUFSIZE);
|
|
|
|
team = pr->team;
|
|
|
|
sprintf(tempbuffer,"%d)",count);
|
|
memcpy(&buffer[0],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%.6s",DMFCBase->GetTeamString(team));
|
|
memcpy(&buffer[5],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%s%s",(pr->state==STATE_INGAME)?"":"*",pr->callsign);
|
|
memcpy(&buffer[12],tempbuffer,strlen(tempbuffer));
|
|
|
|
if(ps){
|
|
sprintf(tempbuffer,"%d[%d]",ps->Score[DSTAT_LEVEL],ps->Score[DSTAT_OVERALL]);
|
|
memcpy(&buffer[41],tempbuffer,strlen(tempbuffer));
|
|
}
|
|
|
|
sprintf(tempbuffer,"%d[%d]",pr->dstats.kills[DSTAT_LEVEL],pr->dstats.kills[DSTAT_OVERALL]);
|
|
memcpy(&buffer[53],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d[%d]",pr->dstats.deaths[DSTAT_LEVEL],pr->dstats.deaths[DSTAT_OVERALL]);
|
|
memcpy(&buffer[65],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%d[%d]",pr->dstats.suicides[DSTAT_LEVEL],pr->dstats.suicides[DSTAT_OVERALL]);
|
|
memcpy(&buffer[76],tempbuffer,strlen(tempbuffer));
|
|
|
|
sprintf(tempbuffer,"%s",DMFCBase->GetTimeString(DMFCBase->GetTimeInGame(real_slot)));
|
|
memcpy(&buffer[86],tempbuffer,strlen(tempbuffer));
|
|
|
|
int pos;
|
|
pos = 86 + strlen(tempbuffer) + 1;
|
|
if(pos<BUFSIZE)
|
|
buffer[pos] = '\0';
|
|
|
|
buffer[BUFSIZE-1] = '\0';
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
count++;
|
|
}
|
|
}//end for
|
|
|
|
|
|
DLLcf_WriteString(file,TXT_STAT_HEADINGB);
|
|
|
|
count = 1;
|
|
for(int s=0;s<MAX_PLAYER_RECORDS;s++){
|
|
p = sortedslots[s];
|
|
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_STAT_TIG,DMFCBase->GetTimeString(DMFCBase->GetTimeInGame(p)));
|
|
DLLcf_WriteString(file,buffer);
|
|
|
|
if(DMFCBase->FindPInfoStatFirst(p,&stat)){
|
|
sprintf(buffer,TXT_STAT_HEADINGC);
|
|
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_STAT_SAVED);
|
|
}
|
|
|
|
#define ROOTFILENAME "CTF"
|
|
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);
|
|
}
|
|
|
|
void OnPrintScores(int level)
|
|
{
|
|
char buffer[256];
|
|
char name[70];
|
|
int t,i;
|
|
int pos[6];
|
|
int len[6];
|
|
|
|
|
|
for(i=0;i<CTFNumOfTeams;i++)
|
|
{
|
|
sprintf(buffer,"%s:%d\n",DMFCBase->GetTeamString(i),TeamScores[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;
|
|
|
|
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';
|
|
|
|
tPlayerStat *stat;
|
|
stat = (tPlayerStat *)pr->user_info;
|
|
|
|
memset(buffer,' ',256);
|
|
t = strlen(name); memcpy(&buffer[pos[0]],name,(t<len[0])?t:len[0]);
|
|
sprintf(name,"%d",(stat)?stat->Score[DSTAT_LEVEL]:0);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
// DMFCApp::HandlePlayerSpew
|
|
//
|
|
// If a player dies, becomes an observer or disconnects, it's possible that they
|
|
// have a flag or more. This function will handle setting certain variables, timer
|
|
// and other various settings related to a flag spew
|
|
void HandlePlayerSpew(int pnum)
|
|
{
|
|
//Handle dropping the flag if the player had one
|
|
ubyte flaginfo = GetFlagCountForPlayer(pnum);
|
|
ubyte flagmask = GetFlagMaskForPlayer(pnum);
|
|
|
|
if(flaginfo==0){
|
|
return;
|
|
}
|
|
|
|
//Ok the player has flags, lets make sure everything that needs to happen, happens
|
|
// 1) We need to clear flags and colored ball indicator
|
|
// 2) If they are dying in a homebase of one of the flags they have, than set the
|
|
// flag home.
|
|
// 3) Start a timer if the flag spews outside of a base
|
|
|
|
//If we got here than the player has a flag
|
|
vector fpos; //used to hold the center pos of the room
|
|
|
|
bool play_lose = false; //set true if the player lost a flag (ummm, this is guaranteed)
|
|
|
|
//loop through all the possible flags and check to see what they had
|
|
for(int color=0;color<DLLMAX_TEAMS;color++){
|
|
//check if the ID exists, and if this player had that color flag
|
|
if( (FlagIDs[color]!=-1) && (flagmask&0x01) ){
|
|
|
|
play_lose = true;
|
|
|
|
//now check to see if they are in the flag's home goal
|
|
if(GoalRooms[color]==dObjects[pnum].roomnum){
|
|
//we are!
|
|
//so remove the flag from the inventory (so it don't get spewed)
|
|
DLLInvRemove(pnum,OBJ_POWERUP,FlagIDs[color]);
|
|
DoFlagReturnedHome(color);
|
|
|
|
//set the at home flag
|
|
FlagAtHome[color] = true;
|
|
if(DMFCBase->GetLocalRole()==LR_SERVER){
|
|
//if we are the server put the flag back in the center of the goal and tell all the players to do the same
|
|
DLLComputeRoomCenter(&fpos,&dRooms[GoalRooms[color]]);
|
|
int objnum = DLLObjCreate(OBJ_POWERUP,FlagIDs[color],GoalRooms[color],&fpos,NULL,OBJECT_HANDLE_NONE);
|
|
DLLMultiSendObject(&dObjects[objnum],1,true);
|
|
}
|
|
}else{
|
|
//ok the flag is spewing out into the great beyond
|
|
//Start the timer!
|
|
Flag_timeout_timers[color] = DMFCBase->GetGametime() + FLAG_TIMEOUT_VALUE;
|
|
}
|
|
|
|
//player has the flag
|
|
LoseFlagForPlayer(pnum,color,false);
|
|
}
|
|
//rotate flagmask so it is pointing at the next bit
|
|
flagmask = (flagmask>>1);
|
|
}
|
|
|
|
// Reset colored balls
|
|
SetColoredBalls(pnum,true);
|
|
|
|
|
|
if(play_lose)
|
|
DoLoseFlag(DMFCBase->GetPlayerTeam(pnum));
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
//CTF Functions
|
|
void DisplayHUDScores(struct tHUDItem *hitem)
|
|
{
|
|
if(display_my_welcome)
|
|
{
|
|
//announce our arrival to ourselves (as server)
|
|
DisplayWelcomeMessage(DMFCBase->GetPlayerNum());
|
|
display_my_welcome = false;
|
|
}
|
|
|
|
if(!First_game_frame || DisplayScoreScreen) //interval hasn't been called yet or we are display the stats
|
|
return;
|
|
|
|
ubyte alpha = DMFCBase->ConvertHUDAlpha((ubyte)((DisplayScoreScreen)?128:255));
|
|
|
|
int height = DLLgrfont_GetHeight((DMFCBase->GetGameFontTranslateArray())[HUD_FONT_INDEX]) + 3;
|
|
|
|
int y = 170;
|
|
int x = 540;
|
|
int team = DMFCBase->GetPlayerTeam(DMFCBase->GetPlayerNum());
|
|
int myteam = team;
|
|
int i;
|
|
|
|
//Flag bitmaps
|
|
//if (HasFlag[team]!=-1) then draw a dimmed flag with the team flag of who has it on top
|
|
//if (HasFlag[team]==-1) && (FlagAtHome[team]==true) then draw normal flag
|
|
//if (HasFlag[team]==-1) && (FlagAtHome[team]==false) then draw dimmed flag
|
|
int cx,cy;
|
|
for(i=0;i<CTFNumOfTeams;i++){
|
|
//first determine the x and y
|
|
switch(i){
|
|
case RED_TEAM:
|
|
cx = x;
|
|
cy = height + 5;
|
|
break;
|
|
case BLUE_TEAM:
|
|
cx = x + 33;
|
|
cy = height + 5;
|
|
break;
|
|
case GREEN_TEAM:
|
|
cx = x;
|
|
cy = 2*height + 41;
|
|
break;
|
|
case YELLOW_TEAM:
|
|
cx = x + 33;
|
|
cy = 2*height + 41;
|
|
break;
|
|
}
|
|
|
|
if( (WhoJustFlagged!=i) || (DisplayFlagBlink) ){
|
|
if(HasFlag[i]!=-1){
|
|
//draw dimmed flag with corner as the team who has the flag
|
|
DLLRenderHUDQuad(cx,cy,DLLbm_w(DimFlagAHBmp[i],0),DLLbm_h(DimFlagAHBmp[i],0),0,0,1,1,DimFlagAHBmp[i],alpha,0);
|
|
DLLRenderHUDQuad(cx+16,cy,16,16,0,0,1,1,FlagBmp[DMFCBase->GetPlayerTeam(HasFlag[i])],alpha,0);
|
|
}
|
|
else{
|
|
if(FlagAtHome[i]){
|
|
//draw normal flag
|
|
DLLRenderHUDQuad(cx,cy,DLLbm_w(FlagAHBmp[i],0),DLLbm_h(FlagAHBmp[i],0),0,0,1,1,FlagAHBmp[i],alpha,0);
|
|
}
|
|
else{
|
|
//draw dimmed flag
|
|
int f_height = DLLbm_h(DimFlagAHBmp[i],0);
|
|
DLLRenderHUDQuad(cx,cy,DLLbm_w(DimFlagAHBmp[i],0),f_height,0,0,1,1,DimFlagAHBmp[i],alpha,0);
|
|
|
|
//Draw timeout time
|
|
int time_left;
|
|
time_left = (int)( Flag_timeout_timers[i] - DMFCBase->GetGametime());
|
|
if(time_left>0 && Flag_timeout_timers[i]!=0){
|
|
int minutes;
|
|
minutes = time_left/60;
|
|
time_left = time_left%60;
|
|
DLLRenderHUDText(GR_GREEN,alpha,0,cx,cy+2+f_height,"%01d:%02d",minutes,time_left);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
x = 520;
|
|
|
|
if(Highlight_bmp<=BAD_BITMAP_HANDLE){
|
|
//write the name of your team at the top of the screen since for some reason we don't a highlight bmp
|
|
DLLRenderHUDText(DMFCBase->GetTeamColor(team),alpha,0,x,y,TXT_TEAMFORM,DMFCBase->GetTeamString(team)); y+=height;
|
|
}
|
|
|
|
//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 = 85.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;
|
|
y = (DMFCBase->GetGameWindowH()/2) - ((height*DMFCBase->GetNumTeams())/2);
|
|
|
|
//draw the team scores
|
|
for(team=0;team<DLLMAX_TEAMS;team++){
|
|
i = SortedTeams[team];
|
|
|
|
if(i>=CTFNumOfTeams)
|
|
continue;
|
|
|
|
if((WhoJustScored!=i) || (DisplayScoreBlink) ){
|
|
|
|
//determine the number of players on the team
|
|
int num_players;
|
|
num_players = 0;
|
|
for(int w=0;w<DLLMAX_PLAYERS;w++){
|
|
if(DMFCBase->CheckPlayerNum(w) && dPlayers[w].team==i && !DMFCBase->IsPlayerDedicatedServer(w))
|
|
num_players++;
|
|
}
|
|
|
|
if(i==myteam && Highlight_bmp>BAD_BITMAP_HANDLE){
|
|
//draw the highlite bar in the background
|
|
DLLrend_SetAlphaValue(alpha*0.50f);
|
|
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,BITMAP_FORMAT_1555,NULL);
|
|
DLLrend_SetZBufferState (1);
|
|
}
|
|
|
|
char team_name[MAX_TEAMNAME_LEN+5];
|
|
sprintf(team_name,"[%d]%s",num_players,DMFCBase->GetTeamString(i));
|
|
//DMFCBase->ClipString(615 - x - 10,team_name,true);
|
|
//DLLRenderHUDText(DMFCBase->GetTeamColor(i),alpha,0,x,y,team_name);
|
|
//DLLRenderHUDText(DMFCBase->GetTeamColor(i),alpha,0,615,y,"%d",TeamScores[i]);
|
|
DMFCBase->ClipString(name_width,team_name,true);
|
|
|
|
DLLgrtext_SetAlpha(alpha);
|
|
DLLgrtext_SetColor(DMFCBase->GetTeamColor(i));
|
|
DLLgrtext_Printf(name_x,y,team_name);
|
|
DLLgrtext_Printf(score_x,y,"%d",TeamScores[i]);
|
|
|
|
}
|
|
y+=height;
|
|
}
|
|
|
|
//draw the bitmap for any flags you have currently
|
|
int flagcount;
|
|
int flagmask;
|
|
|
|
flagcount = GetFlagCountForPlayer(DMFCBase->GetPlayerNum());
|
|
flagmask = GetFlagMaskForPlayer(DMFCBase->GetPlayerNum());
|
|
|
|
if(flagcount==0)
|
|
return;
|
|
|
|
y+=5;
|
|
|
|
for(i=0;i<CTFNumOfTeams;i++){
|
|
if(flagmask&0x01){
|
|
//we have the flag
|
|
DLLRenderHUDQuad(x,y,DLLbm_w(FlagBmp[i],0)/2,DLLbm_h(FlagBmp[i],0)/2,0,0,1,1,FlagBmp[i],alpha,0);
|
|
x+=DLLbm_w(FlagBmp[i],0)+3;
|
|
}
|
|
//adjust the flagmask for the next flag
|
|
flagmask = flagmask>>1;
|
|
}
|
|
|
|
}
|
|
|
|
#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<DLLMAX_TEAMS;i++){
|
|
sortedindex[i] = i;
|
|
}
|
|
|
|
for(i=1;i<=DLLMAX_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())
|
|
{
|
|
DLLAddHUDMessage(TXT_WELCOME,name_buffer);
|
|
}
|
|
else
|
|
{
|
|
DLLAddHUDMessage(TXT_JOINED,name_buffer);
|
|
}
|
|
}
|
|
|
|
|
|
//adds a colored ball to a player (without removing what he has already)
|
|
void SetColoredBalls(int playernum,bool reset)
|
|
{
|
|
float redb[4];
|
|
float greenb[4];
|
|
float blueb[4];
|
|
|
|
if(reset){
|
|
DLLPlayerSetRotatingBall(playernum,0,0,NULL,NULL,NULL);
|
|
return;
|
|
}
|
|
|
|
int flagcount;
|
|
int flagmask;
|
|
|
|
bool red,blue,green,yellow;
|
|
red=blue=green=yellow = false;
|
|
|
|
flagcount = GetFlagCountForPlayer(playernum);
|
|
flagmask = GetFlagMaskForPlayer(playernum);
|
|
|
|
if(flagcount==0){
|
|
DLLPlayerSetRotatingBall(playernum,0,0,NULL,NULL,NULL);
|
|
return;
|
|
}
|
|
|
|
if(flagmask&FLAGMASK_REDTEAM)
|
|
red = true;
|
|
if(flagmask&FLAGMASK_BLUETEAM)
|
|
blue = true;
|
|
if(flagmask&FLAGMASK_GREENTEAM)
|
|
green = true;
|
|
if(flagmask&FLAGMASK_YELLOWTEAM)
|
|
yellow = true;
|
|
|
|
for(int i=0;i<flagcount;i++){
|
|
if(red){
|
|
red = false;
|
|
redb[i] = 1;
|
|
greenb[i] = 0;
|
|
blueb[i] = 0;
|
|
}else
|
|
if(blue){
|
|
blue = false;
|
|
redb[i] = 0;
|
|
greenb[i] = 0;
|
|
blueb[i] = 1;
|
|
}else
|
|
if(green){
|
|
green = false;
|
|
redb[i] = 0;
|
|
greenb[i] = 1;
|
|
blueb[i] = 0;
|
|
}else
|
|
if(yellow){
|
|
yellow = false;
|
|
redb[i] = 1;
|
|
greenb[i] = 1;
|
|
blueb[i] = 0;
|
|
}
|
|
}
|
|
|
|
DLLPlayerSetRotatingBall(playernum,flagcount,0,redb,greenb,blueb);
|
|
}
|
|
|
|
|
|
//Allows for dynamic changing of the number of teams in the game
|
|
void ChangeNumberOfTeams(int newsize)
|
|
{
|
|
CTFNumOfTeams = newsize;
|
|
DMFCBase->SetNumberOfTeams(CTFNumOfTeams);
|
|
}
|
|
|
|
|
|
void DoFlagReturnedHome(int team)
|
|
{
|
|
if(DMFCBase->GetPlayerTeam(DMFCBase->GetPlayerNum())==team){
|
|
if(snd_return_ownteam!=-1)
|
|
DLLPlay2dSound(snd_return_ownteam,MAX_GAME_VOLUME/2);
|
|
}else{
|
|
if(snd_return_otherteam!=-1)
|
|
DLLPlay2dSound(snd_return_otherteam,MAX_GAME_VOLUME/2);
|
|
}
|
|
}
|
|
|
|
void DoLoseFlag(int team)
|
|
{
|
|
if(DMFCBase->GetPlayerTeam(DMFCBase->GetPlayerNum())==team){
|
|
if(snd_lose_ownteam!=-1)
|
|
DLLPlay2dSound(snd_lose_ownteam,MAX_GAME_VOLUME/2);
|
|
}else{
|
|
if(snd_lose_otherteam!=-1)
|
|
DLLPlay2dSound(snd_lose_otherteam,MAX_GAME_VOLUME/2);
|
|
}
|
|
|
|
}
|
|
|
|
// VerifyFlagPosition
|
|
// Call this at certain intervals to verify a flags position. It will look at the
|
|
// flags room and makes sure that if it's in it's home room, the correct values
|
|
// are set, and vice versa.
|
|
void VerifyFlagPosition(void)
|
|
{
|
|
}
|
|
|
|
// AddFlagToPlayer
|
|
// gives a player a flag
|
|
bool AddFlagToPlayer(int pnum,int team,int flagobjnum)
|
|
{
|
|
object *pobj = &dObjects[dPlayers[pnum].objnum];
|
|
bool ret = true;
|
|
|
|
if(DMFCBase->GetLocalRole()==LR_SERVER){
|
|
//We're the server, so we need to create the flag and tell the clients, and then attach it
|
|
flagobjnum = DLLObjCreate(OBJ_POWERUP,AFlagIDs[team],pobj->roomnum,&pobj->pos,NULL,OBJECT_HANDLE_NONE);
|
|
|
|
if(flagobjnum!=-1){
|
|
//tell the clients that the flag has been created and they should attach it
|
|
TellClientsToAddorDelFlag(pnum,team,flagobjnum,true);
|
|
}
|
|
|
|
// Attach the flag
|
|
|
|
// 1st figure out how many flags the guy already has
|
|
// -------------------------------------------------
|
|
int max_num_attach = 3; //based off chrishack for multiplayer
|
|
int num_attached = 0;
|
|
|
|
if(!pobj->attach_children)
|
|
ret = false;
|
|
else
|
|
{
|
|
for(int ap=0;ap<max_num_attach;ap++)
|
|
{
|
|
if(pobj->attach_children[ap]!=OBJECT_HANDLE_NONE)
|
|
{
|
|
//attempt to make sure it's a valid object
|
|
object *tobj;
|
|
if(DLLObjGet(pobj->attach_children[ap],&tobj))
|
|
{
|
|
num_attached++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2nd num_attached is the current number of flags this object has
|
|
// ---------------------------------------------------------------
|
|
switch(num_attached)
|
|
{
|
|
case 0:
|
|
{
|
|
//the easy case, nothing is attached, so just attach it to ap0
|
|
ret = DLLAttachObject(pobj,0,&dObjects[flagobjnum],0,true);
|
|
}break;
|
|
|
|
case 1:
|
|
{
|
|
bool retval;
|
|
object *tobj;
|
|
|
|
//we should have a flag at ap0, move it to ap1
|
|
ASSERT(pobj->attach_children[0]!=OBJECT_HANDLE_NONE);
|
|
int saved_ap0 = pobj->attach_children[0];
|
|
retval = DLLUnattachChild(pobj,0);
|
|
ASSERT(retval);
|
|
|
|
retval = DLLObjGet(saved_ap0,&tobj);
|
|
ASSERT(retval);
|
|
|
|
//attach to ap1
|
|
retval = DLLAttachObject(pobj,1,tobj,0,true);
|
|
ASSERT(retval);
|
|
|
|
//attach new flag to ap2
|
|
retval = DLLAttachObject(pobj,2,&dObjects[flagobjnum],0,true);
|
|
ASSERT(retval);
|
|
|
|
ret = retval;
|
|
|
|
}break;
|
|
|
|
case 2:
|
|
{
|
|
//we should have a flag at ap1 and ap2
|
|
//so just add this to ap3
|
|
|
|
//attach new flag to ap3
|
|
ret = DLLAttachObject(pobj,0,&dObjects[flagobjnum],0,true);
|
|
|
|
}break;
|
|
|
|
case 3:
|
|
default:
|
|
{
|
|
Int3(); //Get Jeff
|
|
ret = false;
|
|
}break;
|
|
}
|
|
}
|
|
|
|
if(!ret){
|
|
//couldn't attach the flag
|
|
mprintf((0,"CTF: COULDN'T ATTACH FLAG TO PLAYER, DELETING\n"));
|
|
//tell the clients to remove this flag
|
|
DLLSetObjectDeadFlag(&dObjects[flagobjnum],true,false);
|
|
}
|
|
}
|
|
|
|
if(flagobjnum==-1){
|
|
//there was an error creating the flag...not good
|
|
mprintf((0,"CTF: Couldn't create/unhash flag for attachment\n"));
|
|
DMFCBase->DisconnectMe();
|
|
return false;
|
|
}
|
|
|
|
ChildFlags[team] = dObjects[flagobjnum].handle;
|
|
|
|
return ret;
|
|
}
|
|
|
|
// RemoveFlagFromPlayer
|
|
// removes a flag from a player
|
|
bool RemoveFlagFromPlayer(int pnum,int team)
|
|
{
|
|
int flagobjnum = -1;
|
|
|
|
if ( DMFCBase->GetLocalRole()==LR_SERVER) {
|
|
|
|
if(ChildFlags[team]==OBJECT_HANDLE_NONE)
|
|
return false;
|
|
|
|
object *fptr;
|
|
if(!DLLObjGet(ChildFlags[team],&fptr)){
|
|
//the flag is already dead?!?
|
|
return false;
|
|
}
|
|
|
|
DLLSetObjectDeadFlag(fptr,true,false);
|
|
|
|
//tell the clients to remove the flag
|
|
TellClientsToAddorDelFlag(pnum,team,-1,false);
|
|
}
|
|
|
|
ChildFlags[team] = OBJECT_HANDLE_NONE;
|
|
|
|
return true;
|
|
}
|
|
|
|
void TellClientsToAddorDelFlag(int pnum,int team,int objnum,bool add)
|
|
{
|
|
if(add){
|
|
//if we are adding a flag, than we need to send the object to them to make sure that
|
|
//they have it for when we go to process it
|
|
DLLMultiSendObject(&dObjects[objnum],false,true);
|
|
}
|
|
|
|
ubyte data[MAX_GAME_DATA_SIZE];
|
|
int size = 0;
|
|
DMFCBase->StartPacket(data,SPID_ADDDELFLAG,&size);
|
|
|
|
MultiAddByte(pnum,data,&size);
|
|
MultiAddByte(team,data,&size);
|
|
MultiAddByte(add,data,&size);
|
|
|
|
if(add){
|
|
//add the objnum of the flag and pack it into the packet
|
|
MultiAddInt(objnum,data,&size);
|
|
}
|
|
|
|
DMFCBase->SendPacket(data,size,SP_ALL);
|
|
}
|
|
|
|
void ServerIsTellingMeToAddorDelAFlag(ubyte *data)
|
|
{
|
|
int size = 0;
|
|
int pnum,team;
|
|
bool add;
|
|
|
|
pnum = MultiGetByte(data,&size);
|
|
team = MultiGetByte(data,&size);
|
|
add = (MultiGetByte(data,&size))?true:false;
|
|
|
|
//determine if we should add or delete a flag
|
|
if(add){
|
|
int objnum;
|
|
objnum = MultiGetInt(data,&size);
|
|
objnum = DMFCBase->ConvertServerToLocalObjnum(objnum);
|
|
if(objnum==-1){
|
|
//uh oh...corruption???
|
|
FatalError("CTF: Server->Local Object Corruption\n");
|
|
return;
|
|
}
|
|
AddFlagToPlayer(pnum,team,objnum);
|
|
}else{
|
|
RemoveFlagFromPlayer(pnum,team);
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////
|
|
//Timer event handlers
|
|
void OnTimer(void)
|
|
{
|
|
DisplayFlagBlink = !DisplayFlagBlink;
|
|
}
|
|
void OnTimerKill(void)
|
|
{
|
|
DisplayFlagBlink = true;
|
|
WhoJustFlagged = WhoJustFlaggedTimer = -1;
|
|
}
|
|
|
|
void OnTimerScore(void)
|
|
{
|
|
DisplayScoreBlink = !DisplayScoreBlink;
|
|
}
|
|
void OnTimerScoreKill(void)
|
|
{
|
|
DisplayScoreBlink = true;
|
|
WhoJustScored = WhoJustScoredTimer = -1;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
int PackByte(ubyte byte,ubyte *buffer,int pos)
|
|
{
|
|
buffer[pos] = byte;
|
|
pos++;
|
|
return pos;
|
|
}
|
|
|
|
int UnPackByte(ubyte *byte,ubyte *buffer,int pos)
|
|
{
|
|
*byte = buffer[pos];
|
|
pos++;
|
|
return pos;
|
|
}
|
|
|
|
int PackBytes(ubyte *bytes,int count,ubyte *buffer,int pos)
|
|
{
|
|
memcpy(&buffer[pos],bytes,count);
|
|
pos += count;
|
|
return pos;
|
|
}
|
|
|
|
int UnPackBytes(ubyte *bytes,int count,ubyte *buffer,int pos)
|
|
{
|
|
memcpy(bytes,&buffer[pos],count);
|
|
pos += count;
|
|
return pos;
|
|
}
|
|
|
|
int PackWord(ushort word,ubyte *buffer,int pos)
|
|
{
|
|
return PackBytes((ubyte *)&word,sizeof(ushort),buffer,pos);
|
|
}
|
|
|
|
int UnPackWord(ushort *word,ubyte *buffer,int pos)
|
|
{
|
|
return UnPackBytes((ubyte *)word,sizeof(ushort),buffer,pos);
|
|
}
|
|
|
|
int PackInt(int data,ubyte *buffer,int pos)
|
|
{
|
|
return PackBytes((ubyte *)&data,sizeof(int),buffer,pos);
|
|
}
|
|
|
|
int UnPackInt(int *data,ubyte *buffer,int pos)
|
|
{
|
|
return UnPackBytes((ubyte *)data,sizeof(int),buffer,pos);
|
|
}
|
|
|
|
int PackArray(ubyte *data,int size,int count,ubyte *buffer,int pos)
|
|
{
|
|
return PackBytes(data,size*count,buffer,pos);
|
|
}
|
|
|
|
int UnPackArray(ubyte *data,int size,int count,ubyte *buffer,int pos)
|
|
{
|
|
return UnPackBytes(data,size*count,buffer,pos);
|
|
}
|
|
|
|
void SendGameState(int pnum)
|
|
{
|
|
ubyte data[MAX_GAME_DATA_SIZE];
|
|
int count = 0;
|
|
int i;
|
|
|
|
DMFCBase->StartPacket(data,SPID_GAMESTATE,&count);
|
|
|
|
//pack number of teams in this game
|
|
MultiAddInt(CTFNumOfTeams,data,&count);
|
|
|
|
//pack flag whether someone has scored a hattrick
|
|
MultiAddByte(Someone_has_hattrick,data,&count);
|
|
|
|
for(i=0;i<DLLMAX_TEAMS;i++)
|
|
{
|
|
//Pack FlagAtHome
|
|
MultiAddByte(FlagAtHome[i],data,&count);
|
|
|
|
//pack flag timeout timers
|
|
MultiAddFloat(Flag_timeout_timers[i],data,&count);
|
|
|
|
//pack team scores
|
|
MultiAddInt(TeamScores[i],data,&count);
|
|
|
|
//pack overall team scores
|
|
MultiAddInt(OverallTeamScores[i],data,&count);
|
|
|
|
//pack who has flag data
|
|
MultiAddInt(HasFlag[i],data,&count);
|
|
}
|
|
|
|
ushort server_objnums[DLLMAX_TEAMS];
|
|
for(i=0;i<DLLMAX_TEAMS;i++){
|
|
if(ChildFlags[i]==OBJECT_HANDLE_NONE){
|
|
//slot not in use
|
|
server_objnums[i] = 65535;
|
|
}else{
|
|
//should be a valid slot
|
|
object *obj;
|
|
|
|
if(!DLLObjGet(ChildFlags[i],&obj)){
|
|
//ok it's not a valid slot...hrm
|
|
ChildFlags[i] = OBJECT_HANDLE_NONE;
|
|
server_objnums[i] = 65535;
|
|
}else{
|
|
//it's valid
|
|
int objnum = (obj - dObjects);
|
|
server_objnums[i] = objnum;
|
|
}
|
|
}
|
|
}
|
|
|
|
//pack attached flag handles
|
|
for(i=0;i<DLLMAX_TEAMS;i++)
|
|
{
|
|
MultiAddUshort(server_objnums[i],data,&count);
|
|
}
|
|
|
|
DMFCBase->SendPacket(data,count,pnum);
|
|
}
|
|
|
|
void ReceiveGameState(ubyte *data)
|
|
{
|
|
int count = 0;
|
|
int num_teams;
|
|
int i;
|
|
|
|
for( i=0;i<DLLMAX_PLAYERS;i++){
|
|
//reset everything
|
|
SetColoredBalls(i,true);
|
|
for(int t=0;t<DLLMAX_TEAMS;t++){
|
|
while(DLLInvCheckItem(i,OBJ_POWERUP,FlagIDs[t])){
|
|
DLLInvRemove(i,OBJ_POWERUP,FlagIDs[t]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read num teams
|
|
num_teams = MultiGetInt(data,&count);
|
|
ChangeNumberOfTeams(num_teams);
|
|
|
|
// see if someone has had a hattrick yet
|
|
Someone_has_hattrick = (MultiGetByte(data,&count))?true:false;
|
|
|
|
for(i=0;i<DLLMAX_TEAMS;i++)
|
|
{
|
|
//UnPack FlagAtHome
|
|
FlagAtHome[i] = (MultiGetByte(data,&count))?true:false;
|
|
|
|
//unpack flag timeout timers
|
|
Flag_timeout_timers[i] = MultiGetFloat(data,&count);
|
|
|
|
//unpack team scores
|
|
TeamScores[i] = MultiGetInt(data,&count);
|
|
|
|
//unpack overall team scores
|
|
OverallTeamScores[i] = MultiGetInt(data,&count);
|
|
|
|
//unpack who has flag data
|
|
HasFlag[i] = MultiGetInt(data,&count);
|
|
}
|
|
|
|
//go through the HasFlag array and put items in the inventory, and add colored balls
|
|
for(i = 0; i < DLLMAX_TEAMS; i++ ){
|
|
if(HasFlag[i]!=-1){
|
|
DLLInvAddTypeID(HasFlag[i],OBJ_POWERUP,FlagIDs[i],-1,-1,0,NULL);
|
|
|
|
//put some balls on the guy
|
|
SetColoredBalls(HasFlag[i]);
|
|
}
|
|
}
|
|
|
|
ushort server_objnums[DLLMAX_TEAMS];
|
|
//unpack attached flag handles
|
|
for(i=0;i<DLLMAX_TEAMS;i++)
|
|
{
|
|
server_objnums[i] = MultiGetUshort(data,&count);
|
|
}
|
|
|
|
//the final step, match the server_objnums->ChildFlags and Attach the flags
|
|
for(i = 0; i <DLLMAX_TEAMS; i++ ){
|
|
if(server_objnums[i]!=65535){
|
|
//we should have a real object here
|
|
ushort our_objnum = DMFCBase->ConvertServerToLocalObjnum(server_objnums[i]);
|
|
|
|
if(our_objnum==-1){
|
|
//fatal error
|
|
mprintf((0,"CTF: Local Objnums don't match server objnums\n"));
|
|
ChildFlags[i] = OBJECT_HANDLE_NONE;
|
|
DMFCBase->DisconnectMe();
|
|
}else{
|
|
//yeah! a valid objnum, attach it!!!
|
|
if(HasFlag[i]!=-1)
|
|
AddFlagToPlayer(HasFlag[i],i,our_objnum);
|
|
else{
|
|
//hmm, HasFlag doesn't match ChildFlags
|
|
mprintf((0,"CTF: HasFlag doesn't match ChildFlags!!!!\n"));
|
|
ChildFlags[i] = OBJECT_HANDLE_NONE;
|
|
}
|
|
}
|
|
}else{
|
|
//ok invalid...
|
|
ChildFlags[i] = OBJECT_HANDLE_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
********************************************************************************************
|
|
*/
|
|
|
|
|
|
// returns the number of flags a player has, 0 if none, or an invalid pnum
|
|
int GetFlagCountForPlayer(int pnum)
|
|
{
|
|
//1st check the pnum, make sure it is OK, is it isn't, return 0
|
|
if(pnum<0 || pnum>=DLLMAX_PLAYERS){
|
|
//invalid player number, return 0 flags
|
|
mprintf((0,"CTF: Invalid PNUM passed to GetFlagCountForPlayer()\n"));
|
|
return 0;
|
|
}
|
|
|
|
int flag_count = 0;
|
|
//2nd, go through all the team flags, and check the player's inventory, see if they have the ID,
|
|
//if so, add it to their count
|
|
for(int i = 0; i < DLLMAX_TEAMS; i++){
|
|
if(DLLInvCheckItem(pnum,OBJ_POWERUP,FlagIDs[i])){
|
|
//they have this flag
|
|
flag_count++;
|
|
}
|
|
}
|
|
|
|
return flag_count;
|
|
}
|
|
|
|
// returns the mask of which flags this player currently has
|
|
ubyte GetFlagMaskForPlayer(int pnum)
|
|
{
|
|
//1st check the pnum, make sure it is OK, if it isn't, return 0, meaning no flags
|
|
if(pnum<0 || pnum>=DLLMAX_PLAYERS){
|
|
//invalid player number, return 0 flags
|
|
mprintf((0,"CTF: Invalid PNUM passed to GetFlagMaskForPlayer()\n"));
|
|
return 0;
|
|
}
|
|
|
|
int flag_mask = 0;
|
|
ubyte mask = 0x01;
|
|
|
|
//2nd go through all the teams flags, and check the player's inventory, see if they have the ID,
|
|
//if so, OR the current mask to the running flag_mask
|
|
for(int i = 0; i < DLLMAX_TEAMS; i++){
|
|
if(DLLInvCheckItem(pnum,OBJ_POWERUP,FlagIDs[i])){
|
|
//the have this flag
|
|
flag_mask |= mask;
|
|
}
|
|
//adjust the mask because we are moving to the next flag
|
|
mask = mask << 1;
|
|
}
|
|
|
|
return flag_mask;
|
|
}
|
|
|
|
// adds a flag to a player, as a precaution, it will go through all the players and makes sure that no one
|
|
// has the flag that is being added. If they are adding the flag, than remove that flag from whoever we thought had it
|
|
// it will return false if it had to remove a flag from a player
|
|
bool GivePlayerFlag(int pnum,ubyte team)
|
|
{
|
|
//1st check the player num, make sure it is valid
|
|
if(!DMFCBase->CheckPlayerNum(pnum)){
|
|
//not a valid player
|
|
mprintf((0,"CTF: Invalid pnum passed to GivePlayerFlag()\n"));
|
|
return false;
|
|
}
|
|
|
|
//2nd check to make sure the team given is valid, and not our own team
|
|
if(team >= CTFNumOfTeams){
|
|
//not a valid team
|
|
mprintf((0,"CTF: Invalid team passed to GivePlayerFlag() (team>=CTFNumOfTeams)\n"));
|
|
return false;
|
|
}
|
|
if(team == DMFCBase->GetPlayerTeam(pnum)){
|
|
//we can't add a flag of the same team to a player
|
|
mprintf((0,"CTF: In GivePlayerFlag(), trying to add a player's home team flag\n"));
|
|
return false;
|
|
}
|
|
|
|
//3rd, make sure no one else currently has this flag
|
|
//we'll check our HasFlags[] first
|
|
if(HasFlag[team]!=-1){
|
|
//hmm, we have someone listed as already having this flag...odd
|
|
mprintf((0,"CTF: In GivePlayerFlag(), trying to add a flag, but we see someone else should already have it\n"));
|
|
int player = HasFlag[team];
|
|
if(DMFCBase->CheckPlayerNum(player)){
|
|
//this player is in the game...
|
|
//make sure this player doesn't have the flag in his inventory
|
|
while(DLLInvCheckItem(player,OBJ_POWERUP,FlagIDs[team])){
|
|
//we have it listed that he does
|
|
mprintf((0,"CTF: In GivePlayerFlag(), we detected the flag in someone elses inventory\n"));
|
|
//remove all the flags that this player has of this team...very weird
|
|
DLLInvRemove(player,OBJ_POWERUP,FlagIDs[team]);
|
|
SetColoredBalls(player,false);
|
|
//check to see if the player had a flag attached to him
|
|
if(ChildFlags[team] != OBJECT_HANDLE_NONE && DMFCBase->GetLocalRole()==LR_SERVER){
|
|
//he does have a flag attached to him...kill it
|
|
RemoveFlagFromPlayer(player,team);
|
|
}
|
|
}
|
|
}
|
|
//reset this value of the array
|
|
HasFlag[team] = -1;
|
|
if(DMFCBase->GetLocalRole()!=LR_SERVER){
|
|
mprintf((0,"CTF: Game must be out of sync, requesting game state\n"));
|
|
DMFCBase->RequestGameState();
|
|
}
|
|
}
|
|
|
|
//loop through all the players and make sure they don't have this flag
|
|
for(int player = 0; player < DLLMAX_PLAYERS; player++ ){
|
|
//check to see if it's an active player
|
|
if(!DMFCBase->CheckPlayerNum(player))
|
|
continue;
|
|
|
|
//remove all the flags the player has
|
|
while(DLLInvCheckItem(player,OBJ_POWERUP,FlagIDs[team])){
|
|
mprintf((0,"CTF: In GivePlayerFlag(), detected a flag in a stranger's inventory\n"));
|
|
DLLInvRemove(player,OBJ_POWERUP,FlagIDs[team]);
|
|
SetColoredBalls(player,false);
|
|
//check to see if the player had a flag attached to him
|
|
if(ChildFlags[team]!=OBJECT_HANDLE_NONE && DMFCBase->GetLocalRole()==LR_SERVER){
|
|
//he does have a flag attached to him...kill it
|
|
RemoveFlagFromPlayer(player,team);
|
|
}
|
|
}
|
|
}
|
|
|
|
//ok, when we get here everything should be ducky, just add the flag and do the necessary things
|
|
DLLInvAddTypeID(pnum,OBJ_POWERUP,FlagIDs[team],-1,-1,0,NULL);
|
|
HasFlag[team] = pnum;
|
|
SetColoredBalls(pnum);
|
|
|
|
if(DMFCBase->GetLocalRole()==LR_SERVER){
|
|
//so we got here and added a flag to the player, now we need to attach the flag to the player
|
|
if(!AddFlagToPlayer(pnum,team)){
|
|
//there was an error adding the flag,,,,ack!
|
|
mprintf((0,"CTF: In GivePlayerFlag(), couldn't attach the flag to the player\n"));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//this function takes a flag away from the player, useful for when he scores, spews, disconnects, or observer modes
|
|
void LoseFlagForPlayer(int pnum,ubyte team,bool remove_from_inven)
|
|
{
|
|
//1st check the player number
|
|
if(pnum<0 || pnum>=DLLMAX_PLAYERS){
|
|
mprintf((0,"CTF:Invalid pnum passed to LoseFlagForPlayer()\n"));
|
|
return;
|
|
}
|
|
|
|
//2nd check the team number
|
|
if(team>=CTFNumOfTeams){
|
|
mprintf((0,"CTF:Invalid team passed to LoseFlagForPlayer()\n"));
|
|
return;
|
|
}
|
|
|
|
if(team==DMFCBase->GetPlayerTeam(pnum)){
|
|
mprintf((0,"CTF:Invalid team passed to LoseFlagForPlayer()...same team as player\n"));
|
|
return;
|
|
}
|
|
|
|
//ok, we have it registered that the flag belongs to us
|
|
while(remove_from_inven && DLLInvCheckItem(pnum,OBJ_POWERUP,FlagIDs[team])){
|
|
DLLInvRemove(pnum,OBJ_POWERUP,FlagIDs[team]);
|
|
}
|
|
|
|
SetColoredBalls(pnum);
|
|
HasFlag[team] = -1;
|
|
|
|
//check to see if the player had a flag attached to him
|
|
if(ChildFlags[team] != OBJECT_HANDLE_NONE){
|
|
//he does have a flag attached to him...kill it
|
|
if(DMFCBase->GetLocalRole()==LR_SERVER){
|
|
//remove this flag and tell the clients to do so, cause we're the server
|
|
RemoveFlagFromPlayer(pnum,team);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnGetTokenString(char *src,char *dest,int dest_size)
|
|
{
|
|
if(!stricmp(src,"flag"))
|
|
{
|
|
int mypnum = DMFCBase->GetPlayerNum();
|
|
int flagcount = GetFlagCountForPlayer(mypnum);
|
|
int flagmask = GetFlagMaskForPlayer(mypnum);
|
|
int team;
|
|
bool hasflag[DLLMAX_TEAMS];
|
|
|
|
for(team=0;team<CTFNumOfTeams;team++){
|
|
//draw all the flags the player has in his inventory
|
|
if(flagmask&0x01){
|
|
//player has this flag
|
|
hasflag[team] = true;
|
|
}else
|
|
{
|
|
hasflag[team] = false;
|
|
}
|
|
|
|
//rotate 1 bit for next flag
|
|
flagmask = flagmask>>1;
|
|
}
|
|
for(;team<DLLMAX_TEAMS;team++)
|
|
{
|
|
hasflag[team] = false;
|
|
}
|
|
|
|
switch(flagcount)
|
|
{
|
|
case 1:
|
|
{
|
|
char t[64];
|
|
for(team=0;team<CTFNumOfTeams;team++)
|
|
{
|
|
if(hasflag[team])
|
|
{
|
|
strcpy(t,DMFCBase->GetTeamString(team));
|
|
break;
|
|
}
|
|
}
|
|
|
|
strncpy(dest,t,dest_size-1);
|
|
dest[dest_size-1] = '\0';
|
|
return;
|
|
}break;
|
|
case 2:
|
|
{
|
|
char t[2][64];
|
|
int found = 0;
|
|
for(team=0;team<CTFNumOfTeams;team++)
|
|
{
|
|
if(hasflag[team])
|
|
{
|
|
strcpy(t[found],DMFCBase->GetTeamString(team));
|
|
found++;
|
|
if(found==flagcount)
|
|
break;
|
|
}
|
|
}
|
|
|
|
char buffer[256];
|
|
sprintf(buffer,"%s and %s",t[0],t[1]);
|
|
strncpy(dest,buffer,dest_size-1);
|
|
dest[dest_size-1] = '\0';
|
|
return;
|
|
}break;
|
|
case 3:
|
|
{
|
|
char t[3][64];
|
|
int found = 0;
|
|
for(team=0;team<CTFNumOfTeams;team++)
|
|
{
|
|
if(hasflag[team])
|
|
{
|
|
strcpy(t[found],DMFCBase->GetTeamString(team));
|
|
found++;
|
|
if(found==flagcount)
|
|
break;
|
|
}
|
|
}
|
|
|
|
char buffer[256];
|
|
sprintf(buffer,"%s, %s and %s",t[0],t[1],t[2]);
|
|
strncpy(dest,buffer,dest_size-1);
|
|
dest[dest_size-1] = '\0';
|
|
return;
|
|
|
|
}break;
|
|
default:
|
|
strncpy(dest,"No",dest_size-1);
|
|
dest[dest_size-1] = '\0';
|
|
return;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
DMFCBase->OnGetTokenString(src,dest,dest_size);
|
|
}
|
|
|
|
#ifdef MACINTOSH
|
|
#pragma export off
|
|
#endif
|