示例#1
0
文件: bg_lua.cpp 项目: Stoiss/japp
static int JPLua_RegisterPlugin( lua_State *L ) {
	int top;

	Q_strncpyz( JPLua.currentPlugin->longname, lua_tostring( L, 1 ), sizeof(JPLua.currentPlugin->longname) );
	Q_CleanString( JPLua.currentPlugin->longname, STRIP_COLOUR );
	Q_strncpyz( JPLua.currentPlugin->version, lua_tostring( L, 2 ), sizeof(JPLua.currentPlugin->version) );
	Q_CleanString( JPLua.currentPlugin->version, STRIP_COLOUR );
	JPLua.currentPlugin->requiredJPLuaVersion = lua_isnumber( L, 3 ) ? lua_tointeger( L, 3 ) : JPLUA_VERSION;
	JPLua.currentPlugin->UID = (intptr_t)JPLua.currentPlugin;

	lua_newtable( L );
	top = lua_gettop( L );

	lua_pushstring( L, "name" );
		lua_pushstring( L, JPLua.currentPlugin->longname );
		lua_settable( L, top );
	lua_pushstring( L, "version" );
		lua_pushstring( L, JPLua.currentPlugin->version );
		lua_settable( L, top );
	lua_pushstring( L, "UID" );
		lua_pushstring( L, va( "0x%" PRIxPTR, (void *)JPLua.currentPlugin->UID ) );
		lua_settable( L, top );

	//save in the registry, but push on stack again straight away
	JPLua.currentPlugin->handle = luaL_ref( L, LUA_REGISTRYINDEX );
	lua_rawgeti( L, LUA_REGISTRYINDEX, JPLua.currentPlugin->handle );

	return 1;
}
示例#2
0
	static void Player_SetName( lua_State *L, jpluaEntity_t *ent ) {
		const char *name = luaL_checkstring(L, 3);
		char info[MAX_INFO_STRING], oldName[MAX_NETNAME];

		if (!name || !*name || strlen(name) >= MAX_NETNAME)
			return;

		Q_strncpyz(oldName, ent->client->pers.netname, sizeof(oldName));

		ClientCleanName(name, ent->client->pers.netname, sizeof(ent->client->pers.netname));

		if (!strcmp(oldName, ent->client->pers.netname))
			return;

		Q_strncpyz(ent->client->pers.netnameClean, ent->client->pers.netname, sizeof(ent->client->pers.netnameClean));
		Q_CleanString(ent->client->pers.netnameClean, STRIP_COLOUR);

		if (CheckDuplicateName(ent->s.number)) {
			Q_strncpyz(ent->client->pers.netnameClean, ent->client->pers.netname, sizeof(ent->client->pers.netnameClean));
			Q_CleanString(ent->client->pers.netnameClean, STRIP_COLOUR);
		}

		// update clientinfo
		trap->GetConfigstring(CS_PLAYERS + ent->s.number, info, sizeof(info));
		Info_SetValueForKey(info, "n", name);
		trap->SetConfigstring(CS_PLAYERS + ent->s.number, info);

		// update userinfo (in engine)
		trap->GetUserinfo(ent->s.number, info, sizeof(info));
		Info_SetValueForKey(info, "name", name);
		trap->SetUserinfo(ent->s.number, info);
	}
