Esempio n. 1
0
/*
==================
Host_Demos_f

Return to looping demos
==================
*/
static void
Host_Demos_f(void)
{
    if (cls.state == ca_dedicated)
	return;
    if (cls.demonum == -1)
	cls.demonum = 1;
    CL_Disconnect_f();
    CL_NextDemo();
}
Esempio n. 2
0
static void Demo_Playlist_Start (int i)
{
	key_dest = key_game;
	m_state = m_none;
	demo_playlist_current_played = i;
	demo_playlist_started_test = 0 ;

	if (cls.demoplayback)
	{
		CL_Disconnect_f();
	}

	demo_playlist_started_test = 0 ;
	demo_playlist_started = true;
	strlcpy(track_name, demo_playlist[demo_playlist_current_played].trackname, sizeof(track_name));
	Cbuf_AddText (va("playdemo \"%s\"\n", demo_playlist[demo_playlist_current_played].path));
}
Esempio n. 3
0
/* <3617e> ../engine/host.c:201 */
NOXREF void Host_EndGame(const char *message, ...)
{
	int oldn;
	va_list argptr;
	char string[1024];

	va_start(argptr,message);
	Q_vsnprintf(string, sizeof(string), message, argptr);
	va_end(argptr);

	Con_DPrintf("Host_EndGame: %s\n", string);

	oldn = g_pcls.demonum;

	if (g_psv.active)
		Host_ShutdownServer(FALSE);

	g_pcls.demonum = oldn;

	if (!g_pcls.state)
	{
		Sys_Error("Host_EndGame: %s\n", string);
	}

	if (oldn != -1)
	{
		CL_Disconnect_f();
		g_pcls.demonum = oldn;
		Host_NextDemo();
		longjmp(host_enddemo, 1);
	}

	CL_Disconnect();
	Cbuf_AddText("cd stop\n");
	Cbuf_Execute();
	longjmp(host_abortserver, 1);
}
Esempio n. 4
0
/*
===============
Host_Loadgame_f
===============
*/
void Host_Loadgame_f (void)
{
	char	name[MAX_OSPATH];
	FILE	*f;
	char	mapname[MAX_QPATH];
	float	time, tfloat;
	char	str[32768];
	const char  *start;
	int	i, r;
	edict_t	*ent;
	int	entnum;
	int	version;
	float	spawn_parms[NUM_SPAWN_PARMS];

	if (cmd_source != src_command)
		return;

	if (Cmd_Argc() != 2)
	{
		Con_Printf ("load <savename> : load a game\n");
		return;
	}

	cls.demonum = -1;		// stop demo loop in case this fails

	q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1));
	COM_AddExtension (name, ".sav", sizeof(name));

// we can't call SCR_BeginLoadingPlaque, because too much stack space has
// been used.  The menu calls it before stuffing loadgame command
//	SCR_BeginLoadingPlaque ();

	Con_Printf ("Loading game from %s...\n", name);
	f = fopen (name, "r");
	if (!f)
	{
		Con_Printf ("ERROR: couldn't open.\n");
		return;
	}

	fscanf (f, "%i\n", &version);
	if (version != SAVEGAME_VERSION)
	{
		fclose (f);
		Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		return;
	}
	fscanf (f, "%s\n", str);
	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		fscanf (f, "%f\n", &spawn_parms[i]);
// this silliness is so we can load 1.06 save files, which have float skill values
	fscanf (f, "%f\n", &tfloat);
	current_skill = (int)(tfloat + 0.1);
	Cvar_SetValue ("skill", (float)current_skill);

	fscanf (f, "%s\n",mapname);
	fscanf (f, "%f\n",&time);

	CL_Disconnect_f ();

	SV_SpawnServer (mapname);

	if (!sv.active)
	{
		fclose (f);
		Con_Printf ("Couldn't load map\n");
		return;
	}
	sv.paused = true;		// pause until all clients connect
	sv.loadgame = true;

// load the light styles

	for (i = 0; i < MAX_LIGHTSTYLES; i++)
	{
		fscanf (f, "%s\n", str);
		sv.lightstyles[i] = (const char *)Hunk_Strdup (str, "lightstyles");
	}

