Merge ioef with latest ioquake3 master. No function tests have been done yet. GL2 renderer not done either, which is a different beast.

This commit is contained in:
Thilo Schulz 2016-06-16 04:10:34 +02:00
parent 9d6a95d4ad
commit bd8c98e3ac
68 changed files with 4000 additions and 265 deletions

View file

@ -32,8 +32,11 @@ endif
ifndef BUILD_MISSIONPACK
BUILD_MISSIONPACK=
endif
ifndef BUILD_ELITEFORCE
BUILD_ELITEFORCE =
endif
ifndef BUILD_RENDERER_OPENGL2
BUILD_RENDERER_OPENGL2=
BUILD_RENDERER_OPENGL2=0
endif
#############################################################################
@ -101,7 +104,11 @@ endif
export CROSS_COMPILING
ifndef VERSION
VERSION=1.36
ifeq ($(BUILD_ELITEFORCE),1)
VERSION=1.38
else
VERSION=1.36
endif
endif
ifndef CLIENTBIN
@ -176,6 +183,10 @@ ifndef USE_CODEC_VORBIS
USE_CODEC_VORBIS=0
endif
ifndef USE_CODEC_MP3
USE_CODEC_MP3=0
endif
ifndef USE_CODEC_OPUS
USE_CODEC_OPUS=1
endif
@ -263,6 +274,10 @@ NSISDIR=misc/nsis
SDLHDIR=$(MOUNT_DIR)/SDL2
LIBSDIR=$(MOUNT_DIR)/libs
ifeq ($(BUILD_ELITEFORCE),1)
CFLAGS += -DELITEFORCE
endif
bin_path=$(shell which $(1) 2> /dev/null)
# We won't need this if we only build the server
@ -360,6 +375,7 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu")
THREAD_LIBS=-lpthread
LIBS=-ldl -lm
LIBS += -L/emul/linux/x86/usr/lib
CLIENT_LIBS=$(SDL_LIBS)
RENDERER_LIBS = $(SDL_LIBS) -lGL
@ -377,6 +393,10 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu")
endif
endif
ifeq ($(USE_CODEC_MP3),1)
CLIENT_LIBS += -lmad
endif
ifeq ($(USE_MUMBLE),1)
CLIENT_LIBS += -lrt
endif
@ -450,6 +470,11 @@ ifeq ($(PLATFORM),darwin)
endif
endif
ifeq ($(USE_CODEC_MP3),1)
BASE_CFLAGS += -DUSE_CODEC_MP3=1
CLIENT_LIBS += -lmad
endif
ifeq ($(USE_CURL),1)
CLIENT_CFLAGS += $(CURL_CFLAGS)
ifneq ($(USE_CURL_DLOPEN),1)
@ -547,6 +572,14 @@ ifdef MINGW
endif
endif
ifeq ($(USE_CODEC_MP3),1)
ifeq ($(ARCH),x64)
CLIENT_LIBS += $(LIBSDIR)/win64/libmad.a
else
CLIENT_LIBS += $(LIBSDIR)/win32/libmad.a
endif
endif
ifeq ($(ARCH),x86_64)
OPTIMIZEVM = -O3
OPTIMIZE = $(OPTIMIZEVM) -ffast-math
@ -681,6 +714,10 @@ ifeq ($(PLATFORM),freebsd)
endif
endif
ifeq ($(USE_CODEC_MP3),1)
CLIENT_LIBS += -lmad
endif
# cross-compiling tweaks
ifeq ($(ARCH),x86)
ifeq ($(CROSS_COMPILING),1)
@ -986,6 +1023,10 @@ ifeq ($(USE_VOIP),1)
NEED_OPUS=1
endif
ifeq ($(USE_CODEC_MP3),1)
CLIENT_CFLAGS += -DUSE_CODEC_MP3=1
endif
ifeq ($(USE_CODEC_OPUS),1)
CLIENT_CFLAGS += -DUSE_CODEC_OPUS
NEED_OPUS=1
@ -1563,6 +1604,7 @@ Q3OBJ = \
$(B)/client/snd_codec.o \
$(B)/client/snd_codec_wav.o \
$(B)/client/snd_codec_ogg.o \
$(B)/client/snd_codec_mp3.o \
$(B)/client/snd_codec_opus.o \
\
$(B)/client/qal.o \
@ -2082,6 +2124,7 @@ endif
endif
$(B)/client/snd_codec_mp3.o : $(CDIR)/snd_codec_mp3.c; $(DO_CC)
#############################################################################
# DEDICATED SERVER

View file

@ -51,7 +51,20 @@ enum {
ET_PLAYER,
ET_ITEM,
ET_MISSILE,
#ifdef ELITEFORCE
ET_ALT_MISSILE,
ET_MOVER,
ET_BEAM,
ET_PORTAL,
ET_SPEAKER,
ET_PUSH_TRIGGER,
ET_TELEPORT_TRIGGER,
ET_INVISIBLE,
ET_USEABLE,
ET_EVENTS
#else
ET_MOVER
#endif
};
//===========================================================================

View file

@ -2805,10 +2805,17 @@ int BotChatLength(int chatstate)
void BotEnterChat(int chatstate, int clientto, int sendto)
{
bot_chatstate_t *cs;
int clientnum;
cs = BotChatStateFromHandle(chatstate);
if (!cs) return;
#ifdef ELITEFORCE
clientnum = clientto;
#else
clientnum = cs->client;
#endif
if (strlen(cs->chatmessage))
{
BotRemoveTildes(cs->chatmessage);
@ -2818,13 +2825,15 @@ void BotEnterChat(int chatstate, int clientto, int sendto)
else {
switch(sendto) {
case CHAT_TEAM:
EA_Command(cs->client, va("say_team %s", cs->chatmessage));
EA_Command(clientnum, va("say_team %s", cs->chatmessage));
break;
#ifndef ELITEFORCE
case CHAT_TELL:
EA_Command(cs->client, va("tell %d %s", clientto, cs->chatmessage));
EA_Command(clientnum, va("tell %d %s", clientto, cs->chatmessage));
break;
#endif
default: //CHAT_ALL
EA_Command(cs->client, va("say %s", cs->chatmessage));
EA_Command(clientnum, va("say %s", cs->chatmessage));
break;
}
}
@ -2876,13 +2885,19 @@ void BotSetChatGender(int chatstate, int gender)
// Returns: -
// Changes Globals: -
//===========================================================================
#ifdef ELITEFORCE
void BotSetChatName(int chatstate, char *name)
#else
void BotSetChatName(int chatstate, char *name, int client)
#endif
{
bot_chatstate_t *cs;
cs = BotChatStateFromHandle(chatstate);
if (!cs) return;
#ifndef ELITEFORCE
cs->client = client;
#endif
Com_Memset(cs->name, 0, sizeof(cs->name));
strncpy(cs->name, name, sizeof(cs->name));
cs->name[sizeof(cs->name)-1] = '\0';
@ -2981,11 +2996,13 @@ int BotSetupChatAI(void)
file = LibVarString("matchfile", "match.c");
matchtemplates = BotLoadMatchTemplates(file);
//
#ifndef ELITEFORCE
if (!LibVarValue("nochat", "0"))
{
file = LibVarString("rchatfile", "rchat.c");
replychats = BotLoadReplyChat(file);
} //end if
#endif
InitConsoleMessageHeap();

View file

@ -109,5 +109,8 @@ int BotLoadChatFile(int chatstate, char *chatfile, char *chatname);
//store the gender of the bot in the chat state
void BotSetChatGender(int chatstate, int gender);
//store the bot name in the chat state
#ifdef ELITEFORCE
void BotSetChatName(int chatstate, char *name);
#else
void BotSetChatName(int chatstate, char *name, int client);
#endif

View file

@ -374,7 +374,11 @@ void InitLevelItemHeap(void)
if (levelitemheap) FreeMemory(levelitemheap);
#ifdef ELITEFORCE
max_levelitems = (int) LibVarValue("max_levelitems", "1024");
#else
max_levelitems = (int) LibVarValue("max_levelitems", "256");
#endif
levelitemheap = (levelitem_t *) GetClearedMemory(max_levelitems * sizeof(levelitem_t));
for (i = 0; i < max_levelitems-1; i++)

View file

@ -417,7 +417,11 @@ int BotChooseBestFightWeapon(int weaponstate, int *inventory)
if (!ws->weaponweightconfig) return 0;
bestweight = 0;
#ifdef ELITEFORCE
bestweapon = 1;
#else
bestweapon = 0;
#endif
for (i = 0; i < wc->numweapons; i++)
{
if (!wc->weaponinfo[i].valid) continue;

View file

@ -171,6 +171,22 @@ void EA_Attack(int client)
// Returns: -
// Changes Globals: -
//===========================================================================
#ifdef ELITEFORCE
void EA_AltAttack(int client)
{
bot_input_t *bi;
bi = &botinputs[client];
bi->actionflags |= ACTION_ALTATTACK;
} //end of the function EA_AltAttack
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
#endif
void EA_Talk(int client)
{
bot_input_t *bi;
@ -205,7 +221,11 @@ void EA_Respawn(int client)
bi = &botinputs[client];
#ifdef ELITEFORCE
bi->actionflags |= ACTION_ATTACK;
#else
bi->actionflags |= ACTION_RESPAWN;
#endif
} //end of the function EA_Respawn
//===========================================================================
//

View file

@ -45,6 +45,13 @@ void EA_MoveBack(int client);
void EA_MoveLeft(int client);
void EA_MoveRight(int client);
void EA_Attack(int client);
#ifdef ELITEFORCE
void EA_AltAttack(int client);
void EA_UseItem(int client, char *it);
void EA_DropItem(int client, char *it);
void EA_UseInv(int client, char *inv);
void EA_DropInv(int client, char *inv);
#endif
void EA_Respawn(int client);
void EA_Talk(int client);
void EA_Gesture(int client);

View file

@ -740,6 +740,13 @@ static void Init_EA_Export( ea_export_t *ea ) {
ea->EA_Gesture = EA_Gesture;
ea->EA_Talk = EA_Talk;
ea->EA_Attack = EA_Attack;
#ifdef ELITEFORCE
ea->EA_AltAttack = EA_AltAttack;
ea->EA_UseItem = EA_UseItem;
ea->EA_DropItem = EA_DropItem;
ea->EA_UseInv = EA_UseInv;
ea->EA_DropInv = EA_DropInv;
#endif
ea->EA_Use = EA_Use;
ea->EA_Respawn = EA_Respawn;
ea->EA_Crouch = EA_Crouch;

View file

@ -81,6 +81,9 @@ struct weaponinfo_s;
//action flags
#define ACTION_ATTACK 0x00000001
#define ACTION_USE 0x00000002
#ifdef ELITEFORCE
#define ACTION_ALTATTACK 0x00000004
#endif
#define ACTION_RESPAWN 0x00000008
#define ACTION_JUMP 0x00000010
#define ACTION_MOVEUP 0x00000020
@ -276,6 +279,13 @@ typedef struct ea_export_s
void (*EA_Gesture)(int client);
void (*EA_Talk)(int client);
void (*EA_Attack)(int client);
#ifdef ELITEFORCE
void (*EA_AltAttack)(int client);
void (*EA_UseItem)(int client, char *it);
void (*EA_DropItem)(int client, char *it);
void (*EA_UseInv)(int client, char *inv);
void (*EA_DropInv)(int client, char *inv);
#endif
void (*EA_Use)(int client);
void (*EA_Respawn)(int client);
void (*EA_MoveUp)(int client);
@ -331,7 +341,11 @@ typedef struct ai_export_s
void (*BotReplaceSynonyms)(char *string, unsigned long int context);
int (*BotLoadChatFile)(int chatstate, char *chatfile, char *chatname);
void (*BotSetChatGender)(int chatstate, int gender);
#ifdef ELITEFORCE
void (*BotSetChatName)(int chatstate, char *name);
#else
void (*BotSetChatName)(int chatstate, char *name, int client);
#endif
//-----------------------------------
// be_ai_goal.h
//-----------------------------------

View file

@ -131,6 +131,7 @@ typedef enum {
CG_SETUSERCMDVALUE,
CG_R_REGISTERSHADERNOMIP,
CG_MEMORY_REMAINING,
#ifndef ELITEFORCE
CG_R_REGISTERFONT,
CG_KEY_ISDOWN,
CG_KEY_GETCATCHER,
@ -170,7 +171,10 @@ typedef enum {
CG_STARTCAMERA,
CG_GETCAMERAINFO,
*/
#else
CG_R_REGISTERSHADER3D, //59
CG_CVAR_SET_NO_MODIFY, // 60
#endif
CG_MEMSET = 100,
CG_MEMCPY,
CG_STRNCPY,
@ -182,7 +186,9 @@ typedef enum {
CG_CEIL,
CG_TESTPRINTINT,
CG_TESTPRINTFLOAT,
#ifndef ELITEFORCE
CG_ACOS
#endif
} cgameImport_t;
@ -225,7 +231,7 @@ typedef enum {
CG_LAST_ATTACKER,
// int (*CG_LastAttacker)( void );
#ifndef ELITEFORCE
CG_KEY_EVENT,
// void (*CG_KeyEvent)( int key, qboolean down );
@ -233,6 +239,7 @@ typedef enum {
// void (*CG_MouseEvent)( int dx, int dy );
CG_EVENT_HANDLING
// void (*CG_EventHandling)(int type);
#endif
} cgameExport_t;
//----------------------------------------------

View file

@ -291,9 +291,19 @@ rescan:
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=552
// allow server to indicate why they were disconnected
if ( argc >= 2 )
{
#ifdef ELITEFORCE
Cbuf_AddText(va("err_dialog \"%s\"", Cmd_Argv(1)));
#endif
Com_Error( ERR_SERVERDISCONNECT, "Server disconnected - %s", Cmd_Argv( 1 ) );
}
else
{
#ifdef ELITEFORCE
Cbuf_AddText(va("err_dialog \"%s\"", Cmd_Argv(1)));
#endif
Com_Error( ERR_SERVERDISCONNECT, "Server disconnected" );
}
}
if ( !strcmp( cmd, "bcs0" ) ) {
@ -448,17 +458,21 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
case CG_FS_FCLOSEFILE:
FS_FCloseFile( args[1] );
return 0;
#ifndef ELITEFORCE
case CG_FS_SEEK:
return FS_Seek( args[1], args[2], args[3] );
#endif
case CG_SENDCONSOLECOMMAND:
Cbuf_AddText( VMA(1) );
return 0;
case CG_ADDCOMMAND:
CL_AddCgameCommand( VMA(1) );
return 0;
#ifndef ELITEFORCE
case CG_REMOVECOMMAND:
Cmd_RemoveCommandSafe( VMA(1) );
return 0;
#endif
case CG_SENDCLIENTCOMMAND:
CL_AddReliableCommand(VMA(1), qfalse);
return 0;
@ -479,8 +493,10 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
return CM_InlineModel( args[1] );
case CG_CM_TEMPBOXMODEL:
return CM_TempBoxModel( VMA(1), VMA(2), /*int capsule*/ qfalse );
#ifndef ELITEFORCE
case CG_CM_TEMPCAPSULEMODEL:
return CM_TempBoxModel( VMA(1), VMA(2), /*int capsule*/ qtrue );
#endif
case CG_CM_POINTCONTENTS:
return CM_PointContents( VMA(1), args[2] );
case CG_CM_TRANSFORMEDPOINTCONTENTS:
@ -488,15 +504,19 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
case CG_CM_BOXTRACE:
CM_BoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qfalse );
return 0;
#ifndef ELITEFORCE
case CG_CM_CAPSULETRACE:
CM_BoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qtrue );
return 0;
#endif
case CG_CM_TRANSFORMEDBOXTRACE:
CM_TransformedBoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], VMA(8), VMA(9), /*int capsule*/ qfalse );
return 0;
#ifndef ELITEFORCE
case CG_CM_TRANSFORMEDCAPSULETRACE:
CM_TransformedBoxTrace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], VMA(8), VMA(9), /*int capsule*/ qtrue );
return 0;
#endif
case CG_CM_MARKFRAGMENTS:
return re.MarkFragments( args[1], VMA(2), VMA(3), args[4], VMA(5), args[6], VMA(7) );
case CG_S_STARTSOUND:
@ -511,12 +531,14 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
case CG_S_ADDLOOPINGSOUND:
S_AddLoopingSound( args[1], VMA(2), VMA(3), args[4] );
return 0;
#ifndef ELITEFORCE
case CG_S_ADDREALLOOPINGSOUND:
S_AddRealLoopingSound( args[1], VMA(2), VMA(3), args[4] );
return 0;
case CG_S_STOPLOOPINGSOUND:
S_StopLoopingSound( args[1] );
return 0;
#endif
case CG_S_UPDATEENTITYPOSITION:
S_UpdateEntityPosition( args[1], VMA(2) );
return 0;
@ -526,7 +548,12 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
case CG_S_REGISTERSOUND:
return S_RegisterSound( VMA(1), args[2] );
case CG_S_STARTBACKGROUNDTRACK:
S_StartBackgroundTrack( VMA(1), VMA(2) );
#ifdef ELITEFORCE
if(!VMA(1) || !*((char *) VMA(1)))
S_StopBackgroundTrack();
else
#endif
S_StartBackgroundTrack(VMA(1), VMA(2));
return 0;
case CG_R_LOADWORLDMAP:
re.LoadWorld( VMA(1) );
@ -539,9 +566,11 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
return re.RegisterShader( VMA(1) );
case CG_R_REGISTERSHADERNOMIP:
return re.RegisterShaderNoMip( VMA(1) );
#ifndef ELITEFORCE
case CG_R_REGISTERFONT:
re.RegisterFont( VMA(1), args[2], VMA(3));
return 0;
#endif
case CG_R_CLEARSCENE:
re.ClearScene();
return 0;
@ -551,17 +580,21 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
case CG_R_ADDPOLYTOSCENE:
re.AddPolyToScene( args[1], args[2], VMA(3), 1 );
return 0;
#ifndef ELITEFORCE
case CG_R_ADDPOLYSTOSCENE:
re.AddPolyToScene( args[1], args[2], VMA(3), args[4] );
return 0;
case CG_R_LIGHTFORPOINT:
return re.LightForPoint( VMA(1), VMA(2), VMA(3), VMA(4) );
#endif
case CG_R_ADDLIGHTTOSCENE:
re.AddLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
return 0;
#ifndef ELITEFORCE
case CG_R_ADDADDITIVELIGHTTOSCENE:
re.AddAdditiveLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
return 0;
#endif
case CG_R_RENDERSCENE:
re.RenderScene( VMA(1) );
return 0;
@ -598,6 +631,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
return 0;
case CG_MEMORY_REMAINING:
return Hunk_MemoryRemaining();
#ifndef ELITEFORCE
case CG_KEY_ISDOWN:
return Key_IsDown( args[1] );
case CG_KEY_GETCATCHER:
@ -608,7 +642,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
return 0;
case CG_KEY_GETKEY:
return Key_GetKey( VMA(1) );
#endif
case CG_MEMSET:
@ -632,9 +666,9 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
return FloatAsInt( floor( VMF(1) ) );
case CG_CEIL:
return FloatAsInt( ceil( VMF(1) ) );
#ifndef ELITEFORCE
case CG_ACOS:
return FloatAsInt( Q_acos( VMF(1) ) );
case CG_PC_ADD_GLOBAL_DEFINE:
return botlib_export->PC_AddGlobalDefine( VMA(1) );
case CG_PC_LOAD_SOURCE:
@ -692,7 +726,12 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) {
return re.GetEntityToken( VMA(1), args[2] );
case CG_R_INPVS:
return re.inPVS( VMA(1), VMA(2) );
#else
case CG_R_REGISTERSHADER3D:
return re.RegisterShader3D( VMA(1) );
case CG_CVAR_SET_NO_MODIFY:
return qfalse;
#endif
default:
assert(0);
Com_Error( ERR_DROP, "Bad cgame system trap: %ld", (long int) args[0] );

View file

@ -602,6 +602,21 @@ void Con_DrawNotify (void)
// draw the chat line
if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE )
{
#ifdef ELITEFORCE
if (chat_team)
{
SCR_DrawSmallString (8, v, "say_team:", 1.0f );
skip = 11;
}
else
{
SCR_DrawSmallString (8, v, "say:", 1.0f );
skip = 6;
}
Field_Draw(&chatField, skip * SMALLCHAR_WIDTH, v,
SCREEN_WIDTH - ( skip + 1 ) * SMALLCHAR_WIDTH, qtrue, qtrue);
#else
if (chat_team)
{
SCR_DrawBigString (8, v, "say_team:", 1.0f, qfalse );
@ -615,6 +630,7 @@ void Con_DrawNotify (void)
Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v,
SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue, qtrue );
#endif
}
}
@ -649,10 +665,18 @@ void Con_DrawSolidConsole( float frac ) {
// draw the background
y = frac * SCREEN_HEIGHT;
if ( y < 1 ) {
y = 0;
}
else {
#ifdef ELITEFORCE
color[0] = 0;
color[1] = 0;
color[2] = 0;
color[3] = 0.85;
re.SetColor(color);
#endif
SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader );
}
@ -661,8 +685,6 @@ void Con_DrawSolidConsole( float frac ) {
color[2] = 0;
color[3] = 1;
SCR_FillRect( 0, y, SCREEN_WIDTH, 2, color );
// draw the version number
re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );

View file

