Beispiel #1
0
//
// G_DoNewGame
//
// denis - rewritten so that it does not force client reconnects
//
void G_DoNewGame (void)
{
	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if(!(it->ingame()))
			continue;

		SV_SendLoadMap(wadfiles, patchfiles, d_mapname, &*it);
	}

	sv_curmap.ForceSet(d_mapname);

	G_InitNew (d_mapname);
	gameaction = ga_nothing;

	// run script at the start of each map
	// [ML] 8/22/2010: There are examples in the wiki that outright don't work
	// when onlcvars (addcommandstring's second param) is true.  Is there a
	// reason why the mapscripts ahve to be safe mode?
	if (strlen(sv_startmapscript.cstring()))
		AddCommandString(sv_startmapscript.cstring()/*,true*/);

	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (!(it->ingame()))
			continue;

		if (sv_gametype == GM_TEAMDM || sv_gametype == GM_CTF)
			SV_CheckTeam(*it);
		else
			it->userinfo.color = it->prefcolor;

		SV_ClientFullUpdate(*it);
	}
}
Beispiel #2
0
void WI_initNetgameStats()
{
	state = StatCount;
	acceleratestage = 0;
	ng_state = 1;

	cnt_pause = TICRATE;

	cnt_kills_c.clear();
	cnt_items_c.clear();
	cnt_secret_c.clear();
	cnt_frags_c.clear();

	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (!(it->ingame()))
			continue;

		cnt_kills_c.push_back(0);
		cnt_items_c.push_back(0);
		cnt_secret_c.push_back(0);
		cnt_frags_c.push_back(0);

		dofrags += WI_fragSum(*it);
	}

	dofrags = !!dofrags;

	WI_initAnimatedBack();
}
Beispiel #3
0
void WI_checkForAccelerate(void)
{
	if (!serverside)
		return;

	// check for button presses to skip delays
	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
		{
			player_t *player = &*it;

			if (player->cmd.buttons & BT_ATTACK)
			{
				if (!player->attackdown)
					acceleratestage = 1;
				player->attackdown = true;
			}
			else
				player->attackdown = false;
			if (player->cmd.buttons & BT_USE)
			{
				if (!player->usedown)
					acceleratestage = 1;
				player->usedown = true;
			}
			else
				player->usedown = false;
		}
	}
}
Beispiel #4
0
// Broadcast warmup state to all clients.
void SV_BroadcastWarmupState(Warmup::status_t status, short count = 0)
{
    for (Players::iterator it = players.begin(); it != players.end(); ++it)
    {
        if (!it->ingame())
            continue;
        SV_SendWarmupState(*it, status, count);
    }
}
Beispiel #5
0
void WI_drawNetgameStats(void)
{
	unsigned int x, y;
	short pwidth = percent->width();

	// draw animated background
	WI_drawAnimatedBack();

	WI_drawLF();

	// draw stat titles (top line)
	screen->DrawPatchClean (kills, NG_STATSX+NG_SPACINGX-kills->width(), NG_STATSY);

	screen->DrawPatchClean (items, NG_STATSX+2*NG_SPACINGX-items->width(), NG_STATSY);

	screen->DrawPatchClean (scrt, NG_STATSX+3*NG_SPACINGX-scrt->width(), NG_STATSY);

	if (dofrags)
		screen->DrawPatchClean (frags, NG_STATSX+4*NG_SPACINGX-frags->width(), NG_STATSY);

	// draw stats
	y = NG_STATSY + kills->height();

	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		// [RH] Quick hack: Only show the first four players.
		if (it->id > 4)
			break;

		byte i = (it->id) - 1;

		if (!it->ingame())
			continue;

		x = NG_STATSX;
		// [RH] Only use one graphic for the face backgrounds
		V_ColorMap = translationref_t(translationtables + i * 256, i);
        screen->DrawTranslatedPatchClean (p, x - p->width(), y);
		// classic face background colour
		//screen->DrawTranslatedPatchClean (faceclassic[i], x-p->width(), y);

		if (i == me)
			screen->DrawPatchClean (star, x-p->width(), y);

		x += NG_SPACINGX;
		WI_drawPercent (cnt_kills_c[i], x-pwidth, y+10, wbs->maxkills);	x += NG_SPACINGX;
		WI_drawPercent (cnt_items_c[i], x-pwidth, y+10, wbs->maxitems);	x += NG_SPACINGX;
		WI_drawPercent (cnt_secret_c[i], x-pwidth, y+10, wbs->maxsecret); x += NG_SPACINGX;

		if (dofrags)
			WI_drawNum(cnt_frags_c[i], x, y+10, -1);

		y += WI_SPACINGY;
	}
}
Beispiel #6
0
//
// P_ArchivePlayers
//
void P_SerializePlayers (FArchive &arc)
{
	if (arc.IsStoring ())
	{
		for (Players::const_iterator it = players.begin();it != players.end();++it)
			arc << (int)(it->playerstate);
	}
	else
	{
		int playerstate = (playerstate_t)0;
		for (Players::iterator it = players.begin();it != players.end();++it)
		{
			arc >> playerstate;
			it->playerstate = (playerstate_t)playerstate;
		}
	}

	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
			it->Serialize(arc);
	}
}
Beispiel #7
0
void DEarthquake::RunThink ()
{
    if (level.time % 48 == 0)
        S_Sound (m_Spot, CHAN_BODY, "world/quake", 1, ATTN_NORM);

    if (serverside)
    {
        for (Players::iterator it = players.begin(); it != players.end(); ++it)
        {
            if (it->ingame() && !(it->cheats & CF_NOCLIP))
            {
                AActor *mo = it->mo;

                if (!(level.time & 7) &&
                        mo->x >= m_DamageBox[BOXLEFT] && mo->x < m_DamageBox[BOXRIGHT] &&
                        mo->y >= m_DamageBox[BOXTOP] && mo->y < m_DamageBox[BOXBOTTOM])
                {
                    int mult = 1024 * m_Intensity;
                    P_DamageMobj (mo, NULL, NULL, m_Intensity / 2, MOD_UNKNOWN);
                    mo->momx += (P_Random ()-128) * mult;
                    mo->momy += (P_Random ()-128) * mult;
                }

                if (mo->x >= m_TremorBox[BOXLEFT] && mo->x < m_TremorBox[BOXRIGHT] &&
                        mo->y >= m_TremorBox[BOXTOP] && mo->y < m_TremorBox[BOXBOTTOM])
                {
                    it->xviewshift = m_Intensity;
                }
            }
        }
    }

    if (--m_Countdown == 0)
    {
        Destroy ();
    }
}
Beispiel #8
0
void WI_updateNetgameStats()
{
	unsigned int i;
	int fsum;
	BOOL stillticking;

	WI_updateAnimatedBack();

	if (acceleratestage && ng_state != 10)
	{
		acceleratestage = 0;

		i = 0;
		for (Players::iterator it = players.begin();it != players.end();++it,++i)
		{
			if (!(it->ingame()))
				continue;

			cnt_kills_c[i] = plrs[i].skills;
			cnt_items_c[i] = plrs[i].sitems;
			cnt_secret_c[i] = plrs[i].ssecret;

			if (dofrags)
				cnt_frags_c[i] = WI_fragSum(*it);
		}
		S_Sound (CHAN_INTERFACE, "weapons/rocklx", 1, ATTN_NONE);
		ng_state = 10;
	}

	if (ng_state == 2)
	{
		if (!(bcnt&3))
			S_Sound (CHAN_INTERFACE, "weapons/pistol", 1, ATTN_NONE);

		stillticking = false;

		i = 0;
		for (Players::iterator it = players.begin();it != players.end();++it,++i)
		{
			if (!(it->ingame()))
				continue;

			cnt_kills_c[i] += 2;

			if (cnt_kills_c[i] > plrs[i].skills)
				cnt_kills_c[i] = plrs[i].skills;
			else
				stillticking = true;
		}

		if (!stillticking)
		{
			S_Sound (CHAN_INTERFACE, "weapons/rocklx", 1, ATTN_NONE);
			ng_state++;
		}
	}
	else if (ng_state == 4)
	{
		if (!(bcnt&3))
			S_Sound (CHAN_INTERFACE, "weapons/pistol", 1, ATTN_NONE);

		stillticking = false;

		i = 0;
		for (Players::iterator it = players.begin();it != players.end();++it,++i)
		{
			if (!(it->ingame()))
				continue;

			cnt_items_c[i] += 2;
			if (cnt_items_c[i] > plrs[i].sitems)
				cnt_items_c[i] = plrs[i].sitems;
			else
				stillticking = true;
		}
		if (!stillticking)
		{
			S_Sound (CHAN_INTERFACE, "weapons/rocklx", 1, ATTN_NONE);
			ng_state++;
		}
	}
	else if (ng_state == 6)
	{
		if (!(bcnt&3))
			S_Sound (CHAN_INTERFACE, "weapons/pistol", 1, ATTN_NONE);

		stillticking = false;

		i = 0;
		for (Players::iterator it = players.begin();it != players.end();++it,++i)
		{
			if (!(it->ingame()))
				continue;

			cnt_secret_c[i] += 2;

			if (cnt_secret_c[i] > plrs[i].ssecret)
				cnt_secret_c[i] = plrs[i].ssecret;
			else
				stillticking = true;
		}

		if (!stillticking)
		{
			S_Sound (CHAN_INTERFACE, "weapons/rocklx", 1, ATTN_NONE);
			ng_state += 1 + 2*!dofrags;
		}
	}
	else if (ng_state == 8)
	{
		if (!(bcnt&3))
			S_Sound (CHAN_INTERFACE, "weapons/pistol", 1, ATTN_NONE);

		stillticking = false;

		i = 0;
		for (Players::iterator it = players.begin();it != players.end();++it,++i)
		{
			if (!(it->ingame()))
				continue;

			cnt_frags_c[i] += 1;

			if (cnt_frags_c[i] >= (fsum = WI_fragSum(*it)))
				cnt_frags_c[i] = fsum;
			else
				stillticking = true;
		}

		if (!stillticking)
		{
			S_Sound (CHAN_INTERFACE, "player/male/death1", 1, ATTN_NONE);
			ng_state++;
		}
	}
	else if (ng_state == 10)
	{
		if (acceleratestage)
		{
			S_Sound (CHAN_INTERFACE, "weapons/shotgr", 1, ATTN_NONE);
			if ( (gameinfo.flags & GI_MAPxx) )
				WI_initNoState();
			else
				WI_initShowNextLoc();
		}
	}
	else if (ng_state & 1)
	{
		if (!--cnt_pause)
		{
			ng_state++;
			cnt_pause = TICRATE;
		}
	}
}
Beispiel #9
0
//
// SV_SendServerInfo
// 
// Sends server info to a launcher
// TODO: Clean up and reinvent.
void SV_SendServerInfo()
{
	size_t i;

	SZ_Clear(&ml_message);
	
	MSG_WriteLong(&ml_message, CHALLENGE);
	MSG_WriteLong(&ml_message, SV_NewToken());

	// if master wants a key to be presented, present it we will
	if(MSG_BytesLeft() == 4)
		MSG_WriteLong(&ml_message, MSG_ReadLong());

	MSG_WriteString(&ml_message, (char *)sv_hostname.cstring());

	byte playersingame = 0;
	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
			playersingame++;
	}

	MSG_WriteByte(&ml_message, playersingame);
	MSG_WriteByte(&ml_message, sv_maxclients.asInt());

	MSG_WriteString(&ml_message, level.mapname);

	size_t numwads = wadfiles.size();
	if(numwads > 0xff)numwads = 0xff;

	MSG_WriteByte(&ml_message, numwads - 1);

	for (i = 1; i < numwads; ++i)
		MSG_WriteString(&ml_message, D_CleanseFileName(wadfiles[i], "wad").c_str());

	MSG_WriteBool(&ml_message, (sv_gametype == GM_DM || sv_gametype == GM_TEAMDM));
	MSG_WriteByte(&ml_message, sv_skill.asInt());
	MSG_WriteBool(&ml_message, (sv_gametype == GM_TEAMDM));
	MSG_WriteBool(&ml_message, (sv_gametype == GM_CTF));

	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
		{
			MSG_WriteString(&ml_message, it->userinfo.netname.c_str());
			MSG_WriteShort(&ml_message, it->fragcount);
			MSG_WriteLong(&ml_message, it->ping);

			if (sv_gametype == GM_TEAMDM || sv_gametype == GM_CTF)
				MSG_WriteByte(&ml_message, it->userinfo.team);
			else
				MSG_WriteByte(&ml_message, TEAM_NONE);
		}
	}

	for (i = 1; i < numwads; ++i)
		MSG_WriteString(&ml_message, wadhashes[i].c_str());

	MSG_WriteString(&ml_message, sv_website.cstring());

	if (sv_gametype == GM_TEAMDM || sv_gametype == GM_CTF)
	{
		MSG_WriteLong(&ml_message, sv_scorelimit.asInt());
		
		for(size_t i = 0; i < NUMTEAMS; i++)
		{
			if ((sv_gametype == GM_CTF && i < 2) || (sv_gametype != GM_CTF && i < sv_teamsinplay)) {
				MSG_WriteByte(&ml_message, 1);
				MSG_WriteLong(&ml_message, TEAMpoints[i]);
			} else {
				MSG_WriteByte(&ml_message, 0);
			}
		}
	}
	
	MSG_WriteShort(&ml_message, VERSION);

