Beispiel #1
0
// Main functions
qbool SNDDMA_Init(void)
{
    int retval;

#ifdef __FreeBSD__
    Com_Printf("sound: Initializing OSS...\n");
    retval = SNDDMA_Init_OSS();
#else
    // Give user the option to force OSS...
    if (Cvar_Value("s_noalsa")) {
        // User wants us to use OSS...
        SNDDMA_ALSA = false;
        Com_Printf("sound: Using OSS at user's request...\n");
        retval = SNDDMA_Init_OSS();
    } else {
        // Try ALSA first...
        Com_Printf("sound: Attempting to initialise ALSA...\n");
        retval = SNDDMA_Init_ALSA();
        if (retval) {
            SNDDMA_ALSA = true;
        } else {
            // Fall back to OSS...
            SNDDMA_ALSA = false;
            Com_Printf("sound: Falling back to OSS...\n");
            Cvar_Set(&s_device, "/dev/dsp");
            retval = SNDDMA_Init_OSS();
        }
    }
#endif
    return retval;
}
Beispiel #2
0
// returns true if we should draw this player, we don't if we are chase camming
qbool Cam_DrawPlayer(int playernum) {
	if (cl.spectator && autocam && locked && cl_chasecam.value && 
#ifdef JSS_CAM
		!Cvar_Value("cam_thirdperson") &&
#endif
		spec_track == playernum)
		return false;
	return true;
}
Beispiel #3
0
/**
 * Writes the tags of the server for filtering in the Steam server browser.
 *
 * @param tags string where to write the tags (at least MAX_STEAMQUERY_TAG_STRING bytes)
 */
static void SV_GetSteamTags( char *tags )
{
	// Currently there is no way to filter by tag in the game itself,
	// so this is mostly to make sure the tags aren't empty on old servers if they are added.

	Q_strncpyz( tags, Cvar_String( "g_gametype" ), MAX_STEAMQUERY_TAG_STRING );

	if( Cvar_Value( "g_instagib" ) )
	{
		if( tags[0] )
			Q_strncatz( tags, ",", MAX_STEAMQUERY_TAG_STRING );
		Q_strncatz( tags, "instagib", MAX_STEAMQUERY_TAG_STRING );
	}

	// If sv_tags cvar is added, every comma-separated tag from the cvar must be added separately
	// (so the last tag exceeding MAX_STEAMQUERY_TAG_STRING isn't cut off)
	// and validated not to contain any characters disallowed in userinfo (CVAR_SERVERINFO).
}
Beispiel #4
0
/*
=======================
CL_SendConnectPacket

called by CL_Connect_f and CL_CheckResend
======================
*/
void CL_SendConnectPacket (void)
{
	char	data[2048];
	char	biguserinfo[MAX_INFO_STRING + 32];

	if (cls.state != ca_disconnected)
		return;

	connect_time = cls.realtime;	// for retransmit requests

	cls.qport = Cvar_Value("qport");

	// let the server know what extensions we support
	strcpy (biguserinfo, cls.userinfo);
	Info_SetValueForStarKey (biguserinfo, "*z_ext", va("%i", CLIENT_EXTENSIONS), sizeof(biguserinfo));

	sprintf (data, "\xff\xff\xff\xff" "connect %i %i %i \"%s\"\n",
		PROTOCOL_VERSION, cls.qport, cls.challenge, biguserinfo);
	NET_SendPacket (NS_CLIENT, strlen(data), data, cls.server_adr);
}
Beispiel #5
0
void IN_Frame( void )
{
	qboolean m_active = qfalse;

	if( !input_inited )
		return;

	HandleEvents();

	if( focus ) {
		if( !Cvar_Value( "vid_fullscreen" ) && ( ( cls.key_dest == key_console ) && !in_grabinconsole->integer ) )
		{
			m_active = qfalse;
		}
		else
		{
			m_active = qtrue;
		}
	}

	IN_Activate( m_active );
}
Beispiel #6
0
void IN_Frame( void )
{
	if( !input_inited )
		return;

	if( !mapped || ( ( x11display.features.wmStateFullscreen || !Cvar_Value( "vid_fullscreen" ) ) && ( !focus || ( ( cls.key_dest == key_console ) && !in_grabinconsole->integer ) ) ) )
	{
		if( input_active )
			IN_Activate( qfalse );
	}
	else
	{
		if( !input_active )
			IN_Activate( qtrue );
	}

	HandleEvents();

	if( input_active && in_dgamouse->modified )
	{
		uninstall_grabs();
		install_grabs();
	}
}
Beispiel #7
0
/**
 * This function is called for every frame and gives us some time to poll
 * for events that occured at our input devices.
 */