示例#3
0
//RAZFIXME: Use G_ClientFromString
gclient_t *ClientForString( const char *s ) {
	gclient_t	*cl;
	int			idnum;
	char		cleanName[MAX_STRING_CHARS];

	// numeric values could be slot numbers
	if ( Q_StringIsInteger( s ) ) {
		idnum = atoi( s );
		if ( idnum >= 0 && idnum < level.maxclients ) {
			cl = &level.clients[idnum];
			if ( cl->pers.connected == CON_CONNECTED ) {
				return cl;
			}
		}
	}

	// check for a name match
	for ( idnum = 0, cl = level.clients; idnum < level.maxclients; idnum++, cl++ ) {
		if ( cl->pers.connected != CON_CONNECTED ) {
			continue;
		}
		Q_strncpyz( cleanName, cl->pers.netname, sizeof(cleanName) );
		Q_CleanString( cleanName, STRIP_COLOUR );
		if ( !Q_stricmp( cleanName, s ) ) {
			return cl;
		}
	}

	trap->Print( "User %s is not on the server\n", s );
	return NULL;
}
示例#4
0
// This will only happen on the very first snapshot, or on tourney restarts.
//	All other times will use CG_TransitionSnapshot instead.
// FIXME: Also called by map_restart?
void CG_SetInitialSnapshot( snapshot_t *snap ) {
	int				i;
	centity_t		*cent;
	entityState_t	*state;

	cg.snap = snap;

	if ( !cg_entities[snap->ps.clientNum].ghoul2 && trap->G2_HaveWeGhoul2Models( cgs.clientinfo[snap->ps.clientNum].ghoul2Model ) ) {
		trap->G2API_DuplicateGhoul2Instance( cgs.clientinfo[snap->ps.clientNum].ghoul2Model, &cg_entities[snap->ps.clientNum].ghoul2 );
		CG_CopyG2WeaponInstance( &cg_entities[snap->ps.clientNum], FIRST_WEAPON, cg_entities[snap->ps.clientNum].ghoul2 );

		// check now to see if we have this bone for setting anims and such
		if ( trap->G2API_AddBolt( cg_entities[snap->ps.clientNum].ghoul2, 0, "face" ) == -1 )
			cg_entities[snap->ps.clientNum].noFace = qtrue;
	}
	BG_PlayerStateToEntityState( &snap->ps, &cg_entities[snap->ps.clientNum].currentState, qfalse );

	// sort out solid entities
	CG_BuildSolidList();

	CG_ExecuteNewServerCommands( snap->serverCommandSequence );

	// set our local weapon selection pointer to
	// what the server has indicated the current weapon is
	CG_Respawn();

	for ( i = 0; i < cg.snap->numEntities; i++ ) {
		state = &cg.snap->entities[i];
		cent = &cg_entities[state->number];

		memcpy( &cent->currentState, state, sizeof(entityState_t) );
		//	cent->currentState = *state;
		cent->interpolate = qfalse;
		cent->currentValid = qtrue;

		CG_ResetEntity( cent );

		// check for events
		CG_CheckEvents( cent );
	}

	// auto record demo
	if ( cg_autoRecordDemo.integer & (1 << cgs.gametype) && cg.warmup <= 0 && !cg.demoPlayback ) {
		time_t rawtime;
		char buf[256] = { 0 }, timeStr[64] = { 0 }, mapName[MAX_QPATH] = { 0 };

		time( &rawtime );
		strftime( timeStr, sizeof(timeStr), "%Y-%m-%d_%H-%M-%S", localtime( &rawtime ) );
		Q_strncpyz( mapName, cgs.mapname + 5, sizeof(mapName) );
		Q_strstrip( mapName, "/", "-" );
		COM_StripExtension( mapName, mapName, sizeof(mapName) );
		Com_sprintf( buf, sizeof(buf), "%s_%s_%s_%s", timeStr, gametypeStringShort[cgs.gametype], mapName, cgs.clientinfo[cg.clientNum].name );
		Q_strstrip( buf, "\n\r;?*<>|\\/\"", NULL );
		Q_strstrip( buf, " ", "_" );
		Q_CleanString( buf, STRIP_COLOUR | STRIP_EXTASCII );
		trap->SendConsoleCommand( va( "stoprecord; record %s\n", buf ) );
	}

}
示例#5
0
static void SV_ListMaps_f( void ) {
	int i;
	char map[24] = "--", longname[32] = "--", type[64] = "--";

	trap->Print( "  map                     longname                        types\n" );
	trap->Print( "  --------                --------                        --------\n" );

	for ( i = 0; i < level.arenas.num; i++ ) {
		Q_strncpyz( map, Info_ValueForKey( level.arenas.infos[i], "map" ), sizeof(map) );
		Q_CleanString( map, STRIP_COLOUR );

		Q_strncpyz( longname, Info_ValueForKey( level.arenas.infos[i], "longname" ), sizeof(longname) );
		Q_CleanString( longname, STRIP_COLOUR );

		Q_strncpyz( type, Info_ValueForKey( level.arenas.infos[i], "type" ), sizeof(type) );
		Q_CleanString( type, STRIP_COLOUR );

		trap->Print( "  %-24s%-32s%-64s\n", map, longname, type );
	}
}
示例#6
0
static void SV_BotList_f( void ) {
	int i;
	char name[MAX_TOKEN_CHARS], funname[MAX_TOKEN_CHARS], model[MAX_TOKEN_CHARS], personality[MAX_TOKEN_CHARS];

	trap->Print( "name             model            personality              funname\n" );
	for ( i = 0; i < level.bots.num; i++ ) {
		Q_strncpyz( name, Info_ValueForKey( level.bots.infos[i], "name" ), sizeof(name) );
		Q_CleanString( name, STRIP_COLOUR );

		Q_strncpyz( funname, Info_ValueForKey( level.bots.infos[i], "funname" ), sizeof(funname) );
		Q_CleanString( funname, STRIP_COLOUR );

		Q_strncpyz( model, Info_ValueForKey( level.bots.infos[i], "model" ), sizeof(model) );
		Q_CleanString( model, STRIP_COLOUR );

		Q_strncpyz( personality, Info_ValueForKey( level.bots.infos[i], "personality" ), sizeof(personality) );
		Q_CleanString( personality, STRIP_COLOUR );

		trap->Print( "%-16s %-16s %-20s %-20s\n", name, model, personality, funname );
	}
}
示例#7
0
// The string has been tokenized and can be retrieved with Cmd_Argc() / Cmd_Argv()
static void CG_ServerCommand( void ) {
	const char	*cmd;
	char		text[MAX_SAY_TEXT];
	qboolean	IRCG = qfalse;

	if ( JPLua_Event_ServerCommand() )
		return;

	cmd = CG_Argv( 0 );

	// server claimed the command
	if ( !cmd[0] )
		return;

	if ( !strcmp( cmd, "sxd" ) ) {
		// siege extended data, contains extra info certain classes may want to know about other clients
		CG_ParseSiegeExtendedData();
		return;
	}

	if ( !strcmp( cmd, "sb" ) ) {
		// siege briefing display
		CG_SiegeBriefingDisplay( atoi( CG_Argv( 1 ) ), qfalse );
		return;
	}

	if ( !strcmp( cmd, "scl" ) ) {
		trap->OpenUIMenu( UIMENU_CLASSSEL );
		return;
	}

	if ( !strcmp( cmd, "spc" ) ) {
		if ( !cg.demoPlayback ) {
			trap->Cvar_Set( "ui_myteam", "3" );
			trap->OpenUIMenu( UIMENU_PLAYERCONFIG );
		}
		return;
	}

	if ( !strcmp( cmd, "nfr" ) ) {
		// new force rank
		int doMenu = 0, setTeam = 0, newRank = 0;

		if ( trap->Cmd_Argc() < 3 ) {
#ifdef _DEBUG
			Com_Printf( "WARNING: Invalid newForceRank string\n" );
#endif
			return;
		}

		newRank = atoi( CG_Argv( 1 ) );
		doMenu = atoi( CG_Argv( 2 ) );
		setTeam = atoi( CG_Argv( 3 ) );

		trap->Cvar_Set( "ui_rankChange", va( "%i", newRank ) );

		trap->Cvar_Set( "ui_myteam", va( "%i", setTeam ) );

		if ( !(trap->Key_GetCatcher() & KEYCATCH_UI) && doMenu && !cg.demoPlayback )
			trap->OpenUIMenu( UIMENU_PLAYERCONFIG );

		return;
	}

	if ( !strcmp( cmd, "kg2" ) ) {
		// Kill a ghoul2 instance in this slot.
		// If it has been occupied since this message was sent somehow, the worst that can (should) happen is the instance
		//	will have to reinit with its current info.
		int i, indexNum = 0, argNum = trap->Cmd_Argc();

		if ( argNum < 1 )
			return;

		for ( i = 1; i < argNum; i++ ) {
			indexNum = atoi( CG_Argv( i ) );

			if ( cg_entities[indexNum].ghoul2 && trap->G2_HaveWeGhoul2Models( cg_entities[indexNum].ghoul2 ) ) {
				if ( indexNum < MAX_CLIENTS ) { //You try to do very bad thing!
#ifdef _DEBUG
					Com_Printf( "WARNING: Tried to kill a client ghoul2 instance with a kg2 command!\n" );
#endif
					return;
				}

				CG_KillCEntityG2( indexNum );
			}
		}

		return;
	}

	if ( !strcmp( cmd, "kls" ) ) {
		// kill looping sounds
		int indexNum = 0, argNum = trap->Cmd_Argc();
		centity_t *clent = NULL, *trackerent = NULL;

		if ( argNum < 1 ) {
			assert( 0 );
			return;
		}

		indexNum = atoi( CG_Argv( 1 ) );

		if ( indexNum != -1 )
			clent = &cg_entities[indexNum];

		if ( argNum >= 2 ) {
			indexNum = atoi( CG_Argv( 2 ) );

			if ( indexNum != -1 )
				trackerent = &cg_entities[indexNum];
		}

		if ( clent )
			CG_S_StopLoopingSound( clent->currentState.number, -1 );
		if ( trackerent )
			CG_S_StopLoopingSound( trackerent->currentState.number, -1 );

		return;
	}

	// this means param 2 is the body index and we want to copy to bodyqueue on it
	if ( !strcmp( cmd, "ircg" ) )
		IRCG = qtrue;

	if ( !strcmp( cmd, "rcg" ) || IRCG ) {
		//rcg - Restore Client Ghoul (make sure limbs are reattached and ragdoll state is reset - this must be done reliably)
		int indexNum = 0, argNum = trap->Cmd_Argc();
		centity_t *clent;

		if ( argNum < 1 ) {
			assert( 0 );
			return;
		}

		indexNum = atoi( CG_Argv( 1 ) );
		if ( indexNum < 0 || indexNum >= MAX_CLIENTS ) {
			assert( 0 );
			return;
		}

		clent = &cg_entities[indexNum];

		// this can happen while connecting as a client
		if ( !clent->ghoul2 )
			return;

#ifdef _DEBUG
		if ( !trap->G2_HaveWeGhoul2Models( clent->ghoul2 ) )
			assert( !"Tried to reset state on a bad instance. Crash is inevitable." );
#endif

		if ( IRCG ) {
			int bodyIndex = 0, weaponIndex = 0, side = 0;
			centity_t *body;

			assert( argNum >= 3 );
			bodyIndex = atoi( CG_Argv( 2 ) );
			weaponIndex = atoi( CG_Argv( 3 ) );
			side = atoi( CG_Argv( 4 ) );

			body = &cg_entities[bodyIndex];
			body->teamPowerType = side ? 1 : 0;

			CG_BodyQueueCopy( body, clent->currentState.number, weaponIndex );
		}

		// reattach any missing limbs
		if ( clent->torsoBolt )
			CG_ReattachLimb( clent );

		// make sure ragdoll state is reset
		if ( clent->isRagging ) {
			clent->isRagging = qfalse;
			trap->G2API_SetRagDoll( clent->ghoul2, NULL ); //calling with null parms resets to no ragdoll.
		}

		// clear all the decals as well
		trap->G2API_ClearSkinGore( clent->ghoul2 );

		clent->weapon = 0;
		clent->ghoul2weapon = NULL; //force a weapon reinit

		return;
	}

	if ( !strcmp( cmd, "cp" ) ) {
		char strEd[MAX_STRINGED_SV_STRING];
		CG_CheckSVStringEdRef( strEd, CG_Argv( 1 ) );
		CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.30f, BIGCHAR_WIDTH );
		return;
	}

	if ( !strcmp( cmd, "cps" ) ) {
		char strEd[MAX_STRINGED_SV_STRING];
		char *x = (char *)CG_Argv( 1 );
		if ( x[0] == '@' )
			x++;
		trap->SE_GetStringTextString( x, strEd, MAX_STRINGED_SV_STRING );
		//Raz: From OJP
		//	CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.30f, BIGCHAR_WIDTH );
		CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.20f, BIGCHAR_WIDTH );
		return;
	}

	if ( !strcmp( cmd, "cs" ) ) {
		CG_ConfigStringModified();
		return;
	}

	if ( !strcmp( cmd, "print" ) ) {
		char strEd[MAX_STRINGED_SV_STRING];
		CG_CheckSVStringEdRef( strEd, CG_Argv( 1 ) );
		CG_LogPrintf( cg.log.console, strEd );
		trap->Print( "%s", strEd );
		return;
	}

	if ( !strcmp( cmd, "chat" ) ) {
		char *msg = JPLua_Event_ChatMessageRecieved( CG_Argv( 1 ) );

		//If a JPLua plugin cancelled it, bail
		if ( !msg )
			return;

		if ( !cg_teamChatsOnly.integer ) {
			char cbName[MAX_CHATBOX_IDENTIFIER_SIZE] = "normal";
			trap->S_StartLocalSound( media.sounds.interface.talk, CHAN_LOCAL_SOUND );
			Q_strncpyz( text, msg, MAX_SAY_TEXT );

			if ( CG_ContainsChannelEscapeChar( text ) )
				Q_strncpyz( cbName, CG_RemoveChannelEscapeChar( text ), sizeof(cbName) );

			CG_RemoveChatEscapeChar( text );
			CG_LogPrintf( cg.log.console, va( "%s\n", text ) );
			if ( cg_newChatbox.integer )
				CG_ChatboxAddMessage( text, qfalse, cbName );
			else
				CG_ChatBox_AddString( text );
			trap->Print( "*%s\n", text );
			Q_CleanString( text, STRIP_COLOUR );
			CG_LogPrintf( cg.log.chat, va( "%s\n", text ) );
		}

		return;
	}

	if ( !strcmp( cmd, "tchat" ) ) {
		trap->S_StartLocalSound( media.sounds.interface.talk, CHAN_LOCAL_SOUND );
		Q_strncpyz( text, CG_Argv( 1 ), MAX_SAY_TEXT );
		CG_RemoveChatEscapeChar( text );
		CG_LogPrintf( cg.log.console, va( "%s\n", text ) );
		if ( cg_newChatbox.integer )
			CG_ChatboxAddMessage( text, qfalse, "team" );
		else
			CG_ChatBox_AddString( text );
		trap->Print( "*%s\n", text );
		Q_CleanString( text, STRIP_COLOUR );
		CG_LogPrintf( cg.log.chat, va( "%s\n", text ) );

		return;
	}

	//chat with location, possibly localized.
	if ( !strcmp( cmd, "lchat" ) ) {
		if ( !cg_teamChatsOnly.integer ) {
			char name[MAX_STRING_CHARS], loc[MAX_STRING_CHARS], color[8], message[MAX_STRING_CHARS];

			if ( trap->Cmd_Argc() < 4 )
				return;

			Q_strncpyz( name, CG_Argv( 1 ), sizeof(name) );
			Q_strncpyz( loc, CG_Argv( 2 ), sizeof(loc) );
			Q_strncpyz( color, CG_Argv( 3 ), sizeof(color) );
			Q_strncpyz( message, CG_Argv( 4 ), sizeof(message) );

			if ( loc[0] == '@' )
				trap->SE_GetStringTextString( loc + 1, loc, sizeof(loc) );

			trap->S_StartLocalSound( media.sounds.interface.talk, CHAN_LOCAL_SOUND );
			//	Q_strncpyz( text, CG_Argv( 1 ), MAX_SAY_TEXT );
			Com_sprintf( text, sizeof(text), "%s" S_COLOR_WHITE "<%s> ^%s%s", name, loc, color, message );
			CG_RemoveChatEscapeChar( text );
			//Raz: Siege chat now uses the fancy new chatbox
			if ( cg_newChatbox.integer )
				CG_ChatboxAddMessage( text, qfalse, "normal" );
			else
				CG_ChatBox_AddString( text );
			trap->Print( "*%s\n", text );
			Q_CleanString( text, STRIP_COLOUR );
			CG_LogPrintf( cg.log.chat, va( "%s\n", text ) );
		}
		return;
	}
	if ( !strcmp( cmd, "ltchat" ) ) {
		char name[MAX_STRING_CHARS], loc[MAX_STRING_CHARS], color[8], message[MAX_STRING_CHARS];

		if ( trap->Cmd_Argc() < 4 )
			return;

		Q_strncpyz( name, CG_Argv( 1 ), sizeof(name) );
		Q_strncpyz( loc, CG_Argv( 2 ), sizeof(loc) );
		Q_strncpyz( color, CG_Argv( 3 ), sizeof(color) );
		Q_strncpyz( message, CG_Argv( 4 ), sizeof(message) );

		if ( loc[0] == '@' )
			trap->SE_GetStringTextString( loc + 1, loc, sizeof(loc) );

		trap->S_StartLocalSound( media.sounds.interface.talk, CHAN_LOCAL_SOUND );
		//	Q_strncpyz( text, CG_Argv( 1 ), MAX_SAY_TEXT );
		Com_sprintf( text, sizeof(text), "%s" S_COLOR_WHITE "<%s> ^%s%s", name, loc, color, message );
		CG_RemoveChatEscapeChar( text );
		if ( cg_newChatbox.integer )
			CG_ChatboxAddMessage( text, qfalse, "team" );
		else
			CG_ChatBox_AddString( text );
		trap->Print( "*%s\n", text );
		Q_CleanString( text, STRIP_COLOUR );
		CG_LogPrintf( cg.log.chat, va( "%s\n", text ) );

		return;
	}

	if ( !strcmp( cmd, "scores" ) ) {
		CG_ParseScores();
		return;
	}

	if ( !strcmp( cmd, "tinfo" ) ) {
		CG_ParseTeamInfo();
		return;
	}

	if ( !strcmp( cmd, "map_restart" ) ) {
		CG_MapRestart();
		return;
	}

	if ( !Q_stricmp( cmd, "remapShader" ) ) {
		if ( trap->Cmd_Argc() == 4 ) {
			char shader1[MAX_QPATH], shader2[MAX_QPATH];
			Q_strncpyz( shader1, CG_Argv( 1 ), sizeof(shader1) );
			Q_strncpyz( shader2, CG_Argv( 2 ), sizeof(shader2) );
			trap->R_RemapShader( shader1, shader2, CG_Argv( 3 ) );
			return;
		}
		return;
	}

	// loaddeferred can be both a servercmd and a consolecmd
	if ( !strcmp( cmd, "loaddefered" ) ) {	// FIXME: spelled wrong, but not changing for demo
		CG_LoadDeferredPlayers();
		return;
	}

	// clientLevelShot is sent before taking a special screenshot for the menu system during development
	if ( !strcmp( cmd, "clientLevelShot" ) ) {
		cg.levelShot = qtrue;
		return;
	}

	trap->Print( "Unknown client game command: %s\n", cmd );
}
示例#8
0
	//Func: GetPlayer( clientNum )
	//Retn: Player object
	int GetPlayer( lua_State *L ) {
	#if defined(PROJECT_GAME)
		int clientNum;

		if ( lua_type( L, 1 ) == LUA_TNUMBER ) {
			clientNum = lua_tointeger( L, 1 );
		}

		else if ( lua_type( L, 1 ) == LUA_TSTRING ) {
			const char *name = lua_tostring( L, 1 );
			clientNum = G_ClientFromString( NULL, name, FINDCL_SUBSTR );
			if ( clientNum == -1 ) {
				lua_pushnil( L );
				return 1;
			}
		}

		else {
			lua_pushnil( L );
			return 1;
		}

		Player_CreateRef( L, clientNum );
		return 1;
	#elif defined(PROJECT_CGAME)
		int num = -1;
		uint32_t clientsFound = 0;

		if ( lua_type( L, 1 ) == LUA_TNUMBER ) {
			num = lua_tointeger( L, 1 );
		}

		else if ( lua_type( L, 1 ) == LUA_TSTRING ) {
			const char *name = lua_tostring( L, 1 );
			int numFound = 0;
			//RAZTODO: copy G_ClientFromString
			for ( int i = 0; i < cgs.maxclients; i++ ) {
				char nameClean[MAX_NETNAME], nameClean2[MAX_NETNAME];

				if ( !cgs.clientinfo[i].infoValid ) {
					continue;
				}

				Q_strncpyz( nameClean, cgs.clientinfo[i].name, sizeof(nameClean) );
				Q_strncpyz( nameClean2, name, sizeof(nameClean2) );
				Q_CleanString( nameClean, STRIP_COLOUR );
				Q_CleanString( nameClean2, STRIP_COLOUR );
				if ( !Q_stricmp( nameClean, nameClean2 ) ) {
					num = i;
					clientsFound |= (1 << i);
					numFound++;
				}
			}

			if ( numFound > 1 ) {
				int top = 0;
				lua_pushnil( L );
				lua_pushstring( L, "Multiple matches" );

				lua_newtable( L );
				top = lua_gettop( L );
				for ( int i = 0; i < cgs.maxclients; i++ ) {
					if ( clientsFound & (1 << i) ) {
						lua_pushnumber( L, i );
						Player_CreateRef( L, i );
						lua_settable( L, top );
					}
				}
				return 3;
			}
			else if ( !numFound ) {
				lua_pushnil( L );
				return 1;
			}
		}

		else {//if ( lua_type( L, 1 ) == LUA_TNIL )
			num = cg.clientNum;
		}

		Player_CreateRef( L, num );
		return 1;
	#endif
	}