//bond===========================
	MSG_WriteString(&ml_message, (char *)sv_email.cstring());

	int timeleft = (int)(sv_timelimit - level.time/(TICRATE*60));
	if (timeleft<0) timeleft=0;

	MSG_WriteShort(&ml_message,sv_timelimit.asInt());
	MSG_WriteShort(&ml_message,timeleft);
	MSG_WriteShort(&ml_message,sv_fraglimit.asInt());

	MSG_WriteBool(&ml_message, (sv_itemsrespawn ? true : false));
	MSG_WriteBool(&ml_message, (sv_weaponstay ? true : false));
	MSG_WriteBool(&ml_message, (sv_friendlyfire ? true : false));
	MSG_WriteBool(&ml_message, (sv_allowexit ? true : false));
	MSG_WriteBool(&ml_message, (sv_infiniteammo ? true : false));
	MSG_WriteBool(&ml_message, (sv_nomonsters ? true : false));
	MSG_WriteBool(&ml_message, (sv_monstersrespawn ? true : false));
	MSG_WriteBool(&ml_message, (sv_fastmonsters ? true : false));
	MSG_WriteBool(&ml_message, (sv_allowjump ? true : false));
	MSG_WriteBool(&ml_message, (sv_freelook ? true : false));
	MSG_WriteBool(&ml_message, (sv_waddownload ? true : false));
	MSG_WriteBool(&ml_message, (sv_emptyreset ? true : false));
	MSG_WriteBool(&ml_message, false);		// used to be sv_cleanmaps
	MSG_WriteBool(&ml_message, (sv_fragexitswitch ? true : false));

	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
		{
			MSG_WriteShort(&ml_message, it->killcount);
			MSG_WriteShort(&ml_message, it->deathcount);
			
			int timeingame = (time(NULL) - it->JoinTime)/60;
			if (timeingame<0) timeingame=0;
				MSG_WriteShort(&ml_message, timeingame);
		}
	}
	
