#include "windows.h" #include "gamedll_header.h" #include //########################Start DMFC Specifics########################## #include "DMFC.h" #include "powerball.h" //#include "tanarchystr.h" //##########################End DMFC Specifics########################### ////////////////////////////////// // defines #define SPID_NEWPLAYER 0 #define SPID_COLLIDE 1 #define POWERBALL_ID_NAME "Powerball" #define POWERBALL_SND_SCORE "Extra life" #define POWERBALL_SND_PICKUP "" /* $$TABLE_GENERIC "Powerball" $$TABLE_SOUND "Extra life" */ ////////////////////////////////// // Structs typedef struct{ int Score[2]; }tPlayerStat; ////////////////////////////////// // Globals int SortedPLRPlayers[DLLMAX_TEAMS][DLLMAX_PLAYERS]; int TeamScores[DLLMAX_TEAMS]; bool DisplayScoreScreen = false; int NumOfTeams = 2; int SortedTeams[DLLMAX_TEAMS]; int SortedPlayers[DLLMAX_PLAYERS]; bool players_sorted = false; int PowerBallID = -1; int PowerBallRoom = -1; int PowerBallObjnum = -1; vector PowerBallPos; bool DisplayPowerBBlink = true; bool DisplayScoreBlink = true; int WhoJustScored = -1,WhoJustScoredTimer=-1; int WhoJustPowerB = -1,WhoJustPowerBTimer=-1; int ShieldRegenTimer = -1; int WhoHasPowerBall = -1; int RegenTimer = -1; int GoalRooms[DLLMAX_TEAMS]; int PowerBallIcon = -1; int PBallHazehandle = -1; CDmfcStats stat; ////////////////////////////////// // Prototypes void DisplayHUDScores(struct tHUDItem *hitem); void DisplayStats(void); void GetGameStartPacket(ubyte *data); void SendGameStartPacket(int pnum); bool GetPowerBallInfo(int id); void UpdatePowerBallEffectOnPlayer(int pnum,bool pickedup); void SortTeams(void); void DisplayWelcomeMessage(int player_num); void OnTimerScore(void); void OnTimer(void); void OnTimerScoreKill(void); void OnTimerKill(void); void OnTimerRegen(void); void OnTimerRegenKill(void); void SaveEndOfLevelStats(void); void SaveStatsToFile(char *filename); void HandlePlayerCollideWithPowerball(object *pobj,object *pball); void HandlePlayerLosingPowerball(object *pball); void HandleWeaponCollide(object *me_obj,object *it_obj); void GetCollideInfo(ubyte *data); void SendCollideInfo(object *pobj,object *wobj,int towho,vector *point,vector *normal); void DetermineScore(int precord_num,int column_num,char *buffer,int buffer_size) { player_record *pr = PBall.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 && teamstate==STATE_INGAME && WhoHasPowerBall==pr->pnum){ DLLRenderHUDQuad(x+2,y,10,10,0,0,1,1,PowerBallIcon,alpha_to_use); } } // 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; options->max_teams = 2; strcpy(options->game_name,"PowerBall"); } // Initializes the game function pointers void DLLFUNCCALL DLLGameInit (int *api_func,ubyte *all_ok) { *all_ok = 1; PBall.LoadFunctions(api_func); PBall.GameInit(NumOfTeams); //DLLCreateStringTable("tanarchy.str",&StringTable,&StringTableSize); //DLLmprintf((0,"%d strings loaded from string table\n",StringTableSize)); //add the death and suicide messages PBall.AddDeathMessage("%s was killed by %s",true); PBall.AddSuicideMessage("%s is suicidal"); //setup the Playerstats struct so DMFC can handle it automatically when a new player enters the game PBall.SetupPlayerRecord(sizeof(tPlayerStat)); //register special packet receivers PBall.RegisterPacketReceiver(SPID_NEWPLAYER,GetGameStartPacket); PBall.RegisterPacketReceiver(SPID_COLLIDE,GetCollideInfo); PBall.SetNumberOfTeams(NumOfTeams); PBall.AddHUDItemCallback(HI_TEXT,DisplayHUDScores); PowerBallIcon = DLLbm_AllocLoadFileBitmap("PowerBallIcon.ogf",0); if(PowerBallIcon==-1) PowerBallIcon = BAD_BITMAP_HANDLE; DisplayScoreScreen = false; //TableFileAdd("PowerBall.Gam"); // Initialize the Stats Manager // ---------------------------- tDmfcStatsInit tsi; tDmfcStatsColumnInfo pl_col[7]; char gname[20]; strcpy(gname,"Powerball"); 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 = 15; pl_col[1].color_type = DSCOLOR_TEAM; strcpy(pl_col[1].title,"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,"Score"); pl_col[2].type = DSCOL_CUSTOM; pl_col[2].width = 47; pl_col[3].color_type = DSCOLOR_TEAM; strcpy(pl_col[3].title,"Kills"); pl_col[3].type = DSCOL_KILLS_BOTH; pl_col[3].width = 47; pl_col[4].color_type = DSCOLOR_TEAM; strcpy(pl_col[4].title,"Deaths"); pl_col[4].type = DSCOL_DEATHS_BOTH; pl_col[4].width = 57; pl_col[5].color_type = DSCOLOR_TEAM; strcpy(pl_col[5].title,"Suicides"); pl_col[5].type = DSCOL_SUICIDES_BOTH; pl_col[5].width = 65; pl_col[6].color_type = DSCOLOR_TEAM; strcpy(pl_col[6].title,"Ping"); pl_col[6].type = DSCOL_PING; pl_col[6].width = 40; stat.Initialize(&tsi); PBallHazehandle = DLLbm_AllocBitmap(32,32,0); if(PBallHazehandle>BAD_BITMAP_HANDLE){ ushort *data = DLLbm_data(PBallHazehandle,0); for(int i=0;i<32*32;i++){ data[i] = GR_RGB16(80,200,255)|OPAQUE_FLAG; } }else{ Int3(); } } // Called when the DLL is shutdown void DLLFUNCCALL DLLGameClose () { if(PowerBallIcon>BAD_BITMAP_HANDLE) DLLbm_FreeBitmap(PowerBallIcon); if(PBallHazehandle>BAD_BITMAP_HANDLE) DLLbm_FreeBitmap(PBallHazehandle); if(RegenTimer!=-1) PBall.KillTimer(RegenTimer); PBall.GameClose(); //DLLDestroyStringTable(StringTable,StringTableSize); } void DMFCApp::OnClientPlayerDisconnect(int player_num) { if(player_num==WhoHasPowerBall) HandlePowerballLoss(player_num,true); DMFCBase::OnClientPlayerDisconnect(player_num); } void DMFCApp::OnPlayerEntersObserver(int pnum,object *piggy) { if(pnum==WhoHasPowerBall) HandlePowerballLoss(pnum,false); DMFCBase::OnPlayerEntersObserver(pnum,piggy); } bool DMFCApp::OnCanChangeTeam(int pnum,int newteam) { if(!DMFCBase::OnCanChangeTeam(pnum,newteam)) return false; if(WhoHasPowerBall==pnum){ AnnounceTeamChangeDeny(pnum); return false; } return true; } void DMFCApp::OnHUDInterval(void) { stat.DoFrame(); DisplayOutrageLogo(); DMFCBase::OnHUDInterval(); } void DMFCApp::OnInterval(void) { GetSortedPlayerSlots(SortedPlayers,DLLMAX_PLAYERS); players_sorted = true; SortTeams(); DMFCBase::OnInterval(); } void DMFCApp::OnKeypress(int key) { switch(key){ case K_F7: DisplayScoreScreen = !DisplayScoreScreen; PBall.EnableOnScreenMenu(false); stat.Enable(DisplayScoreScreen); break; case K_PAGEDOWN: if(DisplayScoreScreen){ stat.ScrollDown(); Data->iRet = 1; } break; case K_PAGEUP: if(DisplayScoreScreen){ stat.ScrollUp(); Data->iRet = 1; } break; case K_F6: DisplayScoreScreen = false; stat.Enable(false); break; } DMFCBase::OnKeypress(key); } // The server has just started, so clear out all the stats and game info void DMFCApp::OnServerGameCreated(void) { DMFCBase::OnServerGameCreated(); player_record *pr; tPlayerStat *stat; for(int i=0;iuser_info; if(stat){ stat->Score[DSTAT_LEVEL] = stat->Score[DSTAT_OVERALL] = 0; } } for(i=0;itype==OBJ_PLAYER && me_obj->type==OBJ_POWERUP && me_obj->id==PowerBallID && -1==WhoHasPowerBall){ CallClientEvent(EVT_CLIENT_GAMECOLLIDE,GetMeObjNum(),GetItObjNum(),-1); OnClientCollide(me_obj,it_obj); } DMFCBase::OnServerCollide(me_obj,it_obj); } void DMFCApp::OnClientCollide(object *me_obj,object *it_obj) { static int sound = -1; WhoHasPowerBall = it_obj->id; if(WhoHasPowerBall==GetPlayerNum()){ //we need to turn off movement Players[GetPlayerNum()].movement_scalar = 0; } if(sound==-1) sound=DLLFindSoundName(IGNORE_TABLE(POWERBALL_SND_SCORE)); if(sound!=-1) DLLPlay3dSound(sound,&Objects[Players[GetPlayerNum()].objnum]); //Set a Timer to display if(WhoJustPowerBTimer!=-1) KillTimer(WhoJustPowerBTimer); WhoJustPowerBTimer = SetTimerInterval(OnTimer,0.5f,5.0f,OnTimerKill); WhoJustPowerB = GetPlayerTeam(it_obj->id); DLLAddHUDMessage("%s Has Picked Up The PowerBall!",Players[it_obj->id].callsign); HandlePlayerCollideWithPowerball(it_obj,&Objects[PowerBallObjnum]); DMFCBase::OnClientCollide(me_obj,it_obj); } void DMFCApp::OnServerPlayerChangeSegment(int player_num,int newseg,int oldseg) { if(player_num==-1) return; if((WhoHasPowerBall==player_num)&&(newseg==GoalRooms[GetPlayerTeam(player_num)])){ CallClientEvent(EVT_CLIENT_GAMEPLAYERCHANGESEG,GetMeObjNum(),GetItObjNum(),-1); OnClientPlayerChangeSegment(player_num,newseg,oldseg); } } void DMFCApp::OnClientPlayerChangeSegment(int player_num,int newseg,int oldseg) { static int sound = -1; //if we got here than the player with the powerball has entered his team's goal! if(IsPlayerDedicatedServer(player_num)) return; //dedicated server HandlePowerballLoss(player_num,false); DLLObjSetPos(&Objects[PowerBallObjnum],&PowerBallPos,PowerBallRoom,NULL,false); WhoHasPowerBall = -1; DLLAddHUDMessage("%s Team Scores!!",GetTeamString(Players[player_num].team)); tPlayerStat *stat = (tPlayerStat *)GetPlayerRecordData(player_num); if(stat){ stat->Score[DSTAT_LEVEL]++; stat->Score[DSTAT_OVERALL]++; } TeamScores[Players[player_num].team]++; if(sound==-1) sound=DLLFindSoundName(IGNORE_TABLE(POWERBALL_SND_SCORE)); if(sound!=-1) DLLPlay3dSound(sound,&Objects[Players[GetPlayerNum()].objnum]); //do killgoal check int goal; if((GetScoreLimit(&goal))&&(GetLocalRole()==LR_SERVER)){ if(TeamScores[Players[player_num].team]>=goal) EndLevel(); } //Set a Timer to display if(WhoJustScoredTimer!=-1) KillTimer(WhoJustScoredTimer); WhoJustScoredTimer = SetTimerInterval(OnTimerScore,0.5f,5.0f,OnTimerScoreKill); WhoJustScored = Players[player_num].team; } // The server has started a new level, so clear out any scores needed to be reset void DMFCApp::OnClientLevelStart(void) { DMFCBase::OnClientLevelStart(); player_record *pr; tPlayerStat *stat; for(int i=0;iuser_info; else stat = NULL; if(stat) stat->Score[DSTAT_LEVEL] = 0; } for(i=0;iScore[DSTAT_LEVEL] = 0; stat->Score[DSTAT_OVERALL] = 0; } DMFCBase::OnPlayerConnect(player_num); DisplayWelcomeMessage(player_num); } // We need to adjust the scores void DMFCApp::OnClientPlayerKilled(object *killer_obj,int victim_pnum) { int kpnum; if(killer_obj){ if((killer_obj->type==OBJ_PLAYER)||(killer_obj->type==OBJ_GHOST)) kpnum = killer_obj->id; else if(killer_obj->type==OBJ_ROBOT || (killer_obj->type == OBJ_BUILDING && killer_obj->ai_info)){ //countermeasure kill kpnum = GetCounterMeasureOwner(killer_obj); }else{ kpnum = -1; } }else kpnum = -1; HandlePowerballLoss(victim_pnum,(bool)(victim_pnum!=kpnum && kpnum!=-1)); DMFCBase::OnClientPlayerKilled(killer_obj,victim_pnum); } void DMFCApp::HandlePowerballLoss(int pnum,bool spew_shields) { static int shield_id = -1; if(WhoHasPowerBall==-1) return; if(pnum == WhoHasPowerBall){ DLLAddHUDMessage("%s Lost The PowerBall!",Players[pnum].callsign); if(WhoHasPowerBall==GetPlayerNum()){ //remove movement restriction Players[GetPlayerNum()].movement_scalar = 1; } } HandlePlayerLosingPowerball(&Objects[PowerBallObjnum]); if(GetLocalRole()==LR_SERVER && spew_shields){ //add a bunch of shield powerups into the inventory so they spew out if(shield_id==-1){ shield_id = DLLFindObjectIDName("Shield"); } if(shield_id!=-1){ int max = rand()%4 + 1; for(int i=0;istate==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 (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 = (astat)?astat->Score[DSTAT_LEVEL]:0; bscore = (bstat)?bstat->Score[DSTAT_LEVEL]:0; 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,DLLMAX_PLAYERS*sizeof(int)); //Now fill in the final structure of sorted names int TeamCount[DLLMAX_TEAMS]; player_record *pr; int team; for(i=0;istate!=STATE_EMPTY){ if(IsPlayerDedicatedServer(pr)) continue;//skip dedicated server team = (pr->state==STATE_INGAME)?Players[pr->pnum].team:pr->team; if(team>=NumOfTeams) team = 0; SortedPLRPlayers[team][TeamCount[team]] = slot; TeamCount[team]++; } } for(i=0;istate!=STATE_EMPTY){ if(IsPlayerDedicatedServer(pr)) continue;//skip dedicated server //valid player stat = (tPlayerStat *)pr->user_info; 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; } }//end for //on to the next team }//end for } 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 PBall.GetSortedPlayerSlots(sortedslots,MAX_PLAYER_RECORDS); SortTeams(); count = 1; sprintf(buffer,"PowerBall\nGame: %s\nLevel: %d\n",PBall.Netgame->name,PBall.Current_mission->cur_level); DLLcf_WriteString(file,buffer); for(p=0;pstate!=STATE_EMPTY) { if(PBall.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(posstate!=STATE_EMPTY) { if(PBall.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,"Total Time In Game: %s",basethis->GetTimeString(basethis->GetTimeInGame(p))); DLLcf_WriteString(file,buffer); if(PBall.FindPInfoStatFirst(p,&stat)){ sprintf(buffer,"Callsign: Kills: Deaths:"); DLLcf_WriteString(file,buffer); if(stat.slot!=p){ memset(buffer,' ',BUFSIZE); dpr = PBall.GetPlayerRecord(stat.slot); int pos; 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(poscallsign); 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(poscur_level; char *name = PBall.Netgame->name; char filename[256]; sprintf(filename,"%s_%s_%d.stats",ROOTFILENAME,name,level); SaveStatsToFile(filename); } ////////////////////////////////////////////// // NON-DMFC Functions ////////////////////////////////////////////// void DisplayHUDScores(struct tHUDItem *hitem) { if(!players_sorted) return; int height = DLLgrfont_GetHeight(PBall.Game_fonts[HUD_FONT_INDEX]) + 3; int y,x,team; if(WhoHasPowerBall==PBall.GetPlayerNum()){ if(PBallHazehandle>BAD_BITMAP_HANDLE){ //DLLRenderHUDQuad(0,0,640,480,0,0,1,1,PBallHazehandle,100); }else{ Int3(); } int w,h; w = DLLbm_w(PowerBallIcon,0); h = DLLbm_h(PowerBallIcon,0); x = 530; y = 10; DLLRenderHUDQuad(x,y,w,h,0,0,1,1,PowerBallIcon,255); } y = 180; x = 520; team = PBall.GetMyTeam(); DLLRenderHUDText(PBall.GetTeamColor(team),255,0,x,0,"%s Team",PBall.GetTeamString(team)); int powerteam = -1; if(WhoHasPowerBall!=-1) powerteam = PBall.GetPlayerTeam(WhoHasPowerBall); for(int i=0;i=0 && compGT(TeamScores[SortedTeams[j]],TeamScores[t]); j--) { SortedTeams[j+1] = SortedTeams[j]; } // insert SortedTeams[j+1] = t; } } void DisplayWelcomeMessage(int player_num) { if(player_num==PBall.GetPlayerNum()) { int team = PBall.GetMyTeam(); if(team==-1) return; DLLAddHUDMessage("Welcome To Powerball %s",PBall.Players[PBall.GetPlayerNum()].callsign); DLLAddColoredHUDMessage(PBall.GetTeamColor(team),"You're On The %s Team",PBall.GetTeamString(team)); } else { int team = PBall.Players[player_num].team; if(team==-1) return; DLLAddColoredHUDMessage(PBall.GetTeamColor(team),"%s Has Joined The %s Team",PBall.Players[player_num].callsign,PBall.GetTeamString(team)); } } void OnTimerScore(void) { DisplayScoreBlink = !DisplayScoreBlink; } void OnTimerScoreKill(void) { DisplayScoreBlink = true; WhoJustScored = WhoJustScoredTimer = -1; } void OnTimer(void) { DisplayPowerBBlink = !DisplayPowerBBlink; } void OnTimerKill(void) { DisplayPowerBBlink = true; WhoJustPowerB = WhoJustPowerBTimer = -1; } void OnTimerRegen(void) { if(PBall.GetLocalRole()!=LR_SERVER) return; if(WhoHasPowerBall==-1) return; float amount = 0; amount = 100 - PBall.Objects[PBall.Players[WhoHasPowerBall].objnum].shields; if( amount > 1 ) amount = 1; if( amount < 0) return; PBall.ShieldDelta[WhoHasPowerBall] -= amount; PBall.Objects[PBall.Players[WhoHasPowerBall].objnum].shields += amount; } void OnTimerRegenKill(void) { RegenTimer = PBall.SetTimerInterval(OnTimerRegen,0.1f,3600.0f,OnTimerRegenKill); } void HandlePlayerCollideWithPowerball(object *pobj,object *pball) { if(PBall.GetLocalRole()!=LR_SERVER) return; // Attach the flag int ret = DLLAttachObject(pobj,0,pball,0,true); if(!ret){ //couldn't attach the flag mprintf((0,"PBALL: COULDN'T ATTACH BALL TO PLAYER\n")); } } void HandlePlayerLosingPowerball(object *pball) { if(PBall.GetLocalRole()!=LR_SERVER) return; DLLUnattachFromParent(pball); } void HandleWeaponCollide(object *me_obj,object *it_obj) { mprintf((0,"Weapon Collide\n")); } void bump_two_objects(object *object0, vector *rotvel, vector *velocity, vector *pos, matrix *orient, float mass, float size,vector *collision_point,vector *collision_normal,float rot_scale,float vel_scale); /* void DMFCApp::OnServerWeaponCollide(object *pobj,object *wobj,vector *point,vector *normal,bool is_electrical) { if(is_electrical){ DMFCBase::OnServerWeaponCollide(pobj,wobj,point,normal,is_electrical); return; } if(pobj->id == WhoHasPowerBall){ if(pobj->id!=GetPlayerNum()) SendCollideInfo(pobj,wobj,pobj->id,point,normal); else bump_two_objects(pobj,&wobj->mtype.phys_info.rotvel,&wobj->mtype.phys_info.velocity, &wobj->pos,&wobj->orient,wobj->mtype.phys_info.mass,wobj->size,point,normal,0.1f,10.0f); } DMFCBase::OnServerWeaponCollide(pobj,wobj,point,normal,is_electrical); } */ void SendCollideInfo(object *pobj,object *wobj,int towho,vector *point,vector *normal) { int maxsize = (sizeof(float)*26) + (sizeof(ushort)*1); int size = 0; ubyte *data = PBall.StartPacket(maxsize,SPID_COLLIDE); memset(data,0,maxsize); memcpy(&data[size],&wobj->mtype.phys_info.rotvel,3*sizeof(float)); size+=(sizeof(float)*3); memcpy(&data[size],&wobj->mtype.phys_info.velocity,3*sizeof(float)); size+=(sizeof(float)*3); memcpy(&data[size],&wobj->pos,3*sizeof(float)); size+=(sizeof(float)*3); memcpy(&data[size],&wobj->mtype.phys_info.mass,sizeof(float)); size+=sizeof(float); memcpy(&data[size],&wobj->size,sizeof(float)); size+=sizeof(float); memcpy(&data[size],&wobj->orient.fvec,sizeof(float)*3); size+=(sizeof(float)*3); memcpy(&data[size],&wobj->orient.rvec,sizeof(float)*3); size+=(sizeof(float)*3); memcpy(&data[size],&wobj->orient.uvec,sizeof(float)*3); size+=(sizeof(float)*3); memcpy(&data[size],point,sizeof(float)*3); size+=(sizeof(float)*3); memcpy(&data[size],normal,sizeof(float)*3); size+=(sizeof(float)*3); ushort id = (pobj-PBall.Objects); memcpy(&data[size],&id,sizeof(ushort)); size+= sizeof(ushort); //we're done PBall.SendPacket(maxsize,towho); } void GetCollideInfo(ubyte *data) { int size = 0; vector rotvel,velocity,pos,point,normal; matrix orient; float mass,fsize; ushort id; int objnum; memcpy(&rotvel,&data[size],3*sizeof(float)); size+=(sizeof(float)*3); memcpy(&velocity,&data[size],3*sizeof(float)); size+=(sizeof(float)*3); memcpy(&pos,&data[size],3*sizeof(float)); size+=(sizeof(float)*3); memcpy(&mass,&data[size],sizeof(float)); size+=sizeof(float); memcpy(&fsize,&data[size],sizeof(float)); size+=sizeof(float); memcpy(&orient.fvec,&data[size],sizeof(float)*3); size+=(sizeof(float)*3); memcpy(&orient.rvec,&data[size],sizeof(float)*3); size+=(sizeof(float)*3); memcpy(&orient.uvec,&data[size],sizeof(float)*3); size+=(sizeof(float)*3); memcpy(&point,&data[size],sizeof(float)*3); size+=(sizeof(float)*3); memcpy(&normal,&data[size],sizeof(float)*3); size+=(sizeof(float)*3); memcpy(&id,&data[size],sizeof(ushort)); size+= sizeof(ushort); objnum = PBall.ConvertServerToLocalObjnum(id); ASSERT(objnum!=-1); if(objnum!=-1){ bump_two_objects(&PBall.Objects[objnum],&rotvel,&velocity,&pos,&orient,mass,fsize,&point,&normal,0.1f,10.0f); } } void bump_two_objects(object *object0, vector *rotvel, vector *velocity, vector *pos, matrix *orient, float mass, float size,vector *collision_point,vector *collision_normal,float rot_scalar,float vel_scalar) { // vector force; //dv, object *t = NULL; object *other = NULL; ASSERT(_finite(rotvel->x) != 0); ASSERT(_finite(rotvel->y) != 0); ASSERT(_finite(rotvel->z) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.x) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.y) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.z) != 0); ASSERT(_finite(velocity->x) != 0); ASSERT(_finite(velocity->y) != 0); ASSERT(_finite(velocity->z) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.x) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.y) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.z) != 0); vector r1 = *collision_point - object0->pos; vector r2 = *collision_point - (*pos); vector w1; vector w2; vector n1; vector n2; float temp1; float temp2; float j; matrix o_t1 = object0->orient; matrix o_t2 = *orient; DLLvm_TransposeMatrix(&o_t1); DLLvm_TransposeMatrix(&o_t2); vector cmp1 = object0->mtype.phys_info.rotvel * o_t1; vector cmp2 = (*rotvel) * o_t2; DLLConvertEulerToAxisAmount(&cmp1, &n1, &temp1); DLLConvertEulerToAxisAmount(&cmp2, &n2, &temp2); n1 *= temp1; n2 *= temp2; if(temp1 != 0.0f) { DLLvm_CrossProduct(&w1, &n1, &r1); } else { w1.x = 0; w1.y = 0; w1.z = 0; } if(temp2 != 0.0f) { DLLvm_CrossProduct(&w2, &n2, &r2); } else { w2.x = 0; w2.y = 0; w2.z = 0; } vector p1 = object0->mtype.phys_info.velocity + w1; vector p2 = (*velocity) + w2; float v_rel; float m1 = object0->mtype.phys_info.mass; float m2 = mass; ASSERT(m1 != 0.0f && m2 != 0.0f); v_rel = *collision_normal * (p1 - p2); float e; e = vel_scalar; vector c1; vector c2; vector cc1; vector cc2; float cv1; float cv2; // matrix i1; // matrix i2; float i1 = (2.0f/5.0f)*m1*object0->size*object0->size; float i2 = (2.0f/5.0f)*m2*size; if(i1 < .0000001) i1 = .0000001f; if(i2 < .0000001) i2 = .0000001f; DLLvm_CrossProduct(&c1, &r1, collision_normal); DLLvm_CrossProduct(&c2, &r2, collision_normal); c1 = c1/i1; c2 = c2/i2; DLLvm_CrossProduct(&cc1, &c1, &r1); DLLvm_CrossProduct(&cc2, &c2, &r2); cv1 = (*collision_normal)*c1; cv2 = (*collision_normal)*c2; j = (-(1.0f + e))*v_rel; j /= (1/m1 + 1/m2 + cv1 + cv2); //apply the force to the player object0->mtype.phys_info.velocity += ((j*(*collision_normal))/m1); vector jcn = j * (*collision_normal); DLLvm_CrossProduct(&c1, &r1, &jcn); n1 = (c1)/i1; temp1 = DLLvm_NormalizeVector(&n1); vector txx1; DLLConvertAxisAmountToEuler(&n1, &temp1, &txx1); float rotscale1; rotscale1 = rot_scalar; //change the player's rotational velocity object0->mtype.phys_info.rotvel += (txx1*object0->orient) * rotscale1; ASSERT(_finite(object0->mtype.phys_info.rotvel.x) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.y) != 0); ASSERT(_finite(object0->mtype.phys_info.rotvel.z) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.x) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.y) != 0); ASSERT(_finite(object0->mtype.phys_info.velocity.z) != 0); }