@ -362,8 +362,10 @@ CL_MouseEvent
void CL_MouseEvent( int dx, int dy, int time ) {
if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
VM_Call( uivm, UI_MOUSE_EVENT, dx, dy );
#ifndef ELITEFORCE
} else if (Key_GetCatcher( ) & KEYCATCH_CGAME) {
VM_Call (cgvm, CG_MOUSE_EVENT, dx, dy);
#endif
} else {
cl.mouseDx[cl.mouseIndex] += dx;
cl.mouseDy[cl.mouseIndex] += dy;
@ -742,7 +744,10 @@ void CL_WritePacket( void ) {
usercmd_t nullcmd;
int packetNum;
int oldPacketNum;
int count, key;
int count;
#ifndef ELITEFORCE
int key;
#endif
// don't send anything if playing back a demo
if ( clc.demoplaying || clc.state == CA_CINEMATIC ) {
@ -752,9 +757,21 @@ void CL_WritePacket( void ) {
Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
oldcmd = &nullcmd;
MSG_Init( &buf, data, sizeof(data) );
#ifdef ELITEFORCE
if(clc.compat)
{
MSG_InitOOB( &buf, data, sizeof(data) );
buf.compat = clc.compat;
}
else
{
#endif
MSG_Init( &buf, data, sizeof(data) );
MSG_Bitstream( &buf );
#ifdef ELITEFORCE
}
#endif
MSG_Bitstream( &buf );
// write the current serverId so the server
// can tell if this is from the current gameState
MSG_WriteLong( &buf, cl.serverId );
@ -856,18 +873,24 @@ void CL_WritePacket( void ) {
// write the command count
MSG_WriteByte( &buf, count );
#ifndef ELITEFORCE
// use the checksum feed in the key
key = clc.checksumFeed;
// also use the message acknowledge
key ^= clc.serverMessageSequence;
// also use the last acknowledged server command in the key
key ^= MSG_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);
#endif
// write all the commands, including the predicted command
for ( i = 0 ; i < count ; i++ ) {
j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
cmd = &cl.cmds[j];
#ifdef ELITEFORCE
MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
#else
MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);
#endif
oldcmd = cmd;
}
}
@ -964,6 +987,12 @@ void CL_InitInput( void ) {
Cmd_AddCommand ("-button3", IN_Button3Up);
Cmd_AddCommand ("+button4", IN_Button4Down);
Cmd_AddCommand ("-button4", IN_Button4Up);
#ifdef ELITEFORCE
Cmd_AddCommand ("+altattack", IN_Button5Down);
Cmd_AddCommand ("-altattack", IN_Button5Up);
Cmd_AddCommand ("+use", IN_Button6Down);
Cmd_AddCommand ("-use", IN_Button6Up);
#endif
Cmd_AddCommand ("+button5", IN_Button5Down);
Cmd_AddCommand ("-button5", IN_Button5Up);
Cmd_AddCommand ("+button6", IN_Button6Down);
@ -1041,6 +1070,12 @@ void CL_ShutdownInput(void)
Cmd_RemoveCommand("-button3");
Cmd_RemoveCommand("+button4");
Cmd_RemoveCommand("-button4");
#ifdef ELITEFORCE
Cmd_RemoveCommand ("+altattack");
Cmd_RemoveCommand ("-altattack");
Cmd_RemoveCommand ("+use");
Cmd_RemoveCommand ("-use");
#endif
Cmd_RemoveCommand("+button5");
Cmd_RemoveCommand("-button5");
Cmd_RemoveCommand("+button6");

View file

@ -1244,13 +1244,14 @@ void CL_KeyDownEvent( int key, unsigned time )
return;
}
#ifndef ELITEFORCE
// escape always gets out of CGAME stuff
if (Key_GetCatcher( ) & KEYCATCH_CGAME) {
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CGAME );
VM_Call (cgvm, CG_EVENT_HANDLING, CGAME_EVENT_NONE);
return;
}
#endif
if ( !( Key_GetCatcher( ) & KEYCATCH_UI ) ) {
if ( clc.state == CA_ACTIVE && !clc.demoplaying ) {
VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_INGAME );
@ -1262,8 +1263,11 @@ void CL_KeyDownEvent( int key, unsigned time )
}
return;
}
#ifdef ELITEFORCE
VM_Call( uivm, UI_KEY_EVENT, key );
#else
VM_Call( uivm, UI_KEY_EVENT, key, qtrue );
#endif
return;
}
@ -1277,10 +1281,12 @@ void CL_KeyDownEvent( int key, unsigned time )
if ( uivm ) {
VM_Call( uivm, UI_KEY_EVENT, key, qtrue );
}
#ifndef ELITEFORCE
} else if ( Key_GetCatcher( ) & KEYCATCH_CGAME ) {
if ( cgvm ) {
VM_Call( cgvm, CG_KEY_EVENT, key, qtrue );
}
#endif
} else if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) {
Message_Key( key );
} else if ( clc.state == CA_DISCONNECTED ) {
@ -1317,11 +1323,13 @@ void CL_KeyUpEvent( int key, unsigned time )
//
CL_ParseBinding( key, qfalse, time );
#ifndef ELITEFORCE
if ( Key_GetCatcher( ) & KEYCATCH_UI && uivm ) {
VM_Call( uivm, UI_KEY_EVENT, key, qfalse );
} else if ( Key_GetCatcher( ) & KEYCATCH_CGAME && cgvm ) {
VM_Call( cgvm, CG_KEY_EVENT, key, qfalse );
}
#endif
}
/*

View file

@ -723,9 +723,14 @@ void CL_Record_f( void ) {
if ( Cmd_Argc() == 2 ) {
s = Cmd_Argv(1);
Q_strncpyz( demoName, s, sizeof( demoName ) );
#ifdef LEGACY_PROTOCOL
if(clc.compat)
#ifdef ELITEFORCE
Com_sprintf(name, sizeof(name), "demos/%s.efdemo", demoName);
#else
Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_legacyprotocol->integer);
#endif
else
#endif
Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_protocol->integer);
@ -737,7 +742,11 @@ void CL_Record_f( void ) {
CL_DemoFilename( number, demoName, sizeof( demoName ) );
#ifdef LEGACY_PROTOCOL
if(clc.compat)
#ifdef ELITEFORCE
Com_sprintf(name, sizeof(name), "demos/%s.efdemo", demoName);
#else
Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_legacyprotocol->integer);
#endif
else
#endif
Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_protocol->integer);
@ -768,11 +777,23 @@ void CL_Record_f( void ) {
clc.demowaiting = qtrue;
// write out the gamestate message
MSG_Init (&buf, bufData, sizeof(bufData));
MSG_Bitstream(&buf);
#ifdef ELITEFORCE
if(clc.compat)
{
MSG_InitOOB(&buf, bufData, sizeof(bufData));
buf.compat = qtrue;
}
else
{
#endif
MSG_Init (&buf, bufData, sizeof(bufData));
MSG_Bitstream(&buf);
// NOTE, MRE: all server->client messages now acknowledge
MSG_WriteLong( &buf, clc.reliableSequence );
// NOTE, MRE: all server->client messages now acknowledge
MSG_WriteLong( &buf, clc.reliableSequence );
#ifdef ELITEFORCE
}
#endif
MSG_WriteByte (&buf, svc_gamestate);
MSG_WriteLong (&buf, clc.serverCommandSequence );
@ -799,17 +820,30 @@ void CL_Record_f( void ) {
MSG_WriteDeltaEntity (&buf, &nullstate, ent, qtrue );
}
MSG_WriteByte( &buf, svc_EOF );
#ifdef ELITEFORCE
if(buf.compat)
MSG_WriteByte(&buf, 0);
else
#endif
MSG_WriteByte( &buf, svc_EOF );
// finished writing the gamestate stuff
// write the client num
MSG_WriteLong(&buf, clc.clientNum);
// write the checksum feed
MSG_WriteLong(&buf, clc.checksumFeed);
#ifdef ELITEFORCE
if(!buf.compat)
{
#endif
// write the client num
MSG_WriteLong(&buf, clc.clientNum);
// finished writing the client packet
MSG_WriteByte( &buf, svc_EOF );
// write the checksum feed
MSG_WriteLong(&buf, clc.checksumFeed);
// finished writing the client packet
MSG_WriteByte( &buf, svc_EOF );
#ifdef ELITEFORCE
}
#endif
// write it to the demo file
len = LittleLong( clc.serverMessageSequence - 1 );
@ -952,7 +986,15 @@ void CL_ReadDemoMessage( void ) {
clc.serverMessageSequence = LittleLong( s );
// init the message
MSG_Init( &buf, bufData, sizeof( bufData ) );
#ifdef ELITEFORCE
if(clc.compat)
{
MSG_InitOOB(&buf, bufData, sizeof(bufData));
buf.compat = qtrue;
}
else
#endif
MSG_Init( &buf, bufData, sizeof( bufData ) );
// get the length
r = FS_Read (&buf.cursize, 4, clc.demofile);
@ -989,11 +1031,15 @@ static int CL_WalkDemoExt(char *arg, char *name, int *demofile)
{
int i = 0;
*demofile = 0;
#ifdef LEGACY_PROTOCOL
if(com_legacyprotocol->integer > 0)
{
#ifdef ELITEFORCE
Com_sprintf(name, MAX_OSPATH, "demos/%s.efdemo", arg);
#else
Com_sprintf(name, MAX_OSPATH, "demos/%s.%s%d", arg, DEMOEXT, com_legacyprotocol->integer);
#endif
FS_FOpenFileRead(name, demofile, qtrue);
if (*demofile)
@ -1084,9 +1130,20 @@ void CL_PlayDemo_f( void ) {
// open the demo file
arg = Cmd_Argv(1);
CL_Disconnect( qtrue );
CL_Disconnect( qtrue );
#ifdef ELITEFORCE
ext_test = arg + strlen(arg) - 7;
if(!strcmp(ext_test, ".efdemo"))
{
Com_sprintf (name, sizeof(name), "demos/%s", arg);
FS_FOpenFileRead(name, &clc.demofile, qtrue);
protocol = com_legacyprotocol->integer;
}
else
#endif
{
// check for an extension .DEMOEXT_?? (?? is protocol)
ext_test = strrchr(arg, '.');
@ -1126,6 +1183,7 @@ void CL_PlayDemo_f( void ) {
}
else
protocol = CL_WalkDemoExt(arg, name, &clc.demofile);
}
if (!clc.demofile) {
Com_Error( ERR_DROP, "couldn't open %s", name);
@ -1900,7 +1958,12 @@ void CL_SendPureChecksums( void ) {
char cMsg[MAX_INFO_VALUE];
// if we are pure we need to send back a command with our referenced pk3 checksums
Com_sprintf(cMsg, sizeof(cMsg), "cp %d %s", cl.serverId, FS_ReferencedPakPureChecksums());
#ifdef ELITEFORCE
if(clc.compat)
Com_sprintf(cMsg, sizeof(cMsg), "cp %s", FS_ReferencedPakPureChecksums());
else
#endif
Com_sprintf(cMsg, sizeof(cMsg), "cp %d %s", cl.serverId, FS_ReferencedPakPureChecksums());
CL_AddReliableCommand(cMsg, qfalse);
}
@ -2389,7 +2452,11 @@ void CL_CheckForResend( void ) {
Info_SetValueForKey( info, "challenge", va("%i", clc.challenge ) );
Com_sprintf( data, sizeof(data), "connect \"%s\"", info );
NET_OutOfBandData( NS_CLIENT, clc.serverAddress, (byte *) data, strlen ( data ) );
#ifdef ELITEFORCE
NET_OutOfBandPrint( NS_CLIENT, clc.serverAddress, "%s", data);
#else
NET_OutOfBandData( NS_CLIENT, clc.serverAddress, (byte *) data, strlen ( data ) );
#endif
// the most current userinfo has been sent, so watch for any
// newer changes to userinfo variables
cvar_modifiedFlags &= ~CVAR_USERINFO;
@ -2467,6 +2534,9 @@ void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extend
int numservers;
byte* buffptr;
byte* buffend;
#ifdef ELITEFORCE
char strbyte[3] = "FF";
#endif
Com_Printf("CL_ServersResponsePacket\n");
@ -2496,12 +2566,30 @@ void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extend
if (*buffptr == '\\')
{
buffptr++;
#ifdef ELITEFORCE
if (buffend - buffptr < sizeof(addresses[numservers].ip) * 2 + sizeof(addresses[numservers].port) * 2 + 1)
break;
// EliteForce uses a slightly different format with bytes encoded
// in hex values.
for(i = 0; i < 6; i++)
{
strbyte[0] = toupper(*buffptr++);
strbyte[1] = toupper(*buffptr++);
if(i < 4)
addresses[numservers].ip[i] = strtoul(strbyte, NULL, 16);
else
((unsigned char *) &addresses[numservers].port)[i - 4] =
strtoul(strbyte, NULL, 16);
}
#else
if (buffend - buffptr < sizeof(addresses[numservers].ip) + sizeof(addresses[numservers].port) + 1)
break;
for(i = 0; i < sizeof(addresses[numservers].ip); i++)
addresses[numservers].ip[i] = *buffptr++;
#endif
addresses[numservers].type = NA_IP;
}
@ -2517,17 +2605,24 @@ void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extend
addresses[numservers].ip6[i] = *buffptr++;
addresses[numservers].type = NA_IP6;
#ifdef ELITEFORCE
// parse out port
addresses[numservers].port = (*buffptr++) << 8;
addresses[numservers].port += *buffptr++;
addresses[numservers].port = BigShort( addresses[numservers].port );
#endif
addresses[numservers].scope_id = from->scope_id;
}
else
// syntax error!
break;
#ifndef ELITEFORCE
// parse out port
addresses[numservers].port = (*buffptr++) << 8;
addresses[numservers].port += *buffptr++;
addresses[numservers].port = BigShort( addresses[numservers].port );
#endif
// syntax check
if (*buffptr != '\\' && *buffptr != '/')
break;
@ -2728,6 +2823,9 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
clc.challenge, qfalse);
#endif
#ifdef ELITEFORCE
clc.netchan.compat = clc.compat;
#endif
clc.state = CA_CONNECTED;
clc.lastPacketSentTime = -9999; // send first packet immediately
return;
@ -2800,7 +2898,10 @@ void CL_PacketEvent( netadr_t from, msg_t *msg ) {
int headerBytes;
clc.lastPacketTime = cls.realtime;
#ifdef ELITEFORCE
msg->compat = clc.compat;
#endif
if ( msg->cursize >= 4 && *(int *)msg->data == -1 ) {
CL_ConnectionlessPacket( from, msg );
return;
@ -3117,7 +3218,11 @@ void CL_InitRenderer( void ) {
re.BeginRegistration( &cls.glconfig );
// load character sets
#ifdef ELITEFORCE
cls.charSetShader = re.RegisterShaderNoMip( "gfx/2d/charsgrid_med" );
#else
cls.charSetShader = re.RegisterShader( "gfx/2d/bigchars" );
#endif
cls.whiteShader = re.RegisterShader( "white" );
cls.consoleShader = re.RegisterShader( "console" );
g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2;
@ -3496,6 +3601,8 @@ void CL_Init( void ) {
}
cls.realtime = 0;
clc.lastPacketTime = 0;
clc.lastPacketSentTime = -9999;
CL_InitInput ();
@ -3530,7 +3637,11 @@ void CL_Init( void ) {
cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "140", CVAR_ARCHIVE);
cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
#ifdef ELITEFORCE
cl_maxpackets = Cvar_Get ("cl_maxpackets", "43", CVAR_ARCHIVE );
#else
cl_maxpackets = Cvar_Get ("cl_maxpackets", "30", CVAR_ARCHIVE );
#endif
cl_packetdup = Cvar_Get ("cl_packetdup", "1", CVAR_ARCHIVE );
cl_run = Cvar_Get ("cl_run", "1", CVAR_ARCHIVE);
@ -3611,12 +3722,14 @@ void CL_Init( void ) {
Cvar_Get ("name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE );
cl_rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("model", "sarge", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("headmodel", "sarge", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("model", "munro/red", CVAR_USERINFO | CVAR_ARCHIVE );
#ifndef ELITEFORCE
Cvar_Get ("headmodel", "munro", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("team_model", "james", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("team_headmodel", "*james", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("g_redTeam", "Stroggs", CVAR_SERVERINFO | CVAR_ARCHIVE);
Cvar_Get ("g_blueTeam", "Pagans", CVAR_SERVERINFO | CVAR_ARCHIVE);
#endif
Cvar_Get ("color1", "4", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("color2", "5", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("handicap", "100", CVAR_USERINFO | CVAR_ARCHIVE );
@ -3824,6 +3937,19 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
char *gamename;
qboolean gameMismatch;
#ifdef ELITEFORCE
// eliteforce doesn't send a \n after infoResponse..
infoString = strchr((char *) msg->data, '"');
if(!infoString)
return;
msg->readcount = (int) ((byte *) ++infoString - msg->data);
msg->bit = msg->readcount << 3;
// find the second " character and empty it.
infoString = strchr(infoString, '"');
if(infoString)
*infoString = '\0';
#endif
infoString = MSG_ReadString( msg );
// if this isn't the correct gamename, ignore it
@ -3861,6 +3987,10 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
{
if ( cl_pinglist[i].adr.port && !cl_pinglist[i].time && NET_CompareAdr( from, cl_pinglist[i].adr ) )
{
#ifdef ELITEFORCE
char *str = "";
#endif
// calc ping time
cl_pinglist[i].time = Sys_Milliseconds() - cl_pinglist[i].start;
Com_DPrintf( "ping time %dms from %s\n", cl_pinglist[i].time, NET_AdrToString( from ) );
@ -3875,15 +4005,25 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
case NA_BROADCAST:
case NA_IP:
type = 1;
#ifdef ELITEFORCE
str = "udp";
#endif
break;
case NA_IP6:
type = 2;
#ifdef ELITEFORCE
str = "udp6";
#endif
break;
default:
type = 0;
break;
}
Info_SetValueForKey( cl_pinglist[i].info, "nettype", va("%d", type) );
#ifdef ELITEFORCE
Info_SetValueForKey( cl_pinglist[i].info, "nettype", str);
#else
Info_SetValueForKey( cl_pinglist[i].info, "nettype", va("%d", type));
#endif
CL_SetServerInfoByAddress(from, infoString, cl_pinglist[i].time);
return;
@ -4183,7 +4323,7 @@ void CL_GlobalServers_f( void ) {
// -1 is used to distinguish a "no response"
i = NET_StringToAdr(masteraddress, &to, NA_UNSPEC);
if(!i)
{
Com_Printf( "CL_GlobalServers_f: Error: could not resolve address of master %s\n", masteraddress);
@ -4217,8 +4357,13 @@ void CL_GlobalServers_f( void ) {
Com_sprintf(command, sizeof(command), "getservers %s",
Cmd_Argv(2));
else
#ifdef ELITEFORCE
Com_sprintf(command, sizeof(command), "getservers %s",
Cmd_Argv(2));
#else
Com_sprintf(command, sizeof(command), "getservers %s %s",
com_gamename->string, Cmd_Argv(2));
#endif
for (i=3; i < count; i++)
{

View file

@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../qcommon/qcommon.h"
#include "client.h"
#ifndef ELITEFORCE
#ifdef LEGACY_PROTOCOL
/*
==============
@ -36,6 +37,7 @@ CL_Netchan_Encode
==============
*/
static void CL_Netchan_Encode( msg_t *msg ) {
int serverId, messageAcknowledge, reliableAcknowledge;
int i, index, srdc, sbit, soob;
@ -90,6 +92,7 @@ CL_Netchan_Decode
==============
*/
static void CL_Netchan_Decode( msg_t *msg ) {
long reliableAcknowledge, i, index;
byte key, *string;
@ -127,6 +130,7 @@ static void CL_Netchan_Decode( msg_t *msg ) {
}
}
#endif
#endif
/*
=================
@ -150,11 +154,16 @@ CL_Netchan_Transmit
================
*/
void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) {
MSG_WriteByte( msg, clc_EOF );
#ifdef ELITEFORCE
if(!chan->compat)
#endif
MSG_WriteByte( msg, clc_EOF );
#ifndef ELITEFORCE
#ifdef LEGACY_PROTOCOL
if(chan->compat)
CL_Netchan_Encode(msg);
#endif
#endif
Netchan_Transmit(chan, msg->cursize, msg->data);
@ -177,10 +186,11 @@ qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg ) {
ret = Netchan_Process( chan, msg );
if (!ret)
return qfalse;
#ifndef ELITEFORCE
#ifdef LEGACY_PROTOCOL
if(chan->compat)
CL_Netchan_Decode(msg);
#endif
#endif
return qtrue;

View file

@ -210,7 +210,10 @@ void CL_ParseSnapshot( msg_t *msg ) {
// get the reliable sequence acknowledge number
// NOTE: now sent with all server to client messages
//clc.reliableAcknowledge = MSG_ReadLong( msg );
#ifdef ELITEFORCE
if(msg->compat)
clc.reliableAcknowledge = MSG_ReadLong( msg );
#endif
// read in the new snapshot to a temporary buffer
// we will only copy to cl.snap if it is valid
@ -483,9 +486,12 @@ void CL_ParseGamestate( msg_t *msg ) {
while ( 1 ) {
cmd = MSG_ReadByte( msg );
if ( cmd == svc_EOF ) {
#ifdef ELITEFORCE
if((msg->compat && cmd <= 0) || cmd == svc_EOF)
#else
if ( cmd == svc_EOF )
#endif
break;
}
if ( cmd == svc_configstring ) {
int len;
@ -518,9 +524,16 @@ void CL_ParseGamestate( msg_t *msg ) {
}
}
clc.clientNum = MSG_ReadLong(msg);
#ifdef ELITEFORCE
if(!msg->compat)
#endif
clc.clientNum = MSG_ReadLong(msg);
// read the checksum feed
clc.checksumFeed = MSG_ReadLong( msg );
#ifdef ELITEFORCE
if(!clc.demoplaying || !msg->compat)
#endif
clc.checksumFeed = MSG_ReadLong( msg );
// save old gamedir
Cvar_VariableStringBuffer("fs_game", oldGame, sizeof(oldGame));
@ -864,14 +877,21 @@ void CL_ParseServerMessage( msg_t *msg ) {
Com_Printf ("------------------\n");
}
MSG_Bitstream(msg);
#ifdef ELITEFORCE
if(!msg->compat)
{
#endif
MSG_Bitstream(msg);
// get the reliable sequence acknowledge number
clc.reliableAcknowledge = MSG_ReadLong( msg );
//
if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {
clc.reliableAcknowledge = clc.reliableSequence;
// get the reliable sequence acknowledge number
clc.reliableAcknowledge = MSG_ReadLong( msg );
//
if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {
clc.reliableAcknowledge = clc.reliableSequence;
}
#ifdef ELITEFORCE
}
#endif
//
// parse the message
@ -884,7 +904,12 @@ void CL_ParseServerMessage( msg_t *msg ) {
cmd = MSG_ReadByte( msg );
if (cmd == svc_EOF) {
#ifdef ELITEFORCE
if(cmd == svc_EOF || (msg->compat && cmd == -1))
#else
if ( cmd == svc_EOF)
#endif
{
SHOWNET( msg, "END OF MESSAGE" );
break;
}

View file

@ -160,7 +160,7 @@ static void SCR_DrawChar( int x, int y, float size, int ch ) {
void SCR_DrawSmallChar( int x, int y, int ch ) {
int row, col;
float frow, fcol;
float size;
float vsize, hsize;
ch &= 255;
@ -177,11 +177,16 @@ void SCR_DrawSmallChar( int x, int y, int ch ) {
frow = row*0.0625;
fcol = col*0.0625;
size = 0.0625;
vsize = 0.0625;
#ifdef ELITEFORCE
hsize = 0.03125;
#else
hsize = 0.0625;
#endif
re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
fcol, frow,
fcol + size, frow + size,
fcol + hsize, frow + vsize,
cls.charSetShader );
}
@ -255,6 +260,16 @@ void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color, qboolean
SCR_DrawStringExt( x, y, BIGCHAR_WIDTH, s, color, qtrue, noColorEscape );
}
#ifdef ELITEFORCE
void SCR_DrawSmallString(int x, int y, const char *s, float alpha)
{
float color[4];
color[0] = color[1] = color[2] = 1.0;
color[3] = alpha;
SCR_DrawSmallStringExt(x, y, s, color, qfalse, qfalse);
}
#endif
/*
==================

View file

@ -84,7 +84,7 @@ void LAN_SaveServersToCache( void ) {
FS_FCloseFile(fileOut);
}
#ifndef ELITEFORCE
/*
====================
LAN_ResetPings
@ -204,7 +204,7 @@ static void LAN_RemoveServer(int source, const char *addr) {
}
}
}
#endif
/*
====================
@ -226,7 +226,6 @@ static int LAN_GetServerCount( int source ) {
}
return 0;
}
/*
====================
LAN_GetLocalServerAddressString
@ -257,6 +256,7 @@ static void LAN_GetServerAddressString( int source, int n, char *buf, int buflen
buf[0] = '\0';
}
#ifndef ELITEFORCE
/*
====================
LAN_GetServerInfo
@ -365,7 +365,6 @@ static serverInfo_t *LAN_GetServerPtr( int source, int n ) {
}
return NULL;
}
/*
====================
LAN_CompareServers
@ -435,6 +434,8 @@ static int LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int
return res;
}
#endif
/*
====================
LAN_GetPingQueueCount
@ -471,6 +472,7 @@ static void LAN_GetPingInfo( int n, char *buf, int buflen ) {
CL_GetPingInfo( n, buf, buflen );
}
#ifndef ELITEFORCE
/*
====================
LAN_MarkServerVisible
@ -549,6 +551,8 @@ static int LAN_ServerIsVisible(int source, int n ) {
return qfalse;
}
#endif
/*
=======================
LAN_UpdateVisiblePings
@ -627,6 +631,7 @@ static void Key_GetBindingBuf( int keynum, char *buf, int buflen ) {
CLUI_GetCDKey
====================
*/
#ifndef ELITEFORCE
static void CLUI_GetCDKey( char *buf, int buflen ) {
#ifndef STANDALONE
cvar_t *fs;
@ -642,7 +647,7 @@ static void CLUI_GetCDKey( char *buf, int buflen ) {
*buf = 0;
#endif
}
#endif
/*
====================
@ -659,7 +664,12 @@ static void CLUI_SetCDKey( char *buf ) {
// set the flag so the fle will be written at the next opportunity
cvar_modifiedFlags |= CVAR_ARCHIVE;
} else {
#ifdef ELITEFORCE
Com_Memcpy(cl_cdkey, buf, 22);
cl_cdkey[22] = '\0';
#else
Com_Memcpy( cl_cdkey, buf, 16 );
#endif
// set the flag so the fle will be written at the next opportunity
cvar_modifiedFlags |= CVAR_ARCHIVE;
}
@ -794,8 +804,10 @@ intptr_t CL_UISystemCalls( intptr_t *args ) {
case UI_FS_GETFILELIST:
return FS_GetFileList( VMA(1), VMA(2), VMA(3), args[4] );
#ifndef ELITEFORCE
case UI_FS_SEEK:
return FS_Seek( args[1], args[2], args[3] );
#endif
case UI_R_REGISTERMODEL:
return re.RegisterModel( VMA(1) );
@ -902,6 +914,7 @@ intptr_t CL_UISystemCalls( intptr_t *args ) {
case UI_GETCONFIGSTRING:
return GetConfigString( args[1], VMA(2), args[3] );
#ifndef ELITEFORCE
case UI_LAN_LOADCACHEDSERVERS:
LAN_LoadCachedServers();
return 0;
@ -916,6 +929,7 @@ intptr_t CL_UISystemCalls( intptr_t *args ) {
case UI_LAN_REMOVESERVER:
LAN_RemoveServer(args[1], VMA(2));
return 0;
#endif
case UI_LAN_GETPINGQUEUECOUNT:
return LAN_GetPingQueueCount();
@ -932,13 +946,26 @@ intptr_t CL_UISystemCalls( intptr_t *args ) {
LAN_GetPingInfo( args[1], VMA(2), args[3] );
return 0;
#ifdef ELITEFORCE
case UI_LAN_GETLOCALSERVERCOUNT:
return LAN_GetServerCount(AS_LOCAL);
case UI_LAN_GETLOCALSERVERADDRESSSTRING:
LAN_GetServerAddressString( AS_LOCAL, args[1], VMA(2), args[3] );
return 0;
case UI_LAN_GETGLOBALSERVERCOUNT:
return LAN_GetServerCount(AS_GLOBAL);
case UI_LAN_GETGLOBALSERVERADDRESSSTRING:
LAN_GetServerAddressString( AS_GLOBAL, args[1], VMA(2), args[3] );
return 0;
#else
case UI_LAN_GETSERVERCOUNT:
return LAN_GetServerCount(args[1]);
case UI_LAN_GETSERVERADDRESSSTRING:
LAN_GetServerAddressString( args[1], args[2], VMA(3), args[4] );
return 0;
case UI_LAN_GETSERVERINFO:
LAN_GetServerInfo( args[1], args[2], VMA(3), args[4] );
return 0;
@ -965,26 +992,32 @@ intptr_t CL_UISystemCalls( intptr_t *args ) {
case UI_LAN_COMPARESERVERS:
return LAN_CompareServers( args[1], args[2], args[3], args[4], args[5] );
#endif
case UI_MEMORY_REMAINING:
return Hunk_MemoryRemaining();
#ifndef ELITEFORCE
case UI_GET_CDKEY:
CLUI_GetCDKey( VMA(1), args[2] );
return 0;
#endif
case UI_SET_CDKEY:
#ifndef STANDALONE
CLUI_SetCDKey( VMA(1) );
#ifdef ELITEFORCE
return qtrue;
#endif
#endif
return 0;
#ifndef ELITEFORCE
case UI_SET_PBCLSTATUS:
return 0;
case UI_R_REGISTERFONT:
re.RegisterFont( VMA(1), args[2], VMA(3));
return 0;
#endif
case UI_MEMSET:
Com_Memset( VMA(1), args[2], args[3] );
@ -1016,6 +1049,7 @@ intptr_t CL_UISystemCalls( intptr_t *args ) {
case UI_CEIL:
return FloatAsInt( ceil( VMF(1) ) );
#ifndef ELITEFORCE
case UI_PC_ADD_GLOBAL_DEFINE:
return botlib_export->PC_AddGlobalDefine( VMA(1) );
case UI_PC_LOAD_SOURCE:
@ -1061,6 +1095,7 @@ intptr_t CL_UISystemCalls( intptr_t *args ) {
case UI_VERIFY_CDKEY:
return CL_CDKeyValidate(VMA(1), VMA(2));
#endif
default:
Com_Error( ERR_DROP, "Bad UI system trap: %ld", (long int) args[0] );
@ -1117,6 +1152,10 @@ void CL_InitUI( void ) {
// Com_Printf(S_COLOR_YELLOW "WARNING: loading old Quake III Arena User Interface version %d\n", v );
// init for this gamestate
VM_Call( uivm, UI_INIT, (clc.state >= CA_AUTHORIZING && clc.state < CA_ACTIVE));
#ifdef ELITEFORCE
Cvar_SetValue("ui_cdkeychecked2", 1);
#endif
}
else if (v != UI_API_VERSION) {
// Free uivm now, so UI_SHUTDOWN doesn't get called later.
@ -1129,16 +1168,24 @@ void CL_InitUI( void ) {
else {
// init for this gamestate
VM_Call( uivm, UI_INIT, (clc.state >= CA_AUTHORIZING && clc.state < CA_ACTIVE) );
#ifdef ELITEFORCE
Cvar_SetValue("ui_cdkeychecked2", 1);
#endif
}
}
#ifndef STANDALONE
qboolean UI_usesUniqueCDKey( void ) {
#ifdef ELITEFORCE
return qfalse;
#else
if (uivm) {
return (VM_Call( uivm, UI_HASUNIQUECDKEY) == qtrue);
} else {
return qfalse;
}
#endif
}
#endif

View file

@ -575,6 +575,9 @@ void SCR_DrawNamedPic( float x, float y, float width, float height, const char *
void SCR_DrawBigString( int x, int y, const char *s, float alpha, qboolean noColorEscape ); // draws a string with embedded color control characters with fade
void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color, qboolean noColorEscape ); // ignores embedded color control characters
#ifdef ELITEFORCE
void SCR_DrawSmallString( int x, int y, const char *s, float alpha ); // draws a string with embedded color control characters with fade
#endif
void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor, qboolean noColorEscape );
void SCR_DrawSmallChar( int x, int y, int ch );

View file

@ -26,6 +26,34 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
static snd_codec_t *codecs;
static void *S_CodecGetSound(const char *filename, snd_info_t *info);
#ifdef ELITEFORCE
int sem = qtrue;
#define VOXDIR "sound/voice"
void *S_MangleNameEF(char *filename, snd_info_t *info)
{
char localName[MAX_QPATH];
if(
!Q_strncmp(filename, VOXDIR, ARRAY_LEN(VOXDIR) - 1) &&
!Q_stricmp(Cvar_VariableString("s_language"), "DEUTSCH")
)
{
Q_strncpyz(localName, filename, MAX_QPATH - 10);
localName[8] = 'x';
localName[9] = '_';
localName[10] = 'd';
return S_CodecGetSound(localName, info);
}
return NULL;
}
#endif
/*
=================
S_CodecGetSound
@ -46,6 +74,12 @@ static void *S_CodecGetSound(const char *filename, snd_info_t *info)
Q_strncpyz(localName, filename, MAX_QPATH);
#ifdef ELITEFORCE
rtn = S_MangleNameEF(localName, info);
if(rtn)
return rtn;
#endif
ext = COM_GetExtension(localName);
if( *ext )
@ -110,7 +144,7 @@ static void *S_CodecGetSound(const char *filename, snd_info_t *info)
}
}
Com_Printf(S_COLOR_YELLOW "WARNING: Failed to %s sound %s!\n", info ? "load" : "open", filename);
Com_DPrintf(S_COLOR_YELLOW "WARNING: Failed to %s sound %s!\n", info ? "load" : "open", filename);
return NULL;
}
@ -131,6 +165,9 @@ void S_CodecInit()
#ifdef USE_CODEC_VORBIS
S_CodecRegister(&ogg_codec);
#endif
#if USE_CODEC_MP3
S_CodecRegister(&mp3_codec);
#endif
// Register wav codec last so that it is always tried first when a file extension was not found
S_CodecRegister(&wav_codec);
@ -162,6 +199,7 @@ void S_CodecRegister(snd_codec_t *codec)
S_CodecLoad
=================
*/
void *S_CodecLoad(const char *filename, snd_info_t *info)
{
return S_CodecGetSound(filename, info);

View file

@ -95,6 +95,15 @@ void S_OGG_CodecCloseStream(snd_stream_t *stream);
int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
#endif // USE_CODEC_VORBIS
// MP3 codec
#ifdef USE_CODEC_MP3
extern snd_codec_t mp3_codec;
void *S_MP3_CodecLoad(const char *filename, snd_info_t *info);
snd_stream_t *S_MP3_CodecOpenStream(const char *filename);
void S_MP3_CodecCloseStream(snd_stream_t *stream);
int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
#endif // USE_CODEC_MP3
// Ogg Opus codec
#ifdef USE_CODEC_OPUS
extern snd_codec_t opus_codec;

716
code/client/snd_codec_mp3.c Normal file
View file

@ -0,0 +1,716 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
Copyright (C) 2006 Thilo Schulz <arny@ats.s.bawue.de>
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// MP3 support is enabled by this define
#if USE_CODEC_MP3
// includes for the Q3 sound system
#include "client.h"
#include "snd_codec.h"
// includes for the MP3 codec
#include <mad.h>
#define MP3_SAMPLE_WIDTH 2
#define MP3_PCMSAMPLES_PERSLICE 32
// buffer size used when reading through the mp3
#define MP3_DATA_BUFSIZ 128*1024
// undefine this if you don't want any dithering.
#define MP3_DITHERING
// Q3 MP3 codec
snd_codec_t mp3_codec =
{
"mp3",
S_MP3_CodecLoad,
S_MP3_CodecOpenStream,
S_MP3_CodecReadStream,
S_MP3_CodecCloseStream,
NULL
};
// structure used for info purposes
struct snd_codec_mp3_info
{
byte encbuf[MP3_DATA_BUFSIZ]; // left over bytes not consumed
// by the decoder.
struct mad_stream madstream; // uses encbuf as buffer.
struct mad_frame madframe; // control structures for libmad.
struct mad_synth madsynth;
byte *pcmbuf; // buffer for not-used samples.
int buflen; // length of buffer data.
int pcmbufsize; // amount of allocated memory for
// pcmbuf. This should have at least
// the size of a decoded mp3 frame.
byte *dest; // copy decoded data here.
int destlen; // amount of already copied data.
int destsize; // amount of bytes we must decode.
};
/*************** MP3 utility functions ***************/
/*
=================
S_MP3_ReadData
=================
*/
// feed libmad with data
int S_MP3_ReadData(snd_stream_t *stream, struct mad_stream *madstream, byte *encbuf, int encbufsize)
{
int retval;
int leftover;
if(!stream)
return -1;
leftover = madstream->bufend - madstream->next_frame;
if(leftover > 0)
memmove(encbuf, madstream->this_frame, leftover);
// Fill the buffer right to the end
retval = FS_Read(&encbuf[leftover], encbufsize - leftover, stream->file);
if(retval <= 0)
{
// EOF reached, that's ok.
return 0;
}
mad_stream_buffer(madstream, encbuf, retval + leftover);
return retval;
}
/*
=================
S_MP3_Scanfile
to determine the samplecount, we apparently must get *all* headers :(
I basically used the xmms-mad plugin source to see how this stuff works.
returns a value < 0 on error.
=================
*/
int S_MP3_Scanfile(snd_stream_t *stream)
{
struct mad_stream madstream;
struct mad_header madheader;
int retval;
int samplecount;
byte encbuf[MP3_DATA_BUFSIZ];
// error out on invalid input.
if(!stream)
return -1;
mad_stream_init(&madstream);
mad_header_init(&madheader);
while(1)
{
retval = S_MP3_ReadData(stream, &madstream, encbuf, sizeof(encbuf));
if(retval < 0)
return -1;
else if(retval == 0)
break;
// Start decoding the headers.
while(1)
{
if((retval = mad_header_decode(&madheader, &madstream)) < 0)
{
if(madstream.error == MAD_ERROR_BUFLEN)
{
// We need to read more data
break;
}
if(!MAD_RECOVERABLE (madstream.error))
{
// unrecoverable error... we must bail out.
return retval;
}
mad_stream_skip(&madstream, madstream.skiplen);
continue;
}
// we got a valid header.
if(madheader.layer != MAD_LAYER_III)
{
// we don't support non-mp3s
return -1;
}
if(!stream->info.samples)
{
// This here is the very first frame. Set initial values now,
// that we expect to stay constant throughout the whole mp3.
stream->info.rate = madheader.samplerate;
stream->info.width = MP3_SAMPLE_WIDTH;
stream->info.channels = MAD_NCHANNELS(&madheader);
stream->info.samples = 0;
stream->info.size = 0; // same here.
stream->info.dataofs = 0;
}
else
{
// Check whether something changed that shouldn't.
if(stream->info.rate != madheader.samplerate ||
stream->info.channels != MAD_NCHANNELS(&madheader))
return -1;
}
// Update the counters
samplecount = MAD_NSBSAMPLES(&madheader) * MP3_PCMSAMPLES_PERSLICE;
stream->info.samples += samplecount;
stream->info.size += samplecount * stream->info.channels * stream->info.width;
}
}
// Reset the file pointer so we can do the real decoding.
FS_Seek(stream->file, 0, FS_SEEK_SET);
return 0;
}
/************************ dithering functions ***************************/
#ifdef MP3_DITHERING
// All dithering done here is taken from the GPL'ed xmms-mad plugin.
/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */
/* Any feedback is very welcome. For any question, comments, */
/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */
/* matumoto@math.keio.ac.jp */
/* Period parameters */
#define MP3_DITH_N 624
#define MP3_DITH_M 397
#define MATRIX_A 0x9908b0df /* constant vector a */
#define UPPER_MASK 0x80000000 /* most significant w-r bits */
#define LOWER_MASK 0x7fffffff /* least significant r bits */
/* Tempering parameters */
#define TEMPERING_MASK_B 0x9d2c5680
#define TEMPERING_MASK_C 0xefc60000
#define TEMPERING_SHIFT_U(y) (y >> 11)
#define TEMPERING_SHIFT_S(y) (y << 7)
#define TEMPERING_SHIFT_T(y) (y << 15)
#define TEMPERING_SHIFT_L(y) (y >> 18)
static unsigned long mt[MP3_DITH_N]; /* the array for the state vector */
static int mti=MP3_DITH_N+1; /* mti==MP3_DITH_N+1 means mt[MP3_DITH_N] is not initialized */
/* initializing the array with a NONZERO seed */
void sgenrand(unsigned long seed)
{
/* setting initial seeds to mt[MP3_DITH_N] using */
/* the generator Line 25 of Table 1 in */
/* [KNUTH 1981, The Art of Computer Programming */
/* Vol. 2 (2nd Ed.), pp102] */
mt[0]= seed & 0xffffffff;
for (mti=1; mti<MP3_DITH_N; mti++)
mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
}
unsigned long genrand(void)
{
unsigned long y;
static unsigned long mag01[2]={0x0, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= MP3_DITH_N) { /* generate MP3_DITH_N words at one time */
int kk;
if (mti == MP3_DITH_N+1) /* if sgenrand() has not been called, */
sgenrand(4357); /* a default initial seed is used */
for (kk=0;kk<MP3_DITH_N-MP3_DITH_M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+MP3_DITH_M] ^ (y >> 1) ^ mag01[y & 0x1];
}
for (;kk<MP3_DITH_N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(MP3_DITH_M-MP3_DITH_N)] ^ (y >> 1) ^ mag01[y & 0x1];
}
y = (mt[MP3_DITH_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[MP3_DITH_N-1] = mt[MP3_DITH_M-1] ^ (y >> 1) ^ mag01[y & 0x1];
mti = 0;
}
y = mt[mti++];
y ^= TEMPERING_SHIFT_U(y);
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
y ^= TEMPERING_SHIFT_L(y);
return y;
}
long triangular_dither_noise(int nbits) {
// parameter nbits : the peak-to-peak amplitude desired (in bits)
// use with nbits set to 2 + nber of bits to be trimmed.
// (because triangular is made from two uniformly distributed processes,
// it starts at 2 bits peak-to-peak amplitude)
// see The Theory of Dithered Quantization by Robert Alexander Wannamaker
// for complete proof of why that's optimal
long v = (genrand()/2 - genrand()/2); // in ]-2^31, 2^31[
//int signe = (v>0) ? 1 : -1;
long P = 1 << (32 - nbits); // the power of 2
v /= P;
// now v in ]-2^(nbits-1), 2^(nbits-1) [
return v;
}
#endif // MP3_DITHERING
/************************ decoder functions ***************************/
/*
=================
S_MP3_Scale
Converts the signal to 16 bit LE-PCM data and does dithering.
- borrowed from xmms-mad plugin source.
=================
*/
/*
* xmms-mad - mp3 plugin for xmms
* Copyright (C) 2001-2002 Sam Clegg
*/
signed int S_MP3_Scale(mad_fixed_t sample)
{
int n_bits_to_loose = MAD_F_FRACBITS + 1 - 16;
#ifdef MP3_DITHERING
int dither;
#endif
// round
sample += (1L << (n_bits_to_loose - 1));
#ifdef MP3_DITHERING
dither = triangular_dither_noise(n_bits_to_loose + 1);
sample += dither;
#endif
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> n_bits_to_loose;
}
/*
=================
S_MP3_PCMCopy
Copy and convert pcm data until bytecount bytes have been written.
return the position in pcm->samples.
indicate the amount of actually written bytes in wrotecnt.
=================
*/
int S_MP3_PCMCopy(byte *buf, struct mad_pcm *pcm, int bufofs,
int sampleofs, int bytecount, int *wrotecnt)
{
int written = 0;
signed int sample;
int framesize = pcm->channels * MP3_SAMPLE_WIDTH;
// add new pcm data.
while(written < bytecount && sampleofs < pcm->length)
{
sample = S_MP3_Scale(pcm->samples[0][sampleofs]);
#ifdef Q3_BIG_ENDIAN
// output to 16 bit big endian PCM
buf[bufofs++] = (sample >> 8) & 0xff;
buf[bufofs++] = sample & 0xff;
#else
// output to 16 bit little endian PCM
buf[bufofs++] = sample & 0xff;
buf[bufofs++] = (sample >> 8) & 0xff;
#endif
if(pcm->channels == 2)
{
sample = S_MP3_Scale(pcm->samples[1][sampleofs]);
#ifdef Q3_BIG_ENDIAN
buf[bufofs++] = (sample >> 8) & 0xff;
buf[bufofs++] = sample & 0xff;
#else
buf[bufofs++] = sample & 0xff;
buf[bufofs++] = (sample >> 8) & 0xff;
#endif
}
sampleofs++;
written += framesize;
}
if(wrotecnt)
*wrotecnt = written;
return sampleofs;
}
/*
=================
S_MP3_Decode
=================
*/
// gets executed for every decoded frame.
int S_MP3_Decode(snd_stream_t *stream)
{
struct snd_codec_mp3_info *mp3info;
struct mad_stream *madstream;
struct mad_frame *madframe;
struct mad_synth *madsynth;
struct mad_pcm *pcm;
int cursize;
int samplecount;
int needcount;
int wrote;
int retval;
if(!stream)
return -1;
mp3info = stream->ptr;
madstream = &mp3info->madstream;
madframe = &mp3info->madframe;
if(mad_frame_decode(madframe, madstream))
{
if(madstream->error == MAD_ERROR_BUFLEN)
{
// we need more data. Read another chunk.
retval = S_MP3_ReadData(stream, madstream, mp3info->encbuf, sizeof(mp3info->encbuf));
// call myself again now that buffer is full.
if(retval > 0)
retval = S_MP3_Decode(stream);
}
else if(MAD_RECOVERABLE(madstream->error))
{
mad_stream_skip(madstream, madstream->skiplen);
return S_MP3_Decode(stream);
}
else
retval = -1;
return retval;
}
// check whether this really is an mp3
if(madframe->header.layer != MAD_LAYER_III)
return -1;
// generate pcm data
madsynth = &mp3info->madsynth;
mad_synth_frame(madsynth, madframe);
pcm = &madsynth->pcm;
// perform a few checks to see whether something changed that shouldn't.
if(stream->info.rate != pcm->samplerate ||
stream->info.channels != pcm->channels)
{
return -1;
}
// see whether we have got enough data now.
cursize = pcm->length * pcm->channels * stream->info.width;
needcount = mp3info->destsize - mp3info->destlen;
// Copy exactly as many samples as required.
samplecount = S_MP3_PCMCopy(mp3info->dest, pcm,
mp3info->destlen, 0, needcount, &wrote);
mp3info->destlen += wrote;
if(samplecount < pcm->length)
{
// Not all samples got copied. Copy the rest into the pcm buffer.
samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm,
mp3info->buflen,
samplecount,
mp3info->pcmbufsize - mp3info->buflen,
&wrote);
mp3info->buflen += wrote;
if(samplecount < pcm->length)
{
// The pcm buffer was not large enough. Make it bigger.
byte *newbuf = Z_Malloc(cursize);
if(mp3info->pcmbuf)
{
memcpy(newbuf, mp3info->pcmbuf, mp3info->buflen);
Z_Free(mp3info->pcmbuf);
}
mp3info->pcmbuf = newbuf;
mp3info->pcmbufsize = cursize;
samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm,
mp3info->buflen,
samplecount,
mp3info->pcmbufsize - mp3info->buflen,
&wrote);
mp3info->buflen += wrote;
}
// we're definitely done.
retval = 0;
}
else if(mp3info->destlen >= mp3info->destsize)
retval = 0;
else
retval = 1;
return retval;
}
/*************** Callback functions for quake3 ***************/
/*
=================
S_MP3_CodecOpenStream
=================
*/
snd_stream_t *S_MP3_CodecOpenStream(const char *filename)
{
snd_stream_t *stream;
struct snd_codec_mp3_info *mp3info;
// Open the stream
stream = S_CodecUtilOpen(filename, &mp3_codec);
if(!stream || stream->length <= 0)
return NULL;
// We have to scan through the MP3 to determine the important mp3 info.
if(S_MP3_Scanfile(stream) < 0)
{
// scanning didn't work out...
S_CodecUtilClose(&stream);
return NULL;
}
// Initialize the mp3 info structure we need for streaming
mp3info = Z_Malloc(sizeof(*mp3info));
if(!mp3info)
{
S_CodecUtilClose(&stream);
return NULL;
}
stream->ptr = mp3info;
// initialize the libmad control structures.
mad_stream_init(&mp3info->madstream);
mad_frame_init(&mp3info->madframe);
mad_synth_init(&mp3info->madsynth);
if(S_MP3_ReadData(stream, &mp3info->madstream, mp3info->encbuf, sizeof(mp3info->encbuf)) <= 0)
{
// we didnt read anything, that's bad.
S_MP3_CodecCloseStream(stream);
return NULL;
}
return stream;
}
/*
=================
S_MP3_CodecCloseStream
=================
*/
// free all memory we allocated.
void S_MP3_CodecCloseStream(snd_stream_t *stream)
{
struct snd_codec_mp3_info *mp3info;
if(!stream)
return;
// free all data in our mp3info tree
if(stream->ptr)
{
mp3info = stream->ptr;
if(mp3info->pcmbuf)
Z_Free(mp3info->pcmbuf);
mad_synth_finish(&mp3info->madsynth);
mad_frame_finish(&mp3info->madframe);
mad_stream_finish(&mp3info->madstream);
Z_Free(stream->ptr);
}
S_CodecUtilClose(&stream);
}
/*
=================
S_MP3_CodecReadStream
=================
*/
int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
{
struct snd_codec_mp3_info *mp3info;
int retval;
if(!stream)
return -1;
mp3info = stream->ptr;
// Make sure we get complete frames all the way through.
bytes -= bytes % (stream->info.channels * stream->info.width);
if(mp3info->buflen)
{
if(bytes < mp3info->buflen)
{
// we still have enough bytes in our decoded pcm buffer
memcpy(buffer, mp3info->pcmbuf, bytes);
// remove the portion from our buffer.
mp3info->buflen -= bytes;
memmove(mp3info->pcmbuf, &mp3info->pcmbuf[bytes], mp3info->buflen);
return bytes;
}
else
{
// copy over the samples we already have.
memcpy(buffer, mp3info->pcmbuf, mp3info->buflen);
mp3info->destlen = mp3info->buflen;
mp3info->buflen = 0;
}
}
else
mp3info->destlen = 0;
mp3info->dest = buffer;
mp3info->destsize = bytes;
do
{
retval = S_MP3_Decode(stream);
} while(retval > 0);
// if there was an error return nothing.
if(retval < 0)
return 0;
return mp3info->destlen;
}
/*
=====================================================================
S_MP3_CodecLoad
We handle S_MP3_CodecLoad as a special case of the streaming functions
where we read the whole stream at once.
======================================================================
*/
void *S_MP3_CodecLoad(const char *filename, snd_info_t *info)
{
snd_stream_t *stream;
byte *pcmbuffer;
// check if input is valid
if(!filename)
return NULL;
stream = S_MP3_CodecOpenStream(filename);
if(!stream)
return NULL;
// copy over the info
info->rate = stream->info.rate;
info->width = stream->info.width;
info->channels = stream->info.channels;
info->samples = stream->info.samples;
info->dataofs = stream->info.dataofs;
// allocate enough buffer for all pcm data
pcmbuffer = Hunk_AllocateTempMemory(stream->info.size);
if(!pcmbuffer)
{
S_MP3_CodecCloseStream(stream);
return NULL;
}
info->size = S_MP3_CodecReadStream(stream, stream->info.size, pcmbuffer);
if(info->size <= 0)
{
// we didn't read anything at all. darn.
Hunk_FreeTempMemory(pcmbuffer);
pcmbuffer = NULL;
}
S_MP3_CodecCloseStream(stream);
return pcmbuffer;
}
#endif // USE_CODEC_MP3

View file

@ -375,10 +375,20 @@ sfxHandle_t S_Base_RegisterSound( const char *name, qboolean compressed ) {
sfx->inMemory = qfalse;
sfx->soundCompressed = compressed;
S_memoryLoad(sfx);
S_memoryLoad(sfx);
if ( sfx->defaultSound ) {
#ifdef ELITEFORCE
int hash = S_HashSFXName(name);
// free the slot up.
sfx->soundName[0] = '\0';
sfx->inMemory = qfalse;
sfx->defaultSound = qfalse;
// the new entry is head anyways.
sfxHash[hash] = sfx->next;
#else
Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->soundName );
#endif
return 0;
}
@ -400,7 +410,11 @@ void S_Base_BeginRegistration( void ) {
Com_Memset(s_knownSfx, '\0', sizeof(s_knownSfx));
Com_Memset(sfxHash, '\0', sizeof(sfx_t *) * LOOP_HASH);
#ifdef ELITEFORCE
S_Base_RegisterSound("sound/null.wav", qfalse); // Eliteforce specific sound.
#else
S_Base_RegisterSound("sound/feedback/hit.wav", qfalse); // changed to a sound in baseq3
#endif
}
}
@ -1399,9 +1413,11 @@ static void S_OpenBackgroundStream( const char *filename ) {
return;
}
#ifndef ELITEFORCE
if(s_backgroundStream->info.channels != 2 || s_backgroundStream->info.rate != 22050) {
Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", filename );
}
#endif
}
/*

View file

@ -376,7 +376,12 @@ static void S_AL_BufferLoad(sfxHandle_t sfx, qboolean cache)
data = S_CodecLoad(curSfx->filename, &info);
if(!data)
{
#ifdef ELITEFORCE
S_AL_BufferUnload(sfx);
*knownSfx[sfx].filename = '\0';
#else
S_AL_BufferUseDefault(sfx);
#endif
return;
}
@ -481,7 +486,11 @@ qboolean S_AL_BufferInit( void )
numSfx = 0;
// Load the default sound, and lock it
#ifdef ELITEFORCE
default_sfx = S_AL_BufferFind("sound/null.wav");
#else
default_sfx = S_AL_BufferFind("sound/feedback/hit.wav");
#endif
S_AL_BufferUse(default_sfx);
knownSfx[default_sfx].isLocked = qtrue;
@ -529,6 +538,12 @@ sfxHandle_t S_AL_RegisterSound( const char *sample, qboolean compressed )
if((!knownSfx[sfx].inMemory) && (!knownSfx[sfx].isDefault))
S_AL_BufferLoad(sfx, s_alPrecache->integer);
#ifdef ELITEFORCE
if(! *knownSfx[sfx].filename)
return 0;
#endif
knownSfx[sfx].lastUsedTime = Com_Milliseconds();
if (knownSfx[sfx].isDefault) {

View file

@ -263,6 +263,11 @@ typedef enum {
#define EF_AWARD_DENIED 0x00040000 // denied
#define EF_TEAMVOTED 0x00080000 // already cast a team vote
#ifdef ELITEFORCE
#define EF_SHIELD_BOX_X 0x00000800
#define EF_SHIELD_BOX_Y 0x00400000
#endif
// NOTE: may not have more than 16
typedef enum {
PW_NONE,

View file

@ -33,9 +33,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// TTimo
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551
#ifdef ELITEFORCE
#define SVF_SHIELD_BBOX 0x00000002
#define SVF_CLIENTMASK 0x00000004
#else
#define SVF_CLIENTMASK 0x00000002
#endif
#define SVF_BOT 0x00000008 // set if the entity is a bot
#ifdef ELITEFORCE
#define SVF_ELIMINATED 0x00000010
#endif
#define SVF_BROADCAST 0x00000020 // send to all connected clients
#define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots
#define SVF_USE_CURRENT_ORIGIN 0x00000080 // entity->r.currentOrigin instead of entity->s.origin
@ -54,8 +64,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
typedef struct {
#ifndef ELITEFORCE
entityState_t unused; // apparently this field was put here accidentally
// (and is kept only for compatibility, as a struct pad)
#endif
qboolean linked; // qfalse if not in any good cluster
int linkcount;
@ -104,6 +115,280 @@ typedef struct {
//
// system traps provided by the main engine
//
#ifdef ELITEFORCE
typedef enum {
//============== general Quake services ==================
G_PRINT, // ( const char *string );
// print message on the local console
G_ERROR, // ( const char *string );
// abort the game
G_MILLISECONDS, // ( void );
// get current time for profiling reasons
// this should NOT be used for any game related tasks,
// because it is not journaled
// console variable interaction
G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
G_CVAR_UPDATE, // ( vmCvar_t *vmCvar );
G_CVAR_SET, // ( const char *var_name, const char *value );
G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name );
G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize );
G_ARGC, // ( void );
// ClientCommand and ServerCommand parameter access
G_ARGV, // ( int n, char *buffer, int bufferLength );
G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, fsMode_t mode );
G_FS_READ, // ( void *buffer, int len, fileHandle_t f );
G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f );
G_FS_FCLOSE_FILE, // ( fileHandle_t f );
G_SEND_CONSOLE_COMMAND, // ( const char *text );
// add commands to the console as if they were typed in
// for map changing, etc
//=========== server specific functionality =============
G_LOCATE_GAME_DATA, // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
// playerState_t *clients, int sizeofGameClient );
// the game needs to let the server system know where and how big the gentities
// are, so it can look at them directly without going through an interface
G_DROP_CLIENT, // ( int clientNum, const char *reason );
// kick a client off the server with a message
G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... );
// reliably sends a command string to be interpreted by the given
// client. If clientNum is -1, it will be sent to all clients
G_SET_CONFIGSTRING, // ( int num, const char *string );
// config strings hold all the index strings, and various other information
// that is reliably communicated to all clients
// All of the current configstrings are sent to clients when
// they connect, and changes are sent to all connected clients.
// All confgstrings are cleared at each level start.
G_GET_CONFIGSTRING, // ( int num, char *buffer, int bufferSize );
G_GET_USERINFO, // ( int num, char *buffer, int bufferSize );
// userinfo strings are maintained by the server system, so they
// are persistant across level loads, while all other game visible
// data is completely reset
G_SET_USERINFO, // ( int num, const char *buffer );
G_GET_SERVERINFO, // ( char *buffer, int bufferSize );
// the serverinfo info string has all the cvars visible to server browsers
G_SET_BRUSH_MODEL, // ( gentity_t *ent, const char *name );
// sets mins and maxs based on the brushmodel name
G_TRACE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum,
// collision detection against all linked entities
G_POINT_CONTENTS, // ( const vec3_t point, int passEntityNum );
// point contents against all linked entities
G_IN_PVS, // ( const vec3_t p1, const vec3_t p2 );
G_IN_PVS_IGNORE_PORTALS, // ( const vec3_t p1, const vec3_t p2 );
G_ADJUST_AREA_PORTAL_STATE, // ( gentity_t *ent, qboolean open );
G_AREAS_CONNECTED, // ( int area1, int area2 );
G_LINKENTITY, // ( gentity_t *ent );
// an entity will never be sent to a client or used for collision
// if it is not passed to linkentity. If the size, position, or
// solidity changes, it must be relinked.
G_UNLINKENTITY, // ( gentity_t *ent );
// call before removing an interactive entity
G_ENTITIES_IN_BOX, // ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount );
// EntitiesInBox will return brush models based on their bounding box,
// so exact determination must still be done with EntityContact
G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
// perform an exact check against inline brush models of non-square shape
// access for bots to get and free a server client (FIXME?)
G_BOT_ALLOCATE_CLIENT, // ( void );
G_BOT_FREE_CLIENT, // ( int clientNum );
G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd )
G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize )
// Retrieves the next string token from the entity spawn text, returning
// false when all tokens have been parsed.
// This should only be done at GAME_INIT time.
G_FS_GETFILELIST,
G_DEBUG_POLYGON_CREATE,
G_DEBUG_POLYGON_DELETE,
BOTLIB_SETUP = 200, // ( void );
BOTLIB_SHUTDOWN, // ( void );
BOTLIB_LIBVAR_SET,
BOTLIB_LIBVAR_GET,
BOTLIB_DEFINE,
BOTLIB_START_FRAME,
BOTLIB_LOAD_MAP,
BOTLIB_UPDATENTITY,
BOTLIB_TEST,
BOTLIB_GET_SNAPSHOT_ENTITY, // ( int client, int ent );
BOTLIB_GET_CONSOLE_MESSAGE, // ( int client, char *message, int size );
BOTLIB_USER_COMMAND, // ( int client, usercmd_t *ucmd );
BOTLIB_AAS_ENTITY_VISIBLE = 300, //FIXME: remove
BOTLIB_AAS_IN_FIELD_OF_VISION, //FIXME: remove
BOTLIB_AAS_VISIBLE_CLIENTS, //FIXME: remove
BOTLIB_AAS_ENTITY_INFO,
BOTLIB_AAS_INITIALIZED,
BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX,
BOTLIB_AAS_TIME,
BOTLIB_AAS_POINT_AREA_NUM,
BOTLIB_AAS_TRACE_AREAS,
BOTLIB_AAS_POINT_CONTENTS,
BOTLIB_AAS_NEXT_BSP_ENTITY,
BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY,
BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY,
BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY,
BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY,
BOTLIB_AAS_AREA_REACHABILITY,
BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA,
BOTLIB_AAS_SWIMMING,
BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT,
BOTLIB_EA_SAY = 400,
BOTLIB_EA_SAY_TEAM,
BOTLIB_EA_USE_ITEM,
BOTLIB_EA_DROP_ITEM,
BOTLIB_EA_USE_INV,
BOTLIB_EA_DROP_INV,
BOTLIB_EA_GESTURE,
BOTLIB_EA_COMMAND,
BOTLIB_EA_SELECT_WEAPON,
BOTLIB_EA_TALK,
BOTLIB_EA_ATTACK,
BOTLIB_EA_USE,
BOTLIB_EA_RESPAWN,
BOTLIB_EA_JUMP,
BOTLIB_EA_DELAYED_JUMP,
BOTLIB_EA_CROUCH,
BOTLIB_EA_MOVE_UP,
BOTLIB_EA_MOVE_DOWN,
BOTLIB_EA_MOVE_FORWARD,
BOTLIB_EA_MOVE_BACK,
BOTLIB_EA_MOVE_LEFT,
BOTLIB_EA_MOVE_RIGHT,
BOTLIB_EA_MOVE,
BOTLIB_EA_VIEW,
BOTLIB_EA_END_REGULAR,
BOTLIB_EA_GET_INPUT,
BOTLIB_EA_RESET_INPUT,
BOTLIB_EA_ALT_ATTACK,
BOTLIB_AI_LOAD_CHARACTER = 500,
BOTLIB_AI_FREE_CHARACTER,
BOTLIB_AI_CHARACTERISTIC_FLOAT,
BOTLIB_AI_CHARACTERISTIC_BFLOAT,
BOTLIB_AI_CHARACTERISTIC_INTEGER,
BOTLIB_AI_CHARACTERISTIC_BINTEGER,
BOTLIB_AI_CHARACTERISTIC_STRING,
BOTLIB_AI_ALLOC_CHAT_STATE,
BOTLIB_AI_FREE_CHAT_STATE,
BOTLIB_AI_QUEUE_CONSOLE_MESSAGE,
BOTLIB_AI_REMOVE_CONSOLE_MESSAGE,
BOTLIB_AI_NEXT_CONSOLE_MESSAGE,
BOTLIB_AI_NUM_CONSOLE_MESSAGE,
BOTLIB_AI_INITIAL_CHAT,
BOTLIB_AI_REPLY_CHAT,
BOTLIB_AI_CHAT_LENGTH,
BOTLIB_AI_ENTER_CHAT,
BOTLIB_AI_STRING_CONTAINS,
BOTLIB_AI_FIND_MATCH,
BOTLIB_AI_MATCH_VARIABLE,
BOTLIB_AI_UNIFY_WHITE_SPACES,
BOTLIB_AI_REPLACE_SYNONYMS,
BOTLIB_AI_LOAD_CHAT_FILE,
BOTLIB_AI_SET_CHAT_GENDER,
BOTLIB_AI_SET_CHAT_NAME,
BOTLIB_AI_RESET_GOAL_STATE,
BOTLIB_AI_RESET_AVOID_GOALS,
BOTLIB_AI_PUSH_GOAL,
BOTLIB_AI_POP_GOAL,
BOTLIB_AI_EMPTY_GOAL_STACK,
BOTLIB_AI_DUMP_AVOID_GOALS,
BOTLIB_AI_DUMP_GOAL_STACK,
BOTLIB_AI_GOAL_NAME,
BOTLIB_AI_GET_TOP_GOAL,
BOTLIB_AI_GET_SECOND_GOAL,
BOTLIB_AI_CHOOSE_LTG_ITEM,
BOTLIB_AI_CHOOSE_NBG_ITEM,
BOTLIB_AI_TOUCHING_GOAL,
BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE,
BOTLIB_AI_GET_LEVEL_ITEM_GOAL,
BOTLIB_AI_AVOID_GOAL_TIME,
BOTLIB_AI_INIT_LEVEL_ITEMS,
BOTLIB_AI_UPDATE_ENTITY_ITEMS,
BOTLIB_AI_LOAD_ITEM_WEIGHTS,
BOTLIB_AI_FREE_ITEM_WEIGHTS,
BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC,
BOTLIB_AI_ALLOC_GOAL_STATE,
BOTLIB_AI_FREE_GOAL_STATE,
BOTLIB_AI_RESET_MOVE_STATE,
BOTLIB_AI_MOVE_TO_GOAL,
BOTLIB_AI_MOVE_IN_DIRECTION,
BOTLIB_AI_RESET_AVOID_REACH,
BOTLIB_AI_RESET_LAST_AVOID_REACH,
BOTLIB_AI_REACHABILITY_AREA,
BOTLIB_AI_MOVEMENT_VIEW_TARGET,
BOTLIB_AI_ALLOC_MOVE_STATE,
BOTLIB_AI_FREE_MOVE_STATE,
BOTLIB_AI_INIT_MOVE_STATE,
BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON,
BOTLIB_AI_GET_WEAPON_INFO,
BOTLIB_AI_LOAD_WEAPON_WEIGHTS,
BOTLIB_AI_ALLOC_WEAPON_STATE,
BOTLIB_AI_FREE_WEAPON_STATE,
BOTLIB_AI_RESET_WEAPON_STATE,
BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION,
BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC,
BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC,
BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL,
BOTLIB_AI_GET_MAP_LOCATION_GOAL,
BOTLIB_AI_NUM_INITIAL_CHATS,
BOTLIB_AI_GET_CHAT_MESSAGE,
BOTLIB_AI_REMOVE_FROM_AVOID_GOALS,
BOTLIB_AI_PREDICT_VISIBLE_POSITION
} gameImport_t;
#else
typedef enum {
//============== general Quake services ==================
@ -390,7 +675,7 @@ typedef enum {
BOTLIB_PC_SOURCE_FILE_AND_LINE
} gameImport_t;
#endif
//
// functions exported by the game subsystem

View file

@ -24,10 +24,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "qcommon.h"
#include "cm_polylib.h"
#define MAX_SUBMODELS 256
#define BOX_MODEL_HANDLE 255
#define CAPSULE_MODEL_HANDLE 254
#ifdef ELITEFORCE
#define MAX_SUBMODELS 8192
#define BOX_MODEL_HANDLE MAX_SUBMODELS-1
#define CAPSULE_MODEL_HANDLE BOX_MODEL_HANDLE-2
#else
#define MAX_SUBMODELS 256
#define BOX_MODEL_HANDLE 255
#define CAPSULE_MODEL_HANDLE 254
#endif
typedef struct {
cplane_t *plane;

View file

@ -60,8 +60,8 @@ properly.
*/
#define MAX_FACETS 1024
#define MAX_PATCH_PLANES 2048
#define MAX_FACETS 4096
#define MAX_PATCH_PLANES 8192
typedef struct {
float plane[4];

View file

@ -1161,6 +1161,12 @@ void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mi
// fill in a default trace
Com_Memset( &tw, 0, sizeof(tw) );
tw.trace.fraction = 1; // assume it goes the entire distance until shown otherwise
#ifdef ELITEFORCE
// obviously Raven fucked this up. They seem to expect a SURF_NOIMPACT flag if the trace
// went through to the end, or the game will crash when firing the dreadnought weapon and
// it doesn't hit anything.
tw.trace.surfaceFlags = SURF_NOIMPACT;
#endif
VectorCopy(origin, tw.modelOrigin);
if (!cm.numNodes) {

View file

@ -32,14 +32,22 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
int demo_protocols[] =
{ 67, 66, 0 };
#ifdef ELITEFORCE
{ 0 };
#else
{ 67, 66, 0 };
#endif
#define MAX_NUM_ARGVS 50
#define MIN_DEDICATED_COMHUNKMEGS 1
#define MIN_COMHUNKMEGS 56
#define DEF_COMHUNKMEGS 128
#ifdef ELITEFORCE
#define DEF_COMZONEMEGS 32
#else
#define DEF_COMZONEMEGS 24
#endif
#define DEF_COMHUNKMEGS_S XSTRING(DEF_COMHUNKMEGS)
#define DEF_COMZONEMEGS_S XSTRING(DEF_COMZONEMEGS)
@ -75,6 +83,7 @@ cvar_t *com_buildScript; // for automated data building scripts
#ifdef CINEMATICS_INTRO
cvar_t *com_introPlayed;
#endif
cvar_t *com_novmcompat; // set to 1 to indicate VMs are run by the new engine.
cvar_t *cl_paused;
cvar_t *sv_paused;
cvar_t *cl_packetdelay;
@ -2448,8 +2457,14 @@ void Com_ReadCDKey( const char *filename ) {
fileHandle_t f;
char buffer[33];
char fbuffer[MAX_OSPATH];
#ifdef ELITEFORCE
int index = 0;
char curchar;
sprintf(fbuffer, "%s/efq3.key", filename);
#else
Com_sprintf(fbuffer, sizeof(fbuffer), "%s/q3key", filename);
#endif
FS_SV_FOpenFileRead( fbuffer, &f );
if ( !f ) {
@ -2459,6 +2474,59 @@ void Com_ReadCDKey( const char *filename ) {
Com_Memset( buffer, 0, sizeof(buffer) );
#ifdef ELITEFORCE
// check for the normal CD key
while(index < 16)
{
if(FS_Read(&curchar, 1, f) != 1)
{
Q_strncpyz( cl_cdkey, " ", 17 );
FS_FCloseFile(f);
return;
}
curchar = toupper(curchar);
if(curchar < '0' || (curchar > '9' && curchar < 'A') || curchar > 'Z')
continue;
buffer[index] = toupper(curchar);
index++;
}
FS_FCloseFile(f);
// check for the expansion pack cd key
sprintf(fbuffer, "%s/expefq3.key", filename);
FS_SV_FOpenFileRead(fbuffer, &f);
if(f)
{
while(index < 32)
{
// same game
if(FS_Read(&curchar, 1, f) != 1)
{
Q_strncpyz( cl_cdkey, " ", 17 );
FS_FCloseFile(f);
return;
}
curchar = toupper(curchar);
if(curchar < '0' || (curchar > '9' && curchar < 'A') || curchar > 'Z')
continue;
buffer[index] = toupper(curchar);
index++;
}
FS_FCloseFile(f);
}
Q_strncpyz(cl_cdkey, buffer, index+1);
#else
FS_Read( buffer, 16, f );
FS_FCloseFile( f );
@ -2467,6 +2535,7 @@ void Com_ReadCDKey( const char *filename ) {
} else {
Q_strncpyz( cl_cdkey, " ", 17 );
}
#endif
}
/*
@ -2508,20 +2577,30 @@ Com_WriteCDKey
static void Com_WriteCDKey( const char *filename, const char *ikey ) {
fileHandle_t f;
char fbuffer[MAX_OSPATH];
#ifdef ELITEFORCE
char key[23];
#else
char key[17];
#endif
#ifndef _WIN32
mode_t savedumask;
#endif
#ifdef ELITEFORCE
sprintf(fbuffer, "%s/efq3.key", filename);
#else
Com_sprintf(fbuffer, sizeof(fbuffer), "%s/q3key", filename);
#endif
#ifdef ELITEFORCE
Q_strncpyz( key, ikey, 23 );
key[22] = '\0';
#else
Q_strncpyz( key, ikey, 17 );
if(!CL_CDKeyValidate(key, NULL) ) {
return;
}
#endif
#ifndef _WIN32
savedumask = umask(0077);
@ -2532,7 +2611,11 @@ static void Com_WriteCDKey( const char *filename, const char *ikey ) {
goto out;
}
#ifdef ELITEFORCE
FS_Write( key, strlen(key), f );
#else
FS_Write( key, 16, f );
#endif
FS_Printf( f, "\n// generated by quake, do not modify\r\n" );
FS_Printf( f, "// Do not give this file to ANYONE.\r\n" );
@ -2759,6 +2842,7 @@ void Com_Init( char *commandLine ) {
#ifdef CINEMATICS_INTRO
com_introPlayed = Cvar_Get( "com_introplayed", "0", CVAR_ARCHIVE);
#endif
com_novmcompat = Cvar_Get( "com_novmcompat", "1", CVAR_ROM);
s = va("%s %s %s", Q3_VERSION, PLATFORM_STRING, __DATE__ );
com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO );

View file

@ -174,6 +174,15 @@ or configs will never get loaded from disk!
// every time a new demo pk3 file is built, this checksum must be updated.
// the easiest way to get it is to just run the game and see what it spits out
#ifdef ELITEFORCE
static const unsigned pak_checksums[] =
{
3376297517u,
596947475u,
3960871590u,
1592359207u,
};
#else
#define DEMO_PAK0_CHECKSUM 2985612116u
static const unsigned int pak_checksums[] = {
1566731103u,
@ -186,6 +195,7 @@ static const unsigned int pak_checksums[] = {
908855077u,
977125798u
};
#endif
static const unsigned int missionpak_checksums[] =
{
@ -3110,6 +3120,12 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
havepak = qfalse;
// never autodownload any of the id paks
#ifdef ELITEFORCE
#ifndef STANDALONE
if(FS_idPak(fs_serverReferencedPakNames[i], BASEGAME, NUM_ID_PAKS))
continue;
#endif
#else
if(FS_idPak(fs_serverReferencedPakNames[i], BASEGAME, NUM_ID_PAKS)
#ifndef STANDALONE
|| FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS)
@ -3118,6 +3134,7 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
{
continue;
}
#endif
// Make sure the server cannot make us write to non-quake3 directories.
if(FS_CheckDirTraversal(fs_serverReferencedPakNames[i]))
@ -3398,6 +3415,7 @@ static void FS_Startup( const char *gameName )
}
#ifndef STANDALONE
#ifdef ELITEFORCE
/*
===================
FS_CheckPak0
@ -3410,6 +3428,123 @@ Q3 media pak0.pk3, you'll want to remove this by defining
STANDALONE in q_shared.h
===================
*/
static void FS_CheckPak0( void )
{
searchpath_t *path;
pack_t *curpack;
unsigned int foundPak = 0;
for( path = fs_searchpaths; path; path = path->next )
{
const char* pakBasename = path->pack->pakBasename;
if(!path->pack)
continue;
curpack = path->pack;
if(!Q_stricmpn( curpack->pakGamename, BASEGAME, MAX_OSPATH )
&& strlen(pakBasename) == 4 && !Q_stricmpn( pakBasename, "pak", 3 )
&& pakBasename[3] >= '0' && pakBasename[3] <= '0' + NUM_ID_PAKS - 1)
{
if( curpack->checksum != pak_checksums[pakBasename[3]-'0'] )
{
if(pakBasename[3] == '0')
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: " BASEGAME "/pak0.pk3 is present but its checksum (%u)\n"
"is not correct. Please re-copy pak0.pk3 from your\n"
"legitimate EF CDROM.\n"
"**************************************************\n\n\n",
curpack->checksum );
}
else
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: pak%d.pk3 is present but its checksum (%u)\n"
"is not correct. Please copy the .pk3 files from\n"
"Elite Force patches 1.1 and 1.2 to the baseEF directory.\n"
"**************************************************\n\n\n",
pakBasename[3]-'0', curpack->checksum );
}
}
foundPak |= 1<<(pakBasename[3]-'0');
}
else
{
int index;
// Finally check whether this pak's checksum is listed because the user tried
// to trick us by renaming the file, and set foundPak's highest bit to indicate this case.
for(index = 0; index < ARRAY_LEN(pak_checksums); index++)
{
if(curpack->checksum == pak_checksums[index])
{
Com_Printf("\n\n"
"**************************************************\n"
"WARNING: %s is renamed pak file %s%cpak%d.pk3\n"
"Running in standalone mode won't work\n"
"Please rename, or remove this file\n"
"**************************************************\n\n\n",
curpack->pakFilename, BASEGAME, PATH_SEP, index);
foundPak |= 0x80000000;
}
}
}
}
if(!foundPak && Q_stricmp(com_basegame->string, BASEGAME))
{
Cvar_Set("com_standalone", "1");
}
else
Cvar_Set("com_standalone", "0");
if(!com_standalone->integer && (foundPak & 0x07) != 0x07)
{
char errorText[MAX_STRING_CHARS] = "";
if((foundPak & 0x01) != 0x01)
{
Q_strcat(errorText, sizeof(errorText),
"\"pak0.pk3\" is missing. Please copy it "
"from your legitimate EliteForce CDROM. ");
}
if((foundPak & 0x1fe) != 0x1fe)
{
Q_strcat(errorText, sizeof(errorText),
"Patch files are missing. Please\n"
"copy the .pk3 files from EliteForce patch 1.2 to baseEF.\n"); }
Q_strcat(errorText, sizeof(errorText),
va("Also check that your EliteForce executable is in "
"the correct place and that every file "
"in the \"%s\" directory is present and readable", BASEGAME));
Com_Error(ERR_FATAL, "%s", errorText);
}
}
#else
/*
===================
FS_CheckPak0
Checks that pak0.pk3 is present and its checksum is correct
Note: If you're building a game that doesn't depend on the
Q3 media pak0.pk3, you'll want to remove this function
===================
*/
static void FS_CheckPak0( void )
{
searchpath_t *path;
@ -3595,6 +3730,7 @@ static void FS_CheckPak0( void )
}
}
#endif
#endif
/*
=====================
@ -4133,6 +4269,7 @@ void FS_FilenameCompletion( const char *dir, const char *ext,
callback( filename );
}
FS_FreeFileList( filenames );
}
const char *FS_GetCurrentGameDir(void)

File diff suppressed because it is too large Load diff

View file

@ -99,6 +99,102 @@ void Netchan_Setup(netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, int
#endif
}
#ifdef ELITEFORCE
/*
==============
Netchan_ScramblePacket
A probably futile attempt to make proxy hacking somewhat
more difficult.
==============
*/
#define SCRAMBLE_START 6
static void Netchan_ScramblePacket( msg_t *buf ) {
unsigned seed;
int i, j, c, mask, temp;
int seq[MAX_PACKETLEN];
seed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 ) ^ 0x87243987;
c = buf->cursize;
if ( c <= SCRAMBLE_START ) {
return;
}
if ( c > MAX_PACKETLEN ) {
Com_Error( ERR_DROP, "MAX_PACKETLEN" );
}
// generate a sequence of "random" numbers
for (i = 0 ; i < c ; i++) {
seed = (69069 * seed + 1);
seq[i] = seed;
}
// byte xor the data after the header
for (i = SCRAMBLE_START ; i < c ; i++) {
buf->data[i] ^= seq[i];
}
// transpose each character
for ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) {
}
mask >>= 1;
for (i = SCRAMBLE_START ; i < c ; i++) {
j = SCRAMBLE_START + ( seq[i] & mask );
temp = buf->data[j];
buf->data[j] = buf->data[i];
buf->data[i] = temp;
}
// byte xor the data after the header
// for (i = SCRAMBLE_START ; i < c ; i++) {
// buf->data[i] ^= seq[i];
// }
}
static void Netchan_UnScramblePacket( msg_t *buf ) {
unsigned seed;
int i, j, c, mask, temp;
int seq[MAX_PACKETLEN];
seed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 ) ^ 0x87243987;
c = buf->cursize;
if ( c <= SCRAMBLE_START ) {
return;
}
if ( c > MAX_PACKETLEN ) {
Com_Error( ERR_DROP, "MAX_PACKETLEN" );
}
// generate a sequence of "random" numbers
for (i = 0 ; i < c ; i++) {
seed = (69069 * seed + 1);
seq[i] = seed;
}
// byte xor the data after the header
// for (i = SCRAMBLE_START ; i < c ; i++) {
// buf->data[i] ^= seq[i];
// }
// transpose each character in reverse order
for ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) {
}
mask >>= 1;
for (i = c-1 ; i >= SCRAMBLE_START ; i--) {
j = SCRAMBLE_START + ( seq[i] & mask );
temp = buf->data[j];
buf->data[j] = buf->data[i];
buf->data[i] = temp;
}
// byte xor the data after the header
for (i = SCRAMBLE_START ; i < c ; i++) {
buf->data[i] ^= seq[i];
}
}
#endif
/*
=================
Netchan_TransmitNextFragment
@ -138,6 +234,14 @@ void Netchan_TransmitNextFragment( netchan_t *chan ) {
MSG_WriteShort( &send, fragmentLength );
MSG_WriteData( &send, chan->unsentBuffer + chan->unsentFragmentStart, fragmentLength );
#ifdef ELITEFORCE
if(chan->compat)
{
// the original eliteforce uses the old scrambling routines only slightly modified.
Netchan_ScramblePacket( &send );
}
#endif
// send the datagram
NET_SendPacket(chan->sock, send.cursize, send.data, chan->remoteAddress);
@ -213,6 +317,14 @@ void Netchan_Transmit( netchan_t *chan, int length, const byte *data ) {
MSG_WriteData( &send, data, length );
#ifdef ELITEFORCE
if(chan->compat)
{
// the original eliteforce uses the old scrambling routines only slightly modified.
Netchan_ScramblePacket( &send );
}
#endif
// send the datagram
NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
@ -247,7 +359,10 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) {
qboolean fragmented;
// XOR unscramble all data in the packet after the header
// Netchan_UnScramblePacket( msg );
#ifdef ELITEFORCE
if(chan->compat)
Netchan_UnScramblePacket( msg );
#endif
// get sequence numbers
MSG_BeginReadingOOB( msg );
@ -394,7 +509,10 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) {
// TTimo
// clients were not acking fragmented messages
chan->incomingSequence = sequence;
#ifdef ELITEFORCE
if(!chan->compat)
#endif
chan->incomingSequence = sequence;
return qtrue;
}

View file

@ -128,7 +128,11 @@ static struct sockaddr_in6 boundto;
#endif
// use an admin local address per default so that network admins can decide on how to handle quake3 traffic.
#ifdef ELITEFORCE
#define NET_MULTICAST_IP6 "ff04::696f:6566"
#else
#define NET_MULTICAST_IP6 "ff04::696f:7175:616b:6533"
#endif
#define MAX_IPS 32

View file

@ -972,7 +972,11 @@ void PerpendicularVector( vec3_t dst, const vec3_t src )
/*
** find the smallest magnitude axially aligned vector
*/
#ifdef ELITEFORCE
for ( pos = 0, i = 2; i >= 0; i-- )
#else
for ( pos = 0, i = 0; i < 3; i++ )
#endif
{
if ( fabs( src[i] ) < minelem )
{

View file

@ -40,6 +40,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define CINEMATICS_LOGO "foologo.roq"
#define CINEMATICS_INTRO "intro.roq"
// #define LEGACY_PROTOCOL // You probably don't need this for your standalone game
#else
#ifdef ELITEFORCE
#define PRODUCT_NAME "ioST:V HM"
#define BASEGAME "baseEF"
#define CLIENT_WINDOW_TITLE "iostvoyHM"
#define CLIENT_WINDOW_MIN_TITLE "iostvoyHM"
#define HOMEPATH_NAME_UNIX ".stvef"
#define HOMEPATH_NAME_WIN "STVEF"
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
// #define STEAMPATH_NAME "Star Trek Voyager: Elite Force"
// #define STEAMPATH_APPID "2200"
#define GAMENAME_FOR_MASTER "EliteForce"
#define LEGACY_PROTOCOL
#else
#define PRODUCT_NAME "ioq3"
#define BASEGAME "baseq3"
@ -55,9 +68,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define CINEMATICS_INTRO "intro.RoQ"
#define LEGACY_PROTOCOL
#endif
#endif
// Heartbeat for dpmaster protocol. You shouldn't change this unless you know what you're doing
#define HEARTBEAT_FOR_MASTER "DarkPlaces"
#ifdef ELITEFORCE
#define HEARTBEAT_FOR_MASTER "STEF1"
#else
#define HEARTBEAT_FOR_MASTER "DarkPlaces"
#endif
// When com_gamename is LEGACY_MASTER_GAMENAME, use quake3 master protocol.
// You shouldn't change this unless you know what you're doing
@ -1121,7 +1139,11 @@ typedef struct {
#define MAX_POWERUPS 16
#define MAX_WEAPONS 16
#ifdef ELITEFORCE
#define MAX_PS_EVENTS 4
#else
#define MAX_PS_EVENTS 2
#endif
#define PS_PMOVEFRAMECOUNTBITS 6
@ -1145,6 +1167,11 @@ typedef struct playerState_s {
vec3_t origin;
vec3_t velocity;
int weaponTime;
#ifdef ELITEFORCE
int rechargeTime; // for the phaser
short useTime; // use debounce
int introTime; // for the holodoor
#endif
int gravity;
int speed;
int delta_angles[3]; // add to command angles to get view direction
@ -1163,7 +1190,9 @@ typedef struct playerState_s {
// when at rest, the value will remain unchanged
// used to twist the legs during strafing
#ifndef ELITEFORCE
vec3_t grapplePoint; // location of grapple to pull towards if PMF_GRAPPLE_PULL
#endif
int eFlags; // copied to entityState_t->eFlags
@ -1187,20 +1216,27 @@ typedef struct playerState_s {
int damageYaw;
int damagePitch;
int damageCount;
#ifdef ELITEFORCE
int damageShieldCount;
#endif
int stats[MAX_STATS];
int persistant[MAX_PERSISTANT]; // stats that aren't cleared on death
int powerups[MAX_POWERUPS]; // level.time that the powerup runs out
int ammo[MAX_WEAPONS];
#ifndef ELITEFORCE
int generic1;
int loopSound;
int jumppad_ent; // jumppad entity hit this frame
#endif
// not communicated over the net at all
int ping; // server to game info for scoreboard
#ifndef ELITEFORCE
int pmove_framecount;
int jumppad_frame;
#endif
int entityEventSequence;
} playerState_t;
@ -1235,6 +1271,15 @@ typedef struct playerState_s {
// then BUTTON_WALKING should be set
// usercmd_t is sent to the server each client frame
#ifdef ELITEFORCE
typedef struct usercmd_s {
int serverTime;
byte buttons;
byte weapon;
int angles[3];
signed char forwardmove, rightmove, upmove;
} usercmd_t;
#else
typedef struct usercmd_s {
int serverTime;
int angles[3];
@ -1242,7 +1287,7 @@ typedef struct usercmd_s {
byte weapon; // weapon
signed char forwardmove, rightmove, upmove;
} usercmd_t;
#endif
//===================================================================
// if entityState->solid == SOLID_BMODEL, modelindex is an inline model number
@ -1313,7 +1358,9 @@ typedef struct entityState_s {
int legsAnim; // mask off ANIM_TOGGLEBIT
int torsoAnim; // mask off ANIM_TOGGLEBIT
#ifndef ELITEFORCE
int generic1;
#endif
} entityState_t;
typedef enum {

View file

@ -23,6 +23,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef _QCOMMON_H_
#define _QCOMMON_H_
#if defined(ELITEFORCE) && defined(MISSIONPACK)
#undef MISSIONPACK
#endif
#include "../qcommon/cm_public.h"
//Ignore __attribute__ on non-gcc platforms
@ -43,6 +47,9 @@ typedef struct {
qboolean allowoverflow; // if false, do a Com_Error
qboolean overflowed; // set to true if the buffer size failed (with allowoverflow set)
qboolean oob; // set to true if the buffer size failed (with allowoverflow set)
#ifdef ELITEFORCE
qboolean compat; // Compatibility mode for old EliteForce servers.
#endif
byte *data;
int maxsize;
int cursize;
@ -95,6 +102,11 @@ float MSG_ReadAngle16 (msg_t *sb);
void MSG_ReadData (msg_t *sb, void *buffer, int size);
int MSG_LookaheadByte (msg_t *msg);
#ifdef ELITEFORCE
void MSG_WriteDeltaUsercmd( msg_t *msg, struct usercmd_s *from, struct usercmd_s *to );
void MSG_ReadDeltaUsercmd( msg_t *msg, struct usercmd_s *from, struct usercmd_s *to );
#endif
void MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to );
void MSG_ReadDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to );
@ -251,32 +263,63 @@ PROTOCOL
==============================================================
*/
#define PROTOCOL_VERSION 71
#define PROTOCOL_LEGACY_VERSION 68
#ifdef ELITEFORCE
#define PROTOCOL_VERSION 26
#define PROTOCOL_LEGACY_VERSION 24
#else
#define PROTOCOL_VERSION 71
#define PROTOCOL_LEGACY_VERSION 68
#endif
// 1.31 - 67
// maintain a list of compatible protocols for demo playing
// NOTE: that stuff only works with two digits protocols
extern int demo_protocols[];
#if !defined UPDATE_SERVER_NAME && !defined STANDALONE
#define UPDATE_SERVER_NAME "update.quake3arena.com"
#endif
// override on command line, config files etc.
#ifndef MASTER_SERVER_NAME
#define MASTER_SERVER_NAME "master.quake3arena.com"
#ifdef ELITEFORCE
#if !defined UPDATE_SERVER_NAME && !defined STANDALONE
#define UPDATE_SERVER_NAME "motd.stef1.ravensoft.com"
#endif
#ifndef MASTER_SERVER_NAME
#define MASTER_SERVER_NAME "master.stef1.ravensoft.com"
#endif
#define PORT_MASTER 27953
#else
#if !defined UPDATE_SERVER_NAME && !defined STANDALONE
#define UPDATE_SERVER_NAME "update.quake3arena.com"
#endif
#define UPDATE_SERVER_NAME "update.quake3arena.com"
#ifndef MASTER_SERVER_NAME
#define MASTER_SERVER_NAME "master.quake3arena.com"
#endif
#define PORT_MASTER 27950
#endif
#ifndef STANDALONE
#ifndef AUTHORIZE_SERVER_NAME
#define AUTHORIZE_SERVER_NAME "authorize.quake3arena.com"
#endif
#ifndef PORT_AUTHORIZE
#define PORT_AUTHORIZE 27952
#ifdef ELITEFORCE
#ifndef AUTHORIZE_SERVER_NAME
#define AUTHORIZE_SERVER_NAME "authenticate.stef1.ravensoft.com"
#endif
#ifndef PORT_AUTHORIZE
#define PORT_AUTHORIZE 27953
#endif
#else
#ifndef AUTHORIZE_SERVER_NAME
#define AUTHORIZE_SERVER_NAME "authorize.quake3arena.com"
#endif
#ifndef PORT_AUTHORIZE
#define PORT_AUTHORIZE 27952
#endif
#endif
#endif
#define PORT_MASTER 27950
#define PORT_UPDATE 27951
#define PORT_SERVER 27960
#define NUM_SERVER_PORTS 4 // broadcast scan this many ports after
@ -594,16 +637,24 @@ issues.
#define FS_UI_REF 0x02
#define FS_CGAME_REF 0x04
// number of id paks that will never be autodownloaded from baseq3/missionpack
#ifdef ELITEFORCE
#define NUM_ID_PAKS 9
#else
#define NUM_ID_PAKS 9
#define NUM_TA_PAKS 4
#endif
#define MAX_FILE_HANDLES 64
#ifdef ELITEFORCE
#define Q3CONFIG_CFG "hmconfig.cfg"
#else
#ifdef DEDICATED
# define Q3CONFIG_CFG "q3config_server.cfg"
#else
# define Q3CONFIG_CFG "q3config.cfg"
#endif
#endif
qboolean FS_Initialized( void );

View file

@ -41,6 +41,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000
#ifdef ELITEFORCE
#define CONTENTS_SHOTCLIP 0x40000
#endif
//bot specific contents types
#define CONTENTS_TELEPORTER 0x40000
#define CONTENTS_JUMPPAD 0x80000

View file

@ -118,6 +118,7 @@ extern cvar_t *r_saveFontData;
qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode );
float R_NoiseGet4f( float x, float y, float z, float t );
int R_RandomOn( float t );
void R_NoiseInit( void );
image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags );
@ -127,6 +128,9 @@ void R_IssuePendingRenderCommands( void );
qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex );
qhandle_t RE_RegisterShader( const char *name );
qhandle_t RE_RegisterShaderNoMip( const char *name );
#ifdef ELITEFORCE
qhandle_t RE_RegisterShader3D( const char *name );
#endif
qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage);
// font stuff

View file

@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
static float s_noise_table[NOISE_SIZE];
static int s_noise_perm[NOISE_SIZE];
static int s_random[NOISE_SIZE];
static float GetNoiseValue( int x, int y, int z, int t )
{
@ -46,6 +47,7 @@ void R_NoiseInit( void )
{
s_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) );
s_noise_perm[i] = ( unsigned char ) ( rand() / ( float ) RAND_MAX * 255 );
s_random[i] = rand() & 0x01;
}
}
@ -89,3 +91,10 @@ float R_NoiseGet4f( float x, float y, float z, float t )
return finalvalue;
}
// used in the shader functions (GF_RANDOM) to implement a quasi random flickering.
#define VALR( a ) s_random[ ( a ) & ( NOISE_MASK )]
int R_RandomOn(float t)
{
return VALR((unsigned int) floor(t));
}