//bond===========================

    MSG_WriteLong(&ml_message, (DWORD)0x01020304);
    MSG_WriteShort(&ml_message, sv_maxplayers.asInt());
    
    for (Players::iterator it = players.begin();it != players.end();++it)
    {
        if (it->ingame())
        {
            MSG_WriteBool(&ml_message, (it->spectator ? true : false));
        }
    }

    MSG_WriteLong(&ml_message, (DWORD)0x01020305);
    MSG_WriteShort(&ml_message, strlen(join_password.cstring()) ? 1 : 0);
    
    // GhostlyDeath -- Send Game Version info
    MSG_WriteLong(&ml_message, GAMEVER);

    MSG_WriteByte(&ml_message, patchfiles.size());
    
    for (size_t i = 0; i < patchfiles.size(); ++i)
        MSG_WriteString(&ml_message, D_CleanseFileName(patchfiles[i]).c_str());

	NET_SendPacket(ml_message, net_from);
}
Beispiel #10
0
void G_InitNew (const char *mapname)
{
	size_t i;

	if (!savegamerestore)
		G_ClearSnapshots ();

	// [RH] Mark all levels as not visited
	if (!savegamerestore)
	{
		for (i = 0; i < wadlevelinfos.size(); i++)
			wadlevelinfos[i].flags &= ~LEVEL_VISITED;

		for (i = 0; LevelInfos[i].mapname[0]; i++)
			LevelInfos[i].flags &= ~LEVEL_VISITED;
	}

	int old_gametype = sv_gametype.asInt();

	cvar_t::UnlatchCVars ();

	if (old_gametype != sv_gametype || sv_gametype != GM_COOP) {
		unnatural_level_progression = true;

		// Nes - Force all players to be spectators when the sv_gametype is not now or previously co-op.
		for (Players::iterator it = players.begin();it != players.end();++it)
		{
			// [SL] 2011-07-30 - Don't force downloading players to become spectators
			// it stops their downloading
			if (!(it->ingame()))
				continue;

			for (Players::iterator pit = players.begin();pit != players.end();++pit)
			{
				if (!(pit->ingame()))
					continue;
				MSG_WriteMarker (&(pit->client.reliablebuf), svc_spectate);
				MSG_WriteByte (&(pit->client.reliablebuf), it->id);
				MSG_WriteByte (&(pit->client.reliablebuf), true);
			}
			it->spectator = true;
			it->playerstate = PST_LIVE;
			it->joinafterspectatortime = -(TICRATE * 5);
		}
	}

	// [SL] 2011-09-01 - Change gamestate here so SV_ServerSettingChange will
	// send changed cvars
	gamestate = GS_LEVEL;
	SV_ServerSettingChange();

	if (paused)
	{
		paused = false;
	}

	// [RH] If this map doesn't exist, bomb out
	if (W_CheckNumForName (mapname) == -1)
	{
		I_Error ("Could not find map %s\n", mapname);
	}

	if (sv_skill == sk_nightmare || sv_monstersrespawn)
		respawnmonsters = true;
	else
		respawnmonsters = false;

	bool wantFast = sv_fastmonsters || (sv_skill == sk_nightmare);
	if (wantFast != isFast)
	{
		if (wantFast)
		{
			for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
				states[i].tics >>= 1;
			mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
			mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
			mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
		}
		else
		{
			for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
				states[i].tics <<= 1;
			mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
			mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
			mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
		}
		isFast = wantFast;
	}
Beispiel #11
0
void NetDemo::writeLauncherSequence(buf_t *netbuffer)
{
	// Server sends launcher info
	MSG_WriteLong	(netbuffer, CHALLENGE);
	MSG_WriteLong	(netbuffer, 0);		// server_token
	
	// get sv_hostname and write it
	MSG_WriteString (netbuffer, server_host.c_str());
	
	int playersingame = 0;
	for (Players::const_iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
			playersingame++;
	}
	MSG_WriteByte	(netbuffer, playersingame);
	MSG_WriteByte	(netbuffer, 0);				// sv_maxclients
	MSG_WriteString	(netbuffer, level.mapname);

	// names of all the wadfiles on the server	
	size_t numwads = wadfiles.size();
	if (numwads > 0xff)
		numwads = 0xff;
	MSG_WriteByte	(netbuffer, numwads - 1);

	for (size_t n = 1; n < numwads; n++)
	{
		std::string tmpname = wadfiles[n];
		
		// strip absolute paths, as they present a security risk
		FixPathSeparator(tmpname);
		size_t slash = tmpname.find_last_of(PATHSEPCHAR);
		if (slash != std::string::npos)
			tmpname = tmpname.substr(slash + 1, tmpname.length() - slash);

		MSG_WriteString	(netbuffer, tmpname.c_str());
	}
		
	MSG_WriteBool	(netbuffer, 0);		// deathmatch?
	MSG_WriteByte	(netbuffer, 0);		// sv_skill
	MSG_WriteBool	(netbuffer, (sv_gametype == GM_TEAMDM));
	MSG_WriteBool	(netbuffer, (sv_gametype == GM_CTF));

	for (Players::const_iterator it = players.begin();it != players.end();++it)
	{
		// Notes: client just ignores this data but still expects to parse it
		if (it->ingame())
		{
			MSG_WriteString(netbuffer, ""); // player's netname
			MSG_WriteShort(netbuffer, 0); // player's fragcount
			MSG_WriteLong(netbuffer, 0); // player's ping
			MSG_WriteByte(netbuffer, 0); // player's team
		}
	}

	// MD5 hash sums for all the wadfiles on the server
	for (size_t n = 1; n < numwads; n++)
		MSG_WriteString	(netbuffer, wadhashes[n].c_str());

	MSG_WriteString	(netbuffer, "");	// sv_website.cstring()

	if (sv_gametype == GM_TEAMDM || sv_gametype == GM_CTF)
	{
		MSG_WriteLong	(netbuffer, 0);		// sv_scorelimit
		for (size_t n = 0; n < NUMTEAMS; n++)
		{
			MSG_WriteBool	(netbuffer, false);
		}
	}	

    MSG_WriteShort	(netbuffer, VERSION);
  
  	// Note: these are ignored by clients when the client connects anyway
  	// so they don't need real data
	MSG_WriteString	(netbuffer, "");	// sv_email.cstring()  

	MSG_WriteShort	(netbuffer, 0);		// sv_timelimit
	MSG_WriteShort	(netbuffer, 0);		// timeleft before end of level
	MSG_WriteShort	(netbuffer, 0);		// sv_fraglimit

	MSG_WriteBool	(netbuffer, false);	// sv_itemrespawn
	MSG_WriteBool	(netbuffer, false);	// sv_weaponstay
	MSG_WriteBool	(netbuffer, false);	// sv_friendlyfire
	MSG_WriteBool	(netbuffer, false);	// sv_allowexit
	MSG_WriteBool	(netbuffer, false);	// sv_infiniteammo
	MSG_WriteBool	(netbuffer, false);	// sv_nomonsters
	MSG_WriteBool	(netbuffer, false);	// sv_monstersrespawn
	MSG_WriteBool	(netbuffer, false);	// sv_fastmonsters
	MSG_WriteBool	(netbuffer, false);	// sv_allowjump
	MSG_WriteBool	(netbuffer, false);	// sv_freelook
	MSG_WriteBool	(netbuffer, false);	// sv_waddownload
	MSG_WriteBool	(netbuffer, false);	// sv_emptyreset
	MSG_WriteBool	(netbuffer, false);	// sv_cleanmaps
	MSG_WriteBool	(netbuffer, false);	// sv_fragexitswitch
	
	for (Players::const_iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
		{
			MSG_WriteShort(netbuffer, it->killcount);
			MSG_WriteShort(netbuffer, it->deathcount);
			
			int timeingame = (time(NULL) - it->JoinTime) / 60;
			if (timeingame < 0)
				timeingame = 0;
			MSG_WriteShort(netbuffer, timeingame);
		}
	}
	
	MSG_WriteLong(netbuffer, (DWORD)0x01020304);
	MSG_WriteShort(netbuffer, sv_maxplayers);
    
	for (Players::iterator it = players.begin();it != players.end();++it)
	{
		if (it->ingame())
			MSG_WriteBool(netbuffer, it->spectator);
	}
	
	MSG_WriteLong	(netbuffer, (DWORD)0x01020305);
	MSG_WriteShort	(netbuffer, 0);	// join_passowrd

	MSG_WriteLong	(netbuffer, GAMEVER);

    // TODO: handle patch files
	MSG_WriteByte	(netbuffer, 0);  // patchfiles.size()
//	MSG_WriteByte	(netbuffer, patchfiles.size());
    
//	for (size_t n = 0; n < patchfiles.size(); n++)
//		MSG_WriteString(netbuffer, patchfiles[n].c_str());
}