// load the edicts out of the savegame file
	entnum = -1;		// -1 is the globals
	while (!feof(f))
	{
		qboolean inside_string = false;
		for (i = 0; i < (int) sizeof(str) - 1; i++)
		{
			r = fgetc (f);
			if (r == EOF || !r)
				break;
			str[i] = r;
			if (r == '"')
			{
				inside_string = !inside_string;
			}
			else if (r == '}' && !inside_string) // only handle } characters outside of quoted strings
			{
				i++;
				break;
			}
		}
		if (i == (int) sizeof(str) - 1)
		{
			fclose (f);
			Sys_Error ("Loadgame buffer overflow");
		}
		str[i] = 0;
		start = str;
		start = COM_Parse(str);
		if (!com_token[0])
			break;		// end of file
		if (strcmp(com_token,"{"))
		{
			fclose (f);
			Sys_Error ("First token isn't a brace");
		}

		if (entnum == -1)
		{	// parse the global vars
			ED_ParseGlobals (start);
		}
		else
		{	// parse an edict

			ent = EDICT_NUM(entnum);
			memset (&ent->v, 0, progs->entityfields * 4);
			ent->free = false;
			ED_ParseEdict (start, ent);

		// link it into the bsp tree
			if (!ent->free)
				SV_LinkEdict (ent, false);
		}

		entnum++;
	}

	sv.num_edicts = entnum;
	sv.time = time;

	fclose (f);

	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		svs.clients->spawn_parms[i] = spawn_parms[i];

	if (cls.state != ca_dedicated)
	{
		CL_EstablishConnection ("local");
		Host_Reconnect_f ();
	}
}
Esempio n. 5
0
/*
===============
Host_Loadgame_f
===============
*/
void Host_Loadgame_f (void)
{
	char	name[MAX_OSPATH], temp[MAX_OSPATH];
	vfsfile_t	*f;
	char	mapname[MAX_QPATH];
	float	time, tfloat;
	char	str[32768], *start, *c;
	int		i, r, len, n;
	edict_t	*ent;
	int		entnum;
	int		version;
	float			spawn_parms[NUM_SPAWN_PARMS];

	if (cmd_source != src_command)
		return;

	if (Cmd_Argc() != 2)
	{
		Con_Printf ("load <savename> : load a game\n");
		return;
	}

	cls.demonum = -1;		// stop demo loop in case this fails

//	sprintf (name, "%s", Cmd_Argv(1));
	strcpy (name, Cmd_Argv(1));
	COM_DefaultExtension (name, ".sav");
	
// we can't call SCR_BeginLoadingPlaque, because too much stack space has
// been used.  The menu calls it before stuffing loadgame command
//	SCR_BeginLoadingPlaque ();

	Con_Printf ("Loading game from %s...\n", name);
//	f = fopen (name, "r");
	f = FS_OpenVFS(name, "rb", FS_GAMEONLY);
	if (!f)
	{
		Con_Printf ("ERROR: couldn't open.\n");
		return;
	}

//	fscanf (f, "%i\n", &version);
	version = atoi(VFS_GETS(f, name, sizeof(name)));
	if (version != SAVEGAME_VERSION)
	{
//		fclose (f);
		Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		VFS_CLOSE (f);
		return;
	}
//	fscanf (f, "%s\n", str);
	VFS_GETS(f, str, sizeof(str));
	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
		spawn_parms[i] = atof(VFS_GETS(f, temp, sizeof(temp)));
//		fscanf (f, "%f\n", &spawn_parms[i]);
// this silliness is so we can load 1.06 save files, which have float skill values
//	fscanf (f, "%f\n", &tfloat);
	tfloat = atof(VFS_GETS(f, temp, sizeof(temp))); // temp buf
	current_skill = (int)(tfloat + 0.1);
	Cvar_SetValue ("skill", (float)current_skill);

#ifdef QUAKE2
	Cvar_SetValue ("deathmatch", 0);
	Cvar_SetValue ("coop", 0);
	Cvar_SetValue ("teamplay", 0);
#endif

//	fscanf (f, "%s\n",mapname);
//	fscanf (f, "%f\n",&time);
	VFS_GETS(f, mapname, sizeof(mapname));
	for (c = mapname+strlen(mapname)-1; c>=mapname && (*c == '\n' || *c == '\r'); *c--='\0');
	time = atof(VFS_GETS(f, temp, sizeof(temp)));

	CL_Disconnect_f ();
	
	allowcheats = sv_cheats.value != 0; // sv_cheats

	// if the video isn't initialized already, it needs to be
	Host_InitVideo();

#ifdef QUAKE2
	SV_SpawnServer (mapname, NULL);
#else
	SV_SpawnServer (mapname);
#endif
	if (!sv.active)
	{
		Con_Printf ("Couldn't load map\n");
		VFS_CLOSE (f);
		return;
	}
	sv.paused = true;		// pause until all clients connect
	sv.loadgame = true;

// load the light styles

	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
//		fscanf (f, "%s\n", str);
		VFS_GETS(f, str, sizeof(str));
//		sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1); // this is no longer necessary, changed to straight array
		for (c = str+strlen(str)-1; c>=str && (*c == '\n' || *c == '\r'); *c--='\0');
		strcpy (sv.lightstyles[i], str);
	}