View file

@ -49,6 +49,9 @@ typedef struct {
qhandle_t (*RegisterSkin)( const char *name );
qhandle_t (*RegisterShader)( const char *name );
qhandle_t (*RegisterShaderNoMip)( const char *name );
#ifdef ELITEFORCE
qhandle_t (*RegisterShader3D)( const char *name );
#endif
void (*LoadWorld)( const char *name );
// the vis data is a large enough block of data that we go to the trouble

View file

@ -39,10 +39,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define RF_FIRST_PERSON 0x0004 // only draw through eyes (view weapon, damage blood blob)
#define RF_DEPTHHACK 0x0008 // for view weapon Z crunching
#ifdef ELITEFORCE
#define RF_FULLBRIGHT 0x0010
#define RF_CROSSHAIR 0x0020
#else
#define RF_CROSSHAIR 0x0010 // This item is a cross hair and will draw over everything similar to
// DEPTHHACK in stereo rendering mode, with the difference that the
// projection matrix won't be hacked to reduce the stereo separation as
// is done for the gun.
#endif
#define RF_NOSHADOW 0x0040 // don't add stencil shadows
@ -55,6 +60,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define RF_WRAP_FRAMES 0x0200 // mod the model frames by the maxframes to allow continuous
// animation without needing to know the frame count
#ifdef ELITEFORCE
#define RF_FORCE_ENT_ALPHA 0x0800 // override shader alpha value and take the one from the entity.
#endif
// refdef flags
#define RDF_NOWORLDMODEL 0x0001 // used for player configuration screen
#define RDF_HYPERSPACE 0x0004 // teleportation effect
@ -71,6 +80,27 @@ typedef struct poly_s {
polyVert_t *verts;
} poly_t;
#ifdef ELITEFORCE
typedef enum {
RT_MODEL,
RT_SPRITE,
RT_ORIENTEDSPRITE, // Replaces RT_POLY, which wasn't used. --Pat
RT_ALPHAVERTPOLY, // Individual alpha levels on each vertex
RT_BEAM,
RT_RAIL_CORE,
RT_RAIL_RINGS,
RT_LIGHTNING,
RT_PORTALSURFACE, // doesn't draw anything, just info for portals
RT_LINE, // New type for Trek MP --Pat
RT_ORIENTEDLINE,
RT_LINE2, // New line type for Trek MP, with taper support --Pat
RT_BEZIER, // what he said --keith
RT_CYLINDER, // Yet another Trek primitive!
RT_ELECTRICITY, // Yet another Trek primitive!
RT_MAX_REF_ENTITY_TYPE
} refEntityType_t;
#else
typedef enum {
RT_MODEL,
RT_POLY,
@ -83,6 +113,7 @@ typedef enum {
RT_MAX_REF_ENTITY_TYPE
} refEntityType_t;
#endif
typedef struct {
refEntityType_t reType;
@ -115,8 +146,49 @@ typedef struct {
float shaderTime; // subtracted from refdef time to control effect start times
// extra sprite information
#ifdef ELITEFORCE
union
{
struct
{
float rotation;
float radius;
byte vertRGBA[4][4];
} sprite;
struct
{
float width;
float width2;
float stscale;
} line;
struct // that whole put-the-opening-brace-on-the-same-line-as-the-beginning-of-the-definition coding style is fecal // I agree.
{
float width;
vec3_t control1;
vec3_t control2;
} bezier;
struct
{
float width;
float width2;
float stscale;
float height;
float bias;
qboolean wrap;
} cylinder;
struct
{
float width;
float deviation;
float stscale;
qboolean wrap;
qboolean taper;
} electricity;
} data;
#else
float radius;
float rotation;
#endif
} refEntity_t;
@ -137,8 +209,10 @@ typedef struct {
// 1 bits will prevent the associated area from rendering at all
byte areamask[MAX_MAP_AREA_BYTES];
#ifndef ELITEFORCE
// text messages for deform text shaders
char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
#endif
} refdef_t;
@ -186,7 +260,11 @@ typedef struct {
char renderer_string[MAX_STRING_CHARS];
char vendor_string[MAX_STRING_CHARS];
char version_string[MAX_STRING_CHARS];
#ifdef ELITEFORCE
char extensions_string[2*MAX_STRING_CHARS];
#else
char extensions_string[BIG_INFO_STRING];
#endif
int maxTextureSize; // queried from GL
int numTextureUnits; // multitexture ability
@ -199,6 +277,9 @@ typedef struct {
qboolean deviceSupportsGamma;
textureCompression_t textureCompression;
qboolean textureEnvAddAvailable;
#ifdef ELITEFORCE
qboolean textureFilterAnisotropicAvailable;
#endif
int vidWidth, vidHeight;
// aspect is the screen's physical width / height, which may be different

View file

@ -448,10 +448,17 @@ void RB_BeginDrawingView (void) {
if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
{
clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used
#ifdef ELITEFORCE
if(r_origfastsky->integer)
qglClearColor(0.8f, 0.7f, 0.4f, 1.0f);
else
qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
#else
#ifdef _DEBUG
qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky
#else
qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky
#endif
#endif
}
qglClear( clearBits );

View file

@ -69,6 +69,9 @@ cvar_t *r_measureOverdraw;
cvar_t *r_inGameVideo;
cvar_t *r_fastsky;
#ifdef ELITEFORCE
cvar_t *r_origfastsky;
#endif
cvar_t *r_drawSun;
cvar_t *r_dynamiclight;
cvar_t *r_dlightBacks;
@ -197,6 +200,10 @@ static void InitOpenGL( void )
GLimp_Init();
#ifdef ELITEFORCE
glConfig.textureFilterAnisotropicAvailable = textureFilterAnisotropic;
#endif
strcpy( renderer_buffer, glConfig.renderer_string );
Q_strlwr( renderer_buffer );
@ -1007,7 +1014,11 @@ void R_Register( void )
// latched and archived variables
//
r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH );
#ifdef ELITEFORCE
r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compress_textures", "0", CVAR_ARCHIVE | CVAR_LATCH );
#else
r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH );
#endif
r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH);
@ -1050,7 +1061,11 @@ void R_Register( void )
r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "0", CVAR_LATCH );
ri.Cvar_CheckRange( r_displayRefresh, 0, 200, qtrue );
r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT );
#ifdef ELITEFORCE
r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "1", CVAR_LATCH );
#else
r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH );
#endif
r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH );
r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH );
@ -1066,6 +1081,9 @@ void R_Register( void )
r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE );
r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE );
r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE );
#ifdef ELITEFORCE
r_origfastsky = ri.Cvar_Get( "r_origfastsky", "0", CVAR_ARCHIVE );
#endif
r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE );
r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE );
r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
@ -1171,8 +1189,15 @@ void R_Init( void ) {
Com_Memset( &backEnd, 0, sizeof( backEnd ) );
Com_Memset( &tess, 0, sizeof( tess ) );
#ifdef ELITEFORCE
if(sizeof(glconfig_t) != 5192)
{
ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 5192", (unsigned int) sizeof(glconfig_t));
}
#else
if(sizeof(glconfig_t) != 11332)
ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 11332", (unsigned int) sizeof(glconfig_t));
#endif
// Swap_Init();
@ -1181,6 +1206,8 @@ void R_Init( void ) {
}
Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) );
R_NoiseInit();
//
// init function tables
//
@ -1190,6 +1217,7 @@ void R_Init( void ) {
tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;
tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;
tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i];
tr.noiseTable[i] = R_NoiseGet4f(0, 0, 0, i);
if ( i < FUNCTABLE_SIZE / 2 )
{
@ -1210,8 +1238,6 @@ void R_Init( void ) {
R_InitFogTable();
R_NoiseInit();
R_Register();
max_polys = r_maxpolys->integer;
@ -1338,6 +1364,9 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
re.RegisterSkin = RE_RegisterSkin;
re.RegisterShader = RE_RegisterShader;
re.RegisterShaderNoMip = RE_RegisterShaderNoMip;
#ifdef ELITEFORCE
re.RegisterShader3D = RE_RegisterShader3D;
#endif
re.LoadWorld = RE_LoadWorldMap;
re.SetWorldVisData = RE_SetWorldVisData;
re.EndRegistration = RE_EndRegistration;

View file

@ -300,6 +300,20 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
}
ent->lightingCalculated = qtrue;
#ifdef ELITEFORCE
if(ent->e.renderfx & RF_FULLBRIGHT)
{
// ent->ambientLight[0] = ent->ambientLight[1] = ent->ambientLight[1] = 0xFF;
((byte *)&ent->ambientLightInt)[0] = 0x7F;
((byte *)&ent->ambientLightInt)[1] = 0x7F;
((byte *)&ent->ambientLightInt)[2] = 0x7F;
((byte *)&ent->ambientLightInt)[3] = 0xFF;
ent->lightDir[0] = ent->lightDir[1] = ent->lightDir[2] = 0;
return;
}
#endif
//
// trace a sample point down to find ambient light
//

View file

@ -117,7 +117,8 @@ typedef enum {
GF_SAWTOOTH,
GF_INVERSE_SAWTOOTH,
GF_NOISE
GF_NOISE,
GF_RANDOM
} genFunc_t;
@ -942,6 +943,7 @@ typedef struct {
float triangleTable[FUNCTABLE_SIZE];
float sawToothTable[FUNCTABLE_SIZE];
float inverseSawToothTable[FUNCTABLE_SIZE];
float noiseTable[FUNCTABLE_SIZE];
float fogTable[FOG_TABLE_SIZE];
} trGlobals_t;
@ -982,6 +984,9 @@ extern cvar_t *r_primitives; // "0" = based on compiled vertex array existance
extern cvar_t *r_inGameVideo; // controls whether in game video should be draw
extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn
#ifdef ELITEFORCE
extern cvar_t *r_origfastsky; // controls whether fastsky color is like in original EF.
#endif
extern cvar_t *r_drawSun; // controls drawing of sun quad
extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled
extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity

View file

@ -1006,6 +1006,7 @@ See if a sprite is inside a fog volume
int R_SpriteFogNum( trRefEntity_t *ent ) {
int i, j;
fog_t *fog;
float radius;
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
return 0;
@ -1015,13 +1016,19 @@ int R_SpriteFogNum( trRefEntity_t *ent ) {
return 0;
}
#ifdef ELITEFORCE
radius = ent->e.data.sprite.radius;
#else
radius = ent->e.radius;
#endif
for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
fog = &tr.world->fogs[i];
for ( j = 0 ; j < 3 ; j++ ) {
if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {
if ( ent->e.origin[j] - radius >= fog->bounds[1][j] ) {
break;
}
if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {
if ( ent->e.origin[j] + radius <= fog->bounds[0][j] ) {
break;
}
}
@ -1212,6 +1219,18 @@ void R_AddEntitySurfaces (void) {
switch ( ent->e.reType ) {
case RT_PORTALSURFACE:
break; // don't draw anything
#ifdef ELITEFORCE
case RT_ORIENTEDSPRITE:
case RT_ALPHAVERTPOLY:
case RT_LINE:
case RT_ORIENTEDLINE:
case RT_LINE2:
case RT_BEZIER:
case RT_CYLINDER:
case RT_ELECTRICITY:
#endif
case RT_SPRITE:
case RT_BEAM:
case RT_LIGHTNING:

View file

@ -304,7 +304,9 @@ void RE_RenderScene( const refdef_t *fd ) {
ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
}
#ifndef ELITEFORCE
Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
#endif
tr.refdef.x = fd->x;
tr.refdef.y = fd->y;

View file

@ -1109,6 +1109,10 @@ static void ComputeTexCoords( shaderStage_t *pStage ) {
static void RB_IterateStagesGeneric( shaderCommands_t *input )
{
int stage;
#ifdef ELITEFORCE
qboolean overridealpha;
int oldalphaGen = 0;
#endif
for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
{
@ -1119,7 +1123,25 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
break;
}
#ifdef ELITEFORCE
// Override the shader alpha channel if requested.
if(backEnd.currentEntity->e.renderfx & RF_FORCE_ENT_ALPHA)
{
overridealpha = qtrue;
oldalphaGen = pStage->alphaGen;
pStage->alphaGen = AGEN_ENTITY;
}
else
overridealpha = qfalse;
#endif
ComputeColors( pStage );
#ifdef ELITEFORCE
if(overridealpha)
pStage->alphaGen = oldalphaGen;
#endif
ComputeTexCoords( pStage );
if ( !setArraysOnce )
@ -1147,7 +1169,15 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
//
R_BindAnimatedImage( &pStage->bundle[0] );
GL_State( pStage->stateBits );
#ifdef ELITEFORCE
if(overridealpha && backEnd.currentEntity->e.shaderRGBA[3] < 0xFF && !(pStage->stateBits & GLS_ATEST_BITS))
{
GL_State((pStage->stateBits & ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_ATEST_BITS)) // remove the shader set values.
| GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_ATEST_GT_0); // Now add the default values.
}
else
#endif
GL_State( pStage->stateBits );
//
// draw

View file

@ -43,6 +43,8 @@ static float *TableForFunc( genFunc_t func )
return tr.sawToothTable;
case GF_INVERSE_SAWTOOTH:
return tr.inverseSawToothTable;
case GF_NOISE:
return tr.noiseTable;
case GF_NONE:
default:
break;
@ -577,7 +579,9 @@ void RB_DeformTessGeometry( void ) {
case DEFORM_TEXT5:
case DEFORM_TEXT6:
case DEFORM_TEXT7:
#ifndef ELITEFORCE
DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );
#endif
break;
}
}
@ -688,6 +692,8 @@ void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors )
if ( wf->func == GF_NOISE ) {
glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude;
} else if( wf->func == GF_RANDOM ) {
glow = wf->base + R_RandomOn( (tess.shaderTime + wf->phase) * wf->frequency ) * wf->amplitude;
} else {
glow = EvalWaveForm( wf ) * tr.identityLight;
}

View file

@ -293,6 +293,10 @@ static genFunc_t NameToGenFunc( const char *funcname )
{
return GF_NOISE;
}
else if( !Q_stricmp( funcname, "random" ) )
{
return GF_RANDOM;
}
ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
return GF_SIN;
@ -768,6 +772,12 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
{
depthFuncBits = 0;
}
#ifdef ELITEFORCE
if ( !Q_stricmp( token, "disable" ) )
{
depthFuncBits = 0;
}
#endif
else if ( !Q_stricmp( token, "equal" ) )
{
depthFuncBits = GLS_DEPTHFUNC_EQUAL;
@ -2837,6 +2847,37 @@ qhandle_t RE_RegisterShaderNoMip( const char *name ) {
return sh->index;
}
#ifdef ELITEFORCE
/*
====================
RE_RegisterShader3D
For explicitly defined shaders that need LIGHTMAP_NONE
as lightmapIndex.
====================
*/
qhandle_t RE_RegisterShader3D( const char *name ) {
shader_t *sh;
if ( strlen( name ) >= MAX_QPATH ) {
Com_Printf( "Shader name exceeds MAX_QPATH\n" );
return 0;
}
sh = R_FindShader( name, LIGHTMAP_NONE, qfalse );
// we want to return 0 if the shader failed to
// load for some reason, but R_FindShader should
// still keep a name allocated for it, so if
// something calls RE_RegisterShader again with
// the same name, we don't try looking for it again
if ( sh->defaultShader ) {
return 0;
}
return sh->index;
}
#endif
/*
====================

View file

@ -156,17 +156,25 @@ RB_SurfaceSprite
static void RB_SurfaceSprite( void ) {
vec3_t left, up;
float radius;
float rotation;
// calculate the xyz locations for the four corners
#ifdef ELITEFORCE
radius = backEnd.currentEntity->e.data.sprite.radius;
rotation = backEnd.currentEntity->e.data.sprite.rotation;
#else
radius = backEnd.currentEntity->e.radius;
if ( backEnd.currentEntity->e.rotation == 0 ) {
rotation = backEnd.currentEntity->e.rotation;
#endif
if ( rotation == 0 ) {
VectorScale( backEnd.viewParms.or.axis[1], radius, left );
VectorScale( backEnd.viewParms.or.axis[2], radius, up );
} else {
float s, c;
float ang;
ang = M_PI * backEnd.currentEntity->e.rotation / 180;
ang = M_PI * rotation / 180;
s = sin( ang );
c = cos( ang );
@ -551,6 +559,576 @@ static void RB_SurfaceLightningBolt( void ) {
}
}
#ifdef ELITEFORCE
/*
==============
RB_SurfaceOrientedSprite
==============
*/
static void RB_SurfaceOrientedSprite( void )
{
vec3_t left, up;
float radius;
float rotation;
// calculate the xyz locations for the four corners
radius = backEnd.currentEntity->e.data.sprite.radius;
rotation = backEnd.currentEntity->e.data.sprite.rotation;
if (rotation == 0)
{
VectorScale( backEnd.currentEntity->e.axis[1], radius, left );
VectorScale( backEnd.currentEntity->e.axis[2], radius, up );
}
else
{
float s, c;
float ang;
ang = M_PI * rotation / 180;
s = sin( ang );
c = cos( ang );
VectorScale( backEnd.currentEntity->e.axis[1], c * radius, left );
VectorMA( left, -s * radius, backEnd.currentEntity->e.axis[2], left );
VectorScale( backEnd.currentEntity->e.axis[2], c * radius, up );
VectorMA( up, s * radius, backEnd.currentEntity->e.axis[1], up );
}
if ( backEnd.viewParms.isMirror )
VectorSubtract( vec3_origin, left, left );
RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA );
}
void RB_Line(vec3_t start, vec3_t end, vec3_t linedirection, vec3_t left,
vec3_t *corners, float starttex, float endtex, refEntity_t *e)
{
int ndx, numind;
color4ub_t *vertcols;
RB_CHECKOVERFLOW( 4, 6 );
// Set up the triangles ..
ndx = tess.numVertexes;
numind = tess.numIndexes;
tess.indexes[ numind ] = ndx;
tess.indexes[ numind + 1 ] = ndx + 1;
tess.indexes[ numind + 2 ] = ndx + 3;
tess.indexes[ numind + 3 ] = ndx + 3;
tess.indexes[ numind + 4 ] = ndx + 1;
tess.indexes[ numind + 5 ] = ndx + 2;
// now create the corner vertices
if(corners)
{
// we have the corner points for the start already given.
VectorCopy(corners[0], tess.xyz[ndx]);
VectorCopy(corners[1], tess.xyz[ndx+1]);
}
else
{
// start left corner
VectorAdd(start, left, tess.xyz[ndx]);
// start right corner
VectorSubtract(start, left, tess.xyz[ndx+1]);
}
// end right corner
VectorSubtract(end, left, tess.xyz[ndx+2]);
// end left corner
VectorAdd(end, left, tess.xyz[ndx+3]);
if(corners)
{
// save the end corner points here.
VectorCopy(tess.xyz[ndx+3], corners[0]);
VectorCopy(tess.xyz[ndx+2], corners[1]);
}
// Texture stuff....
tess.texCoords[ndx][0][0] = 0;
tess.texCoords[ndx][0][1] = starttex;
tess.texCoords[ndx+1][0][0] = 1;
tess.texCoords[ndx+1][0][1] = starttex;
tess.texCoords[ndx+2][0][0] = 1;
tess.texCoords[ndx+2][0][1] = endtex;
tess.texCoords[ndx+3][0][0] = 0;
tess.texCoords[ndx+3][0][1] = endtex;
vertcols = tess.vertexColors;
vertcols[ndx][0] = vertcols[ndx+1][0] = vertcols[ndx+2][0] = vertcols[ndx+3][0] = e->shaderRGBA[0];
vertcols[ndx][1] = vertcols[ndx+1][1] = vertcols[ndx+2][1] = vertcols[ndx+3][1] = e->shaderRGBA[1];
vertcols[ndx][2] = vertcols[ndx+1][2] = vertcols[ndx+2][2] = vertcols[ndx+3][2] = e->shaderRGBA[2];
vertcols[ndx][3] = vertcols[ndx+1][3] = vertcols[ndx+2][3] = vertcols[ndx+3][3] = e->shaderRGBA[3];
tess.numVertexes += 4;
tess.numIndexes += 6;
}
// Create a normal vector and scale it to the right length
void RB_LineNormal(vec3_t vec1, vec3_t vec2, float scale, vec3_t result)
{
// Create the offset vector for the width of the line
CrossProduct(vec1, vec2, result);
// Normalize the offset vector first.
VectorNormalize(result);
// Scale the offset vector to the intended width.
VectorScale(result, scale / 2, result);
}
// Let's draw a thick line from A to B and dance happily around a christmas tree!
void RB_SurfaceLine( void )
{
refEntity_t *e;
vec3_t left; // I vote the green party...
vec3_t start, end, linedirection, start2origin;
shader_t *surfshader;
e = &backEnd.currentEntity->e;
// Getting up before 1:00 pm to attend HM I lectures finally paid off..
// Get the start and end point of the line
VectorCopy(e->origin, start);
VectorCopy(e->oldorigin, end);
// Direction vector for the line:
VectorSubtract(end, start, linedirection);
// Direction vector for the start to current point of view
VectorSubtract(backEnd.viewParms.or.origin, start, start2origin);
RB_LineNormal(start2origin, linedirection, e->data.line.width, left);
RB_Line(start, end, linedirection, left, NULL, 0, e->data.line.stscale, e);
// Hack to make the dreadnought lightning bolt work: set the correct cull type...
if((surfshader = R_GetShaderByHandle(e->customShader)))
surfshader->cullType = CT_TWO_SIDED;
}
void RB_SurfaceOrientedLine(void)
{
refEntity_t *e;
vec3_t left;
vec3_t linedirection;
shader_t *surfshader;
e = &backEnd.currentEntity->e;
VectorSubtract(e->oldorigin, e->origin, linedirection);
VectorCopy(e->axis[1], left);
VectorNormalize(left);
VectorScale(left, e->data.line.width / 2, left);
RB_Line(e->origin, e->oldorigin, linedirection, left, NULL, 0, 1, e);
surfshader = R_GetShaderByHandle(e->customShader);
surfshader->cullType = CT_TWO_SIDED;
}
// This time it's not a rectangle but a trapezoid I guess ...
void RB_SurfaceLine2( void )
{
refEntity_t *e;
vec3_t startleft, endleft; // I still vote the green party...
vec3_t start, end, linedirection, start2origin;
color4ub_t *vertcols;
int ndx, numind;
RB_CHECKOVERFLOW( 6, 12 );
e = &backEnd.currentEntity->e;
// Set up the triangle ..
ndx = tess.numVertexes;
numind = tess.numIndexes;
tess.indexes[ numind ] = ndx;
tess.indexes[ numind + 1 ] = ndx + 1;
tess.indexes[ numind + 2 ] = ndx + 5;
tess.indexes[ numind + 3 ] = ndx + 5;
tess.indexes[ numind + 4 ] = ndx + 4;
tess.indexes[ numind + 5 ] = ndx + 1;
tess.indexes[ numind + 6 ] = ndx + 1;
tess.indexes[ numind + 7 ] = ndx + 4;
tess.indexes[ numind + 8 ] = ndx + 3;
tess.indexes[ numind + 9 ] = ndx + 3;
tess.indexes[ numind + 10 ] = ndx + 2;
tess.indexes[ numind + 11 ] = ndx + 1;
// Get the start and end point of the line
VectorCopy(e->origin, start);
VectorCopy(e->oldorigin, end);
// Direction vector for the line:
VectorSubtract(end, start, linedirection);
// Direction vector for the start to current point of view
VectorSubtract(backEnd.viewParms.or.origin, start, start2origin);
// Create the offset vector for the width of the line
CrossProduct(start2origin, linedirection, startleft);
// Normalize the offset vector first.
VectorNormalize(startleft);
// The normal of the triangle we just thought up:
// Scale the offset vector to the intended width.
VectorScale(startleft, e->data.line.width2 / 2, endleft);
VectorScale(startleft, e->data.line.width / 2, startleft);
// now create the corner vertices
// start left corner
VectorAdd(start, startleft, tess.xyz[ndx]);
// start point
VectorCopy(start, tess.xyz[ndx+1]);
// start right corner
VectorSubtract(start, startleft, tess.xyz[ndx+2]);
// end right corner
VectorSubtract(end, endleft, tess.xyz[ndx+3]);
// end point
VectorCopy(end, tess.xyz[ndx+4]);
// end left corner
VectorAdd(end, endleft, tess.xyz[ndx+5]);
// Texture stuff....
tess.texCoords[ndx][0][0] = 0;
tess.texCoords[ndx][0][1] = 0;
tess.texCoords[ndx+1][0][0] = 0.5;
tess.texCoords[ndx+1][0][1] = 0;
tess.texCoords[ndx+2][0][0] = 1;
tess.texCoords[ndx+2][0][1] = 0;
tess.texCoords[ndx+3][0][0] = 1;
tess.texCoords[ndx+3][0][1] = 1;
tess.texCoords[ndx+4][0][0] = 0.5;
tess.texCoords[ndx+4][0][1] = 1;
tess.texCoords[ndx+5][0][0] = 0;
tess.texCoords[ndx+5][0][1] = 1;
vertcols = tess.vertexColors;
vertcols[ndx][0] = vertcols[ndx+1][0] = vertcols[ndx+2][0] =
vertcols[ndx+3][0] = vertcols[ndx+4][0] = vertcols[ndx+5][0] = e->shaderRGBA[0];
vertcols[ndx][1] = vertcols[ndx+1][1] = vertcols[ndx+2][1] =
vertcols[ndx+3][1] = vertcols[ndx+4][1] = vertcols[ndx+5][1] = e->shaderRGBA[1];
vertcols[ndx][2] = vertcols[ndx+1][2] = vertcols[ndx+2][2] =
vertcols[ndx+3][2] = vertcols[ndx+4][2] = vertcols[ndx+5][2] = e->shaderRGBA[2];
vertcols[ndx][3] = vertcols[ndx+1][3] = vertcols[ndx+2][3] =
vertcols[ndx+3][3] = vertcols[ndx+4][3] = vertcols[ndx+5][3] = e->shaderRGBA[3];
tess.numVertexes += 6;
tess.numIndexes += 12;
}
// Draw a cubic bezier curve for the imod weapon.
#define BEZIER_SEGMENTS 32
#define BEZIER_STEPSIZE 1.0 / BEZIER_SEGMENTS
void RB_SurfaceBezier(void)
{
refEntity_t *e = &backEnd.currentEntity->e;
double tvar = 0, one_tvar; // use double to not lose as much precision on cubing and squaring.
float starttc, endtc;
vec3_t segstartpos, segendpos, prevend[2];
vec3_t linedirection, start2origin, left;
int index;
VectorCopy(e->origin, segstartpos);
// start of the bezier curve is pointy
VectorCopy(segstartpos, prevend[0]);
VectorCopy(segstartpos, prevend[1]);
// iterate through all segments we have to create.
while(tvar <= 1.0)
{
// get the texture position for the rectangular approximating the bezier curve.
starttc = tvar / 2.0;
tvar += BEZIER_STEPSIZE;
endtc = tvar / 2.0;
one_tvar = 1.0 - tvar;
// get the endpoint for this segment.
for(index = 0; index < 3; index++)
{
// C(t) = P0 (t-1)^3 + 3 P1 t (t-1)^2 + 3 P2 t^2 (t-1) + P3 t^3
segendpos[index] =
e->origin[index] * one_tvar * one_tvar * one_tvar +
3 * e->data.bezier.control1[index] * tvar * one_tvar * one_tvar +
3 * e->data.bezier.control2[index] * tvar * tvar * one_tvar +
e->oldorigin[index] * tvar * tvar * tvar;
}
// Direction vector for the line:
VectorSubtract(segendpos, segstartpos, linedirection);
// Direction vector for the start to current point of view
VectorSubtract(backEnd.viewParms.or.origin, segstartpos, start2origin);
RB_LineNormal(start2origin, linedirection, e->data.bezier.width, left);
RB_Line(segstartpos, segendpos, linedirection, left, prevend, starttc, endtc, e);
// Our next segment starts where the old one ends.
VectorCopy(segendpos, segstartpos);
}
}
// this actually isn't a cylinder but a frustum, but for the sake of naming
// conventions we'll keep calling it a cylinder.
// number of rectangles we'll use to approximate a frustum of a cone.
#define CYLINDER_MAXPLANES 64
#define LOD_CONSTANT 4.0f
void RB_SurfaceCylinder(void)
{
int planes, index = 0; // calculate the number of planes based on the level of detail.
vec3_t bottom, top, bottom2top, zerodeg_bottom, zerodeg_top, faxis;
vec3_t bottomcorner, topcorner, vieworigin;
float anglestep, tcstep = 0, width, width2, height;
int ndx, numind;
color4ub_t *vertcols;
refEntity_t *e = &backEnd.currentEntity->e;
// for LOD calculation:
vec3_t bottom2origin, top2origin, lodcalc, projection;
float maxradius, startdistance, enddistance, distance;
height = e->data.cylinder.height;
width = e->data.cylinder.width;
width2 = e->data.cylinder.width2;
maxradius = (width > width2) ? width : width2;
// get the start and end point of the frustum:
VectorCopy(backEnd.viewParms.or.origin, vieworigin);
VectorCopy(e->axis[0], faxis);
VectorCopy(e->origin, bottom);
VectorScale(faxis, height, bottom2top);
VectorAdd(bottom, bottom2top, top);
// Get distance from frustum:
// first distance from endpoints
VectorSubtract(vieworigin, bottom, bottom2origin);
VectorSubtract(vieworigin, top, top2origin);
// get projection of view origin on the middle line:
distance = DotProduct(bottom2origin, faxis);
startdistance = VectorLength(bottom2origin);
enddistance = VectorLength(top2origin);
if(distance < 0 || distance > height)
{
// projected point is not between bottom and top.
distance = (startdistance < enddistance) ? startdistance : enddistance;
}
else
{
VectorMA(bottom, distance, faxis, projection);
VectorSubtract(vieworigin, projection, lodcalc);
distance = VectorLength(lodcalc);
if(startdistance < distance)
distance = startdistance;
if(enddistance < distance)
distance = enddistance;
}
planes = LOD_CONSTANT * maxradius/distance * CYLINDER_MAXPLANES;
if(planes < 8)
planes = 8;
else if(planes > CYLINDER_MAXPLANES)
planes = CYLINDER_MAXPLANES;
RB_CHECKOVERFLOW(4 * planes, 6 * planes);
// create a normalized perpendicular vector to the frustum height.
PerpendicularVector(zerodeg_bottom, faxis);
// This vector gets rotated to create the top ring
VectorScale(zerodeg_bottom, width2 / 2.0f, zerodeg_top);
// Likewise the vector for the lower ring:
VectorScale(zerodeg_bottom, width / 2.0f, zerodeg_bottom);
anglestep = 360.0f / planes;
if(e->data.cylinder.wrap)
tcstep = e->data.cylinder.stscale / planes;
ndx = tess.numVertexes;
numind = tess.numIndexes;
vertcols = tess.vertexColors;
// this loop is creating all surface planes.
while(index < planes)
{
index++;
// Set up the indexes for the new plane:
tess.indexes[numind++] = ndx;
tess.indexes[numind++] = ndx + 2;
tess.indexes[numind++] = ndx + 3;
tess.indexes[numind++] = ndx;
tess.indexes[numind++] = ndx + 3;
tess.indexes[numind++] = ndx + 1;
if(index <= 1)
{
VectorAdd(bottom, zerodeg_bottom, tess.xyz[ndx]);
VectorAdd(top, zerodeg_top, tess.xyz[ndx + 1]);
}
else
{
VectorCopy(bottomcorner, tess.xyz[ndx]);
VectorCopy(topcorner, tess.xyz[ndx + 1]);
}
// Create on the right side two new vertices, first the bottom, then the top one.
if(index >= planes)
{
VectorAdd(bottom, zerodeg_bottom, bottomcorner);
VectorAdd(top, zerodeg_top, topcorner);
}
else
{
RotatePointAroundVector(bottomcorner, faxis, zerodeg_bottom, anglestep * index);
VectorAdd(bottom, bottomcorner, bottomcorner);
RotatePointAroundVector(topcorner, faxis, zerodeg_top, index * anglestep);
VectorAdd(top, topcorner, topcorner);
}
VectorCopy(bottomcorner, tess.xyz[ndx + 2]);
VectorCopy(topcorner, tess.xyz[ndx + 3]);
// Take care about the texture stuff
if(e->data.cylinder.wrap)
{
tess.texCoords[ndx][0][0] = tcstep * (index - 1);
tess.texCoords[ndx][0][1] = 0;
tess.texCoords[ndx+1][0][0] = tcstep * (index - 1);
tess.texCoords[ndx+1][0][1] = 1;
tess.texCoords[ndx+2][0][0] = tcstep * index;
tess.texCoords[ndx+2][0][1] = 0;
tess.texCoords[ndx+3][0][0] = tcstep * index;
tess.texCoords[ndx+3][0][1] = 1;
}
else
{
tess.texCoords[ndx][0][0] = 0;
tess.texCoords[ndx][0][1] = 0;
tess.texCoords[ndx+1][0][0] = 0;
tess.texCoords[ndx+1][0][1] = 1;
tess.texCoords[ndx+2][0][0] = e->data.cylinder.stscale;
tess.texCoords[ndx+2][0][1] = 0;
tess.texCoords[ndx+3][0][0] = e->data.cylinder.stscale;
tess.texCoords[ndx+3][0][1] = 1;
}
vertcols[ndx][0] = vertcols[ndx+1][0] = vertcols[ndx+2][0] = vertcols[ndx+3][0] = e->shaderRGBA[0];
vertcols[ndx][1] = vertcols[ndx+1][1] = vertcols[ndx+2][1] = vertcols[ndx+3][1] = e->shaderRGBA[1];
vertcols[ndx][2] = vertcols[ndx+1][2] = vertcols[ndx+2][2] = vertcols[ndx+3][2] = e->shaderRGBA[2];
vertcols[ndx][3] = vertcols[ndx+1][3] = vertcols[ndx+2][3] = vertcols[ndx+3][3] = 0xff;
ndx += 4;
}
tess.numVertexes = ndx;
tess.numIndexes = numind;
}
// Draws lightning using a multisegment line with jumpy connecting points.
#define ELECTRICITY_SEGMENTS 16
#define ELECTRICITY_STEPSIZE 1.0 / ELECTRICITY_SEGMENTS
void RB_SurfaceElectricity(void)
{
vec3_t start, end, linedirection, segstartpos, segendpos;
vec3_t prevend[2], left, start2origin, start2end;
refEntity_t *e = &backEnd.currentEntity->e;
float width, deviation, veclen;
int index;
VectorCopy(e->origin, start);
VectorCopy(e->oldorigin, end);
VectorSubtract(end, start, start2end);
veclen = VectorLength(start2end);
width = e->data.electricity.width;
deviation = e->data.electricity.deviation;
VectorCopy(start, segendpos);
for(index = 0; index < ELECTRICITY_SEGMENTS; index++)
{
VectorCopy(segendpos, segstartpos);
if(index > ELECTRICITY_SEGMENTS - 2)
{
// This is the last segment.
VectorCopy(end, segendpos);
}
else
{
if(index > ELECTRICITY_SEGMENTS - 3)
{
// The line should have somewhat deviated by now.
// Make the last two segments go to the endpoint
// get the middle point between startpos and endpos
VectorAdd(segstartpos, end, segendpos);
VectorScale(segendpos, 0.5f, segendpos);
}
// Slightly misplace the next point on the line.
segendpos[PITCH] += (start2end[PITCH] + crandom() * deviation * veclen) * ELECTRICITY_STEPSIZE;
segendpos[YAW] += (start2end[YAW] + crandom() * deviation * veclen) * ELECTRICITY_STEPSIZE;
segendpos[ROLL] += (start2end[ROLL] + crandom() * deviation * veclen / 2.0) * ELECTRICITY_STEPSIZE;
}
// Direction vector for the line:
VectorSubtract(segendpos, segstartpos, linedirection);
// Direction vector for the start to current point of view
VectorSubtract(backEnd.viewParms.or.origin, segstartpos, start2origin);
RB_LineNormal(start2origin, linedirection, width, left);
if(!index)
{
// this is our first segment, create the starting points
VectorAdd(segstartpos, left, prevend[0]);
VectorSubtract(segstartpos, left, prevend[1]);
}
RB_Line(segstartpos, segendpos, linedirection, left, prevend, 0, e->data.electricity.stscale, e);
}
}
#endif
/*
** VectorArrayNormalize
*
@ -1142,7 +1720,6 @@ static void RB_SurfaceGrid( srfGridMesh_t *cv ) {
}
}
/*
===========================================================================
@ -1187,6 +1764,9 @@ Entities that have a single procedurally generated surface
*/
static void RB_SurfaceEntity( surfaceType_t *surfType ) {
switch( backEnd.currentEntity->e.reType ) {
#ifdef ELITEFORCE
case RT_ALPHAVERTPOLY:
#endif
case RT_SPRITE:
RB_SurfaceSprite();
break;
@ -1202,6 +1782,29 @@ static void RB_SurfaceEntity( surfaceType_t *surfType ) {
case RT_LIGHTNING:
RB_SurfaceLightningBolt();
break;
#ifdef ELITEFORCE
case RT_ORIENTEDSPRITE:
RB_SurfaceOrientedSprite();
break;
case RT_LINE:
RB_SurfaceLine();
break;
case RT_ORIENTEDLINE:
RB_SurfaceOrientedLine();
break;
case RT_LINE2:
RB_SurfaceLine2();
break;
case RT_BEZIER:
RB_SurfaceBezier();
break;
case RT_CYLINDER:
RB_SurfaceCylinder();
break;
case RT_ELECTRICITY:
RB_SurfaceElectricity();
break;
#endif
default:
RB_SurfaceAxis();
break;

View file

@ -71,6 +71,9 @@ cvar_t *r_measureOverdraw;
cvar_t *r_inGameVideo;
cvar_t *r_fastsky;
#ifdef ELITEFORCE
cvar_t *r_origfastsky;
#endif
cvar_t *r_drawSun;
cvar_t *r_dynamiclight;
cvar_t *r_dlightBacks;
@ -1155,7 +1158,11 @@ void R_Register( void )
// latched and archived variables
//
r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH );
#ifdef ELITEFORCE
r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compress_textures", "0", CVAR_ARCHIVE | CVAR_LATCH );
#else
r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "0", CVAR_ARCHIVE | CVAR_LATCH );
#endif
r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH);
@ -1284,6 +1291,9 @@ void R_Register( void )
r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE );
r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE );
r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE );
#ifdef ELITEFORCE
r_origfastsky = ri.Cvar_Get( "r_origfastsky", "0", CVAR_ARCHIVE );
#endif
r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE );
r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE );
r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
@ -1409,8 +1419,15 @@ void R_Init( void ) {
Com_Memset( &backEnd, 0, sizeof( backEnd ) );
Com_Memset( &tess, 0, sizeof( tess ) );
#ifdef ELITEFORCE
if(sizeof(glconfig_t) != 5192)
{
ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 5192", (unsigned int) sizeof(glconfig_t));
}
#else
if(sizeof(glconfig_t) != 11332)
ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 11332", (unsigned int) sizeof(glconfig_t));
#endif
// Swap_Init();
@ -1428,6 +1445,7 @@ void R_Init( void ) {
tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;
tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;
tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i];
tr.noiseTable[i] = R_NoiseGet4f(0, 0, 0, i);
if ( i < FUNCTABLE_SIZE / 2 )
{
@ -1448,8 +1466,6 @@ void R_Init( void ) {
R_InitFogTable();
R_NoiseInit();
R_Register();
max_polys = r_maxpolys->integer;
@ -1592,6 +1608,9 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
re.RegisterSkin = RE_RegisterSkin;
re.RegisterShader = RE_RegisterShader;
re.RegisterShaderNoMip = RE_RegisterShaderNoMip;
#ifdef ELITEFORCE
re.RegisterShader3D = RE_RegisterShader3D;
#endif
re.LoadWorld = RE_LoadWorldMap;
re.SetWorldVisData = RE_SetWorldVisData;
re.EndRegistration = RE_EndRegistration;

View file

@ -332,6 +332,20 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
}
ent->lightingCalculated = qtrue;
#ifdef ELITEFORCE
if(ent->e.renderfx & RF_FULLBRIGHT)
{
// ent->ambientLight[0] = ent->ambientLight[1] = ent->ambientLight[1] = 0xFF;
((byte *)&ent->ambientLightInt)[0] = 0x7F;
((byte *)&ent->ambientLightInt)[1] = 0x7F;
((byte *)&ent->ambientLightInt)[2] = 0x7F;
((byte *)&ent->ambientLightInt)[3] = 0xFF;
ent->lightDir[0] = ent->lightDir[1] = ent->lightDir[2] = 0;
return;
}
#endif
//
// trace a sample point down to find ambient light
//

View file

@ -178,7 +178,8 @@ typedef enum {
GF_SAWTOOTH,
GF_INVERSE_SAWTOOTH,
GF_NOISE
GF_NOISE,
GF_RANDOM
} genFunc_t;
@ -1656,6 +1657,7 @@ typedef struct {
float triangleTable[FUNCTABLE_SIZE];
float sawToothTable[FUNCTABLE_SIZE];
float inverseSawToothTable[FUNCTABLE_SIZE];
float noiseTable[FUNCTABLE_SIZE];
float fogTable[FOG_TABLE_SIZE];
} trGlobals_t;
@ -1691,6 +1693,9 @@ extern cvar_t *r_lodscale;
extern cvar_t *r_inGameVideo; // controls whether in game video should be draw
extern cvar_t *r_fastsky; // controls whether sky should be cleared or drawn
#ifdef ELITEFORCE
extern cvar_t *r_origfastsky; // controls whether fastsky color is like in original EF.
#endif
extern cvar_t *r_drawSun; // controls drawing of sun quad
extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled
extern cvar_t *r_dlightBacks; // dlight non-facing surfaces for continuity

View file

@ -43,6 +43,8 @@ static float *TableForFunc( genFunc_t func )
return tr.sawToothTable;
case GF_INVERSE_SAWTOOTH:
return tr.inverseSawToothTable;
case GF_NOISE:
return tr.noiseTable;
case GF_NONE:
default:
break;
@ -589,7 +591,9 @@ void RB_DeformTessGeometry( void ) {
case DEFORM_TEXT5:
case DEFORM_TEXT6:
case DEFORM_TEXT7:
#ifndef ELITEFORCE
DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );
#endif
break;
}
}

