diff --git a/dlls/Android.mk b/dlls/Android.mk index c6b0a3d3..a5096ad9 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -52,6 +52,7 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ effects.cpp \ egon.cpp \ explode.cpp \ + enttools.cpp \ flyingmonster.cpp \ func_break.cpp \ func_tank.cpp \ @@ -134,7 +135,8 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ ../pm_shared/pm_math.c \ ../pm_shared/pm_shared.c \ coop.cpp \ - gateofbabylon.cpp + gateofbabylon.cpp \ + gravgunmod.cpp \ # ../game_shared/voice_gamemgr.cpp LOCAL_LDLIBS := -llog diff --git a/dlls/client.cpp b/dlls/client.cpp index 932d438b..4b273f39 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -563,7 +563,7 @@ void ClientCommand( edict_t *pEntity ) MENU_STR(touch_addbutton "_coops5" "#" "menuselect 5;touch_hide _coops*" 0.16 0.61 0.39 0.7 255 255 255 255 335 1.5;wait;slot10\n) ); } - else + else if( !Ent_ProcessClientCommand( pEntity ) ) { // tell the user they entered an unknown command char command[128]; @@ -595,7 +595,7 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) return; // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) - if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq( STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" )) ) + if ( pEntity->v.netname && (STRING(pEntity->v.netname))[0] != 0 && !FStrEq( STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" )) ) { char sName[256]; char *pName = g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ); diff --git a/dlls/coop.cpp b/dlls/coop.cpp index ddc3f1d4..622b12f3 100644 --- a/dlls/coop.cpp +++ b/dlls/coop.cpp @@ -2,7 +2,8 @@ #include "util.h" #include "cbase.h" #include "player.h" -#include "coop_util.h"" +#include "coop_util.h" +#include "gravgunmod.h" GlobalMenu g_GlobalMenu; @@ -11,6 +12,24 @@ struct SavedCoords g_SavedCoords, s_SavedCoords; static float msglimittime1, msglimittime2; +cvar_t mp_coop = { "mp_coop", "0", FCVAR_SERVER }; +cvar_t mp_coop_changelevel = { "mp_coop_changelevel", "0", FCVAR_SERVER }; +cvar_t mp_coop_nofriendlyfire = { "mp_coop_nofriendlyfire", "0", FCVAR_SERVER }; +cvar_t mp_coop_disabledmap = { "mp_coop_disabledmap", "", FCVAR_SERVER }; +cvar_t mp_coop_reconnect_hack = { "mp_coop_reconnect_hack", "0", FCVAR_SERVER }; +cvar_t mp_coop_noangry = { "mp_coop_noangry", "0", FCVAR_SERVER }; +cvar_t mp_coop_checkpoints = { "mp_coop_checkpoints", "1", FCVAR_SERVER }; +cvar_t mp_skipdefaults = { "mp_skipdefaults", "0", FCVAR_SERVER }; +cvar_t mp_coop_strongcheckpoints = { "mp_coop_strongcheckpoints", "0", FCVAR_SERVER }; + +cvar_t mp_unduck = { "mp_unduck", "0", FCVAR_SERVER }; +cvar_t mp_semclip = { "mp_semclip", "0", FCVAR_SERVER }; +cvar_t mp_spectator = { "mp_spectator", "0", FCVAR_SERVER }; + +cvar_t materials_txt = { "materials_txt", "sound/materials.txt", FCVAR_SERVER }; +cvar_t sentences_txt = { "sentences_txt", "sound/sentences.txt", FCVAR_SERVER }; + + void UTIL_CoopPlayerMessage( CBaseEntity *pPlayer, int channel, float time, unsigned int color1, unsigned int color2, float x, float y, const char *format, ... ) { @@ -858,6 +877,8 @@ int UTIL_CheckForEntTools( edict_t *pent ) return 0; } + + int UTIL_CoopCheckSpawn( edict_t *pent ) { if( mp_checkentities.value ) @@ -908,3 +929,22 @@ int UTIL_CoopCheckSpawn( edict_t *pent ) } return 0; } + +void COOP_RegisterCVars() +{ + CVAR_REGISTER( &mp_coop ); + CVAR_REGISTER( &mp_coop_changelevel ); + CVAR_REGISTER( &mp_coop_nofriendlyfire ); + CVAR_REGISTER( &mp_coop_disabledmap ); + CVAR_REGISTER( &mp_unduck ); + CVAR_REGISTER( &mp_semclip ); + CVAR_REGISTER( &mp_coop_reconnect_hack ); + CVAR_REGISTER( &mp_coop_noangry ); + CVAR_REGISTER( &mp_spectator ); + CVAR_REGISTER( &mp_coop_checkpoints ); + CVAR_REGISTER( &mp_skipdefaults ); + CVAR_REGISTER( &mp_coop_strongcheckpoints ); + + CVAR_REGISTER( &sentences_txt ); + CVAR_REGISTER( &materials_txt ); +} diff --git a/dlls/coop_util.h b/dlls/coop_util.h index 93277aa7..f2fa3653 100644 --- a/dlls/coop_util.h +++ b/dlls/coop_util.h @@ -1,17 +1,5 @@ #ifndef COOP_UTIL_H #define COOP_UTIL_H -extern cvar_t cvar_allow_gravgun; -extern cvar_t cvar_allow_ar2; -extern cvar_t cvar_ar2_mp5; -extern cvar_t cvar_ar2_bullets; -extern cvar_t cvar_ar2_balls; -extern cvar_t cvar_wresptime; -extern cvar_t cvar_iresptime; - -extern cvar_t cvar_gibtime; -extern cvar_t cvar_hgibcount; -extern cvar_t cvar_agibcount; - extern cvar_t mp_gravgun_players; extern cvar_t mp_coop; extern cvar_t mp_coop_changelevel; @@ -26,9 +14,6 @@ extern cvar_t mp_unduck; extern cvar_t mp_semclip; extern cvar_t mp_coop_reconnect_hack; extern cvar_t mp_coop_noangry; -extern cvar_t mp_spectator; -extern cvar_t mp_fixhornetbug; -extern cvar_t mp_checkentities; extern cvar_t sentences_txt; @@ -77,6 +62,7 @@ void UTIL_CoopPrintMessage( const char *format, ... ); void UTIL_CoopHudMessage( int channel, float time, unsigned int color1, unsigned int color2, float x, float y, const char *format, ... ); void UTIL_CoopPlayerMessage( CBaseEntity *pPlayer, int channel, float time, unsigned int color1, unsigned int color2, float x, float y, const char *format, ... ); +void COOP_RegisterCVars( void ); #ifdef PLAYER_H void UTIL_CoopKickPlayer(CBaseEntity *pPlayer); diff --git a/dlls/enttools.cpp b/dlls/enttools.cpp new file mode 100644 index 00000000..24bded58 --- /dev/null +++ b/dlls/enttools.cpp @@ -0,0 +1,792 @@ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "game.h" + +#define Ent_IsValidEdict( e ) ( e && !e->free ) + +bool Q_isdigit( const char *str ) +{ + if( str && *str ) + { + while( isdigit( *str )) str++; + if( !*str ) return true; + } + return false; +} + +bool Q_stricmpext( const char *pattern, const char *text ); + +static bool Q_starcmp( const char *pattern, const char *text ) +{ + char c, c1; + const char *p = pattern, *t = text; + + while(( c = *p++ ) == '?' || c == '*' ) + { + if( c == '?' && *t++ == '\0' ) + return false; + } + + if( c == '\0' ) return true; + + for( c1 = (( c == '\\' ) ? *p : c ); ; ) + { + if( tolower( *t ) == c1 && Q_stricmpext( p - 1, t )) + return true; + if( *t++ == '\0' ) return false; + } +} + +bool Q_stricmpext( const char *pattern, const char *text ) +{ + char c; + + while(( c = *pattern++ ) != '\0' ) + { + switch( c ) + { + case '?': + if( *text++ == '\0' ) + return false; + break; + case '\\': + if( tolower( *pattern++ ) != tolower( *text++ )) + return false; + break; + case '*': + return Q_starcmp( pattern, text ); + default: + if( tolower( c ) != tolower( *text++ )) + return false; + } + } + return true; +} + +void Ent_ClientPrintf( edict_t *player, const char *format, ... ) +{ + va_list argptr; + char string[256]; + + va_start( argptr, format ); + int len = vsnprintf( string, 256, format, argptr ); + va_end( argptr ); + string[len] = 0; + + MESSAGE_BEGIN( MSG_ONE, 8, g_vecZero, player ); // svc_print + WRITE_BYTE( 0 ); // PRINT_LOW + WRITE_STRING( string ); + MESSAGE_END(); +} + + +static edict_t *Ent_GetCrossEnt( edict_t *player ) +{ + edict_t *ent = g_engfuncs.pfnPEntityOfEntIndex(1); + edict_t *closest = NULL; + float flMaxDot = 0.94; + Vector forward; + int i; + float maxLen = 1000; + + UTIL_MakeVectorsPrivate( player->v.v_angle, forward, NULL, NULL ); + + Vector viewPos = player->v.origin + player->v.view_ofs; + + // find bmodels by trace + { + TraceResult tr; + + UTIL_TraceLine(viewPos, viewPos + forward * 1000, missile, player, &tr); + closest = tr.pHit; + maxLen = (viewPos - tr.vecEndPos).Length() + 30; + } + + // check untraceable entities + for ( i = 1; i < gpGlobals->maxEntities; i++, ent++ ) + { + Vector vecLOS; + Vector vecOrigin; + float flDot, traceLen; + + if( ent->free ) + continue; + + if( ent->v.solid == SOLID_BSP || ent->v.movetype == MOVETYPE_PUSHSTEP ) + continue; //bsp models will be found by trace later + + // do not touch following weapons + if( ent->v.movetype == MOVETYPE_FOLLOW ) + continue; + + if( ent == player ) + continue; + + vecOrigin = VecBModelOrigin(&ent->v); + + vecLOS = vecOrigin - viewPos; + traceLen = vecLOS.Length(); + + if( traceLen > maxLen ) + continue; + + vecLOS = UTIL_ClampVectorToBox(vecLOS, ent->v.size * 0.5); + + flDot = DotProduct(vecLOS , forward); + if ( flDot <= flMaxDot ) + continue; + + TraceResult tr; + UTIL_TraceLine(viewPos, vecOrigin, missile, player, &tr); + if( (tr.vecEndPos - viewPos).Length() + 30 < traceLen ) + continue; + closest = ent, flMaxDot = flDot; + } + + return closest; +} + +/* +=============== +Ent_List_f + +Print list of entities to client +=============== +*/ +void Ent_List_f( edict_t *player ) +{ + edict_t *ent = NULL; + int i; + + for( i = 0; i < gpGlobals->maxEntities; i++ ) + { + ent = g_engfuncs.pfnPEntityOfEntIndex( i ); + if( !Ent_IsValidEdict( ent )) continue; + + // filter by string + if( CMD_ARGC() > 1 ) + if( !Q_stricmpext( CMD_ARGV( 1 ), STRING( ent->v.classname ) ) && !Q_stricmpext( CMD_ARGV( 1 ), STRING( ent->v.targetname ) ) ) + continue; + Vector borigin = VecBModelOrigin( &ent->v ); + + Ent_ClientPrintf( player, "%5i origin: %.f %.f %.f", i, ent->v.origin[0], ent->v.origin[1], ent->v.origin[2] ); + Ent_ClientPrintf( player, "%5i borigin: %.f %.f %.f", i, borigin[0], borigin[1], borigin[2] ); + + if( ent->v.classname ) + Ent_ClientPrintf( player, ", class: %s", STRING( ent->v.classname )); + + if( ent->v.globalname ) + Ent_ClientPrintf( player, ", global: %s", STRING( ent->v.globalname )); + + if( ent->v.targetname ) + Ent_ClientPrintf( player, ", name: %s", STRING( ent->v.targetname )); + + if( ent->v.target ) + Ent_ClientPrintf( player, ", target: %s", STRING( ent->v.target )); + + if( ent->v.model ) + Ent_ClientPrintf( player, ", model: %s", STRING( ent->v.model )); + + Ent_ClientPrintf( player, "\n" ); + } +} + + + +edict_t *Ent_FindSingle( edict_t *player, const char *pattern ) +{ + edict_t *ent = NULL; + int i = 0; + + if( Q_isdigit( pattern ) ) + { + i = atoi( pattern ); + + if( i >= gpGlobals->maxEntities ) + return NULL; + } + else if( !stricmp( pattern, "!cross" ) ) + { + ent = Ent_GetCrossEnt( player ); + + if( !Ent_IsValidEdict( ent ) ) + return NULL; + + i = ENTINDEX( ent ); + } + else if( pattern[0] == '!' ) // Check for correct instanse with !(num)_(serial) + { + const char *p = pattern + 1; + i = atoi( p ); + + while( isdigit(*p) ) p++; + + if( *p++ != '_' ) + return NULL; + + if( i >= gpGlobals->maxEntities ) + return NULL; + + ent = g_engfuncs.pfnPEntityOfEntIndex( i ); + + if( ent->serialnumber != atoi( p ) ) + return NULL; + } + else + { + for( i = gpGlobals->maxClients + 1; i < gpGlobals->maxEntities; i++ ) + { + ent = g_engfuncs.pfnPEntityOfEntIndex( i ); + + if( !Ent_IsValidEdict( ent ) ) + continue; + + if( Q_stricmpext( pattern, STRING( ent->v.targetname ) ) ) + break; + } + } + + ent = g_engfuncs.pfnPEntityOfEntIndex( i ); + + if( !Ent_IsValidEdict( ent ) ) + return NULL; + + return ent; +} + + +/* +=============== +Ent_Info_f + +Print specified entity information to client +=============== +*/ +void Ent_Info_f( edict_t *player ) +{ + edict_t *ent = NULL; + + if( CMD_ARGC() != 2 ) + { + Ent_ClientPrintf( player, "Use ent_info \n" ); + return; + } + + ent = Ent_FindSingle( player, CMD_ARGV( 1 ) ); + + if( !Ent_IsValidEdict( ent )) return; + + Vector borigin = VecBModelOrigin( &ent->v ); + + Ent_ClientPrintf( player, "origin: %.f %.f %.f\n", ent->v.origin[0], ent->v.origin[1], ent->v.origin[2] ); + + Ent_ClientPrintf( player, "angles: %.f %.f %.f\n", ent->v.angles[0], ent->v.angles[1], ent->v.angles[2] ); + + Ent_ClientPrintf( player, "borigin: %.f %.f %.f\n", borigin[0], borigin[1], borigin[2] ); + + if( ent->v.classname ) + Ent_ClientPrintf( player, "class: %s\n", STRING( ent->v.classname )); + + if( ent->v.globalname ) + Ent_ClientPrintf( player, "global: %s\n", STRING( ent->v.globalname )); + + if( ent->v.targetname ) + Ent_ClientPrintf( player, "name: %s\n", STRING( ent->v.targetname )); + + if( ent->v.target ) + Ent_ClientPrintf( player, "target: %s\n", STRING( ent->v.target )); + + if( ent->v.model ) + Ent_ClientPrintf( player, "model: %s\n", STRING( ent->v.model )); + + Ent_ClientPrintf( player, "health: %.f\n", ent->v.health ); + + if( ent->v.gravity != 1.0f ) + Ent_ClientPrintf( player, "gravity: %.2f\n", ent->v.gravity ); + + Ent_ClientPrintf( player, "movetype: %d\n", ent->v.movetype ); + + Ent_ClientPrintf( player, "rendermode: %d\n", ent->v.rendermode ); + Ent_ClientPrintf( player, "renderfx: %d\n", ent->v.renderfx ); + Ent_ClientPrintf( player, "renderamt: %f\n", ent->v.renderamt ); + Ent_ClientPrintf( player, "rendercolor: %f %f %f\n", ent->v.rendercolor[0], ent->v.rendercolor[1], ent->v.rendercolor[2] ); + + Ent_ClientPrintf( player, "maxspeed: %f\n", ent->v.maxspeed ); + + if( ent->v.solid ) + Ent_ClientPrintf( player, "solid: %d\n", ent->v.solid ); + Ent_ClientPrintf( player, "flags: 0x%x\n", ent->v.flags ); + Ent_ClientPrintf( player, "spawnflags: 0x%x\n", ent->v.spawnflags ); +} + +void Ent_SendVars( edict_t *player, edict_t *ent ) +{ + if( !ent ) + return; + + CLIENT_COMMAND( player, UTIL_VarArgs( "set ent_last_name \"%s\"\n", STRING( ent->v.targetname ) )); + CLIENT_COMMAND( player, UTIL_VarArgs( "set ent_last_num %i\n", ENTINDEX( ent ) )); + CLIENT_COMMAND( player, UTIL_VarArgs( "set ent_last_inst !%i_%i\n", ENTINDEX( ent ), ent->serialnumber )); + CLIENT_COMMAND( player, UTIL_VarArgs( "set ent_last_origin \"%f %f %f\"\n", ent->v.origin[0], ent->v.origin[1], ent->v.origin[2])); + CLIENT_COMMAND( player, UTIL_VarArgs( "set ent_last_class \"%s\"\n", STRING( ent->v.classname ))); + CLIENT_COMMAND( player, "ent_getvars_cb\n" ); +} + +void Ent_GetVars_f( edict_t *player ) +{ + edict_t *ent = NULL; + + if( CMD_ARGC() != 2 ) + { + Ent_ClientPrintf( player, "Use ent_getvars \n" ); + return; + } + + ent = Ent_FindSingle( player, CMD_ARGV( 1 ) ); + if( CMD_ARGC() ) + if( !Ent_IsValidEdict( ent )) return; + Ent_SendVars( player, ent ); +} + +/* +=============== +Ent_Fire_f + +Perform some actions +=============== +*/ +void Ent_Fire_f( edict_t *player ) +{ + edict_t *ent = NULL; + int i = 1, count = 0; + qboolean single; // true if user specified something that match single entity + + if( CMD_ARGC() < 3 ) + { + Ent_ClientPrintf( player, "Use ent_fire []\n" + "Use ent_fire 0 help to get command list\n" ); + return; + } + + if( ( single = Q_isdigit( CMD_ARGV( 1 ) ) ) ) + { + i = atoi( CMD_ARGV( 1 ) ); + + if( i < 0 || i >= gpGlobals->maxEntities ) + return; + + ent = g_engfuncs.pfnPEntityOfEntIndex( i ); + } + else if( ( single = !stricmp( CMD_ARGV( 1 ), "!cross" ) ) ) + { + ent = Ent_GetCrossEnt( player ); + + if( !Ent_IsValidEdict( ent ) ) + return; + + i = ENTINDEX( ent ); + } + else if( ( single = ( CMD_ARGV( 1 )[0] == '!') ) ) // Check for correct instanse with !(num)_(serial) + { + const char *cmd = CMD_ARGV( 1 ) + 1; + i = atoi( cmd ); + + while( isdigit( *cmd ) ) cmd++; + + if( *cmd++ != '_' ) + return; + + if( i < 0 || i >= gpGlobals->maxEntities ) + return; + + ent = g_engfuncs.pfnPEntityOfEntIndex( i ); + if( ent->serialnumber != atoi( cmd ) ) + return; + } + else + { + i = gpGlobals->maxClients + 1; + } + + for( ; ( i < gpGlobals->maxEntities ) && ( count < mp_enttools_maxfire.value ); i++ ) + { + ent = g_engfuncs.pfnPEntityOfEntIndex( i ); + if( !Ent_IsValidEdict( ent )) + { + // Ent_ClientPrintf( player, "Got invalid entity\n" ); + if( single ) + break; + continue; + } + + // if user specified not a number, try find such entity + if( !single ) + { + if( !Q_stricmpext( CMD_ARGV( 1 ), STRING( ent->v.targetname ) ) && !Q_stricmpext( CMD_ARGV( 1 ), STRING( ent->v.classname ) )) + continue; + } + + Ent_ClientPrintf( player, "entity %i\n", i ); + + count++; + + if( !stricmp( CMD_ARGV( 2 ), "health" ) ) + ent->v.health = atoi( CMD_ARGV ( 3 ) ); + else if( !stricmp( CMD_ARGV( 2 ), "gravity" ) ) + ent->v.gravity = atof( CMD_ARGV ( 3 ) ); + else if( !stricmp( CMD_ARGV( 2 ), "movetype" ) ) + ent->v.movetype = atoi( CMD_ARGV ( 3 ) ); + else if( !stricmp( CMD_ARGV( 2 ), "solid" ) ) + ent->v.solid = atoi( CMD_ARGV ( 3 ) ); + else if( !stricmp( CMD_ARGV( 2 ), "rename" ) ) + ent->v.targetname = ALLOC_STRING( CMD_ARGV ( 3 ) ); + else if( !stricmp( CMD_ARGV( 2 ), "settarget" ) ) + ent->v.target = ALLOC_STRING( CMD_ARGV ( 3 ) ); + else if( !stricmp( CMD_ARGV( 2 ), "setmodel" ) ) + SET_MODEL( ent, CMD_ARGV( 3 ) ); + else if( !stricmp( CMD_ARGV( 2 ), "set" ) ) + { + char keyname[256]; + char value[256]; + KeyValueData pkvd; + if( CMD_ARGC() != 5 ) + return; + pkvd.szClassName = (char*)STRING( ent->v.classname ); + strncpy( keyname, CMD_ARGV( 3 ), 256 ); + strncpy( value, CMD_ARGV( 4 ), 256 ); + keyname[255] = value[255] = 0; + pkvd.szKeyName = keyname; + pkvd.szValue = value; + pkvd.fHandled = false; + DispatchKeyValue( ent, &pkvd ); + if( pkvd.fHandled ) + Ent_ClientPrintf( player, "value set successfully!\n" ); + } + else if( !stricmp( CMD_ARGV( 2 ), "touch" ) ) + { + if( CMD_ARGC() == 4 ) + { + edict_t *other = Ent_FindSingle( player, CMD_ARGV( 3 ) ); + if( other && other->pvPrivateData ) + DispatchTouch( ent, other ); + } + else + DispatchTouch( ent, player ); + } + else if( !stricmp( CMD_ARGV( 2 ), "use" ) ) + { + if( CMD_ARGC() == 4 ) + { + edict_t *other = Ent_FindSingle( player, CMD_ARGV( 3 ) ); + if( other && other->pvPrivateData ) + DispatchUse( ent, other ); + } + else + DispatchUse( ent, player ); + } + else if( !stricmp( CMD_ARGV( 2 ), "movehere" ) ) + UTIL_SetOrigin( &ent->v, player->v.origin + Vector( 100 * cos( player->v.angles[1]/180*M_PI ), 100 * sin( player->v.angles[1]/180*M_PI), 25 ) ); + else if( !stricmp( CMD_ARGV( 2 ), "drop2floor" ) ) + DROP_TO_FLOOR( ent ); + else if( !stricmp( CMD_ARGV( 2 ), "moveup" ) ) + { + float dist = 25; + + if( CMD_ARGC() >= 4 ) + dist = atof( CMD_ARGV( 3 ) ); + + ent->v.origin[2] += dist; + + if( CMD_ARGC() >= 5 ) + ent->v.origin = ent->v.origin + Vector( cos( player->v.angles[1]/180*M_PI ), sin( player->v.angles[1]/180*M_PI), 0 ) * atof( CMD_ARGV( 4 ) ); + } + else if( !stricmp( CMD_ARGV( 2 ), "becomeowner" ) ) + { + if( CMD_ARGC() == 4 ) + ent->v.owner = Ent_FindSingle( player, CMD_ARGV( 3 ) ); + else + ent->v.owner = player; + } + else if( !stricmp( CMD_ARGV( 2 ), "becomeenemy" ) ) + { + if( CMD_ARGC() == 4 ) + ent->v.enemy = Ent_FindSingle( player, CMD_ARGV( 3 ) ); + else + ent->v.enemy = player; + } + else if( !stricmp( CMD_ARGV( 2 ), "becomeaiment" ) ) + { + if( CMD_ARGC() == 4 ) + ent->v.aiment= Ent_FindSingle( player, CMD_ARGV( 3 ) ); + else + ent->v.aiment = player; + } + else if( !stricmp( CMD_ARGV( 2 ), "hullmin" ) ) + { + if( CMD_ARGC() != 6 ) + return; + ent->v.mins[0] = atof( CMD_ARGV( 3 ) ); + ent->v.mins[1] = atof( CMD_ARGV( 4 ) ); + ent->v.mins[2] = atof( CMD_ARGV( 5 ) ); + } + else if( !stricmp( CMD_ARGV( 2 ), "hullmax" ) ) + { + if( CMD_ARGC() != 6 ) + return; + ent->v.maxs[0] = atof( CMD_ARGV( 3 ) ); + ent->v.maxs[1] = atof( CMD_ARGV( 4 ) ); + ent->v.maxs[2] = atof( CMD_ARGV( 5 ) ); + } + else if( !stricmp( CMD_ARGV( 2 ), "rendercolor" ) ) + { + if( CMD_ARGC() != 6 ) + return; + ent->v.rendercolor[0] = atof( CMD_ARGV( 3 ) ); + ent->v.rendercolor[1] = atof( CMD_ARGV( 4 ) ); + ent->v.rendercolor[2] = atof( CMD_ARGV( 5 ) ); + } + else if( !stricmp( CMD_ARGV( 2 ), "renderamt" ) ) + { + ent->v.renderamt = atof( CMD_ARGV( 3 ) ); + } + else if( !stricmp( CMD_ARGV( 2 ), "renderfx" ) ) + { + ent->v.renderfx = atoi( CMD_ARGV( 3 ) ); + } + else if( !stricmp( CMD_ARGV( 2 ), "rendermode" ) ) + { + ent->v.rendermode = atoi( CMD_ARGV( 3 ) ); + } + else if( !stricmp( CMD_ARGV( 2 ), "angles" ) ) + { + ent->v.angles[0] = atof( CMD_ARGV( 3 ) ); + ent->v.angles[1] = atof( CMD_ARGV( 4 ) ); + ent->v.angles[2] = atof( CMD_ARGV( 5 ) ); + } + else if( !stricmp( CMD_ARGV( 2 ), "setflag" ) ) + { + ent->v.flags |= 1U << atoi( CMD_ARGV ( 3 ) ); + Ent_ClientPrintf( player, "flags set to 0x%x\n", ent->v.flags ); + } + else if( !stricmp( CMD_ARGV( 2 ), "clearflag" ) ) + { + ent->v.flags &= ~( 1U << atoi( CMD_ARGV ( 3 ) ) ); + Ent_ClientPrintf( player, "flags set to 0x%x\n", ent->v.flags ); + } + else if( !stricmp( CMD_ARGV( 2 ), "setspawnflag" ) ) + { + ent->v.spawnflags |= 1U << atoi( CMD_ARGV ( 3 ) ); + Ent_ClientPrintf( player, "spawnflags set to 0x%x\n", ent->v.spawnflags ); + } + else if( !stricmp( CMD_ARGV( 2 ), "clearspawnflag" ) ) + { + ent->v.spawnflags &= ~( 1U << atoi( CMD_ARGV ( 3 ) ) ); + Ent_ClientPrintf( player, "spawnflags set to 0x%x\n", ent->v.flags ); + } + else if( !stricmp( CMD_ARGV( 2 ), "help" ) ) + { + Ent_ClientPrintf( player, "Availiavle commands:\n" + "Set fields:\n" + " (Only set entity field, does not call any functions)\n" + " health\n" + " gravity\n" + " movetype\n" + " solid\n" + " rendermode\n" + " rendercolor (vector)\n" + " renderfx\n" + " renderamt\n" + " hullmin (vector)\n" + " hullmax (vector)\n" + "Actions\n" + " rename: set entity targetname\n" + " settarget: set entity target (only targetnames)\n" + " setmodel: set entity model\n" + " set: set by server library\n" + " See game FGD to get list.\n" + " command takes two arguments\n" + " touch: touch entity by current player.\n" + " use: use entity by current player.\n" + " movehere: place entity in player fov.\n" + " drop2floor: place entity to nearest floor surface\n" + " moveup: move entity to 25 units up\n" + "Flags:\n" + " (Set/clear specified flag bit, arg is bit number)\n" + " setflag\n" + " clearflag\n" + " setspawnflag\n" + " clearspawnflag\n" + ); + return; + } + else + { + Ent_ClientPrintf( player, "Unknown command %s!\nUse \"ent_fire 0 help\" to list commands.\n", CMD_ARGV( 2 ) ); + return; + } + if( single ) + break; + } +} + +/* +=============== +Ent_Create_f + +Create new entity with specified name. +=============== +*/ +void Ent_Create_f( edict_t *player ) +{ + edict_t *ent = NULL; + int i = 0; + string_t classname; + + if( CMD_ARGC() < 2 ) + { + Ent_ClientPrintf( player, "Use ent_create ...\n" ); + return; + } + + classname = ALLOC_STRING( CMD_ARGV( 1 ) ); + ent = CREATE_NAMED_ENTITY( classname ); + + if( !ent ) + { + Ent_ClientPrintf( player, "Invalid entity!\n" ); + return; + } + + // choose default origin + UTIL_SetOrigin( &ent->v, player->v.origin + Vector( 100 * cos( player->v.angles[1]/180*M_PI ), 100 * sin( player->v.angles[1]/180*M_PI), 25 )); + + // apply keyvales + for( i = 2; i < CMD_ARGC() - 1; i++ ) + { + KeyValueData pkvd; + + // allow split keyvalues to prespawn and postspawn + if( !strcmp( CMD_ARGV( i ), "|" ) ) + { + i++; + break; + } + + pkvd.fHandled = false; + pkvd.szClassName = (char*)STRING( ent->v.classname ); + pkvd.szKeyName = (char*)CMD_ARGV( i ); + i++; + pkvd.szValue = (char*)CMD_ARGV( i ); + + DispatchKeyValue( ent, &pkvd ); + if( pkvd.fHandled ) + Ent_ClientPrintf( player, "value \"%s\" set to \"%s\"!\n", pkvd.szKeyName, pkvd.szValue ); + } + + + // set default targetname + if( !ent->v.targetname ) + { + char newname[256], clientname[256]; + + for( i = 0; i < 32; i++ ) + { + char c = tolower( (STRING( player->v.netname ))[i] ); + if( c < 'a' || c > 'z' ) + c = '_'; + if( !(STRING( player->v.netname ))[i] ) + { + clientname[i] = 0; + break; + } + clientname[i] = c; + } + + // generate name based on nick name and index + snprintf( newname, 255, "%s_%i_e%i", clientname, GETPLAYERUSERID( player ), ENTINDEX( ent ) ); + newname[255] = 0; + + // i know, it may break strict aliasing rules + // but we will not lose anything in this case. + //Q_strnlwr( newname, newname, 256 ); + ent->v.targetname = ALLOC_STRING( newname ); + Ent_SendVars( player, ent ); + } + + Ent_ClientPrintf( player, "Created %i: %s, targetname %s\n", ENTINDEX( ent ), CMD_ARGV( 1 ), STRING( ent->v.targetname ) ); + + DispatchSpawn( ent ); + + // now drop entity to floor. + g_engfuncs.pfnDropToFloor( ent ); + + // force think. Otherwise given weapon may crash server if player touch it before. + DispatchThink( ent ); + g_engfuncs.pfnDropToFloor( ent ); + + // apply postspawn keyvales + + for( i = i; i < CMD_ARGC() - 1; i++ ) + { + KeyValueData pkvd; + + pkvd.fHandled = false; + pkvd.szClassName = (char*)STRING( ent->v.classname ); + pkvd.szKeyName = (char*)CMD_ARGV( i ); + i++; + pkvd.szValue = (char*)CMD_ARGV( i ); + DispatchKeyValue( ent, &pkvd ); + if( pkvd.fHandled ) + Ent_ClientPrintf( player, "value \"%s\" set to \"%s\"!\n", pkvd.szKeyName, pkvd.szValue ); + } +} +typedef struct ucmd_s +{ + const char *name; + void (*func)( edict_t *player ); +} ucmd_t; + +ucmd_t enttoolscmds[] = +{ +{ "ent_list", Ent_List_f }, +{ "ent_info", Ent_Info_f }, +{ "ent_fire", Ent_Fire_f }, +{ "ent_create", Ent_Create_f }, +{ "ent_getvars", Ent_GetVars_f }, +{ NULL, NULL } +}; + +bool Ent_ProcessClientCommand( edict_t *player ) +{ + ucmd_t *u; + + + if( !mp_enttools_enable.value ) + return false; + + for( u = enttoolscmds; u->name; u++ ) + { + if( !strcmp( CMD_ARGV( 0 ), u->name )) + { + ALERT( at_console, "enttools->%s(): %s\n", u->name, CMD_ARGS() ); + + ALERT( at_logged, "\"%s<%i><%s><>\" performed: %s\n", STRING(player->v.netname), + GETPLAYERUSERID(player), GETPLAYERAUTHID(player), g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( player ), "ip" ), CMD_ARGS() ); + + if( u->func ) u->func( player ); + return true; + } + } + + return false; +} + +cvar_t mp_enttools_enable = { "mp_enttools_enable", "0", FCVAR_SERVER }; +cvar_t mp_enttools_maxfire = { "mp_enttools_maxfire", "5", FCVAR_SERVER }; + +void ENT_RegisterCVars( void ) +{ + CVAR_REGISTER( &mp_enttools_enable ); + CVAR_REGISTER( &mp_enttools_maxfire ); +} diff --git a/dlls/enttools.h b/dlls/enttools.h new file mode 100644 index 00000000..dcafb682 --- /dev/null +++ b/dlls/enttools.h @@ -0,0 +1,9 @@ +#ifndef ENTTOOLS_H +#define ENTTOOLS_H + +extern cvar_t mp_enttools_maxfire; +extern cvar_t mp_enttools_enable; +bool Ent_ProcessClientCommand( edict_t *player ); +void ENT_RegisterCVars( void ); +#endif // ENTTOOLS_H + diff --git a/dlls/game.cpp b/dlls/game.cpp index 11fe257e..dc1400da 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -38,36 +38,8 @@ cvar_t teamlist = { "mp_teamlist","hgrunt;scientist", FCVAR_SERVER }; cvar_t teamoverride = { "mp_teamoverride","1" }; cvar_t defaultteam = { "mp_defaultteam","0" }; cvar_t allowmonsters = { "mp_allowmonsters","0", FCVAR_SERVER }; -cvar_t cvar_allow_gravgun = { "mp_allow_gravgun","1", FCVAR_SERVER }; -cvar_t cvar_allow_ar2 = { "mp_allow_ar2","0", FCVAR_SERVER }; -cvar_t cvar_ar2_mp5 = { "mp_ar2_mp5","0", FCVAR_SERVER }; -cvar_t cvar_ar2_balls = { "mp_ar2_balls","0", FCVAR_SERVER }; -cvar_t cvar_ar2_bullets = { "mp_ar2_bullets","0", FCVAR_SERVER }; -cvar_t cvar_wresptime = { "mp_wresptime","20", FCVAR_SERVER }; -cvar_t cvar_iresptime = { "mp_iresptime","30", FCVAR_SERVER }; -cvar_t cvar_gibtime = { "mp_gibtime","250", FCVAR_SERVER }; -cvar_t cvar_hgibcount = { "mp_hgibcount","12", FCVAR_SERVER }; -cvar_t cvar_agibcount = { "mp_agibcount","8", FCVAR_SERVER }; + cvar_t mp_chattime = { "mp_chattime","10", FCVAR_SERVER }; -cvar_t mp_gravgun_players = { "mp_gravgun_players", "0", FCVAR_SERVER }; -cvar_t mp_coop = { "mp_coop", "0", FCVAR_SERVER }; -cvar_t mp_coop_changelevel = { "mp_coop_changelevel", "0", FCVAR_SERVER }; -cvar_t mp_coop_nofriendlyfire = { "mp_coop_nofriendlyfire", "0", FCVAR_SERVER }; -cvar_t mp_coop_disabledmap = { "mp_coop_disabledmap", "", FCVAR_SERVER }; -cvar_t mp_coop_reconnect_hack = { "mp_coop_reconnect_hack", "0", FCVAR_SERVER }; -cvar_t mp_coop_noangry = { "mp_coop_noangry", "0", FCVAR_SERVER }; -cvar_t mp_coop_checkpoints = { "mp_coop_checkpoints", "1", FCVAR_SERVER }; -cvar_t mp_skipdefaults = { "mp_skipdefaults", "0", FCVAR_SERVER }; -cvar_t mp_coop_strongcheckpoints = { "mp_coop_strongcheckpoints", "0", FCVAR_SERVER }; - -cvar_t mp_unduck = { "mp_unduck", "0", FCVAR_SERVER }; -cvar_t mp_semclip = { "mp_semclip", "0", FCVAR_SERVER }; -cvar_t mp_spectator = { "mp_spectator", "0", FCVAR_SERVER }; -cvar_t mp_fixhornetbug = { "mp_fixhornetbug", "0", FCVAR_SERVER }; -cvar_t mp_checkentities = { "mp_checkentities", "0", FCVAR_SERVER }; - -cvar_t materials_txt = { "materials_txt", "sound/materials.txt", FCVAR_SERVER }; -cvar_t sentences_txt = { "sentences_txt", "sound/sentences.txt", FCVAR_SERVER }; // Engine Cvars cvar_t *g_psv_gravity = NULL; @@ -480,6 +452,9 @@ void GameDLLInit( void ) g_footsteps = CVAR_GET_POINTER( "mp_footsteps" ); CVAR_REGISTER( &displaysoundlist ); + GGM_RegisterCVars(); + COOP_RegisterCVars(); + ENT_RegisterCVars(); CVAR_REGISTER( &teamplay ); CVAR_REGISTER( &fraglimit ); @@ -499,37 +474,6 @@ void GameDLLInit( void ) CVAR_REGISTER( &teamoverride ); CVAR_REGISTER( &defaultteam ); CVAR_REGISTER( &allowmonsters ); - CVAR_REGISTER( &cvar_allow_ar2 ); - CVAR_REGISTER( &cvar_allow_gravgun ); - CVAR_REGISTER( &cvar_ar2_mp5 ); - CVAR_REGISTER( &cvar_ar2_bullets ); - CVAR_REGISTER( &cvar_ar2_balls ); - CVAR_REGISTER( &cvar_wresptime ); - CVAR_REGISTER( &cvar_iresptime ); - CVAR_REGISTER( &cvar_gibtime ); - CVAR_REGISTER( &cvar_hgibcount ); - CVAR_REGISTER( &cvar_agibcount ); - CVAR_REGISTER( &mp_gravgun_players ); - CVAR_REGISTER( &mp_coop ); - CVAR_REGISTER( &mp_coop_changelevel ); - CVAR_REGISTER( &mp_coop_nofriendlyfire ); - CVAR_REGISTER( &mp_coop_disabledmap ); - CVAR_REGISTER( &mp_unduck ); - CVAR_REGISTER( &mp_semclip ); - CVAR_REGISTER( &mp_coop_reconnect_hack ); - CVAR_REGISTER( &mp_coop_noangry ); - CVAR_REGISTER( &mp_spectator ); - CVAR_REGISTER( &mp_coop_checkpoints ); - CVAR_REGISTER( &mp_skipdefaults ); - CVAR_REGISTER( &mp_coop_strongcheckpoints ); - CVAR_REGISTER( &mp_fixhornetbug ); - CVAR_REGISTER( &mp_checkentities ); - - - - CVAR_REGISTER( &sentences_txt ); - CVAR_REGISTER( &materials_txt ); - CVAR_REGISTER( &mp_chattime ); diff --git a/dlls/game.h b/dlls/game.h index 9828a614..d6a67dd4 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -37,6 +37,8 @@ extern cvar_t defaultteam; extern cvar_t allowmonsters; #include "coop_util.h" +#include "enttools.h" +#include "gravgunmod.h" // Engine Cvars extern cvar_t *g_psv_gravity; diff --git a/dlls/gravgunmod.cpp b/dlls/gravgunmod.cpp new file mode 100644 index 00000000..101e2009 --- /dev/null +++ b/dlls/gravgunmod.cpp @@ -0,0 +1,37 @@ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "gravgunmod.h" +#include "coop_util.h" + +cvar_t cvar_allow_gravgun = { "mp_allow_gravgun","1", FCVAR_SERVER }; +cvar_t cvar_allow_ar2 = { "mp_allow_ar2","0", FCVAR_SERVER }; +cvar_t cvar_ar2_mp5 = { "mp_ar2_mp5","0", FCVAR_SERVER }; +cvar_t cvar_ar2_balls = { "mp_ar2_balls","0", FCVAR_SERVER }; +cvar_t cvar_ar2_bullets = { "mp_ar2_bullets","0", FCVAR_SERVER }; +cvar_t cvar_wresptime = { "mp_wresptime","20", FCVAR_SERVER }; +cvar_t cvar_iresptime = { "mp_iresptime","30", FCVAR_SERVER }; +cvar_t cvar_gibtime = { "mp_gibtime","250", FCVAR_SERVER }; +cvar_t cvar_hgibcount = { "mp_hgibcount","12", FCVAR_SERVER }; +cvar_t cvar_agibcount = { "mp_agibcount","8", FCVAR_SERVER }; +cvar_t mp_gravgun_players = { "mp_gravgun_players", "0", FCVAR_SERVER }; + +cvar_t mp_fixhornetbug = { "mp_fixhornetbug", "0", FCVAR_SERVER }; +cvar_t mp_checkentities = { "mp_checkentities", "0", FCVAR_SERVER }; + +void GGM_RegisterCVars( void ) +{ + CVAR_REGISTER( &cvar_allow_ar2 ); + CVAR_REGISTER( &cvar_allow_gravgun ); + CVAR_REGISTER( &cvar_ar2_mp5 ); + CVAR_REGISTER( &cvar_ar2_bullets ); + CVAR_REGISTER( &cvar_ar2_balls ); + CVAR_REGISTER( &cvar_wresptime ); + CVAR_REGISTER( &cvar_iresptime ); + CVAR_REGISTER( &cvar_gibtime ); + CVAR_REGISTER( &cvar_hgibcount ); + CVAR_REGISTER( &cvar_agibcount ); + CVAR_REGISTER( &mp_gravgun_players ); + CVAR_REGISTER( &mp_fixhornetbug ); + CVAR_REGISTER( &mp_checkentities ); +} diff --git a/dlls/gravgunmod.h b/dlls/gravgunmod.h new file mode 100644 index 00000000..f60887ed --- /dev/null +++ b/dlls/gravgunmod.h @@ -0,0 +1,24 @@ +#ifndef GRAVGUNMOD_H +#define GRAVGUNMOD_H + + +extern cvar_t cvar_allow_gravgun; +extern cvar_t cvar_allow_ar2; +extern cvar_t cvar_ar2_mp5; +extern cvar_t cvar_ar2_bullets; +extern cvar_t cvar_ar2_balls; +extern cvar_t cvar_wresptime; +extern cvar_t cvar_iresptime; + +extern cvar_t cvar_gibtime; +extern cvar_t cvar_hgibcount; +extern cvar_t cvar_agibcount; + +extern cvar_t mp_spectator; +extern cvar_t mp_fixhornetbug; +extern cvar_t mp_checkentities; + +void GGM_RegisterCVars( void ); + +#endif // GRAVGUNMOD_H + diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 55825e2f..fa3b5ea7 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -1135,7 +1135,7 @@ void CFuncTrackTrain::Next( void ) } // prevent train without players going to other map - if( mp_coop.value && pev->globalname && STRING( pev->globalname )[0] ) + if( mp_coop.value && pev->globalname && (STRING( pev->globalname ))[0] ) { CBaseEntity *pList; Vector mins = pev->absmin;