void IN_Frame()
{
	if( !input_inited )
		return;

	if( !input_focus || ( !Cvar_Value( "vid_fullscreen" ) && cls.key_dest == key_console && !in_grabinconsole->integer ) ) {
		if( mouse_active ) {
			if( mouse_relative ) {
				mouse_relative = !(SDL_SetRelativeMouseMode( SDL_FALSE ) == 0);
				if( !mouse_relative ) {
					IN_SetMouseScalingEnabled( true );
				}
			}
			SDL_ShowCursor( SDL_ENABLE );
		}
		mouse_active = false;
		input_active = true;
	} else {
		if( !mouse_active ) {
			SDL_ShowCursor( SDL_DISABLE );

			mouse_relative = SDL_SetRelativeMouseMode( SDL_TRUE ) == 0;
			if( mouse_relative ) {
				IN_SetMouseScalingEnabled( false );
			}
			else {
				IN_WarpMouseToCenter( NULL, NULL );
			}
			IN_SkipRelativeMouseMove();
		}
		mouse_active = true;
		input_active = true;
	}

	IN_HandleEvents();
}
Beispiel #8
0
/*
* CM_LoadMap
* Loads in the map and all submodels
* 
*  for spawning a server with no map at all, call like this:
*  CM_LoadMap( "", qfalse, &checksum );	// no real map
*/
cmodel_t *CM_LoadMap( cmodel_state_t *cms, const char *name, qboolean clientload, unsigned *checksum )
{
	int length;
	unsigned *buf;
	char *header;
	const modelFormatDescr_t *descr;
	bspFormatDesc_t *bspFormat = NULL;

	assert( cms );
	assert( name && strlen( name ) < MAX_CONFIGSTRING_CHARS );
	assert( checksum );

	cms->map_clientload = clientload;

	if( !strcmp( cms->map_name, name ) && ( clientload || !Cvar_Value( "flushmap" ) ) )
	{
		*checksum = cms->checksum;

		if( !clientload )
		{
			memset( cms->map_areaportals, 0, cms->numareas * cms->numareas * sizeof( *cms->map_areaportals ) );
			CM_FloodAreaConnections( cms );
		}

		return cms->map_cmodels; // still have the right version
	}

	CM_Clear( cms );

	if( !name || !name[0] )
	{
		cms->numleafs = 1;
		cms->numcmodels = 2;
		*checksum = 0;
		return cms->map_cmodels;    // cinematic servers won't have anything at all
	}

	//
	// load the file
	//
	length = FS_LoadFile( name, ( void ** )&buf, NULL, 0 );
	if( !buf )
		Com_Error( ERR_DROP, "Couldn't load %s", name );

	cms->checksum = Com_MD5Digest32( ( const qbyte * )buf, length );
	*checksum = cms->checksum;

	// call the apropriate loader
	descr = Q_FindFormatDescriptor( cm_supportedformats, ( const qbyte * )buf, (const bspFormatDesc_t **)&bspFormat );
	if( !descr )
		Com_Error( ERR_DROP, "CM_LoadMap: unknown fileid for %s", name );

	if( !bspFormat )
		Com_Error( ERR_DROP, "CM_LoadMap: %s: unknown bsp format" );

	// copy header into temp variable to be saveed in a cvar
	header = Mem_TempMalloc( descr->headerLen + 1 );
	memcpy( header, buf, descr->headerLen );
	header[descr->headerLen] = '\0';

	// store map format description in cvars
	Cvar_ForceSet( "cm_mapHeader", header );
	Cvar_ForceSet( "cm_mapVersion", va( "%i", LittleLong( *((int *)((qbyte *)buf + descr->headerLen)) ) ) );

	Mem_TempFree( header );

	descr->loader( cms, NULL, buf, bspFormat );

	CM_InitBoxHull( cms );
	CM_InitOctagonHull( cms );

	if( cms->numareas )
	{
		cms->map_areas = Mem_Alloc( cms->mempool, cms->numareas * sizeof( *cms->map_areas ) );
		cms->map_areaportals = Mem_Alloc( cms->mempool, cms->numareas * cms->numareas * sizeof( *cms->map_areaportals ) );

		memset( cms->map_areaportals, 0, cms->numareas * cms->numareas * sizeof( *cms->map_areaportals ) );
		CM_FloodAreaConnections( cms );
	}

	memset( cms->nullrow, 255, MAX_CM_LEAFS / 8 );

	Q_strncpyz( cms->map_name, name, sizeof( cms->map_name ) );

	return cms->map_cmodels;
}
Beispiel #9
0
static char *SV_ShortInfoString( void )
{
	static char string[MAX_STRING_SVCINFOSTRING];
	char hostname[64];
	char entry[20];
	size_t len;
	int i, count, bots;
	const char *password;

	bots = 0;
	count = 0;
	for( i = 0; i < sv_maxclients->integer; i++ )
	{
		if( svs.clients[i].state >= CS_CONNECTED )
		{
			if( svs.clients[i].edict->r.svflags & SVF_FAKECLIENT || svs.clients[i].tvclient )
				bots++;
			count++;
		}
	}

	//format:
	//" \377\377\377\377info\\n\\server_name\\m\\map name\\u\\clients/maxclients\\g\\gametype\\s\\skill\\EOT "

	Q_strncpyz( hostname, sv_hostname->string, sizeof( hostname ) );
	Q_snprintfz( string, sizeof( string ),
		"\\\\n\\\\%s\\\\m\\\\%8s\\\\u\\\\%2i/%2i\\\\",
		hostname,
		sv.mapname,
		count > 99 ? 99 : count,
		sv_maxclients->integer > 99 ? 99 : sv_maxclients->integer
		);

	len = strlen( string );
	Q_snprintfz( entry, sizeof( entry ), "g\\\\%6s\\\\", Cvar_String( "g_gametype" ) );
	if( MAX_SVCINFOSTRING_LEN - len > strlen( entry ) )
	{
		Q_strncatz( string, entry, sizeof( string ) );
		len = strlen( string );
	}

	if( Q_stricmp( FS_GameDirectory(), FS_BaseGameDirectory() ) )
	{
		Q_snprintfz( entry, sizeof( entry ), "mo\\\\%8s\\\\", FS_GameDirectory() );
		if( MAX_SVCINFOSTRING_LEN - len > strlen( entry ) )
		{
			Q_strncatz( string, entry, sizeof( string ) );
			len = strlen( string );
		}
	}

	if( Cvar_Value( "g_instagib" ) )
	{
		Q_snprintfz( entry, sizeof( entry ), "ig\\\\1\\\\" );
		if( MAX_SVCINFOSTRING_LEN - len > strlen( entry ) )
		{
			Q_strncatz( string, entry, sizeof( string ) );
			len = strlen( string );
		}
	}


	Q_snprintfz( entry, sizeof( entry ), "s\\\\%1d\\\\", sv_skilllevel->integer );
	if( MAX_SVCINFOSTRING_LEN - len > strlen( entry ) )
	{
		Q_strncatz( string, entry, sizeof( string ) );
		len = strlen( string );
	}

	password = Cvar_String( "password" );
	if( password[0] != '\0' )
	{
		Q_snprintfz( entry, sizeof( entry ), "p\\\\1\\\\" );
		if( MAX_SVCINFOSTRING_LEN - len > strlen( entry ) )
		{
			Q_strncatz( string, entry, sizeof( string ) );
			len = strlen( string );
		}
	}

	if( bots )
	{
		Q_snprintfz( entry, sizeof( entry ), "b\\\\%2i\\\\", bots > 99 ? 99 : bots );
		if( MAX_SVCINFOSTRING_LEN - len > strlen( entry ) )
		{
			Q_strncatz( string, entry, sizeof( string ) );
			len = strlen( string );
		}
	}

	if( SV_MM_Initialized() )
	{
		Q_snprintfz( entry, sizeof( entry ), "mm\\\\1\\\\" );
		if( MAX_SVCINFOSTRING_LEN - len > strlen( entry ) )
		{
			Q_strncatz( string, entry, sizeof( string ) );
			len = strlen( string );
		}
	}

	if( Cvar_Value( "g_race_gametype" ) )
	{
		Q_snprintfz( entry, sizeof( entry ), "r\\\\1\\\\" );
		if( MAX_SVCINFOSTRING_LEN - len > strlen( entry ) )
		{
			Q_strncatz( string, entry, sizeof( string ) );
			len = strlen( string );
		}
	}

	// finish it
	Q_strncatz( string, "EOT", sizeof( string ) );
	return string;
}
Beispiel #10
0
// Take over the user controls and track a player.
// We find a nice position to watch the player and move there
void Cam_Track(usercmd_t *cmd) 
{
	player_state_t *player, *self;
	frame_t *frame;
	vec3_t vec;

	if (!cl.spectator)
	{
		return;
	}

	// hack: save +movedown command
	cmddown = cmd->upmove < 0;

	// cl_hightrack 
	if (cl_hightrack.value && !locked)
	{
		Cam_CheckHighTarget(); 
	}
	
	if (!autocam || cls.state != ca_active)
	{
		return;
	}

	if (locked && (!cl.players[spec_track].name[0] || cl.players[spec_track].spectator)) 
	{
		locked = false;

		// cl_hightrack 
		if (cl_hightrack.value)
		{
			Cam_CheckHighTarget();
		}
		else 
		{
			Cam_Unlock();
		}
		return;
	}

	frame = &cl.frames[cl.validsequence & UPDATE_MASK];

	if (autocam && cls.mvdplayback)	
	{
		if (ideal_track != spec_track && cls.realtime - last_lock > 0.1 && 
			frame->playerstate[ideal_track].messagenum == cl.parsecount)
		{
			Cam_Lock(ideal_track);
		}

		if (frame->playerstate[spec_track].messagenum != cl.parsecount)	
		{
			int i;

			for (i = 0; i < MAX_CLIENTS; i++) 
			{
				if (frame->playerstate[i].messagenum == cl.parsecount)
					break;
			}

			if (i < MAX_CLIENTS)
			{
				Cam_Lock(i);
			}
		}
	}

	player = frame->playerstate + spec_track;
	self = frame->playerstate + cl.playernum;

	if (!locked || !Cam_IsVisible(player, desired_position))
	{
		if (!locked || cls.realtime - cam_lastviewtime > 0.1) 
		{
			if (!InitFlyby(self, player, true))
				InitFlyby(self, player, false);
			cam_lastviewtime = cls.realtime;
		}
	} 
	else 
	{
		cam_lastviewtime = cls.realtime;
	}
	
	// couldn't track for some reason
	if (!locked || !autocam)
		return;

	if (cl_chasecam.value) 
	{
		cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;

		#ifdef JSS_CAM
		if (!Cvar_Value ("cam_thirdperson"))
		#endif
		{
			VectorCopy(player->viewangles, cl.viewangles);
		}
		VectorCopy(player->origin, desired_position);
		if (memcmp(&desired_position, &self->origin, sizeof(desired_position)) != 0) {
			MSG_WriteByte (&cls.netchan.message, clc_tmove);
			MSG_WriteCoord (&cls.netchan.message, desired_position[0]);
			MSG_WriteCoord (&cls.netchan.message, desired_position[1]);
			MSG_WriteCoord (&cls.netchan.message, desired_position[2]);
			// move there locally immediately
			VectorCopy(desired_position, self->origin);
		}
	} 
	else 
	{
		// Ok, move to our desired position and set our angles to view
		// the player
		VectorSubtract(desired_position, self->origin, vec);
		cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;
		if (VectorLength(vec) > 16) 
		{ 
			// close enough?
			MSG_WriteByte (&cls.netchan.message, clc_tmove);
			MSG_WriteCoord (&cls.netchan.message, desired_position[0]);
			MSG_WriteCoord (&cls.netchan.message, desired_position[1]);
			MSG_WriteCoord (&cls.netchan.message, desired_position[2]);
		}

		// move there locally immediately
		VectorCopy(desired_position, self->origin);
										 
		VectorSubtract(player->origin, desired_position, vec);
		vectoangles(vec, cl.viewangles);
		cl.viewangles[0] = -cl.viewangles[0];
	}
}
Beispiel #11
0
static qbool Cam_FirstPersonMode(void) {
	return cl_chasecam.value && !Cvar_Value("cam_thirdperson") && !Cvar_Value("cl_camera_tpp");
}
Beispiel #12
0
// Send the intended movement message to the server.
void CL_BaseMove (usercmd_t *cmd)
{
	CL_AdjustAngles ();

	memset (cmd, 0, sizeof(*cmd));

	VectorCopy (cl.viewangles, cmd->angles);

	if (cl_iDrive.integer)
	{
		float s1, s2;

		if (in_strafe.state & 1)
		{
			s1 = CL_KeyState (&in_right, false);
			s2 = CL_KeyState (&in_left, false);

			if (s1 && s2)
			{
				if (in_right.downtime > in_left.downtime)
					s2 = 0;
				if (in_right.downtime < in_left.downtime)
					s1 = 0;
			}

			cmd->sidemove += cl_sidespeed.value * s1;
			cmd->sidemove -= cl_sidespeed.value * s2;
		}

		s1 = CL_KeyState (&in_moveright, false);
		s2 = CL_KeyState (&in_moveleft, false);

		if (s1 && s2)
		{
			if (in_moveright.downtime > in_moveleft.downtime)
				s2 = 0;
			if (in_moveright.downtime < in_moveleft.downtime)
				s1 = 0;
		}

		cmd->sidemove += cl_sidespeed.value * s1;
		cmd->sidemove -= cl_sidespeed.value * s2;

		s1 = CL_KeyState (&in_up, false);
		s2 = CL_KeyState (&in_down, false);

		if (s1 && s2)
		{
			if (in_up.downtime > in_down.downtime)
				s2 = 0;
			if (in_up.downtime < in_down.downtime)
				s1 = 0;
		}

		cmd->upmove += cl_upspeed.value * s1;
		cmd->upmove -= cl_upspeed.value * s2;

		if (!(in_klook.state & 1))
		{
			s1 = CL_KeyState (&in_forward, false);
			s2 = CL_KeyState (&in_back, false);

			if (s1 && s2)
			{
				if (in_forward.downtime > in_back.downtime)
					s2 = 0;
				if (in_forward.downtime < in_back.downtime)
					s1 = 0;
			}

			cmd->forwardmove += cl_forwardspeed.value * s1;
			cmd->forwardmove -= cl_backspeed.value * s2;
		}
	}
	else
	{
		if (in_strafe.state & 1)
		{
			cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right, false);
			cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left, false);
		}

		cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright, false);
		cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft, false);

		cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up, false);
		cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down, false);

		if (!(in_klook.state & 1))
		{
			cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward, false);
			cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back, false);
		}
	}

	// adjust for speed key
	if (in_speed.state & 1)
	{
		cmd->forwardmove *= cl_movespeedkey.value;
		cmd->sidemove *= cl_movespeedkey.value;
		cmd->upmove *= cl_movespeedkey.value;
	}

	#ifdef JSS_CAM
	{
		static float zoomspeed = 0;

		if ((cls.demoplayback || cl.spectator) && Cvar_Value("cam_thirdperson") && !Cvar_Value("cam_lockpos"))
		{
			zoomspeed -= CL_KeyState(&in_forward, false) * cls.trueframetime * cam_zoomaccel.value;
			zoomspeed += CL_KeyState(&in_back, false) * cls.trueframetime * cam_zoomaccel.value;
			if (!CL_KeyState(&in_forward, false) && !CL_KeyState(&in_back, false))
			{
				if (zoomspeed > 0)
				{
					zoomspeed -= cls.trueframetime * cam_zoomaccel.value;
					if (zoomspeed < 0)
						zoomspeed = 0;
				}
				else if (zoomspeed < 0)
				{
					zoomspeed += cls.trueframetime * cam_zoomaccel.value;
					if (zoomspeed > 0)
						zoomspeed = 0;
				}
			}
			zoomspeed = bound (-cam_zoomspeed.value, zoomspeed, cam_zoomspeed.value);

			if (zoomspeed)
			{
				float dist = Cvar_Value("cam_dist");

				dist += cls.trueframetime * zoomspeed;
				if (dist < 0)
					dist = 0;
				Cvar_SetValue (Cvar_Find("cam_dist"),  dist);
			}
		}
	}
	#endif // JSS_CAM
}
Beispiel #13
0
void PR_LoadProgs (void)
{
	int	i;
	char num[32];
	char name[MAX_OSPATH];
	int filesize;

	// flush the non-C variable lookup cache
	for (i = 0; i < GEFV_CACHESIZE; i++)
		gefvCache[i].field[0] = 0;

	// clear pr_newstrtbl
	PF_clear_strtbl();

	snprintf(name, sizeof(name), "%s.dat", sv_progsname.string);
	progs = (dprograms_t *)FS_LoadHunkFile (name, &filesize);
	if (!progs)
		progs = (dprograms_t *)FS_LoadHunkFile ("qwprogs.dat", &filesize);
	if (!progs)
		progs = (dprograms_t *)FS_LoadHunkFile ("spprogs.dat", &filesize);
#ifdef WITH_NQPROGS
	pr_nqprogs = false;
	if (!progs || Cvar_Value("sv_forcenqprogs")) {
		progs = (dprograms_t *)FS_LoadHunkFile ("progs.dat", &filesize);
		if (progs)
			pr_nqprogs = true;
	}
#endif
	if (!progs)
		SV_Error ("PR_LoadProgs: couldn't load progs.dat");
	Con_DPrintf ("Programs occupy %iK.\n", filesize/1024);

	// add prog crc to the serverinfo
	snprintf (num, sizeof(num), "%i", CRC_Block ((byte *)progs, filesize));
#ifdef USE_PR2
	Info_SetStar( &_localinfo_, "*qvm", "DAT" );
	//	Info_SetValueForStarKey (svs.info, "*qvm", "DAT", MAX_SERVERINFO_STRING);
#endif
	Info_SetValueForStarKey (svs.info, "*progs", num, MAX_SERVERINFO_STRING);

	// byte swap the header
	for (i = 0; i < (int) sizeof(*progs) / 4 ; i++)
		((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );

	if (progs->version != PROG_VERSION)
		SV_Error ("qwprogs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
	if (progs->crc != (pr_nqprogs ? NQ_PROGHEADER_CRC : PROGHEADER_CRC))
		SV_Error ("You must have the qwprogs.dat from QuakeWorld installed");

	pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
	pr_strings = (char *)progs + progs->ofs_strings;
	pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
	pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
	pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);

	num_prstr = 0;

	pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);
	pr_globals = (float *)pr_global_struct;

	pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);

	// byte swap the lumps
	for (i = 0; i < progs->numstatements; i++)
	{
		pr_statements[i].op = LittleShort(pr_statements[i].op);
		pr_statements[i].a = LittleShort(pr_statements[i].a);
		pr_statements[i].b = LittleShort(pr_statements[i].b);
		pr_statements[i].c = LittleShort(pr_statements[i].c);
	}

	for (i = 0; i < progs->numfunctions; i++)
	{
		pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement);
		pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start);
		pr_functions[i].s_name = LittleLong (pr_functions[i].s_name);
		pr_functions[i].s_file = LittleLong (pr_functions[i].s_file);
		pr_functions[i].numparms = LittleLong (pr_functions[i].numparms);
		pr_functions[i].locals = LittleLong (pr_functions[i].locals);
	}

	for (i = 0; i < progs->numglobaldefs; i++)
	{
		pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);
		pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);
		pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
	}

	for (i = 0; i < progs->numfielddefs; i++)
	{
		pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type);
		if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
			SV_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
		pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);
		pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);
	}

	for (i = 0; i < progs->numglobals; i++)
		((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);

#ifdef WITH_NQPROGS
	PR_InitPatchTables();
#endif

	// find optional QC-exported functions
	SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect");
	SpectatorThink = ED_FindFunctionOffset ("SpectatorThink");
	SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect");
	ChatMessage = ED_FindFunctionOffset ("ChatMessage");
	UserInfo_Changed = ED_FindFunctionOffset ("UserInfo_Changed");
	mod_ConsoleCmd = ED_FindFunctionOffset ("ConsoleCmd");
	mod_UserCmd = ED_FindFunctionOffset ("UserCmd");
	localinfoChanged = ED_FindFunctionOffset ("localinfoChanged");
	GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand");
	GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic");
	GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause");

	CheckKTPro ();
}
Beispiel #14
0
/**
 * Responds to a Steam server query.
 *
 * @param s       query string
 * @param socket  response socket
 * @param address response address
 * @param inmsg   message for arguments
 * @return whether the request was handled as a Steam query
 */