View file

@ -305,6 +305,10 @@ static genFunc_t NameToGenFunc( const char *funcname )
{
return GF_NOISE;
}
else if( !Q_stricmp( funcname, "random" ) )
{
return GF_RANDOM;
}
ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
return GF_SIN;
@ -825,6 +829,12 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
{
depthFuncBits = 0;
}
#ifdef ELITEFORCE
if ( !Q_stricmp( token, "disable" ) )
{
depthFuncBits = 0;
}
#endif
else if ( !Q_stricmp( token, "equal" ) )
{
depthFuncBits = GLS_DEPTHFUNC_EQUAL;
@ -3539,6 +3549,37 @@ qhandle_t RE_RegisterShaderNoMip( const char *name ) {
return sh->index;
}
#ifdef ELITEFORCE
/*
====================
RE_RegisterShader3D
For explicitly defined shaders that need LIGHTMAP_NONE
as lightmapIndex.
====================
*/
qhandle_t RE_RegisterShader3D( const char *name ) {
shader_t *sh;
if ( strlen( name ) >= MAX_QPATH ) {
Com_Printf( "Shader name exceeds MAX_QPATH\n" );
return 0;
}
sh = R_FindShader( name, LIGHTMAP_NONE, qfalse );
// we want to return 0 if the shader failed to
// load for some reason, but R_FindShader should
// still keep a name allocated for it, so if
// something calls RE_RegisterShader again with
// the same name, we don't try looking for it again
if ( sh->defaultShader ) {
return 0;
}
return sh->index;
}
#endif
/*
====================

View file

@ -1499,7 +1499,6 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) {
}
}
/*
===========================================================================
@ -1547,6 +1546,9 @@ Entities that have a single procedurally generated surface
*/
static void RB_SurfaceEntity( surfaceType_t *surfType ) {
switch( backEnd.currentEntity->e.reType ) {
#ifdef ELITEFORCE
case RT_ALPHAVERTPOLY:
#endif
case RT_SPRITE:
RB_SurfaceSprite();
break;
@ -1562,6 +1564,29 @@ static void RB_SurfaceEntity( surfaceType_t *surfType ) {
case RT_LIGHTNING:
RB_SurfaceLightningBolt();
break;
#ifdef ELITEFORCE
case RT_ORIENTEDSPRITE:
RB_SurfaceOrientedSprite();
break;
case RT_LINE:
RB_SurfaceLine();
break;
case RT_ORIENTEDLINE:
RB_SurfaceOrientedLine();
break;
case RT_LINE2:
RB_SurfaceLine2();
break;
case RT_BEZIER:
RB_SurfaceBezier();
break;
case RT_CYLINDER:
RB_SurfaceCylinder();
break;
case RT_ELECTRICITY:
RB_SurfaceElectricity();
break;
#endif
default:
RB_SurfaceAxis();
break;

View file

@ -147,7 +147,11 @@ void SV_GetChallenge(netadr_t from)
#ifndef STANDALONE
// Drop the authorize stuff if this client is coming in via v6 as the auth server does not support ipv6.
// Drop also for addresses coming in on local LAN and for stand-alone games independent from id's assets.
#ifdef ELITEFORCE
if(challenge->adr.type == NA_IP && !com_standalone->integer && !Sys_IsLANAddress(from))
#else
if(challenge->adr.type == NA_IP && !com_standalone->integer && !Sys_IsLANAddress(from))
#endif
{
// look up the authorize server's IP
if (svs.authorizeAddress.type == NA_BAD)
@ -175,12 +179,19 @@ void SV_GetChallenge(netadr_t from)
Com_DPrintf( "authorize server timed out\n" );
else
{
// otherwise send their ip to the authorize server
#ifndef ELITEFORCE
cvar_t *fs;
char game[1024];
#endif
Com_DPrintf( "sending getIpAuthorize for %s\n", NET_AdrToString( from ));
// otherwise send their ip to the authorize server
#ifdef ELITEFORCE
NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
"getIpAuthorize %i %i.%i.%i.%i ", challenge->challenge,
from.ip[0], from.ip[1], from.ip[2], from.ip[3] );
#else
strcpy(game, BASEGAME);
fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
if (fs && fs->string[0] != 0) {
@ -192,7 +203,7 @@ void SV_GetChallenge(netadr_t from)
NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
"getIpAuthorize %i %i.%i.%i.%i %s 0 %s", challenge->challenge,
from.ip[0], from.ip[1], from.ip[2], from.ip[3], game, sv_strictAuth->string );
#endif
return;
}
}
@ -543,6 +554,7 @@ gotnewcl:
ent = SV_GentityNum( clientNum );
newcl->gentity = ent;
// save the challenge
newcl->challenge = challenge;
@ -669,7 +681,12 @@ void SV_DropClient( client_t *drop, const char *reason ) {
VM_Call( gvm, GAME_CLIENT_DISCONNECT, drop - svs.clients );
// add the disconnect command
SV_SendServerCommand( drop, "disconnect \"%s\"", reason);
#ifdef ELITEFORCE
if(drop->compat)
SV_SendServerCommand( drop, "disconnect %s", reason);
else
#endif
SV_SendServerCommand( drop, "disconnect \"%s\"", reason);
if ( isBot ) {
SV_BotFreeClient( drop - svs.clients );
@ -728,11 +745,23 @@ static void SV_SendClientGameState( client_t *client ) {
// gamestate message was not just sent, forcing a retransmit
client->gamestateMessageNum = client->netchan.outgoingSequence;
MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );
#ifdef ELITEFORCE
if(client->compat)
MSG_InitOOB(&msg, msgBuffer, sizeof( msgBuffer ) );
else
#endif
MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );
#ifdef ELITEFORCE
msg.compat = client->compat;
#endif
// NOTE, MRE: all server->client messages now acknowledge
// let the client know which reliable clientCommands we have received
MSG_WriteLong( &msg, client->lastClientCommand );
#ifdef ELITEFORCE
if(!msg.compat)
#endif
MSG_WriteLong( &msg, client->lastClientCommand );
// send any server commands waiting to be sent first.
// we have to do this cause we send the client->reliableSequence
@ -764,9 +793,17 @@ static void SV_SendClientGameState( client_t *client ) {
MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue );
}
MSG_WriteByte( &msg, svc_EOF );
#ifdef ELITEFORCE
if(msg.compat)
MSG_WriteByte(&msg, 0);
else
#endif
MSG_WriteByte( &msg, svc_EOF );
MSG_WriteLong( &msg, client - svs.clients);
#ifdef ELITEFORCE
if(!msg.compat)
#endif
MSG_WriteLong( &msg, client - svs.clients);
// write the checksum feed
MSG_WriteLong( &msg, sv.checksumFeed);
@ -933,6 +970,9 @@ Fill up msg with data, return number of download blocks added
int SV_WriteDownloadToClient(client_t *cl, msg_t *msg)
{
int curindex;
#ifndef ELITEFORCE
int missionPack = 0;
#endif
int unreferenced = 1;
char errorMessage[1024];
char pakbuf[MAX_QPATH], *pakptr;
@ -944,9 +984,11 @@ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg)
if(!cl->download)
{
qboolean idPack = qfalse;
#ifndef ELITEFORCE
#ifndef STANDALONE
qboolean missionPack = qfalse;
#endif
#endif
// Chop off filename extension.
Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName);
@ -975,8 +1017,12 @@ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg)
// now that we know the file is referenced,
// check whether it's legal to download it.
#ifndef STANDALONE
#ifdef ELITEFORCE
idPack = FS_idPak(pakbuf, BASEGAME, NUM_ID_PAKS);
#else
missionPack = FS_idPak(pakbuf, BASETA, NUM_TA_PAKS);
idPack = missionPack;
#endif
#endif
idPack = idPack || FS_idPak(pakbuf, BASEGAME, NUM_ID_PAKS);
@ -1000,6 +1046,10 @@ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg)
Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" is not referenced and cannot be downloaded.", cl->downloadName);
}
else if (idPack) {
#ifdef ELITEFORCE
Com_Printf("clientDownload: %d : \"%s\" cannot download Raven pk3 files\n", (int) (cl - svs.clients), cl->downloadName);
Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload Raven pk3 file \"%s\"", cl->downloadName);
#else
Com_Printf("clientDownload: %d : \"%s\" cannot download id pk3 files\n", (int) (cl - svs.clients), cl->downloadName);
#ifndef STANDALONE
if(missionPack)
@ -1012,6 +1062,7 @@ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg)
{
Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName);
}
#endif
}
else if ( !(sv_allowDownload->integer & DLF_ENABLE) ||
(sv_allowDownload->integer & DLF_NO_UDP) ) {
@ -1036,7 +1087,10 @@ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg)
MSG_WriteByte( msg, svc_download );
MSG_WriteShort( msg, 0 ); // client is expecting block zero
MSG_WriteLong( msg, -1 ); // illegal file size
MSG_WriteString( msg, errorMessage );
#ifdef ELITEFORCE
if(!msg->compat)
#endif
MSG_WriteString( msg, errorMessage );
*cl->downloadName = 0;
@ -1248,21 +1302,28 @@ static void SV_VerifyPaks_f( client_t *cl ) {
// start at arg 2 ( skip serverId cl_paks )
nCurArg = 1;
pArg = Cmd_Argv(nCurArg++);
if(!pArg) {
bGood = qfalse;
}
else
#ifdef ELITEFORCE
if(!cl->compat)
{
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
// we may get incoming cp sequences from a previous checksumFeed, which we need to ignore
// since serverId is a frame count, it always goes up
if (atoi(pArg) < sv.checksumFeedServerId)
{
Com_DPrintf("ignoring outdated cp command from client %s\n", cl->name);
return;
#endif
pArg = Cmd_Argv(nCurArg++);
if(!pArg) {
bGood = qfalse;
}
else
{
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
// we may get incoming cp sequences from a previous checksumFeed, which we need to ignore
// since serverId is a frame count, it always goes up
if (atoi(pArg) < sv.checksumFeedServerId)
{
Com_DPrintf("ignoring outdated cp command from client %s\n", cl->name);
return;
}
}
#ifdef ELITEFORCE
}
#endif
// we basically use this while loop to avoid using 'goto' :)
while (bGood) {
@ -1676,7 +1737,10 @@ each of the backup packets.
==================
*/
static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
int i, key;
int i;
#ifndef ELITEFORCE
int key;
#endif
int cmdCount;
usercmd_t nullcmd;
usercmd_t cmds[MAX_PACKET_USERCMDS];
@ -1700,6 +1764,7 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
return;
}
#ifndef ELITEFORCE
// use the checksum feed in the key
key = sv.checksumFeed;
// also use the message acknowledge
@ -1707,11 +1772,17 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
// also use the last acknowledged server command in the key
key ^= MSG_HashKey(cl->reliableCommands[ cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ], 32);
#endif
Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
oldcmd = &nullcmd;
for ( i = 0 ; i < cmdCount ; i++ ) {
cmd = &cmds[i];
#ifdef ELITEFORCE
MSG_ReadDeltaUsercmd( msg, oldcmd, cmd );
#else
MSG_ReadDeltaUsercmdKey( msg, key, oldcmd, cmd );
#endif
oldcmd = cmd;
}
@ -1902,7 +1973,10 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
int c;
int serverId;
MSG_Bitstream(msg);
#ifdef ELITEFORCE
if(!msg->compat)
MSG_Bitstream(msg);
#endif
serverId = MSG_ReadLong( msg );
cl->messageAcknowledge = MSG_ReadLong( msg );
@ -1968,9 +2042,12 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
do {
c = MSG_ReadByte( msg );
if ( c == clc_EOF ) {
#ifdef ELITEFORCE
if(msg->compat && c == -1)
c = clc_EOF;
#endif
if ( c == clc_EOF )
break;
}
if ( c != clc_clientCommand ) {
break;

View file

@ -335,9 +335,10 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
return 0;
case G_FS_GETFILELIST:
return FS_GetFileList( VMA(1), VMA(2), VMA(3), args[4] );
#ifndef ELITEFORCE
case G_FS_SEEK:
return FS_Seek( args[1], args[2], args[3] );
#endif
case G_LOCATE_GAME_DATA:
SV_LocateGameData( VMA(1), args[2], args[3], VMA(4), args[5] );
return 0;
@ -357,14 +358,18 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
return SV_AreaEntities( VMA(1), VMA(2), VMA(3), args[4] );
case G_ENTITY_CONTACT:
return SV_EntityContact( VMA(1), VMA(2), VMA(3), /*int capsule*/ qfalse );
#ifndef ELITEFORCE
case G_ENTITY_CONTACTCAPSULE:
return SV_EntityContact( VMA(1), VMA(2), VMA(3), /*int capsule*/ qtrue );
#endif
case G_TRACE:
SV_Trace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qfalse );
return 0;
#ifndef ELITEFORCE
case G_TRACECAPSULE:
SV_Trace( VMA(1), VMA(2), VMA(3), VMA(4), VMA(5), args[6], args[7], /*int capsule*/ qtrue );
return 0;
#endif
case G_POINT_CONTENTS:
return SV_PointContents( VMA(1), args[2] );
case G_SET_BRUSH_MODEL:
@ -423,12 +428,13 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
case G_DEBUG_POLYGON_DELETE:
BotImport_DebugPolygonDelete( args[1] );
return 0;
#ifndef ELITEFORCE
case G_REAL_TIME:
return Com_RealTime( VMA(1) );
case G_SNAPVECTOR:
Q_SnapVector(VMA(1));
return 0;
#endif
//====================================
case BOTLIB_SETUP:
@ -440,6 +446,10 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
case BOTLIB_LIBVAR_GET:
return botlib_export->BotLibVarGet( VMA(1), VMA(2), args[3] );
#ifdef ELITEFORCE
case BOTLIB_DEFINE:
return botlib_export->PC_AddGlobalDefine( VMA(1) );
#else
case BOTLIB_PC_ADD_GLOBAL_DEFINE:
return botlib_export->PC_AddGlobalDefine( VMA(1) );
case BOTLIB_PC_LOAD_SOURCE:
@ -450,7 +460,7 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) );
case BOTLIB_PC_SOURCE_FILE_AND_LINE:
return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) );
#endif
case BOTLIB_START_FRAME:
return botlib_export->BotLibStartFrame( VMF(1) );
case BOTLIB_LOAD_MAP:
@ -467,13 +477,14 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
case BOTLIB_USER_COMMAND:
SV_ClientThink( &svs.clients[args[1]], VMA(2) );
return 0;
#ifndef ELITEFORCE
case BOTLIB_AAS_BBOX_AREAS:
return botlib_export->aas.AAS_BBoxAreas( VMA(1), VMA(2), VMA(3), args[4] );
case BOTLIB_AAS_AREA_INFO:
return botlib_export->aas.AAS_AreaInfo( args[1], VMA(2) );
case BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL:
return botlib_export->aas.AAS_AlternativeRouteGoals( VMA(1), args[2], VMA(3), args[4], args[5], VMA(6), args[7], args[8] );
#endif
case BOTLIB_AAS_ENTITY_INFO:
botlib_export->aas.AAS_EntityInfo( args[1], VMA(2) );
return 0;
@ -488,8 +499,10 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
case BOTLIB_AAS_POINT_AREA_NUM:
return botlib_export->aas.AAS_PointAreaNum( VMA(1) );
#ifndef ELITEFORCE
case BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX:
return botlib_export->aas.AAS_PointReachabilityAreaIndex( VMA(1) );
#endif
case BOTLIB_AAS_TRACE_AREAS:
return botlib_export->aas.AAS_TraceAreas( VMA(1), VMA(2), VMA(3), VMA(4), args[5] );
@ -511,11 +524,12 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
case BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA:
return botlib_export->aas.AAS_AreaTravelTimeToGoalArea( args[1], VMA(2), args[3], args[4] );
#ifndef ELITEFORCE
case BOTLIB_AAS_ENABLE_ROUTING_AREA:
return botlib_export->aas.AAS_EnableRoutingArea( args[1], args[2] );
case BOTLIB_AAS_PREDICT_ROUTE:
return botlib_export->aas.AAS_PredictRoute( VMA(1), args[2], VMA(3), args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11] );
#endif
case BOTLIB_AAS_SWIMMING:
return botlib_export->aas.AAS_Swimming( VMA(1) );
case BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT:
@ -532,9 +546,11 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
botlib_export->ea.EA_Command( args[1], VMA(2) );
return 0;
#ifndef ELITEFORCE
case BOTLIB_EA_ACTION:
botlib_export->ea.EA_Action( args[1], args[2] );
return 0;
#endif
case BOTLIB_EA_GESTURE:
botlib_export->ea.EA_Gesture( args[1] );
return 0;
@ -664,7 +680,11 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
botlib_export->ai.BotSetChatGender( args[1], args[2] );
return 0;
case BOTLIB_AI_SET_CHAT_NAME:
#ifdef ELITEFORCE
botlib_export->ai.BotSetChatName( args[1], VMA(2));
#else
botlib_export->ai.BotSetChatName( args[1], VMA(2), args[3] );
#endif
return 0;
case BOTLIB_AI_RESET_GOAL_STATE:
@ -714,9 +734,11 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
return botlib_export->ai.BotGetMapLocationGoal( VMA(1), VMA(2) );
case BOTLIB_AI_AVOID_GOAL_TIME:
return FloatAsInt( botlib_export->ai.BotAvoidGoalTime( args[1], args[2] ) );
#ifndef ELITEFORCE
case BOTLIB_AI_SET_AVOID_GOAL_TIME:
botlib_export->ai.BotSetAvoidGoalTime( args[1], args[2], VMF(3));
return 0;
#endif
case BOTLIB_AI_INIT_LEVEL_ITEMS:
botlib_export->ai.BotInitLevelItems();
return 0;
@ -746,9 +768,11 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
case BOTLIB_AI_RESET_MOVE_STATE:
botlib_export->ai.BotResetMoveState( args[1] );
return 0;
#ifndef ELITEFORCE
case BOTLIB_AI_ADD_AVOID_SPOT:
botlib_export->ai.BotAddAvoidSpot( args[1], VMA(2), VMF(3), args[4] );
return 0;
#endif
case BOTLIB_AI_MOVE_TO_GOAL:
botlib_export->ai.BotMoveToGoal( VMA(1), args[2], VMA(3), args[4] );
return 0;
@ -836,7 +860,23 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) {
case TRAP_CEIL:
return FloatAsInt( ceil( VMF(1) ) );
#ifdef ELITEFORCE
case BOTLIB_EA_USE_ITEM:
botlib_export->ea.EA_UseItem(args[1], VMA(2));
return 0;
case BOTLIB_EA_DROP_ITEM:
botlib_export->ea.EA_DropItem(args[1], VMA(2));
return 0;
case BOTLIB_EA_USE_INV:
botlib_export->ea.EA_UseInv(args[1], VMA(2));
return 0;
case BOTLIB_EA_DROP_INV:
botlib_export->ea.EA_DropInv(args[1], VMA(2));
return 0;
case BOTLIB_EA_ALT_ATTACK:
botlib_export->ea.EA_Attack( args[1] );
return 0;
#endif
default:
Com_Error( ERR_DROP, "Bad game system trap: %ld", (long int) args[0] );
}

