/* * $Logfile: /DescentIII/Main/entropy/EntropyBase.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:41 $ * $Author: kevinb $ * * * * $Log: not supported by cvs2svn $ * * 59 9/24/01 2:28p Matt * Allowed room for longer team name on results screen. * * 58 9/13/01 5:31p Matt * Added a team member list to the stats display. * Fixed a non-terminated string bug. * * 57 10/21/99 9:27p Jeff * B.A. Macintosh code merge * * 56 9/03/99 5:27p Jeff * fixed energy bug (going into an energy center with >100 energy) * * 55 8/17/99 5:53p Jeff * track ranks on PXO * * 54 7/23/99 2:31p Jeff * fixed bug where if the killer is not known, a player would still be * able to carry virus after dying. * * 53 7/15/99 1:18a Jeff * fixed up $scores * * 52 7/15/99 1:01a Jeff * added $scores support * * 51 7/13/99 12:11p Jeff * added some specific text taunt token decoding * * 50 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. Play fanfare and print out a message is * someone takes over the last base * * 49 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 * * 48 6/08/99 7:08p Jeff * begining to comment for SDK release * * 47 5/23/99 3:04a Jason * fixed bug with player rankings not being updated correctly * * 46 5/23/99 2:22a Jeff * added countdown. fixed takeover time...off by .5 seconds * * 45 5/22/99 1:12a Jeff * play a sound on the server when picking up a virus * * 44 5/21/99 10:30p Jason * made some rule changes to make more fun * * 43 5/21/99 10:03a Jeff * hopefully filled in any remaining gaps related to have more than you * can carry virus loads * * 42 5/12/99 11:04p Jeff * dmfc and multiplayer games now have endian friendly packets (*whew*) * * 41 5/12/99 11:28a Jeff * when a player scores, dont remove all virii, just what they used * * $NoKeywords: $ */ #include "gamedll_header.h" //included by all mods, it includes all needed headers, etc. #include #include "idmfc.h" //dmfc! (required) #include "Entropy.h" #include "Entropystr.h" //our string table for Entropy #include "EntropyAux.h" // the DMFC object, used throughout, and required by all mods IDMFC *DMFCBase = NULL; // our DmfcStats object, used for the F7 screen IDmfcStats *dstat = NULL; // these are some helper pointers, so we don't have to constantly query // DMFC for these arrays, we can query once and just save it for just future use. object *dObjects; player *dPlayers; room *dRooms; //////////////////////////////////////////////////// // Customization flags // These are 'the rules' to Entropy basically //scoring #define SCORE_PLYR_TAKEOVER_ROOM 5 //num points for a player when he/she takes over a room #define SCORE_TEAM_WINSGAME 10 //num points for a team when they win a round #define SCORE_TEAM_TAKEOVER_ROOM 3 //num points for a team when a teammate of their's takes over a room //rates #define REPAIR_RATE 5.0f //units/sec of the repair room #define ENERGY_RATE 5.0f //units/sec of the energy room #define DAMAGE_RATE 5.0f //units/sec of damage when in an enemy room #define ENERGY_CAP 100.0f //max energy given to a player via an Energy room #define SHIELD_CAP 100.0f //max shields given to a player via a Repair room #define VIRUS_SPEW 20.0f //How long it takes for a lab to spew a virus #define VIRUS_PER_KILL 2.0f //How many virii a player can carry per kill-in-a-row. #define MINIMUM_VIRUS_COUNT 5 //Minimum number of virii needed to take over a room #define TAKEOVER_TIME 3.0f //How long a player must stand still to take over a room //////////////////////////////////////////////////// typedef struct { float total_time; vector last_pos; }tPlayerPos; 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 TeamOwnedRooms[NUM_TEAMS]; int TeamVirii[NUM_TEAMS][MAX_VIRII]; int NumberOfKillsSinceLastDeath[DLLMAX_PLAYERS]; int SortedPLRPlayers[NUM_TEAMS][MAX_PLAYER_RECORDS]; int TeamScore[NUM_TEAMS]; int SortedTeams[NUM_TEAMS]; int SortedPlayers[MAX_PLAYER_RECORDS]; int EnergyText[NUM_TEAMS]; int RepairText[NUM_TEAMS]; int LabText[NUM_TEAMS]; tPlayerPos TimeInRoom[DLLMAX_PLAYERS]; bool DisplayScoreScreen; int virus_id = -1; int *RoomList = NULL; int RoomCount; int Highlight_bmp = -1; bool display_my_welcome = false; float Server_last_play_damage_sound = 0; int Player_who_took_over_last_base = -1; int snd_repair_center = -1; int snd_energy_center = -1; int snd_score = -1; int snd_virus_destroy = -1; int snd_damage = -1; int snd_virus_pickup = -1; //void DisplayScores(void); void DisplayHUDScores(struct tHUDItem *hitem); void DisplayWelcomeMessage(int player_num); void SortTeamScores(int *sortedindex,int *scores); void SaveStatsToFile(char *filename); void OnLabSpewTimer(void); void RemoveVirusFromPlayer(int player_num,bool remove_all); bool ScanForLaboratory(int team,int *newlab); bool CompareDistanceTravel(vector *curr_pos,vector *last_pos); void OnDisconnectSaveStatsToFile(void); void OnLevelEndSaveStatsToFile(void); void OnGetTokenString(char *src,char *dest,int dest_size); //Player in special room functions void DoIntervalPlayerFrame(void); void DoPlayerInLab(int pnum,float time); void DoPlayerInEnergy(int pnum,float time); void DoPlayerInRepair(int pnum,float time); void DoPlayerInEnemy(int pnum,float time); void DoServerConfigureDialog(void); void OnPrintScores(int level); /////////////////////////////////////////////// //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];} /////////////////////////////////////////////// #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 = NUM_TEAMS; options->min_teams = NUM_TEAMS; strcpy(options->game_name,TXT_GAMENAME); strcpy(options->requirements,"ENTROPY"); } 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[%d]",(stat)?stat->Score[DSTAT_LEVEL]:0,(stat)?stat->Score[DSTAT_OVERALL]:0); } void TeamScoreCallback(int team,char *buffer,int buffer_size) { ASSERT(team>=0 && teamLoadFunctions(api_func); //Setup event handlers 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_OnClientPlayerDisconnect(OnClientPlayerDisconnect); DMFCBase->Set_OnServerPlayerChangeSegment(OnServerPlayerChangeSegment); DMFCBase->Set_OnClientPlayerChangeSegment(OnClientPlayerChangeSegment); DMFCBase->Set_OnServerCollide(OnServerCollide); DMFCBase->Set_OnControlMessage(OnControlMessage); DMFCBase->Set_OnClientShowUI(OnClientShowUI); DMFCBase->Set_OnGetTokenString(OnGetTokenString); DMFCBase->Set_OnPrintScores(OnPrintScores); // Setup arrays for easier to read code dObjects = DMFCBase->GetObjects(); dPlayers = DMFCBase->GetPlayers(); dRooms = DMFCBase->GetRooms(); netgame_info *Netgame = DMFCBase->GetNetgameInfo(); Netgame->flags |= (NF_TRACK_RANK); DMFCBase->GameInit(NUM_TEAMS); DLLCreateStringTable("entropy.str",&StringTable,&StringTableSize); DLLmprintf((0,"%d strings loaded from string table\n",StringTableSize)); if(!StringTableSize){ *all_ok = 0; return; } //add the death and suicide messages DMFCBase->AddDeathMessage(TXT_KILLA,true); DMFCBase->AddSuicideMessage(TXT_SUICIDEA); //register special packet receivers DMFCBase->RegisterPacketReceiver(SPID_NEWPLAYER,GetGameStartPacket); DMFCBase->RegisterPacketReceiver(SPID_TAKEOVER,ReceiveTakeOverPacket); DMFCBase->RegisterPacketReceiver(SPID_ROOMINFO,ReceiveRoomInfo); DMFCBase->RegisterPacketReceiver(SPID_PICKUPVIRUS,ReceivePickupVirus); DMFCBase->RegisterPacketReceiver(SPID_VIRUSCREATE,DoVirusCreate); DMFCBase->SetNumberOfTeams(NUM_TEAMS); DMFCBase->AddHUDItemCallback(HI_TEXT,DisplayHUDScores); EnergyText[RED_TEAM] = DLLFindTextureName("RedEnergy"); EnergyText[BLUE_TEAM] = DLLFindTextureName("BlueEnergy"); RepairText[RED_TEAM] = DLLFindTextureName("RedRepair"); RepairText[BLUE_TEAM] = DLLFindTextureName("BlueRepair"); LabText[RED_TEAM] = DLLFindTextureName("RedLab"); LabText[BLUE_TEAM] = DLLFindTextureName("BlueLab"); snd_repair_center = DLLFindSoundName("EntropyRepair"); snd_energy_center = DLLFindSoundName("EntropyEnergy"); snd_score = DLLFindSoundName("EntropyScore"); snd_virus_destroy = DLLFindSoundName("EntropyDestroy"); snd_damage = DLLFindSoundName("HitEnergy"); snd_virus_pickup = DLLFindSoundName("Powerup pickup"); DMFCBase->SetupPlayerRecord(sizeof(tPlayerStat),(int (*)(void *,ubyte *))pack_pstat,(int (*)(void *,ubyte *))unpack_pstat); virus_id = DLLFindObjectIDName("EntropyVirus"); 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 = 62; 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); if(RoomList){ free(RoomList); RoomList = NULL; } 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(); tPlayerStat *stat; player_record *pr; int i; for(i=0;iGetPlayerRecord(i); if(pr){ stat = (tPlayerStat *)pr->user_info; if(stat){ stat->Score[DSTAT_LEVEL] = 0; stat->Score[DSTAT_OVERALL] = 0; } } } for(i=0;iOnClientLevelStart(); int i; for(i=0;iGetPlayerRecord(i); if(pr){ stat = (tPlayerStat *)pr->user_info; if(stat){ stat->Score[DSTAT_LEVEL] = 0; } } } //reset damage timer Server_last_play_damage_sound = 0; //reset the id to -1, so we are ready for the new level Player_who_took_over_last_base = -1; if(DMFCBase->GetLocalRole()==LR_SERVER){ DMFCBase->SetTimerInterval(OnLabSpewTimer,VIRUS_SPEW,-1.0f); } if(RoomList){ free(RoomList); RoomList = NULL; } RoomCount = 0; int r; for(r=0;r<=DMFCBase->GetHighestRoomIndex();r++){ if(dRooms[r].used){ int flags = dRooms[r].flags; if(flags&RF_SPECIAL1||flags&RF_SPECIAL2||flags&RF_SPECIAL3|| flags&RF_SPECIAL4||flags&RF_SPECIAL5||flags&RF_SPECIAL6){ RoomCount++; } } } if(RoomCount==0){ FatalError("No Special Rooms Defined"); return; } RoomList = (int *)malloc(sizeof(int)*RoomCount); if(!RoomList){ FatalError("Out of memory"); return; } bool room_used_already; int special_room_index = 0; for(r=0;r<=DMFCBase->GetHighestRoomIndex();r++){ if(dRooms[r].used){ if(dRooms[r].flags&RF_FUELCEN) { dRooms[r].flags &= ~RF_FUELCEN; dRooms[r].room_change_flags |= RCF_GOALSPECIAL_FLAGS; } room_used_already = false; if(dRooms[r].flags&RF_SPECIAL1){ //Red Team Laboratory TeamOwnedRooms[RED_TEAM]++; room_used_already = true; PaintRoomWithTexture(LabText[RED_TEAM],r); RoomList[special_room_index] = r; special_room_index++; } if(dRooms[r].flags&RF_SPECIAL4){ //Blue Team Laboratory if(room_used_already) { dRooms[r].flags &= ~RF_SPECIAL4; dRooms[r].room_change_flags |= RCF_GOALSPECIAL_FLAGS; } else { TeamOwnedRooms[BLUE_TEAM]++; room_used_already = true; PaintRoomWithTexture(LabText[BLUE_TEAM],r); RoomList[special_room_index] = r; special_room_index++; } } if(dRooms[r].flags&RF_SPECIAL2){ //Red Team Energy Room if(room_used_already) { dRooms[r].flags &= ~RF_SPECIAL2; dRooms[r].room_change_flags |= RCF_GOALSPECIAL_FLAGS; } else{ TeamOwnedRooms[RED_TEAM]++; room_used_already = true; PaintRoomWithTexture(EnergyText[RED_TEAM],r); RoomList[special_room_index] = r; special_room_index++; } } if(dRooms[r].flags&RF_SPECIAL5){ //Blue Team Energy Room if(room_used_already) { dRooms[r].flags &= ~RF_SPECIAL5; dRooms[r].room_change_flags |= RCF_GOALSPECIAL_FLAGS; } else{ TeamOwnedRooms[BLUE_TEAM]++; room_used_already = true; PaintRoomWithTexture(EnergyText[BLUE_TEAM],r); RoomList[special_room_index] = r; special_room_index++; } } if(dRooms[r].flags&RF_SPECIAL3){ //Red Team Repair Room if(room_used_already) { dRooms[r].flags &= ~RF_SPECIAL3; dRooms[r].room_change_flags |= RCF_GOALSPECIAL_FLAGS; } else{ TeamOwnedRooms[RED_TEAM]++; room_used_already = true; PaintRoomWithTexture(RepairText[RED_TEAM],r); RoomList[special_room_index] = r; special_room_index++; } } if(dRooms[r].flags&RF_SPECIAL6){ //Blue Team Repair Room if(room_used_already) { dRooms[r].flags &= ~RF_SPECIAL6; dRooms[r].room_change_flags |= RCF_GOALSPECIAL_FLAGS; } else{ TeamOwnedRooms[BLUE_TEAM]++; room_used_already = true; PaintRoomWithTexture(RepairText[BLUE_TEAM],r); RoomList[special_room_index] = r; special_room_index++; } } } } //zero out other arrays for(i=0;iGetLocalRole()==LR_SERVER){ //spew 3 virii in each lab for(i=0;i<3;i++) OnLabSpewTimer(); } 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; if(player_num!=-1){ NumberOfKillsSinceLastDeath[player_num] = 0; } TimeInRoom[player_num].total_time = 0; RemoveVirusFromPlayer(player_num,true); } void OnServerPlayerChangeSegment(int player_num,int newseg,int oldseg) { if(player_num==-1){ DMFCBase->OnServerPlayerChangeSegment(player_num,newseg,oldseg); return; } //check to make sure it is an 'indoor' room and not terrain if(!ROOMNUM_OUTSIDE(newseg)) { //Check the room flags, see if we entered a special room room *rp = &dRooms[newseg]; if(rp->flags&RF_EXTERNAL){ DMFCBase->OnServerPlayerChangeSegment(player_num,newseg,oldseg); return; } if( (rp->flags&RF_SPECIAL1) || (rp->flags&RF_SPECIAL2) || (rp->flags&RF_SPECIAL3) || (rp->flags&RF_SPECIAL4) || (rp->flags&RF_SPECIAL5) || (rp->flags&RF_SPECIAL6) ){ DMFCBase->CallClientEvent(EVT_CLIENT_GAMEPLAYERCHANGESEG,DMFCBase->GetMeObjNum(),DMFCBase->GetItObjNum(),-1); DMFCBase->CallOnClientPlayerChangeSegment(player_num,newseg,oldseg); } } DMFCBase->OnServerPlayerChangeSegment(player_num,newseg,oldseg); } void OnClientPlayerChangeSegment(int player_num,int newseg,int oldseg) { //someone has entered a special room TimeInRoom[player_num].total_time = 0; DMFCBase->OnClientPlayerChangeSegment(player_num,newseg,oldseg); } // We need to adjust the scores void OnClientPlayerKilled(object *killer_obj,int victim_pnum) { int kpnum; if(victim_pnum!=-1) RemoveVirusFromPlayer(victim_pnum,true); 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(kpnum!=-1){ if(kpnum==victim_pnum){ NumberOfKillsSinceLastDeath[kpnum] = 0; }else{ NumberOfKillsSinceLastDeath[kpnum]++; if(victim_pnum!=-1) NumberOfKillsSinceLastDeath[victim_pnum] = 0; } }else { //this would be the case if the room killed a player if(victim_pnum!=-1) NumberOfKillsSinceLastDeath[victim_pnum] = 0; } //TODO: Handle a kill if killed by a room DMFCBase->OnClientPlayerKilled(killer_obj,victim_pnum); } void OnHUDInterval(void) { dstat->DoFrame(); DMFCBase->DisplayOutrageLogo(); DMFCBase->OnHUDInterval(); } void OnInterval(void) { SortTeamScores(SortedTeams,TeamScore); //TODO: Correct Sorting based on score DMFCBase->GetSortedPlayerSlots(SortedPlayers,MAX_PLAYER_RECORDS); DoIntervalPlayerFrame(); DMFCBase->OnInterval(); } void OnClientPlayerDisconnect(int pnum) { if(pnum!=-1){ NumberOfKillsSinceLastDeath[pnum] = 0; } DMFCBase->OnClientPlayerDisconnect(pnum); } 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; } //if(key==K_E && DMFCBase->GetLocalRole()==LR_SERVER){ // DMFCBase->StartUIWindow(1); //} DMFCBase->OnKeypress(key); } void OnClientShowUI(int id,void *user_data) { if(id==1) DoServerConfigureDialog(); DMFCBase->OnClientShowUI(id,user_data); } void OnServerCollide(object *me_obj,object *it_obj) { if( !me_obj || !it_obj ) return; if(virus_id==-1){ FatalError("Unable to find Virus Object"); return; } if( (me_obj->type==OBJ_PLAYER) && (it_obj->type==OBJ_POWERUP) && (it_obj->id==virus_id) ) { //determine what to do with this collision int virus_objnum = it_obj - dObjects; int virus_team = -1; int virus_index = -1; int player_num = me_obj->id; //find which team the virus belongs to for(int v=0;vOnServerCollide(me_obj,it_obj); DLLSetObjectDeadFlag(it_obj,true,false); return; } int curr_count = DLLInvGetTypeIDCount(player_num,OBJ_POWERUP,it_obj->id); if(dPlayers[player_num].team==virus_team){ //a player has collided with a virus from his team //see if the player has enough kills to pick up this virus int max_carry = NumberOfKillsSinceLastDeath[player_num]*VIRUS_PER_KILL; if(curr_count+1>max_carry){ //the player can't carry another virii yet if(player_num==DMFCBase->GetPlayerNum()){ DLLAddHUDMessage(TXT_CANTCARRY); }else{ DMFCBase->SendControlMessageToPlayer(player_num,VIRUS_NOTENOUGHKILLS); } }else{ //pick this guy up TeamVirii[virus_team][virus_index] = -1; SendClientPickupVirus(player_num); DLLSetObjectDeadFlag(it_obj,true,true); if(snd_virus_pickup!=-1) { DLLPlay2dSound(snd_virus_pickup,MAX_GAME_VOLUME); } } } else { //a player has collided with a virus from another team //kill this object TeamVirii[virus_team][virus_index] = -1; DLLSetObjectDeadFlag(it_obj,true,false); if(player_num==DMFCBase->GetPlayerNum()) { DLLAddHUDMessage(TXT_VIRUSDESTROYED); if(snd_virus_destroy!=-1) { DLLPlay2dSound(snd_virus_destroy,MAX_GAME_VOLUME); } } else { DMFCBase->SendControlMessageToPlayer(player_num,VIRUS_DESTROYED); } } } DMFCBase->OnServerCollide(me_obj,it_obj); } void TakeOverRoom(int newteam,int oldteam,int roomnum,int victor) { if(ROOMNUM_OUTSIDE(roomnum)) { Int3(); return; } bool server = false; bool success = false; if(DMFCBase->GetLocalRole()==LR_SERVER) server = true; TeamOwnedRooms[newteam]++; TeamOwnedRooms[oldteam]--; tPlayerStat *stat = (tPlayerStat *)DMFCBase->GetPlayerRecordData(victor); if(stat){ stat->Score[DSTAT_LEVEL]+=SCORE_PLYR_TAKEOVER_ROOM; stat->Score[DSTAT_OVERALL]+=SCORE_PLYR_TAKEOVER_ROOM; TeamScore[DMFCBase->GetPlayerTeam(victor)]+=SCORE_TEAM_TAKEOVER_ROOM; if(snd_score!=-1) { DLLPlay2dSound(snd_score,MAX_GAME_VOLUME); } } char room_buf[40]; room *rp = &dRooms[roomnum]; if(oldteam==RED_TEAM){ if(rp->flags&RF_SPECIAL1){ rp->flags &= ~RF_SPECIAL1; rp->flags |= RF_SPECIAL4; rp->room_change_flags |= RCF_GOALSPECIAL_FLAGS; PaintRoomWithTexture(LabText[BLUE_TEAM],roomnum); if(server) SendTakeOverPacket(newteam,oldteam,roomnum,victor); strcpy(room_buf,"Laboratory"); success = true; } if(rp->flags&RF_SPECIAL2){ rp->flags &= ~RF_SPECIAL2; rp->flags |= RF_SPECIAL5; rp->room_change_flags |= RCF_GOALSPECIAL_FLAGS; PaintRoomWithTexture(EnergyText[BLUE_TEAM],roomnum); if(server) SendTakeOverPacket(newteam,oldteam,roomnum,victor); strcpy(room_buf,"Energy"); success = true; } if(rp->flags&RF_SPECIAL3){ rp->flags &= ~RF_SPECIAL3; rp->flags |= RF_SPECIAL6; rp->room_change_flags |= RCF_GOALSPECIAL_FLAGS; PaintRoomWithTexture(RepairText[BLUE_TEAM],roomnum); if(server) SendTakeOverPacket(newteam,oldteam,roomnum,victor); strcpy(room_buf,"Repair"); success = true; } }else{ if(rp->flags&RF_SPECIAL4){ rp->flags &= ~RF_SPECIAL4; rp->flags |= RF_SPECIAL1; rp->room_change_flags |= RCF_GOALSPECIAL_FLAGS; PaintRoomWithTexture(LabText[RED_TEAM],roomnum); if(server) SendTakeOverPacket(newteam,oldteam,roomnum,victor); strcpy(room_buf,"Laboratory"); success = true; } if(rp->flags&RF_SPECIAL5){ rp->flags &= ~RF_SPECIAL5; rp->flags |= RF_SPECIAL2; rp->room_change_flags |= RCF_GOALSPECIAL_FLAGS; PaintRoomWithTexture(EnergyText[RED_TEAM],roomnum); if(server) SendTakeOverPacket(newteam,oldteam,roomnum,victor); strcpy(room_buf,"Energy"); success = true; } if(rp->flags&RF_SPECIAL6){ rp->flags &= ~RF_SPECIAL6; rp->flags |= RF_SPECIAL3; rp->room_change_flags |= RCF_GOALSPECIAL_FLAGS; PaintRoomWithTexture(RepairText[RED_TEAM],roomnum); if(server) SendTakeOverPacket(newteam,oldteam,roomnum,victor); strcpy(room_buf,"Repair"); success = true; } } if(!success){ DLLmprintf((0,"Invalid Takeover!!!!!!!\n")); return; } //print out hud message (and sound?) char buffer[256]; DLLmprintf((0,"old=%d new=%d\n",oldteam,newteam)); sprintf(buffer,TXT_TAKEOVER,(victor!=-1)?dPlayers[victor].callsign:TXT_NONAME,DMFCBase->GetTeamString(oldteam),room_buf); DLLAddHUDMessage(buffer); if(victor!=-1) RemoveVirusFromPlayer(victor,false); if(TeamOwnedRooms[oldteam]<=0){ TeamScore[newteam]+=SCORE_TEAM_WINSGAME; Player_who_took_over_last_base = victor; if(server){ DMFCBase->EndLevel(); } } int newlab; if(!ScanForLaboratory(oldteam,&newlab)){ //we need to turn newlab into a new laboratory int flag = 0; room *rp = &dRooms[newlab]; if(oldteam==RED_TEAM){ rp->flags &= ~RF_SPECIAL2; rp->flags &= ~RF_SPECIAL3; flag = RF_SPECIAL1; }else{ rp->flags &= ~RF_SPECIAL5; rp->flags &= ~RF_SPECIAL6; flag = RF_SPECIAL4; } rp->flags |= flag; rp->room_change_flags |= RCF_GOALSPECIAL_FLAGS; PaintRoomWithTexture(LabText[oldteam],newlab); } } void DoPlayerInLab(int pnum,float time) { //nothing to do in here } void DoPlayerInEnergy(int pnum,float time) { //restore player's energy float amount = REPAIR_RATE*time; if(dPlayers[pnum].energy>=ENERGY_CAP) return; if(dPlayers[pnum].energy+amount>ENERGY_CAP) dPlayers[pnum].energy = ENERGY_CAP; else dPlayers[pnum].energy += amount; if(dPlayers[pnum].energyGetPlayerNum() && snd_energy_center>=0) { DLLPlay2dSound(snd_energy_center); } } void DoPlayerInRepair(int pnum,float time) { //restore player's shields, give at a rate of 3 per second float amount = REPAIR_RATE*time; float curr_shields = dObjects[dPlayers[pnum].objnum].shields; float max_amount = SHIELD_CAP - curr_shields; if(amount>max_amount) amount = max_amount; if(curr_shields>=SHIELD_CAP) return; DMFCBase->DoDamageToPlayer(pnum,PD_ENERGY_WEAPON,-amount); if(amount>0 && pnum==DMFCBase->GetPlayerNum() && snd_repair_center>=0) { DLLPlay2dSound(snd_repair_center,MAX_GAME_VOLUME*0.75f); } } void DoPlayerInEnemy(int pnum,float time) { float damage_amount = DAMAGE_RATE*time; if(dPlayers[pnum].flags&PLAYER_FLAGS_DYING || dPlayers[pnum].flags&PLAYER_FLAGS_DEAD) return; //only play sound if player is a client, else do our own sound //so it isn't framerate dependant if(DMFCBase->GetLocalRole()==LR_SERVER) { if(pnum!=DMFCBase->GetPlayerNum()) { DMFCBase->DoDamageToPlayer(pnum,PD_ENERGY_WEAPON,damage_amount,true); }else { DMFCBase->DoDamageToPlayer(pnum,PD_ENERGY_WEAPON,damage_amount,false); //time to play sound? float gt = DMFCBase->GetGametime(); if(gt - Server_last_play_damage_sound > (1.0f/5.0f) )//fake 5pps { //time to play sound Server_last_play_damage_sound = gt; if(snd_damage!=-1) { DLLPlay2dSound(snd_damage); } } } } //check to see if the player has 5 virii in his inventory, if he does, he's //trying to take over this room if(DLLInvGetTypeIDCount(pnum,OBJ_POWERUP,virus_id)GetLocalRole()==LR_SERVER){ int newteam = DMFCBase->GetPlayerTeam(pnum); int oldteam = (newteam==RED_TEAM)?BLUE_TEAM:RED_TEAM; int room = dObjects[dPlayers[pnum].objnum].roomnum; TakeOverRoom(newteam,oldteam,room,pnum); } } } void DoIntervalPlayerFrame(void) { static float last_frametime = 0; static bool update_this_frame = false; float frametime = 0; if(update_this_frame){ frametime = last_frametime + DMFCBase->GetFrametime(); last_frametime = 0; update_this_frame = false; }else{ last_frametime = DMFCBase->GetFrametime(); update_this_frame = true; return; } for(int i=0;iCheckPlayerNum(i)){ if( i==DMFCBase->GetPlayerNum() || DMFCBase->GetLocalRole()==LR_SERVER ){ if(dObjects[dPlayers[i].objnum].type!=OBJ_PLAYER) continue;//only work with OBJ_PLAYERS...this automatically handles observers,dedicated server //only need to be here if we are the player that has to do with this //or we are the server //first check to see if this player is in a special room if(ROOMNUM_OUTSIDE(dObjects[dPlayers[i].objnum].roomnum)) continue; int team = DMFCBase->GetPlayerTeam(i); room *rp = &dRooms[dObjects[dPlayers[i].objnum].roomnum]; if(rp->flags&RF_SPECIAL1){ if(team==RED_TEAM) DoPlayerInLab(i,frametime); else DoPlayerInEnemy(i,frametime); } if(rp->flags&RF_SPECIAL2){ if(team==RED_TEAM) DoPlayerInEnergy(i,frametime); else DoPlayerInEnemy(i,frametime); } if(rp->flags&RF_SPECIAL3){ if(team==RED_TEAM) DoPlayerInRepair(i,frametime); else DoPlayerInEnemy(i,frametime); } if(rp->flags&RF_SPECIAL4){ if(team==BLUE_TEAM) DoPlayerInLab(i,frametime); else DoPlayerInEnemy(i,frametime); } if(rp->flags&RF_SPECIAL5){ if(team==BLUE_TEAM) DoPlayerInEnergy(i,frametime); else DoPlayerInEnemy(i,frametime); } if(rp->flags&RF_SPECIAL6){ if(team==BLUE_TEAM) DoPlayerInRepair(i,frametime); else DoPlayerInEnemy(i,frametime); } } } } } bool compare_slots(int a,int b) { int ascore,bscore; player_record *apr,*bpr; tPlayerStat *as,*bs; apr = DMFCBase->GetPlayerRecord(a); bpr = DMFCBase->GetPlayerRecord(b); if( !apr ) return true; if( !bpr ) return false; as = (tPlayerStat *)apr->user_info; bs = (tPlayerStat *)bpr->user_info; if( !as ) return true; if( !bs ) 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 = as->Score[DSTAT_LEVEL]; bscore = bs->Score[DSTAT_LEVEL]; return (ascorestate==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 = as->Score[DSTAT_LEVEL]; bscore = bs->Score[DSTAT_LEVEL]; return (ascore=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[NUM_TEAMS]; int team; for(i=0;iGetPlayerRecord(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; SortedPLRPlayers[team][TeamCount[team]] = slot; TeamCount[team]++; } } for(i=0;iOnPLRInit(); } void OnPLRInterval(void) { DMFCBase->OnPLRInterval(); int TeamCol = 35; int NameCol = 165; int KillsCol = 335; int DeathsCol = 375; int SuicidesCol = 425; 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; if(Player_who_took_over_last_base!=-1) { //print out at the top who took over the last room int team = (DMFCBase->GetPlayerTeam(Player_who_took_over_last_base)==RED_TEAM)?BLUE_TEAM:RED_TEAM; DLLgrtext_SetColor(GR_RGB(40,255,40)); char message[384]; sprintf(message,"%s successfully took over %s team's last base!",dPlayers[Player_who_took_over_last_base].callsign,DMFCBase->GetTeamString(team)); DLLgrtext_CenteredPrintf(0,y,message); y+=height; } //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; tPlayerStat *stat; bool has_members; bool doing_connected = true; do_disconnected_folk: for(int team=0;teamWasPlayerInGameAtLevelEnd(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_HUDDISPLAY,DMFCBase->GetTeamString(team),TeamScore[team]); } has_members = false; for(int index=0;indexGetPlayerRecord(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)); } stat = (tPlayerStat *)pr->user_info; //valid player DLLgrtext_Printf(NameCol,y,"%s %d[%d]",pr->callsign,(stat)?stat->Score[DSTAT_LEVEL]:0,(stat)?stat->Score[DSTAT_OVERALL]:0); 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; //on to the next line if(y>=440) goto quick_exit; }//end for if(doing_connected) { doing_connected = false; goto do_disconnected_folk; } quick_exit:; } void OnControlMessage(ubyte msg,int from_pnum) { switch(msg){ case VIRUS_NOTENOUGHKILLS: DLLAddHUDMessage(TXT_CANTCARRY); break; case VIRUS_CANTKILL: DLLAddHUDMessage(TXT_CANTKILLVIRUS); break; case VIRUS_DESTROYED: DLLAddHUDMessage(TXT_VIRUSDESTROYED); if(snd_virus_destroy!=-1) { DLLPlay2dSound(snd_virus_destroy,MAX_GAME_VOLUME); } break; default: DMFCBase->OnControlMessage(msg,from_pnum); break; } } 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 *st; int count,length,p; //sort the stats DMFCBase->GetSortedPlayerSlots(sortedslots,MAX_PLAYER_RECORDS); SortTeamScores(SortedTeams,TeamScore); count = 1; sprintf(buffer,TXT_SAVESTATSA,(DMFCBase->GetNetgameInfo())->name,(DMFCBase->GetCurrentMission())->cur_level); DLLcf_WriteString(file,buffer); for(p=0;pGetTeamString(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;tGetTeamString(team_i)); strcat(buffer,":"); DLLcf_WriteString(file,buffer); for(p=0;pGetPlayerRecord(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_CURRRANKINGS); DLLcf_WriteString(file,buffer); sprintf(buffer,TXT_SAVESTATSB); DLLcf_WriteString(file,buffer); sprintf(buffer,"-----------------------------------------------------------------------------"); DLLcf_WriteString(file,buffer); for(p=0;pGetPlayerRecord(sortedslots[p]); if( pr && pr->state!=STATE_EMPTY) { if(DMFCBase->IsPlayerDedicatedServer(pr)) continue;//skip dedicated server st = (tPlayerStat *)pr->user_info; 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]",(st)?st->Score[DSTAT_LEVEL]:0,(st)?st->Score[DSTAT_OVERALL]:0); 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(posGetPlayerRecord(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_SAVESTATSD); 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(posFindPInfoStatNext(&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(posFindPInfoStatClose(); DLLcf_WriteString(file,""); //skip a line count++; } } //done writing stats DLLcfclose(file); DLLAddHUDMessage(TXT_SAVED); } #define ROOTFILENAME "Entropy" 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 DisplayHUDScores(struct tHUDItem *hitem) { if(display_my_welcome) { DisplayWelcomeMessage(DMFCBase->GetPlayerNum()); display_my_welcome = false; } if(DisplayScoreScreen) return; // Display the countdown if there should be one if(IsPlayerInEnemy(DMFCBase->GetPlayerNum()) && DLLInvGetTypeIDCount(DMFCBase->GetPlayerNum(),OBJ_POWERUP,virus_id)>=MINIMUM_VIRUS_COUNT) { float time_remaining = (TAKEOVER_TIME - TimeInRoom[DMFCBase->GetPlayerNum()].total_time); int font=(DMFCBase->GetGameFontTranslateArray())[BIG_FONT_INDEX]; DLLgrtext_SetFont(font); int fontheight=DLLgrfont_GetHeight(font); char buffer[255]; int max_w=DMFCBase->GetGameWindowW(); sprintf(buffer,"T - %.1f",(time_remaining>=0)?time_remaining:0); int lwidth = DLLgrtext_GetTextLineWidth(buffer); DLLgrtext_SetColor(GR_RGB(40,255,40)); DLLgrtext_SetAlpha(255); DLLgrtext_Printf((max_w/2) - (lwidth/2),fontheight*5,buffer); } int font = (DMFCBase->GetGameFontTranslateArray())[HUD_FONT_INDEX]; int height = DLLgrfont_GetHeight(font) + 3; DLLgrtext_SetFont(font); int y = (DMFCBase->GetGameWindowH()/2) - ((height*3)/2); int x = 520; int team; ubyte alpha = DMFCBase->ConvertHUDAlpha((ubyte)((DisplayScoreScreen)?128:255)); team = DMFCBase->GetMyTeam(); DLLRenderHUDText(DMFCBase->GetTeamColor(team),alpha,0,x,0,TXT_TEAMINFO,DMFCBase->GetTeamString(team)); //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; char buffer[256]; for(int i=0;iGetMyTeam()) { if(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); DLLrend_SetZBufferState (1); } } sprintf(buffer,TXT_HUDSCORE,DMFCBase->GetTeamString(team),TeamOwnedRooms[team]); DMFCBase->ClipString(name_width,buffer,true); DLLgrtext_SetAlpha(alpha); DLLgrtext_SetColor(DMFCBase->GetTeamColor(team)); DLLgrtext_Printf(name_x,y,buffer); DLLgrtext_Printf(score_x,y,"[%d]",TeamScore[team]); y+=height; } DLLgrtext_SetColor(GR_WHITE); DLLgrtext_Printf(name_x,y,TXT_VIRUSLOAD,DLLInvGetTypeIDCount(DMFCBase->GetPlayerNum(),OBJ_POWERUP,virus_id),(int)(NumberOfKillsSinceLastDeath[DMFCBase->GetPlayerNum()]*VIRUS_PER_KILL)); 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=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_TEAMJOIN,DMFCBase->GetTeamString(team)); } else { int team = dPlayers[player_num].team; if(team==-1) return; DLLAddColoredHUDMessage(DMFCBase->GetTeamColor(team),TXT_JOIN,name_buffer,DMFCBase->GetTeamString(team)); } } void OnLabSpewTimer(void) { int max_rooms = DMFCBase->GetHighestRoomIndex() + 1; int objnum; int index; int virus_count; for(int r=0;r=MINIMUM_VIRUS_COUNT); inv_count = MINIMUM_VIRUS_COUNT; } for(int i=0;iflags&flag){ //we found a lab return true; } if( (rp->flags&ef) && (!found) ){ found = true; *newlab = RoomList[r]; } if( (rp->flags&rf) && (!found) ){ found = true; *newlab = RoomList[r]; } } return false; } bool CompareDistanceTravel(vector *curr_pos,vector *last_pos) { vector result; float a,b,c,bc,dist; result.x = curr_pos->x - last_pos->x; result.y = curr_pos->y - last_pos->y; result.z = curr_pos->z - last_pos->z; a = fabs(result.x); b = fabs(result.y); c = fabs(result.z); if (a < b) { float t=a; a=b; b=t; } if (b < c) { float t=b; b=c; c=t; if (a < b) { float t=a; a=b; b=t; } } bc = (b/4) + (c/8); dist = a + bc + (bc/2); if(dist>5){ memcpy(last_pos,curr_pos,sizeof(vector)); return false; }else{ return true; } } bool IsPlayerInEnemy(int pnum) { if(!DMFCBase->CheckPlayerNum(pnum)) return false; if(dObjects[dPlayers[pnum].objnum].type!=OBJ_PLAYER) return false;//only work with OBJ_PLAYERS...this automatically handles observers,dedicated server //first check to see if this player is in a special room if(ROOMNUM_OUTSIDE(dObjects[dPlayers[pnum].objnum].roomnum)) return false; int team = DMFCBase->GetPlayerTeam(pnum); room *rp = &dRooms[dObjects[dPlayers[pnum].objnum].roomnum]; if(team!=RED_TEAM) { if( (rp->flags&RF_SPECIAL1) || (rp->flags&RF_SPECIAL2) || (rp->flags&RF_SPECIAL3) ) { return true; } } if(team!=BLUE_TEAM) { if( (rp->flags&RF_SPECIAL4) || (rp->flags&RF_SPECIAL5) || (rp->flags&RF_SPECIAL6) ) { return true; } } return false; } void OnGetTokenString(char *src,char *dest,int dest_size) { if(!stricmp(src,"virus")) { int count = DLLInvGetTypeIDCount(DMFCBase->GetPlayerNum(),OBJ_POWERUP,virus_id); char buffer[100]; sprintf(buffer,"%d",count); strncpy(dest,buffer,dest_size-1); dest[dest_size-1] = '\0'; return; } DMFCBase->OnGetTokenString(src,dest,dest_size); } void OnPrintScores(int level) { char buffer[256]; char name[70]; int t,i; int pos[6]; int len[6]; netplayer *dNetPlayers = DMFCBase->GetNetPlayers(); for(i=0;iGetTeamString(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_SCORE); 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_SCORE,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;iGetPlayerRecord(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,(tScore[DSTAT_LEVEL]:0); t = strlen(name); memcpy(&buffer[pos[1]],name,(tdstats.kills[DSTAT_LEVEL]); t = strlen(name); memcpy(&buffer[pos[2]],name,(tdstats.deaths[DSTAT_LEVEL]); t = strlen(name); memcpy(&buffer[pos[3]],name,(tdstats.suicides[DSTAT_LEVEL]); t = strlen(name); memcpy(&buffer[pos[4]],name,(tstate==STATE_INGAME) sprintf(name,"%.0f",dNetPlayers[pr->pnum].ping_time*1000.0f); else strcpy(name,"---"); t = strlen(name); memcpy(&buffer[pos[5]],name,(t