rott/rott/rt_net.c

3339 lines
82 KiB
C
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#ifdef DOS
#include <dos.h>
#include <io.h>
#endif
#include "rt_def.h"
#include "rt_main.h"
#include "rt_net.h"
#include "rt_com.h"
#include "_rt_net.h"
#include "rt_actor.h"
#include "rt_playr.h"
#include "isr.h"
#include "z_zone.h"
#include "develop.h"
#include "rottnet.h"
#include "rt_msg.h"
#include "rt_sound.h"
#include "rt_menu.h"
#include "rt_util.h"
#include "rt_rand.h"
#include "rt_game.h"
#include "rt_draw.h"
#include "myprint.h"
#include "rt_debug.h"
#include "rt_view.h"
#include "rt_battl.h"
#include "rt_dmand.h"
//MED
#include "memcheck.h"
#if (SYNCCHECK == 1)
int lastsynccheck;
COM_CheckSyncType PlayerSync[MAXPLAYERS];
#endif
CommandType * LocalCmds;
CommandType * ServerCmds;
int controlupdatestartedtime=-1;
int controlupdatetime=-1;
int serverupdatetime=-1;
int controlupdatestarted=0;
boolean GamePaused=false;
boolean modemgame;
boolean networkgame;
int numplayers;
int server;
boolean IsServer;
boolean standalone;
boolean restartgame=false;
boolean respawnactive=false;
boolean playerdead=false;
boolean controlschanged=true;
boolean battlegibs=false;
boolean remoteridicule = false;
/*
=============================================================================
LOCAL FUNCTION PROTOTYPES and VARIABLES
=============================================================================
*/
boolean demorecord,
demoplayback;
byte *demoptr,
*lastdemoptr,
*demobuffer=NULL;
boolean demodone = false;
int predemo_violence = -1;
int oldmomx;
int oldmomy;
int oldspdang;
static boolean GameCommandsStarted=false;
static int oldcontrolbuf[3];
static int oldbuttonbits;
static CommandType * PlayerCmds[MAXPLAYERS];
static CommandType * ClientCmds[MAXPLAYERS];
static boolean GotPlayersDesc[MAXPLAYERS];
static boolean PlayersReady[MAXPLAYERS];
static int LastCommandTime[MAXPLAYERS];
static CommandStatusType * CommandState[MAXPLAYERS+1];
static boolean InProcessServer=false;
static int lastcontrolupdatetime;
static int largesttime;
static int PlayerStatus[MAXPLAYERS];
//static int syncservertime;
//static boolean FixingPackets;
static int controldivisor=1;
static int nextupdatetime;
static boolean UpdateServer=true;
void CheckForPacket ( void );
void PrepareLocalPacket ( void );
void SendSyncCheckPacket ( void );
void AddModemSubPacket(void * incoming);
void SetPlayerDescription( void * pkt );
void UpdateDemoPlayback (int time);
int GetTypeSize (int type);
int MaxSpeedForCharacter(playertype *pstate);
/*
=============================================================================
Game Command Section
=============================================================================
*/
//****************************************************************************
//
// ComError ()
//
//****************************************************************************
#define ComError SoftError
#if 0
void ComError (char *error, ...)
{
#if 0
va_list argptr;
#endif
SoftError(error);
#if 0
if (standalone==true)
{
va_start (argptr, error);
vprintf (error, argptr);
va_end (argptr);
}
#endif
}
#endif
//****************************************************************************
//
// ConsoleIsServer()
//
//****************************************************************************
boolean ConsoleIsServer ( void )
{
if (modemgame==true)
{
if (networkgame==true)
{
if (rottcom->client==0)
{
return true;
}
}
}
return false;
}
//****************************************************************************
//
// GamePacketSize()
//
//****************************************************************************
int GamePacketSize( void )
{
if ((remoteridicule == true) || (ConsoleIsServer() == true))
{
return GetTypeSize(COM_SOUNDANDDELTA);
}
else
return GetTypeSize(COM_TEXT);
}
//****************************************************************************
//
// InitializeGameCommands()
//
//****************************************************************************
void InitializeGameCommands( void )
{
int i;
int j;
// default to player 0
if (GameCommandsStarted==true)
return;
GameCommandsStarted=true;
if ((modemgame==true))
controldivisor=rottcom->ticstep;
standalone=false;
IsServer=false;
if (modemgame==true)
{
consoleplayer=rottcom->consoleplayer;
if (networkgame==true)
{
if (rottcom->client==0)
{
IsServer=true;
// turn it on absolutely for the server
remoteridicule = true;
if (consoleplayer==0)
standalone=true;
}
if (consoleplayer>0)
consoleplayer--; // playernumber fixup
}
}
if (standalone==false)
{
int size;
size = GamePacketSize ();
for (i=0;i<numplayers;i++)
{
PlayerCmds[i]=(CommandType *)SafeLevelMalloc(sizeof(CommandType));
for (j=0;j<MAXCMDS;j++)
{
PlayerCommand(i,j)=SafeLevelMalloc(size);
}
}
}
// allocate local commands
LocalCmds=(CommandType *)SafeLevelMalloc(sizeof(CommandType));
for (j=0;j<MAXCMDS;j++)
{
int size;
size = GamePacketSize();
LocalCommand(j)=SafeLevelMalloc(size);
memset(LocalCommand(j),COM_DELTANULL,size);
}
CommandState[0]=(CommandStatusType *)SafeLevelMalloc(sizeof(CommandStatusType));
if (modemgame==true)
{
for (i=0;i<numplayers;i++)
{
PlayerStatus[i]=player_ingame;
}
if (networkgame==true)
{
server=1;
// initialize the Server
if (IsServer==true)
{
server=0;
ServerCmds=(CommandType *)SafeMalloc(sizeof(CommandType));
for (j=0;j<MAXCMDS;j++)
{
int size;
size=( (numplayers * GetTypeSize(COM_TEXT)) +
GetTypeSize(COM_SOUNDANDDELTA) +
sizeof(COM_ServerHeaderType) -
sizeof(byte)
);
ServerCommand(j)=SafeMalloc( size );
memset(ServerCommand(j),COM_DELTANULL,size);
}
for (i=1;i<=numplayers;i++)
{
CommandState[i]=(CommandStatusType *)
SafeMalloc(sizeof(CommandStatusType));
}
for (i=0;i<numplayers;i++)
{
ClientCmds[i]=(CommandType *)SafeMalloc(sizeof(CommandType));
for (j=0;j<MAXCMDS;j++)
{
int size;
size=GetTypeSize(COM_SOUNDANDDELTA);
ClientCommand(i,j)=SafeMalloc(size);
memset(ClientCommand(i,j),COM_DELTANULL,size);
}
}
}
}
else // must be a two player game
{
server=consoleplayer^1;
}
}
#if 0
#if (DEVELOPMENT == 1)
if (IsServer)
ComError("I am the server\n");
ComError("consoleplayer=%ld\n",consoleplayer);
ComError("server=%ld mynumber=%ld\n",server,consoleplayer);
#endif
#endif
}
//****************************************************************************
//
// ShutdownGameCommands()
//
//****************************************************************************
void ShutdownGameCommands( void )
{
int i;
int j;
if (GameCommandsStarted==false)
return;
GameCommandsStarted=false;
// free up playercmds;
if (standalone==false)
{
for (i=0;i<numplayers;i++)
{
for (j=0;j<MAXCMDS;j++)
{
if (PlayerCommand(i,j))
{
SafeFree(PlayerCommand(i,j));
PlayerCommand(i,j)=NULL;
}
}
SafeFree( PlayerCmds[i] );
PlayerCmds[i]=NULL;
}
}
// free up command status
SafeFree(CommandState[0]);
CommandState[0]=NULL;
if (modemgame==true)
{
// free up local commands
for (j=0;j<MAXCMDS;j++)
{
if (LocalCommand(j))
{
SafeFree(LocalCommand(j));
LocalCommand(j)=NULL;
}
}
SafeFree(LocalCmds);
LocalCmds=NULL;
// free up Server
if (networkgame==true)
{
if (IsServer==true)
{
for (j=0;j<MAXCMDS;j++)
{
if (ServerCommand(j))
{
SafeFree(ServerCommand(j));
ServerCommand(j)=NULL;
}
}
SafeFree(ServerCmds);
ServerCmds=NULL;
for (i=1;i<=numplayers;i++)
{
SafeFree(CommandState[i]);
CommandState[i]=NULL;
}
for (i=0;i<numplayers;i++)
{
for (j=0;j<MAXCMDS;j++)
{
if (ClientCommand(i,j))
{
SafeFree(ClientCommand(i,j));
ClientCommand(i,j)=NULL;
}
}
SafeFree( ClientCmds[i] );
ClientCmds[i]=NULL;
}
}
}
}
}
/*
=============================================================================
Client Controls Section
=============================================================================
*/
//****************************************************************************
//
// ShutdownClientControls ()
//
//****************************************************************************
void ShutdownClientControls ( void )
{
int i;
#if (DEVELOPMENT == 1)
SoftError ("LARGEST time difference=%ld\n",largesttime);
#endif
controlupdatestarted=0;
for (i=0;i<numplayers;i++)
{
if (PlayerStatus[i] == player_leftgame)
PlayerStatus[i]=player_ingame;
}
}
//****************************************************************************
//
// StartupClientControls ()
//
//****************************************************************************
void StartupClientControls ( void )
{
int i,j;
if (controlupdatestarted==1)
return;
controlupdatestarted=1;
memset(oldcontrolbuf,-1,sizeof(oldcontrolbuf));
oldbuttonbits=-1;
controlschanged=true;
INL_GetMouseDelta(&i,&i);
locplayerstate->dmomx = 0;
locplayerstate->dmomy = 0;
locplayerstate->angle = 0;
locplayerstate->topspeed=MaxSpeedForCharacter(locplayerstate);
CalcTics();
CalcTics();
// FixingPackets=false;
memset (controlbuf, 0, sizeof (controlbuf));
buttonbits = 0;
lastpolltime=-1;
IN_ClearKeyboardQueue ();
if (modemgame==true)
{
controlupdatetime=controlsynctime+(VBLCOUNTER*2);
SoftError("Controls started at %d\n",controlupdatetime);
}
else if (demoplayback || demorecord)
{
ISR_SetTime(20);
oldtime = 20;
controlupdatetime=20;
}
else
controlupdatetime=GetTicCount();
controlupdatetime-=(controlupdatetime%controldivisor);
serverupdatetime=controlupdatetime;
oldpolltime=controlupdatetime;
nextupdatetime=oldpolltime;
#if (SYNCCHECK == 1)
lastsynccheck=oldpolltime+CHECKSYNCTIME;
#endif
controlupdatestartedtime=controlupdatetime;
for( j = 0; j < numplayers; j++ )
{
memset( PLAYERSTATE[ j ].buttonheld, 0,
sizeof( PLAYERSTATE[ j ].buttonheld ) );
memset( PLAYERSTATE[ j ].buttonstate, 0,
sizeof( PLAYERSTATE[ j ].buttonstate ) );
}
for (i=0;i<MAXCMDS;i++)
{
ServerCommandNumberStatus( i ) = cs_notarrived;
}
LastCommandTime[0]=controlupdatetime-controldivisor;
if (IsServer==true)
{
int size;
UpdateServer=true;
size=( (numplayers * GetTypeSize(COM_TEXT)) +
GetTypeSize(COM_SOUNDANDDELTA) +
sizeof(COM_ServerHeaderType) -
sizeof(byte)
);
for (j=0;j<numplayers;j++)
{
for (i=0;i<MAXCMDS;i++)
{
ClientCommandNumberStatus( j , i ) = cs_notarrived;
}
LastCommandTime[j]=controlupdatetime-controldivisor;
}
for (i=0;i<MAXCMDS;i++)
memset(ServerCommand(i),COM_DELTANULL,size);
}
else if (modemgame==true)
{
int nump;
nump=numplayers;
if (nump<2) nump=2;
for (i=0;i<nump;i++)
{
LastCommandTime[i]=controlupdatetime-controldivisor;
}
}
#if (DEVELOPMENT == 1)
// ComError("StartupClientControls: GetTicCount()=%ld oldtime=%ld controlupdatetime=%ld\n",GetTicCount(),oldtime,controlupdatetime);
#endif
if ((demoplayback==false) && (standalone==false))
{
if (modemgame==true)
{
while (GetTicCount()<(controlupdatetime-10))
{
CalcTics();
}
}
lastcontrolupdatetime=GetTicCount();
largesttime=0;
PollControls();
}
if (standalone==true)
printf("Packet Server started\n");
}
//****************************************************************************
//
// UpdateClientControls ()
//
//****************************************************************************
static boolean InUCC=false;
void UpdateClientControls ( void )
{
int time;
// int delta;
if (controlupdatestarted==0)
return;
if (InUCC)
return;
else
InUCC = true;
wami(6);
#if 0
delta=GetTicCount()-lastcontrolupdatetime;
if (delta>largesttime)
{
if (delta>10)
largesttime=delta;
largesttime=delta;
}
#endif
lastcontrolupdatetime=GetTicCount();
if (standalone==false)
{
time=GetTicCount();
// if we are a fixing the current packet stop update of deltas
// in non-network games.
if (
(networkgame == false) &&
(ServerCommandStatus(oldpolltime)==cs_fixing)
)
{
time=controlupdatetime-controldivisor;
}
while (time>=controlupdatetime)
{
MoveType * Delta;
boolean soundready;
soundready = SD_SoundDataReady();
if (demoplayback==true)
{
UpdateDemoPlayback(controlupdatetime);
}
// else
// {
// PollControls();
// }
if (
(memcmp(&controlbuf[0],&oldcontrolbuf[0],sizeof(controlbuf))!=0) ||
(buttonbits!=oldbuttonbits)
)
{
controlschanged=true;
memcpy(&oldcontrolbuf[0],&controlbuf[0],sizeof(controlbuf));
oldbuttonbits=buttonbits;
}
else
{
controlschanged=false;
}
if ((controlschanged==false) && (soundready==false))
{
NullMoveType * NullDelta;
NullDelta=(NullMoveType *)NextLocalCommand();
NullDelta->type=COM_DELTANULL;
}
else
{
Delta=(MoveType *)NextLocalCommand();
Delta->type=COM_DELTA;
Delta->momx=(controlbuf[0]>>1);
Delta->momy=(controlbuf[1]>>1);
Delta->dangle=controlbuf[2]>>11;
Delta->buttons=buttonbits;
// See if we need to update sound packet
if (soundready==true)
{
COM_SoundType * sndpkt;
recordstate status;
if (remoteridicule == false)
Error("Attempt to record Remote Ridicule without adequate storage");
sndpkt=(COM_SoundType *)Delta->Sounddata;
// Turn the packet into a COM_SOUNDANDDELTA packet
Delta->type=COM_SOUNDANDDELTA;
status = SD_GetSoundData ( &(sndpkt->data[0]),
COM_SOUND_BUFFERSIZE );
switch (status)
{
case rs_nodata:
Delta->type=COM_DELTA;
break;
case rs_newsound:
sndpkt->type=COM_SOUND_START_TRANSMISSION;
break;
case rs_endsound:
sndpkt->type=COM_SOUND_END_TRANSMISSION;
break;
case rs_data:
sndpkt->type=COM_SOUND_NORMAL_TRANSMISSION;
break;
default:
Error("Illegal return value for SD_GetSoundData");
break;
}
}
if (demorecord==true)
RecordDemoCmd();
}
PrepareLocalPacket();
if (
(controlupdatetime != -1) &&
(controlupdatetime > (lastpolltime+MAXPOLLTICS)) &&
(demoplayback==false)
)
{
controlbuf[0] = controlbuf[1] = controlbuf[2] = 0;
}
}
}
if (modemgame==true)
{
CheckForPacket ();
}
if ((standalone == false) && (IsServer==true) && (UpdateServer==true))
ProcessServer();
// take out
if (modemgame==true)
{
//#if (DEVELOPMENT == 1)
if (PanicPressed==true)
{
Error("Game Aborted. Scroll Lock pressed\n");
}
//#endif
if (Keyboard[sc_Insert] && Keyboard[sc_Q])
Error("Game Aborted. Insert->Q pressed\n");
}
InUCC = false;
waminot();
}
//****************************************************************************
//
// PlayerInGame()
//
//****************************************************************************
boolean PlayerInGame ( int p )
{
if (PlayerStatus[p]!=player_ingame)
return false;
return true;
}
/*
=============================================================================
Packet Section
=============================================================================
*/
//****************************************************************************
//
// CheckForPacket()
//
//****************************************************************************
void CheckForPacket ( void )
{
wami(7);
while (ReadPacket()==true)
{
if (badpacket==0)
{
ProcessPacket(&ROTTpacket[0], rottcom->remotenode);
#if (DEVELOPMENT == 1)
// ComError("CheckForPacket: from=%ld\n",rottcom->remotenode);
#endif
}
else
RequestPacket (LastCommandTime[rottcom->remotenode]+controldivisor, rottcom->remotenode, controldivisor);
}
waminot();
}
//****************************************************************************
//
// AddRemoteRidiculeCommand()
//
//****************************************************************************
void AddRemoteRidiculeCommand ( int player, int towho, int num )
{
((COM_RemoteRidiculeType *)NextLocalCommand())->type=COM_REMRID;
((COM_RemoteRidiculeType *)NextLocalCommand())->num=num;
((COM_RemoteRidiculeType *)NextLocalCommand())->player=player;
((COM_RemoteRidiculeType *)NextLocalCommand())->towho=towho;
PrepareLocalPacket();
}
//****************************************************************************
//
// ProcessRemoteRidicule()
//
//****************************************************************************
void ProcessRemoteRidicule ( void * pkt )
{
COM_RemoteRidiculeType * remrot;
char name[ 50 ];
int from;
int who;
remrot = (COM_RemoteRidiculeType *)pkt;
from = remrot->player;
who = remrot->towho;
if ( ( who == consoleplayer ) || ( who == MSG_DIRECTED_TO_ALL ) ||
( ( who == MSG_DIRECTED_TO_TEAM ) && ( BATTLE_Team[ from ] ==
BATTLE_Team[ consoleplayer ] ) ) )
{
strcpy( name, "(<28> RR from " );
strcat( name, PLAYERSTATE[from].codename );
strcat( name, ")" );
AddMessage( name, MSG_REMOTERIDICULE );
SD_Play( SD_REMOTEM1SND + remrot->num );
}
}
//****************************************************************************
//
// AddEndGameCommand()
//
//****************************************************************************
void AddEndGameCommand ( void )
{
((COM_EndGameType *)NextLocalCommand())->type=COM_ENDGAME;
PrepareLocalPacket();
}
//****************************************************************************
//
// AddGameEndCommand()
//
//****************************************************************************
void AddGameEndCommand ( void )
{
((COM_GameEndType *)NextLocalCommand())->type=COM_GAMEEND;
PrepareLocalPacket();
}
//****************************************************************************
//
// AddQuitCommand()
//
//****************************************************************************
void AddQuitCommand ( void )
{
((COM_QuitType *)NextLocalCommand())->type=COM_QUIT;
PrepareLocalPacket();
}
//****************************************************************************
//
// AddExitCommand()
//
//****************************************************************************
void AddExitCommand ( void )
{
((COM_ExitType *)NextLocalCommand())->type=COM_EXIT;
PrepareLocalPacket();
}
//****************************************************************************
//
// AddPauseStateCommand()
//
//****************************************************************************
void AddPauseStateCommand ( int type )
{
((COM_PauseType *)NextLocalCommand())->type=type;
PrepareLocalPacket();
}
//****************************************************************************
//
// AddRespawnCommand()
//
//****************************************************************************
void AddRespawnCommand ( void )
{
if (respawnactive==true)
return;
respawnactive=true;
((COM_RespawnType *)NextLocalCommand())->type=COM_RESPAWN;
PrepareLocalPacket();
}
//****************************************************************************
//
// AddTextMessage()
//
//****************************************************************************
void AddTextMessage
(
char *message,
int length,
int towho
)
{
COM_TextType *Text;
Text = ( COM_TextType * )NextLocalCommand();
Text->type = COM_TEXT;
memset( &Text->string[ 0 ], 0, COM_MAXTEXTSTRINGLENGTH );
if ( length >= COM_MAXTEXTSTRINGLENGTH )
{
length = COM_MAXTEXTSTRINGLENGTH - 1;
}
memcpy( &Text->string[ 0 ], message, length );
Text->towho = towho;
PrepareLocalPacket();
}
//****************************************************************************
//
// PrepareLocalPacket
//
//****************************************************************************
void PrepareLocalPacket ( void )
{
MoveType * pkt;
wami(8);
pkt=(MoveType *)NextLocalCommand();
pkt->time=controlupdatetime;
if (networkgame==false) // Whether it is a modem game or not we do this
{
AddClientPacket (pkt, consoleplayer);
if (modemgame==false)
{
ServerCommandStatus ( controlupdatetime ) = cs_ready;
}
}
if (modemgame==true)
SendPacket (pkt, server);
#if (DEVELOPMENT == 1)
// ComError("packet sent: realtime=%ld time=%ld type=%ld dest=%ld\n",GetTicCount(),pkt->time,pkt->type,server);
#endif
controlupdatetime+=controldivisor;
waminot();
}
//****************************************************************************
//
// GetPacketSize ()
//
//****************************************************************************
int GetPacketSize (void * pkt)
{
int size;
switch (((MoveType *)pkt)->type)
{
case COM_DELTA:
size=sizeof(MoveType);
break;
case COM_DELTANULL:
size=sizeof(NullMoveType);
break;
case COM_REQUEST:
size=sizeof(COM_RequestType);
break;
case COM_FIXUP:
size=sizeof(COM_FixupType);
break;
case COM_TEXT:
size=sizeof(COM_TextType);
break;
case COM_PAUSE:
size=sizeof(COM_PauseType);
break;
case COM_QUIT:
size=sizeof(COM_QuitType);
break;
case COM_EXIT:
size=sizeof(COM_ExitType);
break;
case COM_REMRID:
size=sizeof(COM_RemoteRidiculeType);
break;
case COM_RESPAWN:
size=sizeof(COM_RespawnType);
break;
case COM_UNPAUSE:
size=sizeof(COM_UnPauseType);
break;
case COM_SERVER:
size=sizeof(COM_ServerHeaderType);
size-=sizeof(byte);
break;
case COM_GAMEDESC:
size=sizeof(COM_GamePlayerType);
break;
case COM_GAMEEND:
size=sizeof(COM_GameEndType);
break;
case COM_GAMEPLAY:
size=DUMMYPACKETSIZE;
break;
case COM_GAMEACK:
size=sizeof(COM_GameAckType);
break;
case COM_GAMEMASTER:
size=sizeof(COM_GameMasterType);
break;
case COM_ENDGAME:
size=sizeof(COM_EndGameType);
break;
case COM_SYNCTIME:
size=sizeof(COM_SyncType);
break;
#if (SYNCCHECK == 1)
case COM_SYNCCHECK:
size=sizeof(COM_CheckSyncType);
break;
#endif
case COM_SOUNDANDDELTA:
size=sizeof(MoveType)+sizeof(COM_SoundType);
break;
default:
Error("Unhandled packet type in GetPacketSize type=%d",((MoveType *)pkt)->type);
break;
}
return size;
}
//****************************************************************************
//
// GetTypeSize ()
//
//****************************************************************************
int GetTypeSize (int type)
{
byte pkt[2];
pkt[0]=(byte)type;
return ( GetPacketSize(&(pkt[0])) );
}
//****************************************************************************
//
// GetServerPacketSize ()
//
//****************************************************************************
int GetServerPacketSize (void * pkt)
{
int i;
byte * ptr;
COM_ServerHeaderType * serverpkt;
serverpkt=(COM_ServerHeaderType *)pkt;
if (serverpkt->type==COM_SERVER)
{
ptr=&serverpkt->data;
for (i=0;i<serverpkt->numpackets;i++)
{
ptr+=GetPacketSize(ptr);
}
return ((byte *)ptr-(byte *)pkt);
}
else
return GetPacketSize(pkt);
}
//****************************************************************************
//
// SendPacket ()
//
//****************************************************************************
void SendPacket (void * pkt, int dest)
{
if ((networkgame==false) && (PlayerStatus[dest]!=player_ingame))
return;
if ((IsServer==true) && (dest==server) && (standalone==false)) // must be client on top of server
ProcessPacket(pkt,dest);
else if ((IsServer==false) && (dest!=server) && (standalone==false)) // We shouldn't be sending as client to anyone else
ComError("SendPacket:Problems\n");
else
WritePacket(pkt,GetPacketSize(pkt),dest);
#if (DEVELOPMENT == 1)
// ComError( "SendPacket: time=%ld dest=%ld\n",((MoveType *)pkt)->time,dest);
#endif
}
//****************************************************************************
//
// ResetCurrentCommand ()
//
//****************************************************************************
void ResetCurrentCommand ( void )
{
ServerCommandStatus(oldpolltime)=cs_notarrived;
}
//****************************************************************************
//
// BroadcastServerPacket ()
//
//****************************************************************************
void BroadcastServerPacket (void * pkt, int size)
{
int i;
for (i=0;i<numplayers;i++)
{
if (PlayerStatus[i]!=player_ingame)
continue;
// if ((standalone==false) && (i==consoleplayer))
// ProcessPacket(pkt,i);
// else
WritePacket((byte *)pkt,size,i);
}
}
//****************************************************************************
//
// ResendLocalPackets ()
//
//****************************************************************************
void ResendLocalPackets (int time, int dest, int numpackets)
{
int cmd;
MoveType * pkt;
cmd = CommandAddress(time);
#if 0
if (networkgame==false)
{
int nump;
nump=controlupdatetime-time;
if (nump>numpackets)
numpackets=nump;
}
#endif
if (controlupdatetime<=time)
return;
pkt = (MoveType *)LocalCommand(cmd);
if (pkt->time!=time)
{
Error( "CLIENT: Could not find packet to resend\ntime=%d packettime=%d controlupdatetime=%d\n",
time, pkt->time, controlupdatetime);
}
else
{
byte * tempbuf;
byte * tempptr;
byte * tempstart;
COM_FixupType * fixup;
int i;
int starti;
int size;
boolean done;
// allocate some space
tempbuf=SafeMalloc(MAXCOMBUFFERSIZE);
fixup=(COM_FixupType *)tempbuf;
fixup->type=COM_FIXUP;
tempstart=&(fixup->data);
done=false;
i=0;
while (done==false)
{
tempptr=tempstart;
starti=i;
fixup->time=( (MoveType *)LocalCommand(cmd) )->time;
for (;i<numpackets;i++)
{
pkt = (MoveType *)LocalCommand(cmd);
size=GetPacketSize(pkt);
if (((tempptr+size)-tempbuf)>MAXCOMBUFFERSIZE)
{
break;
}
memcpy(tempptr,pkt,size);
tempptr+=size;
cmd = (cmd + controldivisor) & (MAXCMDS-1);
}
fixup->numpackets=i-starti;
WritePacket(tempbuf,tempptr-tempbuf,dest);
if (i==numpackets)
done=true;
}
SafeFree(tempbuf);
}
}
//****************************************************************************
//
// ResendServerPackets ()
//
//****************************************************************************
void ResendServerPackets (int time, int dest, int numpackets)
{
int cmd;
COM_ServerHeaderType * serverpkt;
cmd = CommandAddress(time);
if (serverupdatetime<=time)
return;
serverpkt = (COM_ServerHeaderType *)ServerCommand(cmd);
if (serverpkt->time!=time)
{
Error( "SERVER: Could not find packet to resend\ntime=%d packettime=%d serverupdatetime=%d\n",
time, serverpkt->time,serverupdatetime);
}
else
{
byte * tempbuf;
byte * tempptr;
byte * tempstart;
COM_FixupType * fixup;
int i;
int starti;
int size;
boolean done;
// allocate some space
tempbuf=SafeMalloc(MAXCOMBUFFERSIZE);
fixup=(COM_FixupType *)tempbuf;
fixup->type=COM_FIXUP;
tempstart=&(fixup->data);
done=false;
i=0;
while (done==false)
{
tempptr=tempstart;
starti=i;
fixup->time=( (MoveType *)ServerCommand(cmd) )->time;
for (;i<numpackets;i++)
{
serverpkt = (COM_ServerHeaderType *)ServerCommand(cmd);
size=GetServerPacketSize(serverpkt);
if (((tempptr+size)-tempbuf)>MAXCOMBUFFERSIZE)
{
break;
}
memcpy(tempptr,serverpkt,size);
tempptr+=size;
cmd = (cmd + controldivisor) & (MAXCMDS-1);
}
fixup->numpackets=i-starti;
WritePacket(tempbuf,tempptr-tempbuf,dest);
if (i==numpackets)
done=true;
}
SafeFree(tempbuf);
}
}
//****************************************************************************
//
// ResendPacket (incoming packet, whoever requested it)
//
//****************************************************************************
void ResendPacket (void * pkt, int dest)
{
int time;
COM_RequestType * request;
if ((networkgame==false) && (PlayerStatus[dest]!=player_ingame))
return;
request=(COM_RequestType * )pkt;
time=request->time;
ComError( "RESEND request received at %d\n packet time=%d dest=%d numpackets=%d\n",
GetTicCount(), time, dest, request->numpackets);
if (IsServer==true)
{
if ((dest==server) && (standalone==false))
Error("Trying to resend packets to client on top of server\n");
ComError( "RESEND SERVER serverupdatetime=%d\n",serverupdatetime);
if (IsServerCommandReady ( time ) == true)
ResendServerPackets(time,dest,request->numpackets);
else
ComError( "RESEND SERVER time=%d is not ready\n",time);
}
else
{
ResendLocalPackets(time,dest,request->numpackets);
}
}
//****************************************************************************
//
// FixupPacket ()
//
//****************************************************************************
void FixupPacket (void * pkt, int src)
{
COM_FixupType * fix;
int i;
int time;
byte * ptr;
fix=(COM_FixupType *)pkt;
ComError( "Fixup received at %d, time=%d numpackets=%d\n", GetTicCount(), fix->time, fix->numpackets);
#if 0
if (networkgame==false)
FixingPackets=false;
#endif
time=fix->time;
ptr=&(fix->data);
for (i=0;i<fix->numpackets;i++,time+=controldivisor)
{
if (time == (LastCommandTime[src]+controldivisor))
LastCommandTime[src]=time;
if (IsServer==true)
{
if (ClientCommandStatus(src, time)!=cs_fixing)
{
ComError("Server Received fixup with no bad packet time=%d from %d\n",time,src);
}
else
{
AddSubPacket(ptr, src);
}
ptr+=GetPacketSize(ptr);
}
else
{
if (ServerCommandStatus(time)!=cs_fixing)
{
ComError("Client Received fixup with no bad packet time=%d from %d\n",time,src);
}
else
{
if (networkgame==true)
{
AddServerSubPacket( (COM_ServerHeaderType *)ptr );
}
else
{
AddModemSubPacket(ptr);
}
}
ptr+=GetServerPacketSize(ptr);
}
}
}
#if (SYNCCHECK == 1)
//****************************************************************************
//
// CheckForSyncCheck
//
//****************************************************************************
void CheckForSyncCheck ( void )
{
int i;
if (modemgame==true)
{
if (oldpolltime==lastsynccheck)
{
for (i=0;i<numplayers;i++)
{
PlayerSync[i].x=PLAYER[i]->x;
PlayerSync[i].y=PLAYER[i]->y;
PlayerSync[i].z=PLAYER[i]->z;
PlayerSync[i].angle=PLAYER[i]->angle;
}
PlayerSync[0].randomindex=GetRNGindex();
PlayerSync[0].synctime=lastsynccheck;
SendSyncCheckPacket();
lastsynccheck+=CHECKSYNCTIME;
}
if (oldpolltime>lastsynccheck)
{
Error("Missed a player sync check time=%d\n",oldpolltime);
}
}
}
#endif
//****************************************************************************
//
// ProcessSyncTimePacket
//
//****************************************************************************
void ProcessSyncTimePacket (void * pkt)
{
COM_SyncType * sync;
sync=(COM_SyncType *)pkt;
ISR_SetTime(sync->synctime);
}
#if (SYNCCHECK == 1)
//****************************************************************************
//
// ProcessSyncCheckPacket
//
//****************************************************************************
void ProcessSyncCheckPacket (void * pkt, int src)
{
COM_CheckSyncType * sync;
sync=(COM_CheckSyncType *)pkt;
// SoftError("Sync packet time=%ld\n",sync->synctime);
if (sync->synctime!=PlayerSync[0].synctime)
{
SoftError("Old sync packet received\n");
return;
}
if (sync->randomindex!=PlayerSync[0].randomindex)
{
Error("Player %d is unsynced localindex=%d remoteindex=%d\n"
"Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
src, PlayerSync[0].randomindex, sync->randomindex,
PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
PlayerSync[src].z,PLAYERSTATE[src].codename);
}
if (sync->x!=PlayerSync[src].x)
{
Error("Player %d is unsynced local x=%d remote x=%d\n"
"Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
src,PlayerSync[src].x,sync->x,
PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
PlayerSync[src].z,PLAYERSTATE[src].codename);
}
if (sync->y!=PlayerSync[src].y)
{
Error("Player %d is unsynced local y=%d remote y=%d\n"
"Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
src,PlayerSync[src].y,sync->y,
PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
PlayerSync[src].z,PLAYERSTATE[src].codename);
}
if (sync->z!=PlayerSync[src].z)
{
Error("Player %d is unsynced local z=%d remote z=%d\n"
"Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
src,PlayerSync[src].z,sync->z,
PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
PlayerSync[src].z,PLAYERSTATE[src].codename);
}
if (sync->angle!=PlayerSync[src].angle)
{
Error("Player %d is unsynced local angle=%d remote angle=%d\n"
"Unsynced Player x=%x y=%x a=%d z=%d name=%s\n",
src,PlayerSync[src].angle,sync->angle,
PlayerSync[src].x, PlayerSync[src].y, PlayerSync[src].angle,
PlayerSync[src].z,PLAYERSTATE[src].codename);
}
}
//****************************************************************************
//
// SendSyncCheckPacket
//
//****************************************************************************
void SendSyncCheckPacket ( void )
{
((COM_CheckSyncType *)NextLocalCommand())->type=COM_SYNCCHECK;
((COM_CheckSyncType *)NextLocalCommand())->synctime=PlayerSync[0].synctime;
((COM_CheckSyncType *)NextLocalCommand())->x=PlayerSync[consoleplayer].x;
((COM_CheckSyncType *)NextLocalCommand())->y=PlayerSync[consoleplayer].y;
((COM_CheckSyncType *)NextLocalCommand())->z=PlayerSync[consoleplayer].z;
((COM_CheckSyncType *)NextLocalCommand())->angle=PlayerSync[consoleplayer].angle;
((COM_CheckSyncType *)NextLocalCommand())->randomindex=PlayerSync[0].randomindex;
PrepareLocalPacket();
}
#endif
#if 0
//****************************************************************************
//
// CheckForSyncTime
//
//****************************************************************************
void CheckForSyncTime ( void )
{
if ((modemgame==true) && (networkgame==false) && (consoleplayer==0))
{
if (controlupdatetime>=syncservertime)
{
SendSyncTimePacket();
syncservertime+=MODEMSYNCSERVERTIME;
}
}
}
#endif
#if 0
//****************************************************************************
//
// SendSyncTimePacket
//
//****************************************************************************
void SendSyncTimePacket ( void )
{
int i;
COM_SyncType sync;
return;
sync.type=COM_SYNCTIME;
if (networkgame==true)
{
for (i=0;i<numplayers;i++)
{
if ((PlayerStatus[i]!=player_ingame) || ( (i==consoleplayer) && (standalone==false) ) )
continue;
sync.synctime=GetTicCount()+GetTransitTime(i);
WritePacket ( &sync.type, GetPacketSize(&sync.type), i);
}
}
else
{
if (PlayerStatus[server]==player_ingame)
{
sync.synctime=GetTicCount()+GetTransitTime(server);
WritePacket ( &sync.type, GetPacketSize(&sync.type), server);
}
}
}
#endif
//****************************************************************************
//
// ProcessSoundAndDeltaPacket
//
//****************************************************************************
void ProcessSoundAndDeltaPacket (void * pkt, int src)
{
MoveType * packet;
COM_SoundType * sndpkt;
byte oldtype;
packet = (MoveType *)pkt;
// Trick packet into being a normal delta packet
oldtype=packet->type;
packet->type=COM_DELTA;
AddClientPacket (pkt,src);
packet->type=oldtype;
// Don't process sound if it is from us
if (src==consoleplayer)
return;
sndpkt = (COM_SoundType *) (packet->Sounddata);
if (sndpkt->type==COM_SOUND_START_TRANSMISSION)
{
SD_StartIncomingSound ();
}
if (sndpkt->type==COM_SOUND_END_TRANSMISSION)
{
SD_StopIncomingSound();
}
else
{
SD_UpdateIncomingSound (&(sndpkt->data[0]), COM_SOUND_BUFFERSIZE);
}
}
//****************************************************************************
//
// SyncToServer
//
//****************************************************************************
#define NETWORKTIMEAHEADOFSERVER (1)
#define MODEMTIMEAHEADOFSERVER (2)
void SyncToServer( void )
{
int diff;
if ((networkgame==false) && (consoleplayer==0))
return;
if (IsServer==true)
return;
// if (networkgame==true)
// {
// diff = (GetTicCount()-controldivisor-LastCommandTime[0])/controldivisor;
// SoftError("diff=%ld\n",diff);
// if (abs(diff)>1)
// ISR_SetTime(GetTicCount()-diff);
#if 0
diff = controlupdatetime-LastCommandTime[0];
if (diff>3)
{
ISR_SetTime(GetTicCount()-1);
}
else if (diff<-3)
{
ISR_SetTime(GetTicCount()+1);
}
#endif
// }
// else
// {
diff = (GetTicCount()-controldivisor-LastCommandTime[server])/controldivisor;
if (abs(diff)>0)
ISR_SetTime(GetTicCount()-diff);
// }
}
//****************************************************************************
//
// ProcessPacket
//
//****************************************************************************
void ProcessPacket (void * pkt, int src)
{
switch (((MoveType *)pkt)->type)
{
case COM_DELTA:
case COM_DELTANULL:
case COM_TEXT:
case COM_PAUSE:
case COM_QUIT:
case COM_EXIT:
case COM_REMRID:
case COM_RESPAWN:
case COM_UNPAUSE:
case COM_ENDGAME:
#if (SYNCCHECK == 1)
case COM_SYNCCHECK:
#endif
// if (FixingPackets==false)
AddPacket(pkt,src);
break;
case COM_SOUNDANDDELTA:
if (remoteridicule == false )
{
((MoveType *)pkt)->type = COM_DELTA;
}
AddPacket(pkt,src);
break;
case COM_SERVER:
AddServerPacket(pkt,src);
break;
case COM_REQUEST:
ResendPacket(pkt, src);
break;
case COM_FIXUP:
FixupPacket(pkt, src);
break;
case COM_SYNCTIME:
ProcessSyncTimePacket(pkt);
break;
case COM_GAMEEND:
case COM_GAMEDESC:
case COM_GAMEACK:
case COM_GAMEMASTER:
if (standalone==true)
restartgame=true;
break;
case COM_START:
break;
default:
Error("ProcessPacket: Unknown packet type=%d\n",((MoveType *)pkt)->type);
}
}
//****************************************************************************
//
// AddServerSubPacket
//
//****************************************************************************
void AddServerSubPacket(COM_ServerHeaderType * serverpkt)
{
byte * pkt;
int i;
ServerCommandStatus(serverpkt->time)=cs_ready;
pkt=&serverpkt->data;
for (i=0;i<serverpkt->numpackets;i++)
{
AddClientPacket(pkt,i);
pkt+=GetPacketSize(pkt);
}
}
//****************************************************************************
//
// AddModemSubPacket
//
//****************************************************************************
void AddModemSubPacket(void * incoming)
{
MoveType * pkt;
pkt=(MoveType *)incoming;
ServerCommandStatus(pkt->time)=cs_ready;
AddClientPacket(incoming,server);
}
//****************************************************************************
//
// AddServerPacket
//
//****************************************************************************
void AddServerPacket(void * pkt, int src)
{
COM_ServerHeaderType * serverpkt;
// The server uses the client's lgts for communicating
// Last good time can be set even for the client/server combo
if (standalone==true)
{
Error("standalone should not be here\n");
}
if (src!=server)
{
Error("Received server packet from non-server src=%d\n",src);
}
serverpkt=(COM_ServerHeaderType *)pkt;
// if (networkgame==false)
// SyncToServer(serverpkt->time);
LastCommandTime[src]+=controldivisor;
if (serverpkt->time != LastCommandTime[src])
{
int numpackets;
numpackets=serverpkt->time-LastCommandTime[src];
if (ServerCommandStatus(LastCommandTime[src])!=cs_fixing)
{
RequestPacket ( LastCommandTime[src] , src , numpackets );
ComError("AddServerPacket: Request packet time=%d lct=%d numpackets=%d\n",
serverpkt->time, LastCommandTime[src], numpackets
);
}
LastCommandTime[src]+=numpackets;
}
AddServerSubPacket( serverpkt );
}
//****************************************************************************
//
// AddClientPacket
//
//****************************************************************************
void AddClientPacket (void * pkt, int src)
{
int size;
MoveType * packet;
packet=(MoveType *)pkt;
switch (packet->type)
{
case COM_DELTA:
case COM_DELTANULL:
case COM_TEXT:
case COM_REMRID:
case COM_PAUSE:
case COM_QUIT:
case COM_EXIT:
case COM_RESPAWN:
case COM_UNPAUSE:
#if (SYNCCHECK == 1)
case COM_SYNCCHECK:
#endif
case COM_ENDGAME:
size=GetPacketSize(packet);
memcpy(PlayerCommand(src,CommandAddress(packet->time)),packet,size);
break;
case COM_SOUNDANDDELTA:
ProcessSoundAndDeltaPacket(packet, src);
break;
default:
Error("AddClientPacket: Unknown packet type = %d\n",packet->type);
}
}
//****************************************************************************
//
// AddSubPacket
//
//****************************************************************************
void AddSubPacket (void * pkt, int src)
{
MoveType * packet;
if (networkgame==false)
Error("Modem game should not be here in AddSubPacket\n");
packet = (MoveType *) pkt;
ClientCommandStatus(src, packet->time)=cs_ready;
memcpy (
ClientTimeCommand(src,packet->time),
pkt,
GetPacketSize(packet)
);
}
//****************************************************************************
//
// AddPacket
//
//****************************************************************************
void AddPacket (void * pkt, int src)
{
MoveType * packet;
// should only be called by server in network game
// in modem game we fall through the first condition
// all packets should be sequential
if ((IsServer==true) && (PlayerStatus[src]!=player_ingame))
return;
packet = (MoveType *) pkt;
// if ((networkgame==false) && (consoleplayer!=0))
// SyncToServer();
if (!((src==server) && (standalone==false) && (IsServer==true)))
{
LastCommandTime[src]+=controldivisor;
if (packet->time != LastCommandTime[src])
{
int numpackets;
numpackets=packet->time-LastCommandTime[src];
if ( ( (networkgame==false) &&
(ServerCommandStatus(LastCommandTime[src])!=cs_fixing)
)
||
( (networkgame==true) &&
(ClientCommandStatus(src,LastCommandTime[src])!=cs_fixing)
)
)
{
RequestPacket ( LastCommandTime[src] , src , numpackets );
ComError("AddPacket: Request packet time=%d lct=%d numpackets=%d\n",
packet->time, LastCommandTime[src], numpackets
);
}
LastCommandTime[src]+=numpackets;
}
}
if (networkgame==true)
{
AddSubPacket ( packet, src );
}
else
{
AddModemSubPacket(packet);
}
}
//****************************************************************************
//
// RequestPacket ( int time, int dest )
//
//****************************************************************************
void RequestPacket (int time, int dest, int numpackets)
{
COM_RequestType request;
int i;
#if (DEVELOPMENT == 1)
if (modemgame==false)
Error("Called Request Packet outside of modem game\n");
#endif
request.type=COM_REQUEST;
request.time=time;
request.numpackets=numpackets/controldivisor;
if (IsServer==true)
{
if ((dest==server) && (standalone==false))
{
Error("Requesting packet from client on top of server\n");
}
if (PlayerStatus[dest]!=player_ingame)
return;
for (i=0;i<numpackets;i+=controldivisor)
{
ClientCommandStatus( dest , (time+i) ) = cs_fixing;
}
}
else
{
if ((networkgame==false) && (PlayerStatus[dest]!=player_ingame))
return;
for (i=0;i<numpackets;i+=controldivisor)
{
ServerCommandStatus( (time+i) ) = cs_fixing;
}
}
// if (networkgame==false)
// FixingPackets=true;
// send out the packet
WritePacket (&request, GetPacketSize(&request), dest);
#if (DEVELOPMENT == 1)
// ComError( "BADPKT, request sent at %ld lgt=%ld dest=%ld\n",GetTicCount(),time,dest);
#endif
}
//****************************************************************************
//
// IsServerCommandReady ()
//
//****************************************************************************
boolean IsServerCommandReady ( int time )
{
if (
(
(COM_ServerHeaderType *)
ServerCommand(CommandAddress (time) ) )->time==time)
return true;
else
{
return false;
}
}
//****************************************************************************
//
// AreClientsReady ()
//
//****************************************************************************
boolean AreClientsReady ( void )
{
int i;
int timeindex;
int status;
timeindex=CommandAddress(serverupdatetime);
for (i=0;i<numplayers;i++)
{
if (PlayerStatus[i]!=player_ingame)
continue;
status=ClientCommandStatus(i, serverupdatetime);
if (status==cs_notarrived)
return false;
else if (status==cs_fixing)
{
// RequestPacket ( serverupdatetime , i , controldivisor );
return false;
}
else if (((MoveType *)ClientCommand(i, timeindex))->time != serverupdatetime)
return false;
}
return true;
}
//****************************************************************************
//
// IsPlayerCommandReady ()
//
//****************************************************************************
boolean IsPlayerCommandReady (int num, int time)
{
MoveType * cmd;
cmd=(MoveType *)PlayerCommand(num,CommandAddress(time));
if (cmd->time==time)
return true;
else
return false;
}
//****************************************************************************
//
// ResetClientCommands ()
//
//****************************************************************************
void ResetClientCommands ( int player )
{
int j;
for (j=0;j<MAXCMDS;j++)
{
memset(ClientCommand(player,j),COM_DELTA,GamePacketSize());
}
}
//****************************************************************************
//
// SendFullServerPacket ()
//
//****************************************************************************
void SendFullServerPacket ( void )
{
int i;
int size;
byte * pkt;
COM_ServerHeaderType * spkt;
int timeindex;
int playerstatus[MAXPLAYERS];
timeindex=CommandAddress(serverupdatetime);
spkt=(COM_ServerHeaderType *)ServerCommand(timeindex);
pkt=&spkt->data;
spkt->time=serverupdatetime;
spkt->type=COM_SERVER;
spkt->numpackets=numplayers;
memset(playerstatus,-1,sizeof(playerstatus));
for (i=0;i<numplayers;i++)
{
size=GetPacketSize(ClientCommand(i,timeindex));
if (((MoveType *)ClientCommand(i,timeindex))->type == COM_QUIT)
{
playerstatus[i]=player_quitgame;
}
if (((MoveType *)ClientCommand(i,timeindex))->type == COM_ENDGAME)
{
playerstatus[i]=player_leftgame;
}
memcpy(pkt,
ClientCommand(i,timeindex),
size
);
pkt+=size;
ClientCommandNumberStatus(i,timeindex)=cs_notarrived;
}
BroadcastServerPacket((void *)spkt,(pkt-(byte *)spkt));
serverupdatetime+=controldivisor;
for (i=0;i<numplayers;i++)
{
if (playerstatus[i]!=-1)
{
if ((standalone==false) && (consoleplayer==i))
{
UpdateServer=false;
}
else
{
ResetClientCommands(i);
PlayerStatus[i]=playerstatus[i];
}
}
}
}
//****************************************************************************
//
// ProcessServer ()
//
//****************************************************************************
void ProcessServer ( void )
{
boolean done;
boolean exit;
int i;
int time;
int quittime;
if (InProcessServer==true)
return;
InProcessServer=true;
if (GetTicCount()<serverupdatetime)
goto exitProcessServer;
time=GetTicCount();
quittime=GetTicCount()+SERVERTIMEOUT;
exit=false;
while (time>=serverupdatetime)
{
int savetime;
savetime=GetTicCount()+NETWORKTIMEOUT;
done = false;
while (done == false)
{
if (standalone==true)
AbortCheck("GameServer aborted\n");
done = AreClientsReady ();
if ( (standalone==false) && (serverupdatetime>=(controlupdatetime-controldivisor)) && (done==false) )
break;
CheckForPacket ();
if (standalone==false)
UpdateClientControls();
if (restartgame==true)
break;
if (GetTicCount()>savetime)
{
for (i=0;i<numplayers;i++)
{
int val;
val=ClientCommandStatus(i, serverupdatetime);
if ((val!=cs_ready) && (PlayerStatus[i]==player_ingame))
{
SoftError("Server timeout\n");
RequestPacket(serverupdatetime, i , controldivisor);
}
}
savetime=GetTicCount()+NETWORKTIMEOUT;
}
// if (GetTicCount()>quittime)
// {
// Error("Server aborting after %ld seconds\n",SERVERTIMEOUT/VBLCOUNTER);
// }
if ((standalone==false) && (done==false))
{
exit=true;
done=true;
}
}
if (exit==true)
break;
if ( (serverupdatetime>=(controlupdatetime-controldivisor)) && (standalone==false))
break;
if (restartgame==true)
break;
SendFullServerPacket();
#if 0
if (serverupdatetime>=syncservertime)
{
SendSyncTimePacket();
syncservertime+=NETSYNCSERVERTIME;
}
#endif
}
exitProcessServer:
InProcessServer=false;
}
//****************************************************************************
//
// SetupCheckForPacket()
//
//****************************************************************************
int SetupCheckForPacket ( void )
{
int retval=scfp_nodata;
if ((ReadPacket()==true) && (badpacket==0))
{
MoveType * pkt;
retval=scfp_data;
pkt=(MoveType *)&ROTTpacket[0];
if ((IsServer==true) && (standalone==true))
{
switch (pkt->type)
{
case COM_GAMEEND:
break;
case COM_GAMEDESC:
if (standalone==true)
printf("Received GameDescription from player#%ld\n",(long int)rottcom->remotenode);
WritePacket(&ROTTpacket[0],GetPacketSize(pkt),0); // Send to player 0
break;
case COM_GAMEACK:
if (standalone==true)
printf("Received GameAcknowledgement from player#%ld\n",(long int)rottcom->remotenode);
WritePacket(&ROTTpacket[0],GetPacketSize(pkt),0); // Send to player 0
break;
case COM_GAMEMASTER:
if (standalone==true)
printf("Received GameMasterPacket from player#%ld\n",(long int)rottcom->remotenode);
BroadcastServerPacket(&ROTTpacket[0],GetPacketSize(pkt)); // Send to all
break;
case COM_GAMEPLAY:
if (standalone==true)
printf("Received StartGamePacket from player#%ld\n",(long int)rottcom->remotenode);
BroadcastServerPacket(&ROTTpacket[0],GetPacketSize(pkt)); // Send to all
retval=scfp_done;
break;
default:
ComError("Server received unknown packet in Game preamble\n");
break;
}
}
else
{
switch (pkt->type)
{
case COM_GAMEPLAY:
retval=scfp_done;
break;
case COM_GAMEMASTER:
SetGameDescription(pkt);
retval=scfp_gameready;
break;
case COM_GAMEACK:
PlayersReady[((COM_GameAckType *)pkt)->player]=true;
break;
case COM_GAMEDESC:
GotPlayersDesc[((COM_GamePlayerType *)pkt)->player]=true;
SetPlayerDescription(pkt);
break;
}
}
}
return retval;
}
//****************************************************************************
//
// ServerLoop ()
//
//****************************************************************************
void ServerLoop( void )
{
boolean done;
while (1)
{
ShutdownClientControls();
restartgame=false;
done=false;
while (done==false)
{
AbortCheck("SetupGameServer aborted\n");
if (SetupCheckForPacket()==scfp_done)
done=true;
}
ComSetTime();
StartupClientControls();
while(1)
{
ProcessServer();
#if (DEVELOPMENT == 1)
Z_CheckHeap();
#endif
CalcTics();
if (restartgame==true)
break;
}
}
}
//****************************************************************************
//
// ProcessPlayerCommand()
//
//****************************************************************************
void ProcessPlayerCommand( int player )
{
MoveType * cmd;
cmd=(MoveType *)PlayerCommand(player,CommandAddress(oldpolltime));
if (cmd->type==COM_DELTA)
{
UpdatePlayerObj(player);
}
else if (cmd->type==COM_RESPAWN)
{
if (player==consoleplayer) // reset spawn state
respawnactive=false;
RespawnPlayerobj(PLAYER[player]);
}
else if (cmd->type==COM_ENDGAME)
{
playstate = ex_battledone;
}
else if (cmd->type==COM_QUIT)
{
if (player==consoleplayer)
QuitGame();
else
{
char str[50]="Player #";
char str2[10];
strcat(str,itoa(player+1,str2,10));
strcat(str,", ");
strcat(str,PLAYERSTATE[player].codename);
strcat(str," has left the game.");
AddMessage(str,MSG_REMOTE);
PlayerStatus[player]=player_quitgame;
}
}
else if (cmd->type==COM_EXIT)
{
QuitGame();
}
else if (cmd->type==COM_REMRID)
{
ProcessRemoteRidicule (cmd);
}
else if (cmd->type==COM_TEXT)
{
int who;
who = ( ( COM_TextType * )cmd )->towho;
if ( ( who == consoleplayer ) ||
( who == MSG_DIRECTED_TO_ALL ) ||
( ( who == MSG_DIRECTED_TO_TEAM ) &&
( BATTLE_Team[ player ] == BATTLE_Team[ consoleplayer ] ) ) )
{
char string[ 50 ];
strcpy( string, "\\N9" );
strcat( string, PLAYERSTATE[player].codename );
strcat( string, ":\\NF" );
strcat( string, ((COM_TextType *)cmd)->string );
SD_PlayPitchedSound ( SD_ENDBONUS1SND, 255, 1200 );
AddMessage( string, MSG_REMOTE );
}
}
#if (SYNCCHECK == 1)
else if (cmd->type==COM_SYNCCHECK)
{
ProcessSyncCheckPacket(cmd, player);
}
#endif
else if (cmd->type==COM_PAUSE)
{
MUSIC_Pause();
GamePaused=true;
pausedstartedticcount = oldpolltime;
}
else if (cmd->type==COM_UNPAUSE)
{
GamePaused=false;
MUSIC_Continue ();
if (RefreshPause == false) // screen is blanked
{
ShutdownScreenSaver();
SetupScreen (true);
RefreshPause = true;
}
}
}
//****************************************************************************
//
// CheckUnPause ()
//
//****************************************************************************
void CheckUnPause ( void )
{
if (oldpolltime==nextupdatetime)
{
nextupdatetime=oldpolltime+controldivisor;
while (1)
{
if (ServerCommandStatus(oldpolltime)==cs_ready)
{
int j;
for (j=0;j<numplayers;j++)
{
if (PlayerStatus[j]==player_ingame)
ProcessPlayerCommand( j );
}
break;
}
else
{
UpdateClientControls();
}
}
}
}
//****************************************************************************
//
// ControlPlayerObj ()
//
//****************************************************************************
void ControlPlayerObj (objtype * ob)
{
playertype * pstate;
int num;
int savetime;
// boolean asked;
// if (GamePaused==true)
// return;
M_LINKSTATE(ob,pstate);
// get player number
num=ob->dirchoosetime;
memcpy (pstate->buttonheld, pstate->buttonstate, sizeof(pstate->buttonstate));
if (oldpolltime==nextupdatetime)
{
if (num==numplayers-1)
nextupdatetime=oldpolltime+controldivisor;
if (networkgame==true)
savetime=GetTicCount()+NETWORKTIMEOUT;
else
savetime=GetTicCount()+MODEMTIMEOUT;
if (PlayerStatus[num]!=player_ingame)
return;
// asked=false;
// copy previous state of buttons
while (1)
{
if (ServerCommandStatus(oldpolltime)==cs_ready)
{
ProcessPlayerCommand (num);
if (demoplayback||demorecord) {
SoftError("x=%4x y=%4x a=%4x time=%5d\n",player->x,player->y,player->angle,oldpolltime);
}
break;
}
// else if ((ServerCommandStatus(oldpolltime)==cs_fixing) &&
// (networkgame==false) &&
// (asked==false)
// )
// {
// asked=true;
// RequestPacket(oldpolltime, server, controldivisor);
// }
else
{
UpdateClientControls();
}
if (GetTicCount()>savetime)
{
SoftError("Client timeout oldpolltime=%d\n",oldpolltime);
if (IsServer==false)
RequestPacket(oldpolltime, server, controldivisor);
if (networkgame==true)
savetime=GetTicCount()+NETWORKTIMEOUT;
else
savetime=GetTicCount()+MODEMTIMEOUT;
}
}
}
if (!(ob->flags&FL_DYING))
{
if (ob->flags&FL_PUSHED)
{
ob->flags&=~FL_PUSHED;
#if 0
if (abs(ob->momentumx)>0)
{
if (abs(ob->momentumx+pstate->dmomx)>=abs(ob->momentumx))
{
ob->momentumx += pstate->dmomx;
ob->momentumy += pstate->dmomy;
}
}
else if (abs(ob->momentumy+pstate->dmomy)>=abs(ob->momentumy))
{
ob->momentumx += pstate->dmomx;
ob->momentumy += pstate->dmomy;
}
#endif
if (abs(ob->momentumx+pstate->dmomx)>=abs(ob->momentumx))
{
ob->momentumx += pstate->dmomx;
}
if (abs(ob->momentumy+pstate->dmomy)>=abs(ob->momentumy))
{
ob->momentumy += pstate->dmomy;
}
}
else
{
ob->momentumx += pstate->dmomx;
ob->momentumy += pstate->dmomy;
}
}
}
//****************************************************************************
//
// MaxSpeedForCharacter ()
//
//****************************************************************************
int MaxSpeedForCharacter(playertype*pstate)
{
if (BATTLEMODE && (gamestate.BattleOptions.Speed == bo_fast_speed))
{
return( FASTSPEED );
}
else
{
if (pstate->buttonstate[bt_run])
return (characters[pstate->player].toprunspeed);
else
return (characters[pstate->player].topspeed);
}
}
//****************************************************************************
//
// UpdatePlayerObj ()
//
//****************************************************************************
void UpdatePlayerObj ( int player )
{
int i, buttonbits;
playertype * pstate;
MoveType * MoveCmd;
MoveCmd=(MoveType *)PlayerCommand(player,CommandAddress(oldpolltime));
pstate=&PLAYERSTATE[player];
buttonbits = MoveCmd->buttons;
for (i = 0; i < NUMTXBUTTONS; i++)
{
pstate->buttonstate[i] = buttonbits & 1;
buttonbits >>= 1;
}
pstate->dmomx = (int)(MoveCmd->momx)<<1;
pstate->dmomy = (int)(MoveCmd->momy)<<1;
pstate->angle = MoveCmd->dangle;
pstate->angle <<= 11;
pstate->topspeed=MaxSpeedForCharacter(pstate);
if (demoplayback||demorecord) {
SoftError(" dmx=%4x dmy=%4x da=%4x time=%5d\n",pstate->dmomx,pstate->dmomy,pstate->angle>>11,oldpolltime);
}
#if 0
#if (DEVELOPMENT == 1)
if ((modemgame==true) || (demoplayback==true) || (demorecord==true))
{
ComError( "player#%2ld\n",player);
ComError( "momx = %6ld\n", PLAYER[player]->momentumx);
ComError( "momy = %6ld\n", PLAYER[player]->momentumy);
ComError( " x = %6ld\n", PLAYER[player]->x);
ComError( " y = %6ld\n", PLAYER[player]->y);
ComError( " z = %6ld\n", PLAYER[player]->z);
ComError( " a = %6ld\n", PLAYER[player]->angle);
if (pstate->buttonstate[bt_attack])
ComError( "FIRING\n");
}
#endif
#endif
}
//****************************************************************************
//
// SendPlayerDescription ()
//
//****************************************************************************
void SendPlayerDescription( void )
{
byte * temp;
COM_GamePlayerType * desc;
int length;
length=sizeof(COM_GamePlayerType);
temp=SafeMalloc(length);
memset(temp,0,length);
desc=(COM_GamePlayerType *)temp;
desc->type=(byte)COM_GAMEDESC;
desc->player=consoleplayer;
desc->violence=gamestate.violence;
desc->Version = gamestate.Version;
desc->Product = gamestate.Product;
desc->playerdescription.character=locplayerstate->player;
desc->playerdescription.uniformcolor=locplayerstate->uniformcolor;
strcpy(&(desc->playerdescription.codename[0]),
&locplayerstate->codename[0]);
WritePacket(temp,length,server);
SafeFree(temp);
}
//****************************************************************************
//
// SendGameDescription ()
//
//****************************************************************************
void SendGameDescription( void )
{
byte * temp;
COM_GameMasterType * desc;
int length;
int i;
length=sizeof(COM_GameMasterType);
temp=SafeMalloc(length);
memset(temp,0,length);
desc=(COM_GameMasterType *)temp;
desc->type=(byte)COM_GAMEMASTER;
desc->level=gamestate.mapon;
desc->mapcrc=GetMapCRC (gamestate.mapon);
desc->mode=gamestate.battlemode;
desc->violence=gamestate.violence;
desc->Version = gamestate.Version;
desc->Product = gamestate.Product;
desc->teamplay = gamestate.teamplay;
memcpy( &desc->SpecialsTimes, &gamestate.SpecialsTimes, sizeof( specials ) );
BATTLE_GetOptions( &( desc->options ) );
GetMapFileName( &(desc->battlefilename[0]) );
desc->randomseed=GetRNGindex ( );
gamestate.randomseed=desc->randomseed;
desc->ludicrousgibs=battlegibs;
ludicrousgibs=battlegibs;
// SetRNGindex ( gamestate.randomseed );
for (i=0;i<numplayers;i++)
{
if (gamestate.Product == ROTT_SHAREWARE)
PLAYERSTATE[i].player = 0;
desc->players[i].character =PLAYERSTATE[i].player;
desc->players[i].uniformcolor =PLAYERSTATE[i].uniformcolor;
strcpy ( &(desc->players[i].codename[0]),&(PLAYERSTATE[i].codename[0]));
}
if (!networkgame)
AssignTeams();
if (IsServer==false)
{
WritePacket(temp,length,server);
}
else
{
BroadcastServerPacket(temp,length); // Send to all
}
SafeFree(temp);
}
//****************************************************************************
//
// SetGameDescription ()
//
//****************************************************************************
void SetGameDescription( void * pkt )
{
COM_GameMasterType * desc;
word localcrc;
int i;
desc=(COM_GameMasterType *)pkt;
gamestate.mapon=desc->level;
gamestate.battlemode=desc->mode;
gamestate.violence=desc->violence;
gamestate.Version = desc->Version;
gamestate.Product = desc->Product;
gamestate.teamplay = desc->teamplay;
memcpy( &gamestate.SpecialsTimes, &desc->SpecialsTimes, sizeof( specials ) );
BATTLE_SetOptions( &( desc->options ) );
gamestate.randomseed=desc->randomseed;
SetRNGindex ( gamestate.randomseed );
SetBattleMapFileName( &(desc->battlefilename[0]) );
localcrc=GetMapCRC (gamestate.mapon);
ludicrousgibs=desc->ludicrousgibs;
if (localcrc!=desc->mapcrc)
Error("You have different maps on your system\n");
for (i=0;i<numplayers;i++)
{
PLAYERSTATE[i].player=desc->players[i].character;
PLAYERSTATE[i].uniformcolor=desc->players[i].uniformcolor;
strcpy ( &(PLAYERSTATE[i].codename[0]),
&(desc->players[i].codename[0])
);
}
AssignTeams();
}
//****************************************************************************
//
// SetPlayerDescription ()
//
//****************************************************************************
void SetPlayerDescription( void * pkt )
{
COM_GamePlayerType * desc;
desc=(COM_GamePlayerType *)pkt;
PLAYERSTATE[desc->player].player=desc->playerdescription.character;
PLAYERSTATE[desc->player].uniformcolor=desc->playerdescription.uniformcolor;
strcpy ( &(PLAYERSTATE[desc->player].codename[0]),
&(desc->playerdescription.codename[0])
);
if ( gamestate.Version != desc->Version )
{
Error("Player %s is using a different version of ROTT\n",PLAYERSTATE[desc->player].codename);
// gamestate.Version = desc->Version;
}
if ( gamestate.violence > desc->violence )
{
gamestate.violence = desc->violence;
}
if ( gamestate.Product > desc->Product )
{
gamestate.Product = desc->Product;
}
}
//****************************************************************************
//
// SendGameAck ()
//
//****************************************************************************
void SendGameAck( void )
{
byte * temp;
int length;
COM_GameAckType * desc;
length=sizeof(COM_GameAckType);
temp=SafeMalloc(length);
desc=(COM_GameAckType *)temp;
desc->type=COM_GAMEACK;
desc->player=consoleplayer;
WritePacket(temp,length,server);
SafeFree(temp);
}
//****************************************************************************
//
// SendGameStart ()
//
//****************************************************************************
void SendGameStart( void )
{
byte * temp;
int length;
length=DUMMYPACKETSIZE;
temp=SafeMalloc(length);
*(temp)=(byte)COM_GAMEPLAY;
if (IsServer==false)
{
WritePacket(temp,length,server);
}
else
{
BroadcastServerPacket(temp,length); // Send to all
}
SafeFree(temp);
}
//****************************************************************************
//
// SetupGamePlayer ()
//
//****************************************************************************
void SetupGamePlayer ( void )
{
int savetime;
boolean done;
boolean gameready;
savetime=GetTicCount();
done=false;
gameready=false;
while (done==false)
{
// Setup individual player
AbortCheck("SetupGamePlayer aborted\n");
// send Player Description
if (GetTicCount() >= savetime)
{
savetime=GetTicCount()+SETUPTIME;
if (gameready==false)
SendPlayerDescription();
else
SendGameAck();
}
switch (SetupCheckForPacket())
{
case scfp_done:
done=true;
break;
case scfp_gameready:
gameready=true;
break;
}
}
savetime=GetTicCount()+(VBLCOUNTER/2);
while (GetTicCount()<savetime)
{
SetupCheckForPacket ();
}
}
//****************************************************************************
//
// AllPlayersReady ()
//
//****************************************************************************
boolean AllPlayersReady ( void )
{
int i;
for (i=0;i<numplayers;i++)
if ((PlayersReady[i]==false) && (PlayerStatus[i]==player_ingame))
return false;
return true;
}
//****************************************************************************
//
// GotAllPlayerDescriptions ()
//
//****************************************************************************
boolean GotAllPlayerDescriptions ( void )
{
int i;
for (i=0;i<numplayers;i++)
if ((GotPlayersDesc[i]==false) && (PlayerStatus[i]==player_ingame))
return false;
return true;
}
//****************************************************************************
//
// SetupGameMaster ()
//
//****************************************************************************
void SetupGameMaster ( void )
{
int savetime;
boolean done;
memset(GotPlayersDesc,false,sizeof(GotPlayersDesc));
GotPlayersDesc[consoleplayer]=true;
memset(PlayersReady,false,sizeof(PlayersReady));
PlayersReady[consoleplayer]=true;
savetime=GetTicCount();
done=false;
InitializeRNG ();
while (done==false)
{
// Setup individual player
AbortCheck("SetupGameMaster aborted\n");
// send Game Description
if (GetTicCount() >= savetime)
{
savetime=GetTicCount()+SETUPTIME;
if (GotAllPlayerDescriptions()==true)
SendGameDescription();
}
if (AllPlayersReady ()==true)
{
SendGameStart();
SendGameStart();
done=true;
}
SetupCheckForPacket();
}
savetime=GetTicCount()+(VBLCOUNTER/2);
while (GetTicCount()<savetime)
{
SetupCheckForPacket ();
}
}
/*
=============================================================================
DEMO CODE
=============================================================================
*/
//****************************************************************************
//
// GetDemoFilename ()
//
//****************************************************************************
void GetDemoFilename (int demonumber, char * filename)
{
strcpy(filename,DATADIR "DEMO0_0.DMO\0");
filename[4 + strlen(DATADIR)] = (char)('0' + (byte)demonumber);
filename[6 + strlen(DATADIR)] = (char)('0' + (byte)gamestate.violence);
FixFilePath(filename);
}
//****************************************************************************
//
// DemoExists ()
//
//****************************************************************************
boolean DemoExists (int demonumber)
{
char demo[20 + sizeof(DATADIR)];
GetDemoFilename (demonumber, &demo[0]);
if (access (demo, F_OK) == 0)
return true;
else
{
/* Saves the users violence level, only do this once, otherwise
we might override the saved level with one already modified by us */
if (predemo_violence == -1)
predemo_violence = gamestate.violence;
/* The demos distributed with rott are all for a violence level of 3 */
gamestate.violence = 3;
GetDemoFilename (demonumber, &demo[0]);
if (access (demo, F_OK) == 0)
return true;
else
return false;
}
}
//****************************************************************************
//
// SaveDemo ()
//
//****************************************************************************
void SaveDemo (int demonumber)
{
char demo[20 + sizeof(DATADIR)];
RecordDemoCmd ();
GetDemoFilename (demonumber, &demo[0]);
SaveFile (demo, demobuffer, (demoptr-demobuffer));
FreeDemo();
}
//****************************************************************************
//
// LoadDemo ()
//
//****************************************************************************
void LoadDemo (int demonumber)
{
char demo[20 + sizeof(DATADIR)];
int size;
GetDemoFilename (demonumber, demo);
if (demobuffer!=NULL)
FreeDemo();
size = LoadFile (demo, (void **)&demobuffer);
playstate = ex_demoplayback;
demoptr = demobuffer;
lastdemoptr = (demoptr+size);
locplayerstate->player=0;
InitializeWeapons(locplayerstate);
ResetPlayerstate(locplayerstate);
InitCharacter();
}
//****************************************************************************
//
// RecordDemo ()
//
//****************************************************************************
void RecordDemo ( void )
{
DemoHeaderType * DemoHeader;
int level;
if (demobuffer!=NULL)
FreeDemo();
godmode=0;
demobuffer = SafeMalloc (DEMOBUFFSIZE);
demoptr = demobuffer;
lastdemoptr = demobuffer+DEMOBUFFSIZE;
// Save off level number
DemoHeader=(DemoHeaderType *)demoptr;
demoptr+=sizeof(gamestate);
memcpy(&(DemoHeader->demostate),&gamestate,sizeof(gamestate));
demorecord = true;
locplayerstate->player=0;
InitializeWeapons(locplayerstate);
ResetPlayerstate(locplayerstate);
level=gamestate.mapon;
InitCharacter();
gamestate.mapon=level;
SoftError(">>>>>>>>>>>>Start demo record\n");
}
//****************************************************************************
//
// SetupDemo ()
//
//****************************************************************************
void SetupDemo ( void )
{
DemoHeaderType * DemoHeader;
demoplayback = true;
godmode=0;
DemoHeader=(DemoHeaderType *)demoptr;
demoptr+=sizeof(gamestate);
// if (gamestate.violence!=DemoHeader->demostate.violence)
// Error ("This demo has a different difficulty level than your current settings\n");
memcpy(&gamestate,&(DemoHeader->demostate),sizeof(gamestate));
SoftError(">>>>>>>>>>>>Start demo playback\n");
}
//****************************************************************************
//
// FreeDemo ()
//
//****************************************************************************
void FreeDemo ( void )
{
demoplayback = false;
demorecord = false;
SafeFree (demobuffer);
demobuffer=NULL;
}
//****************************************************************************
//
// CheckForDemoDone ()
//
//****************************************************************************
void CheckForDemoDone ( void )
{
if ((demoplayback==true) && (demoptr >= lastdemoptr))
{
FreeDemo();
playstate = ex_demodone;
}
}
//****************************************************************************
//
// CheckForDemoOverflowed ()
//
//****************************************************************************
void CheckForDemoOverflowed ( void )
{
if (demoptr >= (lastdemoptr-sizeof(DemoType)))
{
playstate = ex_completed; // demo is done
EndDemo();
}
}
//****************************************************************************
//
// RecordDemoCmd ()
//
//****************************************************************************
void RecordDemoCmd (void)
{
DemoType * dtime;
SoftError("Demo command recorded at %d\n",controlupdatetime);
dtime=(DemoType *)demoptr;
dtime->time = controlupdatetime;
dtime->momx = (controlbuf[0]>>1);
dtime->momy = (controlbuf[1]>>1);
dtime->dangle = controlbuf[2]>>11;
dtime->buttons = buttonbits;
demoptr+=sizeof(DemoType);
CheckForDemoOverflowed();
}
//****************************************************************************
//
// AddDemoCmd ()
//
//****************************************************************************
void AddDemoCmd (void)
{
DemoType * dtime;
//
// get info from demo buffer
//
SoftError("Demo command played at %d\n",controlupdatetime);
if (demoplayback==true)
{
dtime=(DemoType *)demoptr;
controlbuf[0]=dtime->momx<<1;
controlbuf[1]=dtime->momy<<1;
controlbuf[2]=dtime->dangle<<11;
buttonbits =dtime->buttons;
demoptr+=sizeof(DemoType);
}
}
//****************************************************************************
//
// GetNextDemoTime ()
//
//****************************************************************************
int GetNextDemoTime (void)
{
DemoType * dtime;
CheckForDemoDone();
dtime=(DemoType *)demoptr;
if (demoplayback)
return dtime->time;
else
return -1;
}
//****************************************************************************
//
// UpdateDemoPlayback ()
//
//****************************************************************************
void UpdateDemoPlayback (int time)
{
if (demoplayback)
{
if (GetNextDemoTime()==time)
AddDemoCmd();
}
}