// load the edicts out of the savegame file
	entnum = -1;		// -1 is the globals
	len = VFS_GETLEN(f);
	n = 0;
//	while (!feof(f))
	for(;;)
	{
		for (i=0 ; i<sizeof(str)-1 ; i++)
		{
//			r = fgetc (f);
			r = VFS_GETC(f);
			if (r == -1 || !r)
				break;
			str[i] = r;
			if (r == '}')
			{
				i++;
				break;
			}
		}
		if (r == -1 || !r)
			break;
		if (i == sizeof(str)-1)
			Sys_Error ("Loadgame buffer overflow");
		str[i] = 0;
		start = str;
		start = COM_Parse(str);
		if (!com_token[0])
			break;		// end of file
		if (strcmp(com_token,"{"))
			Sys_Error ("First token isn't a brace");
			
		if (entnum == -1)
		{	// parse the global vars
			ED_ParseGlobals (start);
		}
		else
		{	// parse an edict

			ent = EDICT_NUM(entnum);
			memset (&ent->v, 0, progs->entityfields * 4);
			ent->free = false;
			ED_ParseEdict (start, ent);
	
		// link it into the bsp tree
			if (!ent->free)
				SV_LinkEdict (ent, false);
		}

		entnum++;
		n++;
	}
	
	sv.num_edicts = entnum;
	sv.time = time;

//	fclose (f);
	VFS_CLOSE (f);

	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
		svs.clients->spawn_parms[i] = spawn_parms[i];

	if (cls.state != ca_dedicated)
	{
		CL_EstablishConnection ("local");
		Host_Reconnect_f ();
	}
}
Esempio n. 6
0
/*
===============
Host_Loadgame_f
===============
*/
void Host_Loadgame_f (void)
{
    char	name[MAX_OSPATH];
    FILE	*f;
    char	mapname[MAX_QPATH];
    float	time, tfloat;
    char	str[32768], *start;
    int	i, r, line; // Current line # in savegame file
    edict_t	*ent;
    int	entnum, numedicts_save;
    int	version;
    float	spawn_parms[NUM_SPAWN_PARMS];
    qboolean Quote;

    if (cmd_source != src_command)
        return;

    if (Cmd_Argc() != 2)
    {
        Con_Printf ("load <savename> : load a game\n");
        return;
    }

    cls.demonum = -1;		// stop demo loop in case this fails

    sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
    COM_DefaultExtension (name, ".sav");

// we can't call SCR_BeginLoadingPlaque, because too much stack space has
// been used.  The menu calls it before stuffing loadgame command
//	SCR_BeginLoadingPlaque ();

    Con_SafePrintf ("Loading game from %s...\n", name);
    f = fopen (name, "rb"); // Use binary mode to avoid EOF issues in savegame files
    if (!f)
    {
        Con_Printf ("ERROR: couldn't open.\n");
        return;
    }

    fscanf (f, "%i\n", &version);
    if (version != SAVEGAME_VERSION)
    {
        fclose (f);
        Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
        return;
    }

    // Kludge to read saved games with newlines in title
    do
        fscanf (f, "%s\n", str);
    while (!feof(f) && !strstr(str, "kills:"));

    for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
        fscanf (f, "%f\n", &spawn_parms[i]);
// this silliness is so we can load 1.06 save files, which have float skill values
    fscanf (f, "%f\n", &tfloat);
    current_skill = (int)(tfloat + 0.1);
    Cvar_SetValue ("skill", (float)current_skill);

    fscanf (f, "%s\n",mapname);
    fscanf (f, "%f\n",&time);

    CL_Disconnect_f ();

#ifdef QUAKE2
    SV_SpawnServer (mapname, NULL);
#else
    SV_SpawnServer (mapname);
#endif
    if (!sv.active)
    {
        Con_Printf ("Couldn't load map\n");
        return;
    }
    sv.paused = true;		// pause until all clients connect
    sv.loadgame = true;

// load the light styles

    for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
    {
        fscanf (f, "%s\n", str);
        sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);
        strcpy (sv.lightstyles[i], str);
    }

