コード例 #1
0
ファイル: host_cmd.c プロジェクト: bangstk/Quakespasm
/*
=====================
Host_Connect_f

User command to connect to server
=====================
*/
void Host_Connect_f (void)
{
	char	name[MAX_QPATH];

	cls.demonum = -1;		// stop demo loop in case this fails
	if (cls.demoplayback)
	{
		CL_StopPlayback ();
		CL_Disconnect ();
	}
	q_strlcpy (name, Cmd_Argv(1), sizeof(name));
	CL_EstablishConnection (name);
	Host_Reconnect_f ();
}
コード例 #2
0
ファイル: host_cmd.c プロジェクト: DrLabman/Vengeance-r2
/*
=====================
Host_Connect_f

User command to connect to server
=====================
*/
void Host_Connect_f (void)
{
	char	name[MAX_QPATH];
	
	// if the video isn't initialized already, it needs to be
	Host_InitVideo();

	cls.demonum = -1;		// stop demo loop in case this fails
	if (cls.demoplayback)
	{
		CL_StopPlayback ();
		CL_Disconnect ();
	}
	strcpy (name, Cmd_Argv(1));
	CL_EstablishConnection (name);
	Host_Reconnect_f ();
}
コード例 #3
0
ファイル: host_cmd.c プロジェクト: bangstk/Quakespasm
/*
===============
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 ();
	}
}
コード例 #4
0
ファイル: host_cmd.c プロジェクト: DrLabman/Vengeance-r2
/*
===============
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 ();
	}
}
コード例 #5
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 ();
    }
}
コード例 #6
0
ファイル: host_cmd.c プロジェクト: svn2github/uhexen2
/*
===============
Host_Loadgame_f
===============
*/
static void Host_Loadgame_f (void)
{
	FILE	*f;
	char		mapname[MAX_QPATH];
	float		playtime;
	char		str[32768];
	int		version;
	int		i, error_state;
	int		tempi;
	float		tempf;
	edict_t		*ent;
	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
	CL_Disconnect();
	Host_RemoveGIPFiles(NULL);
	Key_SetDest (key_game);		// remove console or menu

	FS_MakePath_BUF (FS_USERDIR, &error_state, savename, sizeof(savename), Cmd_Argv(1));
	if (error_state)
	{
		Con_Printf ("%s: save directory name too long\n", __thisfunc__);
		return;
	}
	Con_Printf ("Loading game from %s...\n", savename);

	if (q_snprintf(savedest, sizeof(savedest), "%s/info.dat", savename) >= (int)sizeof(savedest))
	{
		Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__);
		return;
	}

	f = fopen (savedest, "r");
	if (!f)
	{
		Con_Printf ("%s: ERROR: couldn't open savefile\n", __thisfunc__);
		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", &tempf);
	current_skill = (int)(tempf + 0.1);
	Cvar_SetValue ("skill", current_skill);

	Cvar_Set ("deathmatch", "0");
	Cvar_Set ("coop", "0");
	Cvar_Set ("teamplay", "0");
	Cvar_Set ("randomclass", "0");

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

	tempi = -1;
	fscanf (f, "%d\n", &tempi);
	if (tempi >= 1)
		svs.maxclients = tempi;

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("deathmatch", tempf);

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("coop", tempf);

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("teamplay", tempf);

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("randomclass", tempf);

	tempf = -1;
	fscanf (f, "%f\n", &tempf);
	if (tempf >= 0)
		Cvar_SetValue ("_cl_playerclass", tempf);

	// mission pack, objectives strings
	fscanf (f, "%u\n", &info_mask);
	fscanf (f, "%u\n", &info_mask2);

	fclose (f);

	Host_RemoveGIPFiles(FS_GetUserdir());

	FS_MakePath_BUF (FS_USERDIR, NULL, savedest, sizeof(savedest), Cmd_Argv(1));
	error_state = Host_CopyFiles(savedest, "*.gip", FS_GetUserdir());
	if (error_state)
	{
		Host_Error ("%s: The game could not be loaded properly!", __thisfunc__);
		return;
	}

	if (LoadGamestate(mapname, NULL, 2) != 0)
		return;

	SV_SaveSpawnparms ();

	ent = EDICT_NUM(1);

	Cvar_SetValue ("_cl_playerclass", ent->v.playerclass);//this better be the same as above...

	// this may be rudundant with the setting in PR_LoadProgs, but not sure so its here too
	if (sv_globals.cl_playerclass)
		*sv_globals.cl_playerclass = ent->v.playerclass;

	svs.clients->playerclass = ent->v.playerclass;

	sv.paused = true;		// pause until all clients connect
	sv.loadgame = true;

	if (cls.state != ca_dedicated)
	{
		CL_EstablishConnection ("local");
		Host_Reconnect_f ();
	}
}
コード例 #7
0
ファイル: host_cmd.c プロジェクト: EIREXE/Quakeforge-gcw0
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);
}