View file

@ -668,7 +668,11 @@ void SV_Init (void)
// server vars
sv_rconPassword = Cvar_Get ("rconPassword", "", CVAR_TEMP );
sv_privatePassword = Cvar_Get ("sv_privatePassword", "", CVAR_TEMP );
#ifdef ELITEFORCE
sv_fps = Cvar_Get ("sv_fps", "20", CVAR_SYSTEMINFO | CVAR_TEMP);
#else
sv_fps = Cvar_Get ("sv_fps", "20", CVAR_TEMP );
#endif
sv_timeout = Cvar_Get ("sv_timeout", "200", CVAR_TEMP );
sv_zombietime = Cvar_Get ("sv_zombietime", "2", CVAR_TEMP );
Cvar_Get ("nextmap", "", CVAR_TEMP );
@ -677,8 +681,12 @@ void SV_Init (void)
Cvar_Get ("sv_dlURL", "", CVAR_SERVERINFO | CVAR_ARCHIVE);
sv_master[0] = Cvar_Get("sv_master1", MASTER_SERVER_NAME, 0);
#ifdef ELITEFORCE
sv_master[1] = Cvar_Get("sv_master2", "efmaster.tjps.eu", CVAR_ARCHIVE);
#else
sv_master[1] = Cvar_Get("sv_master2", "master.ioquake3.org", 0);
for(index = 2; index < MAX_MASTER_SERVERS; index++)
#endif
for(index = 1; index < MAX_MASTER_SERVERS; index++)
sv_master[index] = Cvar_Get(va("sv_master%d", index + 1), "", CVAR_ARCHIVE);
sv_reconnectlimit = Cvar_Get ("sv_reconnectlimit", "3", 0);
@ -724,7 +732,13 @@ void SV_FinalMessage( char *message ) {
// don't send a disconnect to a local client
if ( cl->netchan.remoteAddress.type != NA_LOOPBACK ) {
SV_SendServerCommand( cl, "print \"%s\n\"\n", message );
SV_SendServerCommand( cl, "disconnect \"%s\"", message );
#ifdef ELITEFORCE
if(cl->compat)
SV_SendServerCommand(cl, "disconnect Server shutdown: %s", message);
else
#endif
SV_SendServerCommand( cl, "disconnect \"%s\"", message );
}
// force a snapshot to be sent
cl->lastSnapshotTime = 0;

View file

@ -321,11 +321,19 @@ void SV_MasterHeartbeat(const char *message)
// this command should be changed if the server info / status format
// ever incompatably changes
#ifdef ELITEFORCE
if(adr[i][0].type != NA_BAD)
NET_OutOfBandPrint(NS_SERVER, adr[i][0], "\\heartbeat\\%d\\gamename\\%s\\",
Cvar_VariableIntegerValue("net_port"), message);
if(adr[i][1].type != NA_BAD)
NET_OutOfBandPrint(NS_SERVER, adr[i][1], "\\heartbeat\\%d\\gamename\\%s\\",
Cvar_VariableIntegerValue("net_port6"), message);
#else
if(adr[i][0].type != NA_BAD)
NET_OutOfBandPrint( NS_SERVER, adr[i][0], "heartbeat %s\n", message);
if(adr[i][1].type != NA_BAD)
NET_OutOfBandPrint( NS_SERVER, adr[i][1], "heartbeat %s\n", message);
#endif
}
}
@ -682,7 +690,11 @@ void SVC_Info( netadr_t from ) {
Info_SetValueForKey( infostring, "game", gamedir );
}
#ifdef ELITEFORCE
NET_OutOfBandPrint( NS_SERVER, from, "infoResponse \"%s\"", infostring );
#else
NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
#endif
}
/*
@ -787,9 +799,11 @@ static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
MSG_BeginReadingOOB( msg );
MSG_ReadLong( msg ); // skip the -1 marker
#ifndef ELITEFORCE
if (!Q_strncmp("connect", (char *) &msg->data[4], 7)) {
Huff_Decompress(msg, 12);
}
#endif
s = MSG_ReadStringLine( msg );
Cmd_TokenizeString( s );
@ -867,6 +881,10 @@ void SV_PacketEvent( netadr_t from, msg_t *msg ) {
cl->netchan.remoteAddress.port = from.port;
}
#ifdef ELITEFORCE
msg->compat = cl->compat;
#endif
// make sure it is a valid, in sequence packet
if (SV_Netchan_Process(cl, msg)) {
// zombie clients still need to do the Netchan_Process

View file

@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../qcommon/qcommon.h"
#include "server.h"
#ifndef ELITEFORCE
#ifdef LEGACY_PROTOCOL
/*
==============
@ -130,7 +131,7 @@ static void SV_Netchan_Decode( client_t *client, msg_t *msg ) {
}
}
#endif
#endif
/*
@ -164,9 +165,11 @@ void SV_Netchan_TransmitNextInQueue(client_t *client)
Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n");
netbuf = client->netchan_start_queue;
#ifndef ELITEFORCE
#ifdef LEGACY_PROTOCOL
if(client->compat)
SV_Netchan_Encode(client, &netbuf->msg, netbuf->clientCommandString);
#endif
#endif
Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);
@ -223,7 +226,11 @@ then buffer them and make sure they get sent in correct order
void SV_Netchan_Transmit( client_t *client, msg_t *msg)
{
MSG_WriteByte( msg, svc_EOF );
#ifdef ELITEFORCE
if(!msg->compat)
#endif
MSG_WriteByte( msg, svc_EOF );
if(client->netchan.unsentFragments || client->netchan_start_queue)
{
@ -246,9 +253,11 @@ void SV_Netchan_Transmit( client_t *client, msg_t *msg)
}
else
{
#ifndef ELITEFORCE
#ifdef LEGACY_PROTOCOL
if(client->compat)
SV_Netchan_Encode(client, msg, client->lastClientCommandString);
#endif
#endif
Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
}
@ -264,12 +273,12 @@ qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) {
ret = Netchan_Process( &client->netchan, msg );
if (!ret)
return qfalse;
#ifndef ELITEFORCE
#ifdef LEGACY_PROTOCOL
if(client->compat)
SV_Netchan_Decode(client, msg);
#endif
#endif
return qtrue;
}

View file

@ -154,6 +154,12 @@ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) {
MSG_WriteByte (msg, svc_snapshot);
#ifdef ELITEFORCE
if(msg->compat)
#endif
MSG_WriteLong( msg, client->lastClientCommand );
// NOTE, MRE: now sent at the start of every message from server to client
// let the client know which reliable clientCommands we have received
//MSG_WriteLong( msg, client->lastClientCommand );
@ -413,6 +419,7 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra
// if it's a portal entity, add everything visible from its camera position
if ( ent->r.svFlags & SVF_PORTAL ) {
#ifndef ELITEFORCE
if ( ent->s.generic1 ) {
vec3_t dir;
VectorSubtract(ent->s.origin, origin, dir);
@ -420,6 +427,7 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra
continue;
}
}
#endif
SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue );
}
@ -607,12 +615,23 @@ void SV_SendClientSnapshot( client_t *client ) {
return;
}
MSG_Init (&msg, msg_buf, sizeof(msg_buf));
#ifdef ELITEFORCE
if(client->compat)
{
MSG_InitOOB(&msg, msg_buf, sizeof(msg_buf));
msg.compat = qtrue;
}
else
#endif
MSG_Init (&msg, msg_buf, sizeof(msg_buf));
msg.allowoverflow = qtrue;
// NOTE, MRE: all server->client messages now acknowledge
// let the client know which reliable clientCommands we have received
MSG_WriteLong( &msg, client->lastClientCommand );
#ifdef ELITEFORCE
if(!client->compat)
#endif
MSG_WriteLong( &msg, client->lastClientCommand );
// (re)send any reliable server commands
SV_UpdateServerCommandsToClient( client, &msg );

View file

@ -222,27 +222,87 @@ void SV_LinkEntity( sharedEntity_t *gEnt ) {
// encode the size into the entityState_t for client prediction
if ( gEnt->r.bmodel ) {
gEnt->s.solid = SOLID_BMODEL; // a solid_box will never create this value
#ifdef ELITEFORCE
} else if ( gEnt->r.contents & ( CONTENTS_SOLID | CONTENTS_BODY | CONTENTS_SHOTCLIP ) ) {
if(gEnt->r.svFlags & SVF_SHIELD_BBOX)
{
if(gEnt->s.time2 & (1 << 24))
{
i = gEnt->r.maxs[0];
if (i<1)
i = 1;
if (i>255)
i = 255;
// z is not symetric
j = -gEnt->r.mins[0];
if (j<1)
j = 1;
if (j>255)
j = 255;
// and z maxs can be negative...
k = gEnt->r.maxs[2];
if (k<1)
k = 1;
if (k>255)
k = 255;
gEnt->s.eFlags |= EF_SHIELD_BOX_X;
}
else
{
i = gEnt->r.maxs[1];
if (i<1)
i = 1;
if (i>255)
i = 255;
// z is not symetric
j = -gEnt->r.mins[1];
if (j<1)
j = 1;
if (j>255)
j = 255;
// and z maxs can be negative...
k = gEnt->r.maxs[2];
if (k<1)
k = 1;
if (k>255)
k = 255;
gEnt->s.eFlags |= EF_SHIELD_BOX_Y;
}
}
else
{
#else
} else if ( gEnt->r.contents & ( CONTENTS_SOLID | CONTENTS_BODY ) ) {
// assume that x/y are equal and symetric
i = gEnt->r.maxs[0];
if (i<1)
i = 1;
if (i>255)
i = 255;
#endif
// assume that x/y are equal and symetric
i = gEnt->r.maxs[0];
if (i<1)
i = 1;
if (i>255)
i = 255;
// z is not symetric
j = (-gEnt->r.mins[2]);
if (j<1)
j = 1;
if (j>255)
j = 255;
// z is not symetric
j = (-gEnt->r.mins[2]);
if (j<1)
j = 1;
if (j>255)
j = 255;
// and z maxs can be negative...
k = (gEnt->r.maxs[2]+32);
if (k<1)
k = 1;
if (k>255)
k = 255;
// and z maxs can be negative...
k = (gEnt->r.maxs[2]+32);
if (k<1)
k = 1;
if (k>255)
k = 255;
#ifdef ELITEFORCE
}
#endif
gEnt->s.solid = (k<<16) | (j<<8) | i;
} else {

View file

@ -81,6 +81,12 @@ typedef enum {
UI_GETGLCONFIG,
UI_GETCLIENTSTATE,
UI_GETCONFIGSTRING,
#ifdef ELITEFORCE
UI_LAN_GETLOCALSERVERCOUNT,
UI_LAN_GETLOCALSERVERADDRESSSTRING,
UI_LAN_GETGLOBALSERVERCOUNT,
UI_LAN_GETGLOBALSERVERADDRESSSTRING,
#endif
UI_LAN_GETPINGQUEUECOUNT,
UI_LAN_CLEARPING,
UI_LAN_GETPING,
@ -88,6 +94,10 @@ typedef enum {
UI_CVAR_REGISTER,
UI_CVAR_UPDATE,
UI_MEMORY_REMAINING,
#ifdef ELITEFORCE
UI_SET_CDKEY,
UI_R_MODELBOUNDS,
#else
UI_GET_CDKEY,
UI_SET_CDKEY,
UI_R_REGISTERFONT,
@ -124,6 +134,7 @@ typedef enum {
// 1.32
UI_FS_SEEK,
UI_SET_PBCLSTATUS,
#endif
UI_MEMSET = 100,
UI_MEMCPY,
@ -182,7 +193,9 @@ typedef enum {
UI_DRAW_CONNECT_SCREEN,
// void UI_DrawConnectScreen( qboolean overlay );
#ifndef ELITEFORCE
UI_HASUNIQUECDKEY
#endif
// if !overlay, the background will be drawn, otherwise it will be
// overlayed over whatever the cgame has drawn.
// a GetClientState syscall will be made to get the current strings