// load the edicts out of the savegame file
    entnum = -1;		// -1 is the globals

    // Hack to avoid validation errors while parsing savegame file
    numedicts_save = sv.num_edicts;
    sv.num_edicts = MAX_EDICTS;

    line = 86; // 85 lines before globals in savegame
    while (!feof(f))
    {
        for (i=0, Quote = false ; i<sizeof(str)-1 ; i++)
        {
            r = fgetc (f);
            if (r == EOF || !r)
                break;

            if (r == '\n')
                ++line;

            str[i] = r;

            // Handle multiline quoted strings containing '}'
            if (!Quote)
            {
                if (r == '\"')
                    Quote = true;
                else if (r == '}')
                {
                    i++;
                    break;
                }
            }
            else if (Quote)
            {
                if (r == '\"')
                    Quote = false;
            }
        }
        if (i == sizeof(str)-1)
            Sys_Error ("Loadgame buffer overflow (%d, max = %d) on line %d", i + 1, sizeof(str) - 1, line);
        if (Quote)
            Sys_Error ("Host_Loadgame_f: %s in quoted string on line %d", r == EOF ? "EOF" : "EOS", line);
        str[i] = 0;
        start = str;
        start = COM_Parse(str);
        if (!com_token[0])
            break;		// end of file
        if (strcmp(com_token,"{"))
            Sys_Error ("First token (%s) isn't a brace on line %d", com_token, line);

        if (entnum == -1)
        {   // parse the global vars
            ED_ParseGlobals (start, line);
        }
        else
        {   // parse an edict

            ent = EDICT_NUM("Host_Loadgame_f1", entnum);

            if (!pr_free[entnum])
                ED_Free (ent); // Unlink from world

            memset (&ent->v, 0, progs->entityfields * 4);
            pr_free[entnum] = false;
            ED_ParseEdict (start, ent, line);

            // link it into the bsp tree
            if (!pr_free[entnum])
            {
                int	mindx = ent->v.modelindex;
                model_t *model = sv.models[mindx];
                char	*mname = pr_String ("Host_Loadgame_f1", ent->v.model);
                char	*cname = pr_String ("Host_Loadgame_f2", ent->v.classname);

                // Check for missing/invalid models (except e.g. player/eyes RoS switch)
                if (mindx != 0 && (model == NULL || *mname != 0 && strcmp(model->name, mname) && strcmp(cname, "player")))
                {
                    Con_Printf ("\x02Host_Loadgame_f: ");

                    if (model == NULL)
                        Con_Printf ("missing model");
                    else
                        Con_Printf ("invalid model (%s)", model->name);

                    Con_Printf (" for edict %d (%s)\n", entnum, ED_DbgEdict(&ent->v));
                }

                SV_LinkEdict (ent, false);
            }
        }

        entnum++;
    }

    sv.num_edicts = numedicts_save;

    // Free edicts not present in the savegame, might
    // otherwise cause odd SV_TouchLinks errors
    for (i = entnum; i < sv.num_edicts; ++i)
    {
        if (!pr_free[i])
        {
            ent = EDICT_NUM("Host_Loadgame_f2", i);

            // Don't warn if edict_reuse is disabled
            if (ent->area.prev && edict_reuse.value)
            {
                Con_Printf ("\002Host_Loadgame_f: ");
                Con_Printf ("invalid touched edict (%d, max = %d)\n", i, entnum);
            }

            ED_Free (ent); // Unlink from world
        }
    }

    sv.num_edicts = entnum; // Set new edict amount from savegame

    // Count active edicts
    for (i = sv.active_edicts = 0; i < sv.num_edicts; ++i)
    {
        if (!pr_free[i])
            ++sv.active_edicts;
    }

    ED_ChkEdict (true, false);

    sv.time = time;

    fclose (f);

    for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
        svs.clients->spawn_parms[i] = spawn_parms[i];

    // Chack for different saved game mode
    if (deathmatch.value != pr_global_struct->deathmatch ||
            coop.value != pr_global_struct->coop ||
            teamplay.value != pr_global_struct->teamplay)
    {
        Con_Printf ("\002Host_Loadgame_f: ");
        Con_Printf ("saved game mode different (dm=%g/%g, coop=%g/%g, team=%g/%g)\n",
                    deathmatch.value, pr_global_struct->deathmatch, coop.value, pr_global_struct->coop, teamplay.value, pr_global_struct->teamplay);
    }

    if (cls.state != ca_dedicated)
    {
        CL_EstablishConnection ("local");
        Host_Reconnect_f ();
    }
}
Esempio n. 7
0
/*
===================
CL_KeyDownEvent

Called by CL_KeyEvent to handle a keypress
===================
*/
void CL_KeyDownEvent( int key, unsigned time )
{
	keys[key].down = qtrue;
		keys[key].repeats++;
	if( keys[key].repeats == 1 )
			anykeydown++;

#ifndef _WIN32
	if( keys[K_ALT].down && key == K_ENTER )
			{
				Cvar_SetValue( "r_fullscreen",
						!Cvar_VariableIntegerValue( "r_fullscreen" ) );
		Cbuf_ExecuteText( EXEC_APPEND, "vid_restart\n" );
				return;
			}
#endif

	// console key is hardcoded, so the user can never unbind it
	if( key == K_CONSOLE || ( keys[K_SHIFT].down && key == K_ESCAPE ) )
	{
		Con_ToggleConsole_f ();
		Key_ClearStates ();
		return;
	}


	// keys can still be used for bound actions
	if ( ( key < 128 || key == K_MOUSE1 ) 
		&& cls.state == CA_CINEMATIC && Key_GetCatcher( ) == 0 ) {

		if ( Cvar_VariableIntegerValue( "com_cameraMode" ) == 0 ) {
			Cvar_Set ("nextdemo","");
			key = K_ESCAPE;
		}
	}

	// escape is always handled special
	if ( key == K_ESCAPE ) {
		if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) {
			// clear message mode
			Message_Key( key );
			return;
		}

		// 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;
		}

		if ( !( Key_GetCatcher( ) & KEYCATCH_UI ) ) {
			if ( cls.state == CA_ACTIVE && !clc.demoplaying ) {
				VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_INGAME );
			}
			else if ( cls.state != CA_DISCONNECTED ) {
				CL_Disconnect_f();
				S_StopAllSounds();
				VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );
			}
			return;
		}

		VM_Call( uivm, UI_KEY_EVENT, key, qtrue );
		return;
	}


	// distribute the key down event to the apropriate handler
	if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) {
		Console_Key( key );
	} else if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
		if ( uivm ) {
			VM_Call( uivm, UI_KEY_EVENT, key, qtrue );
		} 
	} else if ( Key_GetCatcher( ) & KEYCATCH_CGAME ) {
		if ( cgvm ) {
			VM_Call( cgvm, CG_KEY_EVENT, key, qtrue );
		} 
	} else if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) {
		Message_Key( key );
	} else if ( cls.state == CA_DISCONNECTED ) {
		Console_Key( key );
	} else {
		// send the bound action
		Key_ParseBinding( key, qtrue, time );
	}
	return;
}
Esempio n. 8
0
static void
Host_Loadgame_f (void)
{
	dstring_t  *name = 0;
	QFile      *f;
	char       *mapname = 0;
	script_t   *script = 0;
	plitem_t   *game = 0;
	plitem_t   *list;
	plitem_t   *item;
	char       *script_data = 0;
	int         i;
	int         entnum;
	int         count;
	int         version;
	float       spawn_parms[NUM_SPAWN_PARMS];

	if (cmd_source != src_command)
		goto end;

	if (Cmd_Argc () != 2) {
		Sys_Printf ("load <savename> : load a game\n");
		goto end;
	}

	cls.demonum = -1;					// stop demo loop in case this fails

	name = dstring_newstr ();
	dsprintf (name, "%s/%s", qfs_gamedir->dir.def, Cmd_Argv (1));
	QFS_DefaultExtension (name, ".sav");

	cl.loading = true;
	CL_UpdateScreen (cl.time);

	Sys_Printf ("Loading game from %s...\n", name->str);
	f = QFS_Open (name->str, "rz");
	if (!f) {
		Sys_Printf ("ERROR: couldn't open.\n");
		goto end;
	}
	script_data = malloc (Qfilesize (f) + 1);
	i = Qread (f, script_data, Qfilesize (f));
	script_data[i] = 0;
	Qclose (f);

	script = Script_New ();
	script->single = "";		// disable {}()': lexing
	Script_Start (script, name->str, script_data);

	Script_GetToken (script, 1);
	if (strequal (script->token->str, PACKAGE_NAME)) {
		if (!Script_TokenAvailable (script, 1)) {
			Sys_Printf ("Unexpected EOF reading %s\n", name->str);
			goto end;
		}
		game = PL_GetPropertyList (script->p);
	} else {
		sscanf (script->token->str, "%i", &version);
		if (version != SAVEGAME_VERSION) {
			Sys_Printf ("Savegame is version %i, not %i\n", version,
						SAVEGAME_VERSION);
			goto end;
		}
		game = convert_to_game_dict (script);
	}

	item = PL_ObjectForKey (game, "spawn_parms");
	for (i = 0; i < NUM_SPAWN_PARMS; i++) {
		if (i >= PL_A_NumObjects (item))
			break;
		spawn_parms[i] = atof (PL_String (PL_ObjectAtIndex (item, i)));
	}
	current_skill = atoi (PL_String (PL_ObjectForKey (game, "current_skill")));
	Cvar_SetValue (skill, current_skill);
	mapname = strdup (PL_String (PL_ObjectForKey (game, "name")));

	CL_Disconnect_f ();

	SV_SpawnServer (mapname);
	if (!sv.active) {
		Sys_Printf ("Couldn't load map %s\n", mapname);
		goto end;
	}
	sv.paused = true;					// pause until all clients connect
	sv.loadgame = true;

	list = PL_ObjectForKey (game, "lightstyles");
	for (i = 0; i < MAX_LIGHTSTYLES; i++) {
		const char *style;
		char       *str;
		if (i >= PL_A_NumObjects (list))
			break;
		item = PL_ObjectAtIndex (list, i);
		style = PL_String (item);
		sv.lightstyles[i] = str = Hunk_Alloc (strlen (style) + 1);
		strcpy (str, style);
	}

	ED_InitGlobals (&sv_pr_state, PL_ObjectForKey (game, "globals"));

	list = PL_ObjectForKey (game, "entities");
	entnum = 0;
	count = PL_A_NumObjects (list);
	if (count > sv.max_edicts)
		Host_Error ("too many entities in saved game. adjust max_edicts\n");
	for (entnum = 0; entnum < count; entnum++) {
		plitem_t   *entity = PL_ObjectAtIndex (list, entnum);
		edict_t    *ent = EDICT_NUM (&sv_pr_state, entnum);

		memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4);
		ent->free = false;
		ED_InitEntity (&sv_pr_state, entity, ent);

		// link it into the bsp tree
		if (!ent->free)
			SV_LinkEdict (ent, false);
	}

	sv.num_edicts = entnum;
	sv.time = atof (PL_String (PL_ObjectForKey (game, "time")));

	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		svs.clients->spawn_parms[i] = spawn_parms[i];

	if (cls.state != ca_dedicated) {
		CL_EstablishConnection ("local");
		Host_Reconnect_f ();
	}
end:
	if (game)
		PL_Free (game);
	if (mapname)
		free (mapname);
	if (script)
		Script_Delete (script);
	if (script_data)
		free (script_data);
	if (name)
		dstring_delete (name);
}