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; }
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); }
//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; }
// 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( ¢->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 ) ); } }
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 ); } }
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 ); } }
// 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 ); }
//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 }