bool SV_SteamServerQuery( const char *s, const socket_t *socket, const netadr_t *address, msg_t *inmsg )
{
#if APP_STEAMID
	if( sv.state < ss_loading || sv.state > ss_game )
		return false; // server not running

	if( ( !sv_public->integer && !NET_IsLANAddress( address ) ) || ( sv_maxclients->integer == 1 ) )
		return false;

	if( !strcmp( s, "i" ) )
	{
		// ping
		const char pingResponse[] = "j00000000000000";
		Netchan_OutOfBand( socket, address, sizeof( pingResponse ), ( const uint8_t * )pingResponse );
		return true;
	}

	if( !strcmp( s, "W" ) || !strcmp( s, "U\xFF\xFF\xFF\xFF" ) )
	{
		// challenge - security feature, but since we don't send multiple packets always return 0
		const uint8_t challengeResponse[] = { 'A', 0, 0, 0, 0 };
		Netchan_OutOfBand( socket, address, sizeof( challengeResponse ), ( const uint8_t * )challengeResponse );
		return true;
	}

	if( !strcmp( s, "TSource Engine Query" ) )
	{
		// server info
		char hostname[MAX_INFO_VALUE];
		char gamedir[MAX_QPATH];
		char gamename[128];
		char version[32];
		char tags[MAX_STEAMQUERY_TAG_STRING];
		int i, players = 0, bots = 0, maxclients = 0;
		int flags = 0x80 | 0x01; // game port | game ID containing app ID
		client_t *cl;
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Info Packet %s\n", NET_AddressToString( address ) );

		Q_strncpyz( hostname, COM_RemoveColorTokens( sv_hostname->string ), sizeof( hostname ) );
		if( !hostname[0] )
			Q_strncpyz( hostname, sv_hostname->dvalue, sizeof( hostname ) );
		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );

		Q_strncpyz( gamename, APPLICATION, sizeof( gamename ) );
		if( Cvar_Value( "g_instagib" ) )
			Q_strncatz( gamename, " IG", sizeof( gamename ) );
		if( sv.configstrings[CS_GAMETYPETITLE][0] || sv.configstrings[CS_GAMETYPENAME][0] )
		{
			Q_strncatz( gamename, " ", sizeof( gamename ) );
			Q_strncatz( gamename,
				sv.configstrings[sv.configstrings[CS_GAMETYPETITLE][0] ? CS_GAMETYPETITLE : CS_GAMETYPENAME],
				sizeof( gamename ) );
		}

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( cl->state >= CS_CONNECTED )
			{
				if( cl->tvclient ) // exclude TV from the max players count
					continue;
				if( cl->edict->r.svflags & SVF_FAKECLIENT )
					bots++;
				players++;
			}
			maxclients++;
		}

		Q_snprintfz( version, sizeof( version ), "%i.%i.0.0", APP_VERSION_MAJOR, APP_VERSION_MINOR );

		SV_GetSteamTags( tags );
		if( tags[0] )
			flags |= 0x20;

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'I' );
		MSG_WriteByte( &msg, APP_PROTOCOL_VERSION );
		MSG_WriteString( &msg, hostname );
		MSG_WriteString( &msg, sv.mapname );
		MSG_WriteString( &msg, gamedir );
		MSG_WriteString( &msg, gamename );
		MSG_WriteShort( &msg, 0 ); // app ID specified later
		MSG_WriteByte( &msg, min( players, 99 ) );
		MSG_WriteByte( &msg, min( maxclients, 99 ) );
		MSG_WriteByte( &msg, min( bots, 99 ) );
		MSG_WriteByte( &msg, ( dedicated && dedicated->integer ) ? 'd' : 'l' );
		MSG_WriteByte( &msg, STEAMQUERY_OS );
		MSG_WriteByte( &msg, Cvar_String( "password" )[0] ? 1 : 0 );
		MSG_WriteByte( &msg, 0 ); // VAC insecure
		MSG_WriteString( &msg, version );
		MSG_WriteByte( &msg, flags );
		// port
		MSG_WriteShort( &msg, sv_port->integer );
		// tags
		if( flags & 0x20 )
			MSG_WriteString( &msg, tags );
		// 64-bit game ID - needed to specify app ID
		MSG_WriteLong( &msg, APP_STEAMID & 0xffffff );
		MSG_WriteLong( &msg, 0 );
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( s[0] == 'U' )
	{
		// players
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];
		int i, players = 0;
		client_t *cl;
		char name[MAX_NAME_BYTES];
		unsigned int time = Sys_Milliseconds();

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Players Packet %s\n", NET_AddressToString( address ) );

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'D' );
		MSG_WriteByte( &msg, 0 );

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( ( cl->state < CS_CONNECTED ) || cl->tvclient )
				continue;

			Q_strncpyz( name, COM_RemoveColorTokens( cl->name ), sizeof( name ) );
			if( ( msg.cursize + 10 + strlen( name ) ) > sizeof( msgbuf ) )
				break;

			MSG_WriteByte( &msg, i );
			MSG_WriteString( &msg, name );
			MSG_WriteLong( &msg, cl->edict->r.client->r.frags );
			MSG_WriteFloat( &msg, ( float )( time - cl->lastconnect ) * 0.001f );

			players++;
			if( players == 99 )
				break;
		}

		msgbuf[1] = players;
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( !strcmp( s, "s" ) )
	{
		// master server query, terminated by \n, followed by the challenge
		int i;
		bool fromMaster = false;
		int challenge;
		char gamedir[MAX_QPATH], basedir[MAX_QPATH], tags[MAX_STEAMQUERY_TAG_STRING];
		int players = 0, bots = 0, maxclients = 0;
		client_t *cl;
		char msg[MAX_STEAMQUERY_PACKETLEN];

		for( i = 0; i < MAX_MASTERS; i++ )
		{
			if( sv_masters[i].steam && NET_CompareAddress( address, &sv_masters[i].address ) )
			{
				fromMaster = true;
				break;
			}
		}
		if( !fromMaster )
			return true;

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Master Server Info Packet %s\n", NET_AddressToString( address ) );

		challenge = MSG_ReadLong( inmsg );

		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );
		Q_strncpyz( basedir, FS_BaseGameDirectory(), sizeof( basedir ) );
		SV_GetSteamTags( tags );

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( cl->state >= CS_CONNECTED )
			{
				if( cl->tvclient ) // exclude TV from the max players count
					continue;
				if( cl->edict->r.svflags & SVF_FAKECLIENT )
					bots++;
				players++;
			}
			maxclients++;
		}

		Q_snprintfz( msg, sizeof( msg ),
			"0\n\\protocol\\7\\challenge\\%i" // protocol must be 7 to match Source
			"\\players\\%i\\max\\%i\\bots\\%i"
			"\\gamedir\\%s\\map\\%s"
			"\\password\\%i\\os\\%c"
			"\\lan\\%i\\region\\255"
			"%s%s"
			"\\type\\%c\\secure\\0"
			"\\version\\%i.%i.0.0"
			"\\product\\%s\n",
			challenge,
			min( players, 99 ), min( maxclients, 99 ), min( bots, 99 ),
			gamedir, sv.mapname,
			Cvar_String( "password" )[0] ? 1 : 0, STEAMQUERY_OS,
			sv_public->integer ? 0 : 1,
			tags[0] ? "\\gametype\\" /* legacy - "gametype", not "tags" */ : "", tags,
			( dedicated && dedicated->integer ) ? 'd' : 'l',
			APP_VERSION_MAJOR, APP_VERSION_MINOR,
			basedir );
		NET_SendPacket( socket, ( const uint8_t * )msg, strlen( msg ), address );

		return true;
	}

	if( s[0] == 'O' )
	{
		// out of date message
		static bool printed = false;
		if( !printed )
		{
			int i;
			for( i = 0; i < MAX_MASTERS; i++ )
			{
				if( sv_masters[i].steam && NET_CompareAddress( address, &sv_masters[i].address ) )
				{
					Com_Printf( "Server is out of date and cannot be added to the Steam master servers.\n" );
					printed = true;
					return true;
				}
			}
		}
		return true;
	}
