mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-23 03:58:59 +00:00
1361 lines
35 KiB
C++
1361 lines
35 KiB
C++
|
#include "windows.h"
|
||
|
#include "gamedll_header.h"
|
||
|
#include <string.h>
|
||
|
//########################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 && 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 = PBall.GetPlayerRecord(precord_num);
|
||
|
|
||
|
if(pr->state==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;i<MAX_PLAYER_RECORDS;i++){
|
||
|
pr = GetPlayerRecord(i);
|
||
|
stat = (tPlayerStat *)pr->user_info;
|
||
|
if(stat){
|
||
|
stat->Score[DSTAT_LEVEL] = stat->Score[DSTAT_OVERALL] = 0;
|
||
|
}
|
||
|
}
|
||
|
for(i=0;i<NumOfTeams;i++){
|
||
|
TeamScores[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void DMFCApp::OnServerCollide(object *me_obj,object *it_obj)
|
||
|
{
|
||
|
if( !me_obj || !it_obj )
|
||
|
return;
|
||
|
if(it_obj->type==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;i<MAX_PLAYER_RECORDS;i++){
|
||
|
pr = GetPlayerRecord(i);
|
||
|
if(pr)
|
||
|
stat = (tPlayerStat *)pr->user_info;
|
||
|
else
|
||
|
stat = NULL;
|
||
|
if(stat)
|
||
|
stat->Score[DSTAT_LEVEL] = 0;
|
||
|
}
|
||
|
|
||
|
for(i=0;i<NumOfTeams;i++){
|
||
|
TeamScores[i] = 0;
|
||
|
GoalRooms[i] = DLLGetGoalRoomForTeam(i);
|
||
|
}
|
||
|
|
||
|
DLLMultiPaintGoalRooms();
|
||
|
|
||
|
DLLmprintf((0,"Getting powerball info\n"));
|
||
|
if(!GetPowerBallInfo(DLLFindObjectIDName(IGNORE_TABLE(POWERBALL_ID_NAME)))){
|
||
|
FatalError("Error finding Powerball room\n");
|
||
|
}
|
||
|
|
||
|
if(GetLocalRole()==LR_SERVER){
|
||
|
PowerBallObjnum = DLLObjCreate(OBJ_POWERUP,PowerBallID,PowerBallRoom,&PowerBallPos,NULL);
|
||
|
if(PowerBallObjnum==-1)
|
||
|
FatalError("Unable to create PowerBall");
|
||
|
DLLMultiSendObject(&Objects[PowerBallObjnum],1);
|
||
|
if(RegenTimer!=-1)
|
||
|
KillTimer(RegenTimer);
|
||
|
RegenTimer = SetTimerInterval(OnTimerRegen,0.1f,3600.0f,OnTimerRegenKill);
|
||
|
}else{
|
||
|
RequestGameState();
|
||
|
}
|
||
|
players_sorted = false;
|
||
|
}
|
||
|
|
||
|
void DMFCApp::OnClientLevelEnd(void)
|
||
|
{
|
||
|
SaveEndOfLevelStats();
|
||
|
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 DMFCApp::OnGameStateRequest(int player_num)
|
||
|
{
|
||
|
SendGameStartPacket(player_num);
|
||
|
DMFCBase::OnGameStateRequest(player_num);
|
||
|
}
|
||
|
|
||
|
|
||
|
// A new player has entered the game, zero their stats out
|
||
|
void DMFCApp::OnPlayerConnect(int player_num)
|
||
|
{
|
||
|
tPlayerStat *stat = (tPlayerStat *)GetPlayerRecordData(player_num);
|
||
|
if(stat){
|
||
|
stat->Score[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;i<max;i++)
|
||
|
DLLInvAddTypeID(pnum,OBJ_POWERUP,shield_id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WhoHasPowerBall = -1;
|
||
|
UpdatePowerBallEffectOnPlayer(pnum,false);
|
||
|
}
|
||
|
|
||
|
bool compare_slots(int a,int b)
|
||
|
{
|
||
|
int ascore,bscore;
|
||
|
player_record *apr,*bpr;
|
||
|
tPlayerStat *astat,*bstat;
|
||
|
|
||
|
apr = PBall.GetPlayerRecord(a);
|
||
|
bpr = PBall.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 DMFCApp::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,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;i<NumOfTeams;i++)
|
||
|
TeamCount[i] = 0;
|
||
|
for(i=0;i<DLLMAX_PLAYERS;i++){
|
||
|
int slot = SortedPlayers[i];
|
||
|
pr = GetPlayerRecord(slot);
|
||
|
if(pr->state!=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;i<NumOfTeams;i++){
|
||
|
if(TeamCount[i]<DLLMAX_PLAYERS)
|
||
|
SortedPLRPlayers[i][TeamCount[i]] = -1;
|
||
|
}
|
||
|
|
||
|
DMFCBase::OnPLRInit();
|
||
|
}
|
||
|
|
||
|
void DMFCApp::OnPLRInterval(void)
|
||
|
{
|
||
|
DMFCBase::OnPLRInterval();
|
||
|
|
||
|
int TeamCol = 100;
|
||
|
int NameCol = 210;
|
||
|
int KillsCol = 350;
|
||
|
int DeathsCol = 400;
|
||
|
int SuicidesCol = 450;
|
||
|
int y = 110;
|
||
|
int slot;
|
||
|
player_record *pr;
|
||
|
tPlayerStat *stat;
|
||
|
|
||
|
DLLgrtext_SetFont(Game_fonts[HUD_FONT_INDEX]);
|
||
|
int height = DLLgrfont_GetHeight(Game_fonts[HUD_FONT_INDEX]) + 1;
|
||
|
|
||
|
//print out header
|
||
|
DLLgrtext_SetColor(GR_RGB(255,40,40));
|
||
|
DLLgrtext_Printf(NameCol,y,"Pilot");
|
||
|
DLLgrtext_Printf(KillsCol,y,"Kills");
|
||
|
DLLgrtext_Printf(DeathsCol,y,"Deaths");
|
||
|
DLLgrtext_Printf(SuicidesCol,y,"Suicides");
|
||
|
y+=height;
|
||
|
|
||
|
|
||
|
for(int team=0;team<MAX_TEAMS;team++){
|
||
|
//process this team
|
||
|
if(SortedPLRPlayers[team][0]!=-1){
|
||
|
//is there anyone on this team?
|
||
|
DLLgrtext_SetColor(GetTeamColor(team));
|
||
|
DLLgrtext_Printf(TeamCol,y,"%s Team: %d",GetTeamString(team),TeamScores[team]);
|
||
|
}
|
||
|
|
||
|
for(int index=0;index<DLLMAX_PLAYERS;index++){
|
||
|
//get the player num
|
||
|
slot = SortedPLRPlayers[team][index];
|
||
|
pr = GetPlayerRecord(slot);
|
||
|
if(slot==-1)//we are done with this team
|
||
|
break;
|
||
|
if(pr && pr->state!=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;p<NumOfTeams;p++){
|
||
|
int team_i = SortedTeams[p];
|
||
|
memset(buffer,' ',BUFSIZE);
|
||
|
sprintf(tempbuffer,"%s Team",PBall.GetTeamString(team_i));
|
||
|
memcpy(&buffer[0],tempbuffer,strlen(tempbuffer));
|
||
|
sprintf(tempbuffer,"[%d]",TeamScores[team_i]);
|
||
|
memcpy(&buffer[20],tempbuffer,strlen(tempbuffer));
|
||
|
DLLcf_WriteString(file,buffer);
|
||
|
}
|
||
|
|
||
|
sprintf(buffer,"Current Level Rankings\n");
|
||
|
DLLcf_WriteString(file,buffer);
|
||
|
|
||
|
sprintf(buffer,"Rank Name Score Kills Deaths Suicides");
|
||
|
DLLcf_WriteString(file,buffer);
|
||
|
sprintf(buffer,"-----------------------------------------------------------------------------");
|
||
|
DLLcf_WriteString(file,buffer);
|
||
|
|
||
|
|
||
|
for(p=0;p<MAX_PLAYER_RECORDS;p++){
|
||
|
pr = PBall.GetPlayerRecord(sortedslots[p]);
|
||
|
if( pr && pr->state!=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(pos<BUFSIZE)
|
||
|
buffer[pos] = '\0';
|
||
|
|
||
|
buffer[BUFSIZE-1] = '\0';
|
||
|
DLLcf_WriteString(file,buffer);
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DLLcf_WriteString(file,"\nIndividual Stats\n");
|
||
|
|
||
|
count =1;
|
||
|
for(p=0;p<MAX_PLAYER_RECORDS;p++){
|
||
|
pr = PBall.GetPlayerRecord(p);
|
||
|
if( pr && pr->state!=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(pos<BUFSIZE)
|
||
|
buffer[pos] = '\0';
|
||
|
|
||
|
buffer[BUFSIZE-1] = '\0';
|
||
|
DLLcf_WriteString(file,buffer);
|
||
|
}
|
||
|
|
||
|
|
||
|
while(PBall.FindPInfoStatNext(&stat)){
|
||
|
if(stat.slot!=p){
|
||
|
int pos;
|
||
|
memset(buffer,' ',BUFSIZE);
|
||
|
dpr = PBall.GetPlayerRecord(stat.slot);
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
PBall.FindPInfoStatClose();
|
||
|
DLLcf_WriteString(file,""); //skip a line
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//done writing stats
|
||
|
DLLcfclose(file);
|
||
|
DLLAddHUDMessage("Stats saved to %s",filename);
|
||
|
}
|
||
|
|
||
|
#define ROOTFILENAME "PowerBall"
|
||
|
int stat_filecounter = 0;
|
||
|
void DMFCApp::OnSaveStatsToFile(void)
|
||
|
{
|
||
|
char filename[100];
|
||
|
sprintf(filename,"%s%d.stats",ROOTFILENAME,stat_filecounter); stat_filecounter++;
|
||
|
SaveStatsToFile(filename);
|
||
|
}
|
||
|
|
||
|
void SaveEndOfLevelStats(void)
|
||
|
{
|
||
|
int level = PBall.Current_mission->cur_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<NumOfTeams;i++){
|
||
|
team = SortedTeams[i];
|
||
|
if( ((WhoJustScored!=team)&&(WhoJustPowerB!=team)) || (DisplayPowerBBlink)&&(DisplayScoreBlink)){
|
||
|
if(powerteam==team)
|
||
|
DLLRenderHUDQuad(x-12,y,10,10,0,0,1,1,PowerBallIcon,255);
|
||
|
DLLRenderHUDText(PBall.GetTeamColor(team),255,0,x,y,"%s Team",PBall.GetTeamString(team));
|
||
|
DLLRenderHUDText(PBall.GetTeamColor(team),255,0,615,y,"[%d]",TeamScores[team]);
|
||
|
}
|
||
|
y+=height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GetGameStartPacket(ubyte *data)
|
||
|
{
|
||
|
int size = 0;
|
||
|
|
||
|
//team scores
|
||
|
memcpy(TeamScores,&data[size],sizeof(int)*DLLMAX_TEAMS); size+= (sizeof(int)*DLLMAX_TEAMS);
|
||
|
|
||
|
//who has the powerball
|
||
|
signed char temp;
|
||
|
memcpy(&temp,&data[size],sizeof(char)); size+=sizeof(char);
|
||
|
WhoHasPowerBall = temp;
|
||
|
|
||
|
memcpy(&temp,&data[size],sizeof(char)); size+=sizeof(char);
|
||
|
NumOfTeams = temp;
|
||
|
|
||
|
//Now based on what we have from the server set up our info
|
||
|
if(WhoHasPowerBall!=-1){
|
||
|
UpdatePowerBallEffectOnPlayer(WhoHasPowerBall,true);
|
||
|
}
|
||
|
|
||
|
//we need to find the objnum of the PowerBall...its there somewhere
|
||
|
DLLmprintf((0,"Looking for powerball in level\n"));
|
||
|
for(int i=0;i<MAX_OBJECTS;i++){
|
||
|
if( (PBall.Objects[i].type==OBJ_POWERUP) && (PBall.Objects[i].id==PowerBallID) ){
|
||
|
//here it is
|
||
|
PowerBallObjnum = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
DLLmprintf((0,"Powerball %s\n",(PowerBallObjnum==-1)?"Not Found":"Found"));
|
||
|
if(PowerBallObjnum==-1){
|
||
|
FatalError("Couldn't Find PowerBall when it should be there");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void SendGameStartPacket(int pnum)
|
||
|
{
|
||
|
int maxsize = sizeof(int)*DLLMAX_TEAMS + 2*sizeof(char);
|
||
|
int size = 0;
|
||
|
|
||
|
ubyte *data = PBall.StartPacket(maxsize,SPID_NEWPLAYER);
|
||
|
memset(data,0,maxsize);
|
||
|
|
||
|
//add the team scores
|
||
|
memcpy(&data[size],TeamScores,sizeof(int)*DLLMAX_TEAMS); size += (sizeof(int)*DLLMAX_TEAMS);
|
||
|
|
||
|
signed char temp;
|
||
|
//who has the powerball if anyone
|
||
|
temp = WhoHasPowerBall;
|
||
|
memcpy(&data[size],&temp,sizeof(char)); size+= sizeof(char);
|
||
|
|
||
|
//number of teams
|
||
|
temp = NumOfTeams;
|
||
|
memcpy(&data[size],&temp,sizeof(char)); size+=sizeof(char);
|
||
|
|
||
|
//we're done
|
||
|
DLLmprintf((0,"Sending Game State to %s\n",PBall.Players[pnum].callsign));
|
||
|
PBall.SendPacket(maxsize,pnum);
|
||
|
}
|
||
|
|
||
|
void UpdatePowerBallEffectOnPlayer(int pnum,bool pickedup)
|
||
|
{
|
||
|
float red[3],green[3],blue[3];
|
||
|
red[0] = 1; red[1] = 0; red[2] = 0;
|
||
|
green[0] = 0;green[1] = 1; green[2] = 0;
|
||
|
blue[0] = 0;blue[1] = 0; blue[2] = 1;
|
||
|
|
||
|
if(pickedup){
|
||
|
DLLPlayerSetRotatingBall(pnum,3,0,red,green,blue);
|
||
|
}else{
|
||
|
DLLPlayerSetRotatingBall(pnum,0,0,NULL,NULL,NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool GetPowerBallInfo(int id)
|
||
|
{
|
||
|
if(id==-1)
|
||
|
return false;
|
||
|
|
||
|
PowerBallID = id;
|
||
|
|
||
|
//find the room with the RF_SPECIAL1
|
||
|
for(int i=0;i<=*PBall.Highest_room_index;i++){
|
||
|
if(PBall.Rooms[i].flags&RF_SPECIAL1){
|
||
|
//here's the powerball!
|
||
|
PowerBallRoom = i;
|
||
|
DLLComputeRoomCenter(&PowerBallPos,&PBall.Rooms[i]);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#define compGT(a,b) (a < b)
|
||
|
// insert sort
|
||
|
void SortTeams(void)
|
||
|
{
|
||
|
int t;
|
||
|
int i, j;
|
||
|
|
||
|
//copy scores into scoreinfo array
|
||
|
for(i=0;i<DLLMAX_TEAMS;i++)
|
||
|
{
|
||
|
SortedTeams[i] = i;
|
||
|
}
|
||
|
|
||
|
for(i=1;i<=DLLMAX_TEAMS-1;i++)
|
||
|
{
|
||
|
t=SortedTeams[i];
|
||
|
|
||
|
// Shift elements down until
|
||
|
// insertion point found.
|
||
|
for(j=i-1;j>=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);
|
||
|
}
|