#endif

	return false;
}
Beispiel #15
0
static void HandleEvents( void )
{
	XEvent event;
	qboolean dowarp = qfalse, was_focused = focus;
	int mwx = x11display.win_width / 2;
	int mwy = x11display.win_height / 2;
	char *p;
	int key = 0;
	int time = 0;

	assert( x11display.dpy && x11display.win );

#ifdef WSW_EVDEV
	if( mouse_active && m_evdev_num )
	{
		evdev_read();
	}
	else
#endif
		if( mouse_active && !dgamouse )
		{
			int root_x, root_y, win_x, win_y;
			unsigned int mask;
			Window root, child;

			if( XQueryPointer( x11display.dpy, x11display.win, &root, &child,
				&root_x, &root_y, &win_x, &win_y, &mask ) )
			{
				mx += ( (int)win_x - mwx );
				my += ( (int)win_y - mwy );
				mwx = win_x;
				mwy = win_y;

				if( mx || my )
					dowarp = qtrue;

				if( ignore_one )
				{
					mx = my = 0;
					ignore_one = qfalse;
				}
			}
		}


		while( XPending( x11display.dpy ) )
		{
			XNextEvent( x11display.dpy, &event );

			switch( event.type )
			{
			case KeyPress:
				time = Sys_XTimeToSysTime(event.xkey.time);
				p = XLateKey( &event.xkey, &key );
				if( key )
					Key_Event( key, qtrue, time );
				while ( p && *p )
				{
					qwchar wc = Q_GrabWCharFromUtf8String( (const char **)&p );
					Key_CharEvent( key, wc );
				}
				break;

			case KeyRelease:
				if( repeated_press( &event ) )
					break; // don't send release events when repeating

				time = Sys_XTimeToSysTime(event.xkey.time);
				XLateKey( &event.xkey, &key );
				Key_Event( key, event.type == KeyPress, time );
				break;

			case MotionNotify:
#ifdef WSW_EVDEV
				if( mouse_active && dgamouse && !m_evdev_num )
#else
				if( mouse_active && dgamouse )
#endif
				{
					mx += event.xmotion.x_root;
					my += event.xmotion.y_root;
					if( ignore_one )
					{
						mx = my = 0;
						ignore_one = qfalse;
					}
				}
				break;

			case ButtonPress:
				if( ( cls.key_dest == key_console ) && !in_grabinconsole->integer )
					break;
#ifdef WSW_EVDEV
				if( m_evdev_num )
					break;
#endif
				time = Sys_XTimeToSysTime(event.xkey.time);
				if( event.xbutton.button == 1 ) Key_MouseEvent( K_MOUSE1, 1, time );
				else if( event.xbutton.button == 2 ) Key_MouseEvent( K_MOUSE3, 1, time );
				else if( event.xbutton.button == 3 ) Key_MouseEvent( K_MOUSE2, 1, time );
				else if( event.xbutton.button == 4 ) Key_Event( K_MWHEELUP, 1, time );
				else if( event.xbutton.button == 5 ) Key_Event( K_MWHEELDOWN, 1, time );
				else if( event.xbutton.button >= 6 && event.xbutton.button <= 10 ) Key_MouseEvent( K_MOUSE4+event.xbutton.button-6, 1, time );
				break;

			case ButtonRelease:
				if( ( cls.key_dest == key_console ) && !in_grabinconsole->integer )
					break;
#ifdef WSW_EVDEV
				if( m_evdev_num )
					break;
#endif
				time = Sys_XTimeToSysTime(event.xkey.time);
				if( event.xbutton.button == 1 ) Key_MouseEvent( K_MOUSE1, 0, time );
				else if( event.xbutton.button == 2 ) Key_MouseEvent( K_MOUSE3, 0, time );
				else if( event.xbutton.button == 3 ) Key_MouseEvent( K_MOUSE2, 0, time );
				else if( event.xbutton.button == 4 ) Key_Event( K_MWHEELUP, 0, time );
				else if( event.xbutton.button == 5 ) Key_Event( K_MWHEELDOWN, 0, time );
				else if( event.xbutton.button >= 6 && event.xbutton.button <= 10 ) Key_MouseEvent( K_MOUSE4+event.xbutton.button-6, 0, time );
				break;

			case FocusIn:
				if( x11display.ic )
					XSetICFocus(x11display.ic);
				if( !focus )
				{
					focus = qtrue;
				}
				break;

			case FocusOut:
				if( x11display.ic )
					XUnsetICFocus(x11display.ic);
				if( focus )
				{
					Key_ClearStates();
					focus = qfalse;
				}
				break;

			case ClientMessage:
				if( event.xclient.data.l[0] == x11display.wmDeleteWindow )
					Cbuf_ExecuteText( EXEC_NOW, "quit" );
				break;

			case MapNotify:
				mapped = qtrue;
				if( x11display.modeset )
				{
					if ( x11display.dpy && x11display.win )
					{
						XSetInputFocus( x11display.dpy, x11display.win, RevertToPointerRoot, CurrentTime );
						x11display.modeset = qfalse;
					}
				}
				if( input_active )
				{
					uninstall_grabs();
					install_grabs();
				}
				break;

			case ConfigureNotify:
				VID_AppActivate( qtrue, qfalse );
				break;

			case PropertyNotify:
				if( event.xproperty.window == x11display.win )
				{
					if ( event.xproperty.atom == x11display.wmState )
					{
						qboolean was_minimized = minimized;

						_X11_CheckWMSTATE();

						if( minimized != was_minimized )
						{
							// FIXME: find a better place for this?..
							CL_SoundModule_Activate( !minimized );
						}
					}
				}
				break;
			}
		}

		if( dowarp )
		{
			XWarpPointer( x11display.dpy, None, x11display.win, 0, 0, 0, 0,
				x11display.win_width/2, x11display.win_height/2 );
		}

		// set fullscreen or windowed mode upon focus in/out events if:
		//  a) lost focus in fullscreen -> windowed
		//  b) received focus -> fullscreen if a)
		if( ( focus != was_focused ) )
		{
			if( x11display.features.wmStateFullscreen )
			{
				if( !focus && Cvar_Value( "vid_fullscreen" ) )
				{
					go_fullscreen_on_focus = qtrue;
					Cbuf_ExecuteText( EXEC_APPEND, "vid_fullscreen 0\n" );
				}
				else if( focus && go_fullscreen_on_focus )
				{
					go_fullscreen_on_focus = qfalse;
					Cbuf_ExecuteText( EXEC_APPEND, "vid_fullscreen 1\n" );
				}
			}
		}
}
Beispiel #16
0
static void HandleEvents( void )
{
	XEvent event, response;
	XSelectionRequestEvent* request;

	assert( x11display.dpy && x11display.win );

	while( XPending( x11display.dpy ) )
	{
		XGenericEventCookie *cookie = &event.xcookie;
		XNextEvent( x11display.dpy, &event );

		if( cookie->type == GenericEvent && cookie->extension == xi_opcode 
			&& XGetEventData( x11display.dpy, cookie ) ) {
				handle_cookie( cookie );
				XFreeEventData( x11display.dpy, cookie );
				continue;
		}

		switch( event.type )
		{
		case FocusIn:
			if( event.xfocus.mode == NotifyGrab || event.xfocus.mode == NotifyUngrab ) {
				// Someone is handling a global hotkey, ignore it
				continue;
			}
			if( !focus )
			{
				focus = qtrue;
				install_grabs_keyboard();
			}
			break;

		case FocusOut:
			if( event.xfocus.mode == NotifyGrab || event.xfocus.mode == NotifyUngrab ) {
				// Someone is handling a global hotkey, ignore it
				continue;
			}
			if( focus )
			{
				if( Cvar_Value( "vid_fullscreen" ) ) {
					Cbuf_ExecuteText( EXEC_APPEND, "set vid_fullscreen 0\n" );
				}
				uninstall_grabs_keyboard();
				Key_ClearStates();
				focus = qfalse;
				shift_level = 0;
			}
			break;

		case ClientMessage:
			if( event.xclient.data.l[0] == x11display.wmDeleteWindow )
				Cbuf_ExecuteText( EXEC_NOW, "quit" );
			break;

		case ConfigureNotify:
			VID_AppActivate( qtrue, qfalse );
			break;

		case PropertyNotify:
			if( event.xproperty.window == x11display.win )
			{
				if ( event.xproperty.atom == x11display.wmState )
				{
					qboolean was_minimized = minimized;

					_X11_CheckWMSTATE();

					if( minimized != was_minimized )
					{
						// FIXME: find a better place for this?..
						CL_SoundModule_Activate( !minimized );
					}
				}
			}
			break;

		case SelectionClear:
			// Another app took clipboard ownership away
			// There's not actually anything we need to do here
			break;

		case SelectionRequest:
			// Another app is requesting clipboard information
			request = &event.xselectionrequest;

			memset( &response, 0, sizeof( response ) );
			response.xselection.type = SelectionNotify;
			response.xselection.display = request->display;
			response.xselection.requestor = request->requestor;
			response.xselection.selection = request->selection;
			response.xselection.target = request->target;
			response.xselection.time = request->time;
			response.xselection.property = Sys_ClipboardProperty( request );

			// Send the response
			XSendEvent( x11display.dpy, request->requestor, 0, 0, &response );
			break;
		}
	}
}
Beispiel #17
0
static qboolean Cvar_CheatsAllowed()
{
	return ( Com_ClientState() < CA_CONNECTED ) ||          // not connected
		Com_DemoPlaying() ||                             // playing demo
		( Com_ServerState() && Cvar_Value( "sv_cheats" ) ); // local server, sv_cheats
}
Beispiel #18
0
/*
===============
PR_LoadProgs
===============
*/
void PR_LoadProgs (void)
{
	int	i;
	char	num[32];
	static int lumpsize[6] = { sizeof(dstatement_t), sizeof(ddef_t),
		sizeof(ddef_t), sizeof(dfunction_t), 4, 4 };
	int	filesize = 0;
	const char	*progsname;

	progs = NULL;

	// decide whether to load qwprogs.dat, progs.dat or spprogs.dat

#ifdef WITH_NQPROGS
	if (Cvar_Value("sv_forcenqprogs"))
		goto use_progs;
#endif

	if (!deathmatch.value)
	{
		if (Q_stricmp(com_gamedirfile, "qw") && 
			strcmp(com_gamedirfile, ""))
		{
			// if we're using a custom mod, anything
			// in gamedir is preferred to stock *progs.dat
			qbool check;
			check = FS_FindFile ("spprogs.dat");
			if (check && file_from_gamedir)
				goto use_spprogs;
#ifdef WITH_NQPROGS
			check = FS_FindFile ("progs.dat");
			if (check && file_from_gamedir)
				goto use_progs;
#endif
			check = FS_FindFile ("qwprogs.dat");
			if (check && file_from_gamedir)
				goto use_qwprogs;
		}

use_spprogs:
		progs = (dprograms_t *) FS_LoadHunkFile ("spprogs.dat");
		progsname = "spprogs.dat";
		pr_nqprogs = false;

		if (!progs) {
#ifdef WITH_NQPROGS
use_progs:
			progs = (dprograms_t *)FS_LoadHunkFile ("progs.dat");
			progsname = "progs.dat";
			pr_nqprogs = true;
		}
#endif
		if (!progs) {
use_qwprogs:
			progs = (dprograms_t *)FS_LoadHunkFile ("qwprogs.dat");
			progsname = "qwprogs.dat";
			pr_nqprogs = false;
		}
	}
	else	// deathmatch
	{
		if (Q_stricmp(com_gamedirfile, "qw") && 
			strcmp(com_gamedirfile, ""))
		{
			qbool check;
			check = FS_FindFile ("qwprogs.dat");
			if (check && file_from_gamedir)
				goto dm_use_qwprogs;
#ifdef WITH_NQPROGS
			check = FS_FindFile ("progs.dat");
			if (check && file_from_gamedir)
				goto dm_use_progs;
#endif
		}

dm_use_qwprogs:
		progs = (dprograms_t *) FS_LoadHunkFile ("qwprogs.dat");
		progsname = "qwprogs.dat";
		pr_nqprogs = false;

		if (!progs) {
#ifdef WITH_NQPROGS
dm_use_progs:
			progs = (dprograms_t *)FS_LoadHunkFile ("progs.dat");
			progsname = "progs.dat";
			pr_nqprogs = true;
		}
#endif
	}

	if (!progs)
		Host_Error ("PR_LoadProgs: couldn't load progs.dat");

	filesize = fs_filesize;

	if (filesize < (int)sizeof(*progs))
		Host_Error("%s is corrupt", progsname);

	Com_DPrintf ("Using %s (%i bytes).\n", progsname, filesize);

// add prog crc to the serverinfo
	sprintf (num, "%i", CRC_Block ((byte *)progs, filesize));
	svs.info.set("*progs", num);

// byte swap the header
	for (i = 0; i < sizeof(*progs)/4; i++)
		((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );		

	if (progs->version != PROG_VERSION)
		Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
	if (progs->crc != (pr_nqprogs ? NQ_PROGHEADER_CRC : PROGHEADER_CRC))
		Host_Error ("You must have the qwprogs.dat from QuakeWorld installed");

// check lump offsets and sizes
	for (i = 0; i < 6; i ++) {
		if (((int *)progs)[i*2 + 2] < sizeof(*progs)
			|| ((int *)progs)[i*2 + 2] + ((int *)progs)[i*2 + 3]*lumpsize[i] > filesize)
		Host_Error("progs.dat is corrupt");
	}

	pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
	pr_strings = (char *)progs + progs->ofs_strings;
	pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
	pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
	pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
	pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);

	pr_globals = (float *)pr_global_struct;

	PR_InitStrings ();

	pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);
	
// byte swap the lumps
	for (i=0 ; i<progs->numstatements ; i++)
	{
		pr_statements[i].op = LittleShort(pr_statements[i].op);
		pr_statements[i].a = LittleShort(pr_statements[i].a);
		pr_statements[i].b = LittleShort(pr_statements[i].b);
		pr_statements[i].c = LittleShort(pr_statements[i].c);
	}

	for (i=0 ; i<progs->numfunctions; i++)
	{
	pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement);
	pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start);
	pr_functions[i].s_name = LittleLong (pr_functions[i].s_name);
	pr_functions[i].s_file = LittleLong (pr_functions[i].s_file);
	pr_functions[i].numparms = LittleLong (pr_functions[i].numparms);
	pr_functions[i].locals = LittleLong (pr_functions[i].locals);
	}	

	for (i=0 ; i<progs->numglobaldefs ; i++)
	{
		pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);
		pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);
		pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
	}

	for (i=0 ; i<progs->numfielddefs ; i++)
	{
		pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type);
		if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
			Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
		pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);
		pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);
	}


	for (i=0 ; i<progs->numglobals ; i++)
		((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);


#ifdef WITH_NQPROGS
	if (pr_nqprogs) {
		memcpy (pr_globaloffsetpatch, pr_globaloffsetpatch_nq, sizeof(pr_globaloffsetpatch));
		for (i = 0; i < 106; i++) {
			pr_fieldoffsetpatch[i] = (i < 8) ? i : (i < 25) ? i + 1 :
				(i < 28) ? i + (102 - 25) : (i < 73) ? i - 2 :
				(i < 74) ? i + (105 - 73) : (i < 105) ? i - 3 : /* (i == 105) */ 8;
		}

		for (i=0 ; i<progs->numfielddefs ; i++)
			pr_fielddefs[i].ofs = PR_FIELDOFS(pr_fielddefs[i].ofs);
	}
	else
	{
		memset (pr_globaloffsetpatch, 0, sizeof(pr_globaloffsetpatch));

		for (i = 0; i < 106; i++)
			pr_fieldoffsetpatch[i] = i;
	}
#endif

	// find optional QC-exported functions
	SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect");
	SpectatorThink = ED_FindFunctionOffset ("SpectatorThink");
	SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect");
	GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand");
	GE_ConsoleCommand = ED_FindFunctionOffset ("GE_ConsoleCommand");
	GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic");
	GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause");

	// find optional QC-exported fields
	fofs_maxspeed = ED_FindFieldOffset ("maxspeed");
	fofs_gravity = ED_FindFieldOffset ("gravity");
	fofs_items2 = ED_FindFieldOffset ("items2");
	fofs_movement = ED_FindFieldOffset ("movement");
	fofs_vw_index = ED_FindFieldOffset ("vw_index");
	for (i = 3; i < 8; i++)
		fofs_buttonX[i-3] = ED_FindFieldOffset(va("button%i", i));

	// reset stuff like ZQ_CLIENTCOMMAND, progs must enable it explicitly
	memset (&pr_ext_enabled, sizeof(pr_ext_enabled), 0);

	PR_Exec_Init ();
}