Exemple #1
0
void ACEND_SetGoal(gentity_t * self, int goalNode)
{
	int             node;

	self->bs.goalNode = goalNode;

	node = ACEND_FindClosestReachableNode(self, NODE_DENSITY * 3, NODE_ALL);

	if(node == INVALID)
		return;

	if(ace_debug.integer)
		trap_SendServerCommand(-1, va("print \"%s: new start node selected %d\n\"", self->client->pers.netname, node));

	self->bs.currentNode = node;
	self->bs.nextNode = self->bs.currentNode;	// make sure we get to the nearest node first
	self->bs.node_timeout = 0;

	if(ace_showPath.integer)
	{
		// draw path to LR goal
		ACEND_DrawPath(self->bs.currentNode, self->bs.goalNode);
	}
}
Exemple #2
0
/*
==================
CheckVote
==================
*/
void CheckVote( void ) {
	if ( level.voteExecuteTime && level.voteExecuteTime < level.time ) {
		level.voteExecuteTime = 0;
		trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
	}
	if ( !level.voteTime ) {
		return;
	}
	if ( level.time - level.voteTime >= VOTE_TIME ) {
		if(g_dmflags.integer & DF_LIGHT_VOTING) {
			//Let pass if there was at least twice as many for as against
			if ( level.voteYes > level.voteNo*2 ) {
				trap_SendServerCommand( -1, "print \"Vote passed. At least 2 of 3 voted yes\n\"" );
				level.voteExecuteTime = level.time + 3000;
			} else {
				//Let pass if there is more yes than no and at least 2 yes votes and at least 30% yes of all on the server
				if ( level.voteYes > level.voteNo && level.voteYes >= 2 && (level.voteYes*10)>(level.numVotingClients*3) ) {
					trap_SendServerCommand( -1, "print \"Vote passed. More yes than no.\n\"" );
					level.voteExecuteTime = level.time + 3000;
				} else
					trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
			}
		} else {
			trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
		}
	} else {
		// ATVI Q3 1.32 Patch #9, WNF
		if ( level.voteYes > (level.numVotingClients)/2 ) {
			// execute the command, then remove the vote
			trap_SendServerCommand( -1, "print \"Vote passed.\n\"" );
			level.voteExecuteTime = level.time + 3000;
		} else if ( level.voteNo >= (level.numVotingClients)/2 ) {
			// same behavior as a timeout
			trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
		} else {
			// still waiting for a majority
			return;
		}
	}
	level.voteTime = 0;
	trap_SetConfigstring( CS_VOTE_TIME, "" );

}
Exemple #3
0
/*
==================
TeamplayLocationsMessage

Format:
	clientNum location health armor weapon powerups

==================
*/
void TeamplayInfoMessage( gentity_t *ent ) {
	char		entry[1024];
	char		string[8192];
	int			stringlength;
	int			i, j;
	gentity_t	*player;
	int			cnt;
	int			h, a;
	int			clients[TEAM_MAXOVERLAY];
	int			team;

	if ( ! ent->client->pers.teamInfo )
		return;

	// send team info to spectator for team of followed client
	if (ent->client->sess.sessionTeam == TEAM_SPECTATOR) {
		if ( ent->client->sess.spectatorState != SPECTATOR_FOLLOW
			|| ent->client->sess.spectatorClient < 0 ) {
				return;
		}
		team = g_entities[ ent->client->sess.spectatorClient ].client->sess.sessionTeam;
	} else {
		team = ent->client->sess.sessionTeam;
	}

	if (team != TEAM_RED && team != TEAM_BLUE) {
		return;
	}

	// figure out what client should be on the display
	// we are limited to 8, but we want to use the top eight players
	// but in client order (so they don't keep changing position on the overlay)
	for (i = 0, cnt = 0; i < sv_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
		player = g_entities + level.sortedClients[i];
		if (player->inuse && player->client->sess.sessionTeam == team ) {
			clients[cnt++] = level.sortedClients[i];
		}
	}

	// We have the top eight players, sort them by clientNum
	qsort( clients, cnt, sizeof( clients[0] ), SortClients );

	// send the latest information on all clients
	string[0] = 0;
	stringlength = 0;

	for (i = 0, cnt = 0; i < sv_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++) {
		player = g_entities + i;
		if (player->inuse && player->client->sess.sessionTeam == team ) {

			h = player->client->ps.stats[STAT_HEALTH];
			a = player->client->ps.stats[STAT_ARMOR];
			if (h < 0) h = 0;
			if (a < 0) a = 0;

			Com_sprintf (entry, sizeof(entry),
				" %i %i %i %i %i %i", 
			//	level.sortedClients[i], player->client->pers.teamState.location, h, a, 
				i, player->client->pers.teamState.location, h, a, 
				player->client->ps.weapon, player->s.powerups);
			j = strlen(entry);
			if (stringlength + j >= sizeof(string))
				break;
			strcpy (string + stringlength, entry);
			stringlength += j;
			cnt++;
		}
	}

	trap_SendServerCommand( ent-g_entities, va("tinfo %i %s", cnt, string) );
}
Exemple #4
0
/*
==================
player_die
==================
*/
void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int meansOfDeath )
{
	gentity_t *ent;
	int       anim;
	int       killer;
	int       i;
	const char *killerName, *obit;

	if ( self->client->ps.pm_type == PM_DEAD )
	{
		return;
	}

	if ( level.intermissiontime )
	{
		return;
	}

	self->client->ps.pm_type = PM_DEAD;
	self->suicideTime = 0;

	if ( attacker )
	{
		killer = attacker->s.number;

		if ( attacker->client )
		{
			killerName = attacker->client->pers.netname;
		}
		else
		{
			killerName = "<world>";
		}
	}
	else
	{
		killer = ENTITYNUM_WORLD;
		killerName = "<world>";
	}

	if ( meansOfDeath < 0 || meansOfDeath >= ARRAY_LEN( modNames ) )
	{
		// fall back on the number
		obit = va( "%d", meansOfDeath );
	}
	else
	{
		obit = modNames[ meansOfDeath ];
	}

	G_LogPrintf( "Die: %d %d %s: %s" S_COLOR_WHITE " killed %s\n",
	             killer,
	             ( int )( self - g_entities ),
	             obit,
	             killerName,
	             self->client->pers.netname );

	// deactivate all upgrades
	for ( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
	{
		BG_DeactivateUpgrade( i, self->client->ps.stats );
	}

	// broadcast the death event to everyone
	ent = G_NewTempEntity( self->r.currentOrigin, EV_OBITUARY );
	ent->s.eventParm = meansOfDeath;
	ent->s.otherEntityNum = self->s.number;
	ent->s.otherEntityNum2 = killer;
	ent->r.svFlags = SVF_BROADCAST; // send to everyone

	if ( attacker && attacker->client )
	{
		if ( ( attacker == self || OnSameTeam( self, attacker ) ) )
		{
			//punish team kills and suicides
			if ( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
			{
				G_AddCreditToClient( attacker->client, -ALIEN_TK_SUICIDE_PENALTY, qtrue );
				G_AddCreditsToScore( attacker, -ALIEN_TK_SUICIDE_PENALTY );
			}
			else if ( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
			{
				G_AddCreditToClient( attacker->client, -HUMAN_TK_SUICIDE_PENALTY, qtrue );
				G_AddCreditsToScore( attacker, -HUMAN_TK_SUICIDE_PENALTY );
			}
		}
		else if ( g_showKillerHP.integer )
		{
			trap_SendServerCommand( self - g_entities, va( "print_tr %s %s %3i", QQ( N_("Your killer, $1$^7, had $2$ HP.\n") ),
			                        Quote( killerName ),
			                        attacker->health ) );
		}
	}
	else if ( attacker->s.eType != ET_BUILDABLE )
	{
		if ( self->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
		{
			G_AddCreditsToScore( self, -ALIEN_TK_SUICIDE_PENALTY );
		}
		else if ( self->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
		{
			G_AddCreditsToScore( self, -HUMAN_TK_SUICIDE_PENALTY );
		}
	}

	// give credits for killing this player
	G_RewardAttackers( self );

	ScoreboardMessage( self );  // show scores

	// send updated scores to any clients that are following this one,
	// or they would get stale scoreboards
	for ( i = 0; i < level.maxclients; i++ )
	{
		gclient_t *client;

		client = &level.clients[ i ];

		if ( client->pers.connected != CON_CONNECTED )
		{
			continue;
		}

		if ( client->sess.spectatorState == SPECTATOR_NOT )
		{
			continue;
		}

		if ( client->sess.spectatorClient == self->s.number )
		{
			ScoreboardMessage( g_entities + i );
		}
	}

	VectorCopy( self->s.origin, self->client->pers.lastDeathLocation );

	self->takedamage = qfalse; // can still be gibbed

	self->s.weapon = WP_NONE;
	if ( self->client->noclip )
	{
		self->client->cliprcontents = CONTENTS_CORPSE;
	}
	else
	{
		self->r.contents = CONTENTS_CORPSE;
	}

	self->s.angles[ PITCH ] = 0;
	self->s.angles[ ROLL ] = 0;
	self->s.angles[ YAW ] = self->s.apos.trBase[ YAW ];
	LookAtKiller( self, inflictor, attacker );

	VectorCopy( self->s.angles, self->client->ps.viewangles );

	self->s.loopSound = 0;

	self->r.maxs[ 2 ] = -8;

	// don't allow respawn until the death anim is done
	// g_forcerespawn may force spawning at some later time
	self->client->respawnTime = level.time + 1700;

	// clear misc
	memset( self->client->ps.misc, 0, sizeof( self->client->ps.misc ) );

	{
		static int i;

		if ( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
		{
			switch ( i )
			{
				case 0:
					anim = BOTH_DEATH1;
					break;

				case 1:
					anim = BOTH_DEATH2;
					break;

				case 2:
				default:
					anim = BOTH_DEATH3;
					break;
			}
		}
		else
		{
			switch ( i )
			{
				case 0:
					anim = NSPA_DEATH1;
					break;

				case 1:
					anim = NSPA_DEATH2;
					break;

				case 2:
				default:
					anim = NSPA_DEATH3;
					break;
			}
		}

		self->client->ps.legsAnim =
		  ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;

		if ( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
		{
			self->client->ps.torsoAnim =
			  ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
		}

		// use own entityid if killed by non-client to prevent uint8_t overflow
		G_AddEvent( self, EV_DEATH1 + i,
		            ( killer < MAX_CLIENTS ) ? killer : self - g_entities );

		// globally cycle through the different death animations
		i = ( i + 1 ) % 3;
	}

	trap_LinkEntity( self );

	self->client->pers.infoChangeTime = level.time;
}
/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private
"message"	text to print
"wait"		don't fire off again if triggered within this many milliseconds ago
If "private", only the activator gets the message.  If no checks, all clients get the message.
*/
void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator)
{
	if (!ent || !ent->inuse)
	{
		Com_Printf("ERROR: Bad ent in Use_Target_Print");
		return;
	}

	if (ent->wait)
	{
		if (ent->genericValue14 >= level.time)
		{
			return;
		}
		ent->genericValue14 = level.time + ent->wait;
	}

#ifndef FINAL_BUILD
	if (!ent || !ent->inuse)
	{
		Com_Error(ERR_DROP, "Bad ent in Use_Target_Print");
	}
	else if (!activator || !activator->inuse)
	{
		Com_Error(ERR_DROP, "Bad activator in Use_Target_Print");
	}

	/*if (ent->genericValue15 > level.time) // lol wtf is this bullshit
	{
		Com_Printf("TARGET PRINT ERRORS:\n");
		if (activator && activator->classname && activator->classname[0])
		{
			Com_Printf("activator classname: %s\n", activator->classname);
		}
		if (activator && activator->target && activator->target[0])
		{
			Com_Printf("activator target: %s\n", activator->target);
		}
		if (activator && activator->targetname && activator->targetname[0])
		{
			Com_Printf("activator targetname: %s\n", activator->targetname);
		}
		if (ent->targetname && ent->targetname[0])
		{
			Com_Printf("print targetname: %s\n", ent->targetname);
		}
		Com_Error(ERR_DROP, "target_print used in quick succession, fix it! See the console for details.");
	}
	ent->genericValue15 = level.time + 5000;*/
#endif

	G_ActivateBehavior(ent,BSET_USE);
	if ( ( ent->spawnflags & 4 ) ) 
	{//private, to one client only
		if (!activator || !activator->inuse)
		{
			Com_Printf("ERROR: Bad activator in Use_Target_Print");
		}
		if ( activator && activator->client )
		{//make sure there's a valid client ent to send it to
			if (ent->message[0] == '@' && ent->message[1] != '@')
			{
				trap_SendServerCommand( activator-g_entities, va("cps \"%s\"", ent->message ));
			}
			else
			{
				trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message ));
			}
		}
		//NOTE: change in functionality - if there *is* no valid client ent, it won't send it to anyone at all
		return;
	}

	if ( ent->spawnflags & 3 ) {
		if ( ent->spawnflags & 1 ) {
			if (ent->message[0] == '@' && ent->message[1] != '@')
			{
				G_TeamCommand( TEAM_RED, va("cps \"%s\"", ent->message) );
			}
			else
			{
				G_TeamCommand( TEAM_RED, va("cp \"%s\"", ent->message) );
			}
		}
		if ( ent->spawnflags & 2 ) {
			if (ent->message[0] == '@' && ent->message[1] != '@')
			{
				G_TeamCommand( TEAM_BLUE, va("cps \"%s\"", ent->message) );
			}
			else
			{
				G_TeamCommand( TEAM_BLUE, va("cp \"%s\"", ent->message) );
			}
		}
		return;
	}

	if (ent->message[0] == '@' && ent->message[1] != '@')
	{
		trap_SendServerCommand( -1, va("cps \"%s\"", ent->message ));
	}
	else
	{
		trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ));
	}
}
void Svcmd_CamCmd( void ) {
    char buf[MAX_TOKEN_CHARS];
    char cmd[MAX_TOKEN_CHARS];
    char name[MAX_TOKEN_CHARS];
    int i;
    gclient_t* cl;

    if( !level.cammode ) {
        return;
    }

    if( trap_Argc() < 2 ) {
        return;
    }

    trap_Argv( 1, cmd, sizeof(cmd) );

    if ( !Q_stricmp (cmd, "print")  )
    {
        trap_Argv( 2, buf, sizeof(buf) );
        trap_SendServerCommand( -1, va("cp \"%s\n\"", buf ) );
    }
    else if( !Q_stricmp (cmd, "setclientpos") ) {
        vec3_t	newOrigin;

        if( trap_Argc() != 8 && trap_Argc() != 6 ) {
            Com_Printf("usage: camcmd setclientpos name/id x y z (a b) \na = PITCH-angle, b = YAW-angle\n");
            return;
        }

        trap_Argv( 2, name, sizeof( name ) );

        cl = ClientForString( name ) ;
        if(!cl)
            return;

        for( i=0; i<3; i++) {
            trap_Argv( i+3, buf, sizeof( buf) );
            newOrigin[i] = atof( buf );
        }

        G_SetOrigin( &g_entities[cl->ps.clientNum], newOrigin );
        VectorCopy( newOrigin, cl->ps.origin );

        if(trap_Argc() == 8) {
            vec3_t	newAngles;

            memset(newAngles,0,sizeof(newAngles));
            trap_Argv( 6, buf, sizeof( buf ) );
            newAngles[PITCH] = atoi(buf);
            trap_Argv( 7, buf, sizeof( buf ) );
            newAngles[YAW] = atoi(buf);

            SetClientViewAngle( &g_entities[cl->ps.clientNum], newAngles );
        }
    }
    else if( !Q_stricmp (cmd, "setspawn")  )
    {
        if( trap_Argc() != 8 ) {
            Com_Printf("usage: camcmd setspawn x y z a b c \n");
            return;
        }

        for( i=0; i<3; i++) {
            trap_Argv( i+2, buf, sizeof(buf) );
            level.cam_spawnpos[i] = atof(buf);
        }
        for( i=0; i<3; i++) {
            trap_Argv( i+5, buf, sizeof(buf) );
            level.cam_spawnangles[i] = atof(buf);
        }
    }
    else if( !Q_stricmp (cmd, "botmove")  )
    {
        vec3_t pos;

        if( trap_Argc() != 6 ) {
            Com_Printf("usage: camcmd botmove name x y z \n");
            return;
        }

        trap_Argv( 2, name, sizeof( name ) );

        for( i=0; i<3; i++) {
            trap_Argv( i+3, buf, sizeof( buf) );
            pos[i] = atof( buf );
        }

        cl = ClientForString( name ) ;
        if(!cl)
            return;
        BotCamMoveTo( cl->ps.clientNum, pos );
    }
    else if( !Q_stricmp (cmd, "botviewangles")  )
    {
        vec3_t angles;

        if( trap_Argc() != 5 ) {
            Com_Printf("usage: camcmd botviewangles name x y \n");
            return;
        }

        trap_Argv( 2, name, sizeof( name ) );
        cl = ClientForString( name ) ;
        if(!cl)
            return;
        trap_Argv( 3, buf, sizeof( buf ) );
        angles[PITCH] = atoi(buf);
        trap_Argv( 4, buf, sizeof( buf ) );
        angles[YAW] = atoi(buf);

        BotCamViewangles( cl->ps.clientNum, angles );
    }
    else if( !Q_stricmp (cmd, "botviewtarget")  )
    {
        vec3_t target;

        if( trap_Argc() != 6 ) {
            Com_Printf("usage: camcmd botviewtarget name x y z \n");
            return;
        }

        trap_Argv( 2, name, sizeof( name ) );
        cl = ClientForString( name ) ;
        if(!cl)
            return;
        trap_Argv( 3, buf, sizeof( buf ) );
        target[0] = atoi(buf);
        trap_Argv( 4, buf, sizeof( buf ) );
        target[1] = atoi(buf);
        trap_Argv( 5, buf, sizeof( buf ) );
        target[2] = atoi(buf);

        BotCamViewTarget( cl->ps.clientNum, target );
    }
    else if( !Q_stricmp (cmd, "botviewentity")  )
    {
//		int target_bot;
        gclient_t* target_cl;
        if( trap_Argc() != 4 ) {
            Com_Printf("usage: camcmd botviewentity name targetname \n");
            return;
        }

        trap_Argv( 2, name, sizeof( name ) );
        cl = ClientForString( name ) ;
        if(!cl)
            return;

        trap_Argv( 3, buf, sizeof( buf ) );
        target_cl = ClientForString( buf );
        if(!target_cl)
            return;
        BotCamViewEntitiy( cl->ps.clientNum, target_cl->ps.clientNum );

    }
    else if( !Q_stricmp (cmd, "boteditinv")  )
    {
        if( trap_Argc() < 3)
            return;
        trap_Argv( 2, name, sizeof(name) );
        cl = ClientForString( name );
        if( !cl ) return;
        EditPlayerInventory( &g_entities[cl->ps.clientNum], 3 );
    }
    else if( !Q_stricmp (cmd, "botchooseweap")  )
    {
        if( trap_Argc() != 4 ) {
            Com_Printf("usage: camcmd botchooseweap name weapID \n");
            return;
        }
        trap_Argv( 2, name, sizeof( name ) );
        cl = ClientForString( name ) ;
        if(!cl)
            return;
        trap_Argv( 3, buf, sizeof( buf ) );
        BotChooseWeap( cl->ps.clientNum, atoi(buf) );
    }
    else if( !Q_stricmp (cmd, "bottaunt")  )
    {
        if( trap_Argc() != 3 ) {
            Com_Printf("usage: camcmd bottaunt name \n");
            return;
        }
        trap_Argv( 2, name, sizeof( name ) );
        cl = ClientForString( name ) ;
        if(!cl)
            return;

        BotCamTaunt( cl->ps.clientNum );
    }
    else if( !Q_stricmp(cmd, "botfire") )
    {
        if( trap_Argc() != 3 ) {
            Com_Printf("usage: camcmd botfire name \n");
            return;
        }
        trap_Argv( 2, name, sizeof( name ) );
        cl = ClientForString( name ) ;
        if(!cl)
            return;

        BotCamFire( cl->ps.clientNum );
    }
    else if( !Q_stricmp(cmd, "freeze") ) {
        int on;


        if( trap_Argc() != 3 ) {
            Com_Printf("usage: camcmd freeze [0|1] \n");
            return;
        }
        trap_Argv( 2, name, sizeof( name ) );

        on = atoi( name );
        FreezePlayers( on );
    }

}
Exemple #7
0
/*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame on fast clients.

If "g_synchronousClients 1" is set, this will be called exactly
once for each server frame, which makes for smooth demo recording.
==============
*/
void ClientThink_real(gentity_t *ent) {
	int       msec, oldEventSequence, speed, i, counter, Zaccel;
	pmove_t   pm;
	usercmd_t *ucmd;
	gclient_t *client = ent->client;

	// don't think if the client is not yet connected (and thus not yet spawned in)
	if (client->pers.connected != CON_CONNECTED) {
		return;
	}

	if (ent->s.eFlags & EF_MOUNTEDTANK) {
		client->pmext.centerangles[YAW]   = ent->tagParent->r.currentAngles[YAW];
		client->pmext.centerangles[PITCH] = ent->tagParent->r.currentAngles[PITCH];
	}

	// mark the time, so the connection sprite can be removed
	ucmd = &ent->client->pers.cmd;

	ent->client->ps.identifyClient = ucmd->identClient;     // NERVE - SMF

	// sanity check the command time to prevent speedup cheating
	if (ucmd->serverTime > level.time + 200) {
		ucmd->serverTime = level.time + 200;
	}
	if (ucmd->serverTime < level.time - 1000) {
		ucmd->serverTime = level.time - 1000;
	}

	msec = ucmd->serverTime - client->ps.commandTime;
	// following others may result in bad times, but we still want
	// to check for follow toggles
	if (msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW) {
		return;
	}
	if (msec > 200) {
		msec = 200;
	}

	// Nico, pmove_fixed
	if (client->pers.pmoveFixed) {
		ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer - 1) / pmove_msec.integer) * pmove_msec.integer;
	}

	if (client->wantsscore) {
		G_SendScore(ent);
		client->wantsscore = qfalse;
	}

	// check for inactivity timer, but never drop the local client of a non-dedicated server
	// OSP - moved here to allow for spec inactivity checks as well
	if (!ClientInactivityTimer(client)) {
		return;
	}

	if (!(ucmd->flags & 0x01) || ucmd->forwardmove || ucmd->rightmove || ucmd->upmove || ucmd->wbuttons || ucmd->doubleTap) {
		ent->r.svFlags &= ~(SVF_SELF_PORTAL_EXCLUSIVE | SVF_SELF_PORTAL);
	}

	// spectators don't do much
	// DHM - Nerve :: In limbo use SpectatorThink
	// suburb, check for noclip not to override client->ps.speed
	if ((client->sess.sessionTeam == TEAM_SPECTATOR || client->ps.pm_flags & PMF_LIMBO) && !client->noclip) {
		SpectatorThink(ent, ucmd);
		return;
	}

	if (client->ps.eFlags & EF_VIEWING_CAMERA) {
		ucmd->buttons     = 0;
		ucmd->forwardmove = 0;
		ucmd->rightmove   = 0;
		ucmd->upmove      = 0;
		ucmd->wbuttons    = 0;
		ucmd->doubleTap   = 0;

		// freeze player
		client->ps.pm_type = PM_FREEZE;
	} else if (client->noclip) {
		client->ps.pm_type = PM_NOCLIP;
	} else if (client->ps.stats[STAT_HEALTH] <= 0) {
		client->ps.pm_type = PM_DEAD;
	} else {
		client->ps.pm_type = PM_NORMAL;
	}

	client->ps.aiState = AISTATE_COMBAT;
	client->ps.gravity = DEFAULT_GRAVITY;
	client->ps.speed   = DEFAULT_SPEED;

	if (client->speedScale) {                // Goalitem speed scale
		client->ps.speed *= (client->speedScale * 0.01);
	}

	// set up for pmove
	oldEventSequence = client->ps.eventSequence;

	client->currentAimSpreadScale = (float)client->ps.aimSpreadScale / 255.0;

	memset(&pm, 0, sizeof (pm));

	pm.ps        = &client->ps;
	pm.pmext     = &client->pmext;
	pm.character = client->pers.character;
	pm.cmd       = *ucmd;
	pm.oldcmd    = client->pers.oldcmd;
	// MrE: always use capsule for AI and player
	pm.trace = trap_TraceCapsule;

	// Nico, ghost players
	pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
	if (pm.ps->pm_type == PM_DEAD) {
		pm.ps->eFlags |= EF_DEAD;
	} else if (pm.ps->pm_type == PM_SPECTATOR) {
		pm.trace = trap_TraceCapsuleNoEnts;
	}
	// Nico, end of ghost players

	//DHM - Nerve :: We've gone back to using normal bbox traces
	pm.pointcontents = trap_PointContents;
	pm.debugLevel    = g_debugMove.integer;
	pm.noFootsteps   = qfalse;

	// Nico, pmove_fixed
	// pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
	pm.pmove_fixed = client->pers.pmoveFixed;
	pm.pmove_msec  = pmove_msec.integer;

	// suburb, Noclip speed scale
	pm.noclipSpeed = client->pers.noclipSpeed;

	// Nico, game physics
	pm.physics = physics.integer;

	pm.isTimerun        = isTimerun.integer;
	pm.timerunActive    = client->sess.timerunActive;
	pm.timerunStartTime = client->sess.timerunStartTime + 500;

	// Nico, store logins status in pmove
	if (client->sess.logged) {
		pm.isLogged = 1;
	} else {
		pm.isLogged = 0;
	}

	pm.noWeapClips = qfalse;

	VectorCopy(client->ps.origin, client->oldOrigin);

	// NERVE - SMF
	pm.ltChargeTime       = level.lieutenantChargeTime[client->sess.sessionTeam - 1];
	pm.soldierChargeTime  = level.soldierChargeTime[client->sess.sessionTeam - 1];
	pm.engineerChargeTime = level.engineerChargeTime[client->sess.sessionTeam - 1];
	pm.medicChargeTime    = level.medicChargeTime[client->sess.sessionTeam - 1];
	// -NERVE - SMF

	client->pmext.airleft = ent->client->airOutTime - level.time;

	pm.covertopsChargeTime = level.covertopsChargeTime[client->sess.sessionTeam - 1];

	// Gordon: bit hacky, stop the slight lag from client -> server even on locahost, switching back to the weapon you were holding
	//			and then back to what weapon you should have, became VERY noticible for the kar98/carbine + gpg40, esp now i've added the
	//			animation locking
	if (level.time - client->pers.lastSpawnTime < 1000) {
		pm.cmd.weapon = client->ps.weapon;
	}

	Pmove(&pm);

	// Gordon: thx to bani for this
	// ikkyo - fix leaning players bug
	VectorCopy(client->ps.velocity, ent->s.pos.trDelta);
	SnapVector(ent->s.pos.trDelta);
	// end

	// server cursor hints
	if (ent->lastHintCheckTime < level.time) {
		G_CheckForCursorHints(ent);

		ent->lastHintCheckTime = level.time + FRAMETIME;
	}

	// DHM - Nerve :: Set animMovetype to 1 if ducking
	if (ent->client->ps.pm_flags & PMF_DUCKED) {
		ent->s.animMovetype = 1;
	} else {
		ent->s.animMovetype = 0;
	}

	// save results of pmove
	if (ent->client->ps.eventSequence != oldEventSequence) {
		ent->eventTime   = level.time;
		ent->r.eventTime = level.time;
	}

	// Ridah, fixes jittery zombie movement
	if (g_smoothClients.integer) {
		BG_PlayerStateToEntityStateExtraPolate(&ent->client->ps, &ent->s, level.time, qfalse);
	} else {
		BG_PlayerStateToEntityState(&ent->client->ps, &ent->s, qfalse);
	}

	if (!(ent->client->ps.eFlags & EF_FIRING)) {
		client->fireHeld = qfalse;      // for grapple
	}

//	// use the snapped origin for linking so it matches client predicted versions
	VectorCopy(ent->s.pos.trBase, ent->r.currentOrigin);

	VectorCopy(pm.mins, ent->r.mins);
	VectorCopy(pm.maxs, ent->r.maxs);

	ent->waterlevel = pm.waterlevel;
	ent->watertype  = pm.watertype;

	// execute client events
	ClientEvents(ent, oldEventSequence);

	// link entity now, after any personal teleporters have been used
	trap_LinkEntity(ent);
	if (!ent->client->noclip) {
		G_TouchTriggers(ent);
	}

	// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
	VectorCopy(ent->client->ps.origin, ent->r.currentOrigin);

	// touch other objects
	ClientImpacts(ent, &pm);

	// save results of triggers and client events
	if (ent->client->ps.eventSequence != oldEventSequence) {
		ent->eventTime = level.time;
	}

	// swap and latch button actions
	client->oldbuttons      = client->buttons;
	client->buttons         = ucmd->buttons;
	client->latched_buttons = client->buttons & ~client->oldbuttons;

	//----(SA)	added
	client->oldwbuttons      = client->wbuttons;
	client->wbuttons         = ucmd->wbuttons;
	client->latched_wbuttons = client->wbuttons & ~client->oldwbuttons;

	// suburb, return here for noclippers in spec to avoid following checks
	if (client->sess.sessionTeam == TEAM_SPECTATOR && client->noclip) {
		return;
	}

	// Rafael - Activate
	// Ridah, made it a latched event (occurs on keydown only)
	if (client->latched_buttons & BUTTON_ACTIVATE) {
		Cmd_Activate_f(ent);
	}

	if (g_entities[ent->client->ps.identifyClient].team != ent->team ||
	    !g_entities[ent->client->ps.identifyClient].client) {
		ent->client->ps.identifyClient = -1;
	}

	// check for respawning
	if (client->ps.stats[STAT_HEALTH] <= 0) {
		// Nico, forcing respawn
		limbo(ent);

		return;
	}

	// perform once-a-second actions
	ClientTimerActions(ent, msec);

	// Nico, check ping
	if (client->ps.ping > MAX_PLAYER_PING) {
		if (!client->pers.loadKillNeeded) {
			CP(va("cpm \"%s^w: ^1Too high ping detected, load or kill required.\n\"", GAME_VERSION_COLORED));
			// suburb, prevent trigger bug
			client->pers.loadKillNeeded = qtrue;
		}
	}

	// Nico, pmove_fixed
	if (!client->pers.pmoveFixed) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you can not use pmove_fixed 0.\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "pmoveon");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check rate
	if (client->pers.rate < MIN_PLAYER_RATE_VALUE || client->pers.rate > MAX_PLAYER_RATE_VALUE) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use %d <= rate <= %d.\n\"", GAME_VERSION_COLORED, MIN_PLAYER_RATE_VALUE, MAX_PLAYER_RATE_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetRate");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check snaps (unsigned int)
	if (client->pers.snaps > MAX_PLAYER_SNAPS_VALUE) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use %d <= snaps <= %d.\n\"", GAME_VERSION_COLORED, MIN_PLAYER_SNAPS_VALUE, MAX_PLAYER_SNAPS_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetSnaps");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check timenudge
	if (client->pers.clientTimeNudge != FORCED_PLAYER_TIMENUDGE_VALUE) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use cl_timenudge %d.\n\"", GAME_VERSION_COLORED, FORCED_PLAYER_TIMENUDGE_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetTimeNudge");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check maxpackets
	if (client->pers.clientMaxPackets < MIN_PLAYER_MAX_PACKETS_VALUE || client->pers.clientMaxPackets > MAX_PLAYER_MAX_PACKETS_VALUE) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use %d <= cl_maxpackets <= %d.\n\"", GAME_VERSION_COLORED, MIN_PLAYER_MAX_PACKETS_VALUE, MAX_PLAYER_MAX_PACKETS_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetMaxPackets");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, check max FPS
	if (client->pers.maxFPS < MIN_PLAYER_FPS_VALUE || client->pers.maxFPS > MAX_PLAYER_FPS_VALUE) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use %d <= com_maxfps <= %d.\n\"", GAME_VERSION_COLORED, MIN_PLAYER_FPS_VALUE, MAX_PLAYER_FPS_VALUE));
		trap_SendServerCommand(ent - g_entities, "resetMaxFPS");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// suburb, force yawspeed 0
	if (client->pers.yawspeed != 0) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use cl_yawspeed 0.\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "resetYawspeed");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// suburb, force pitchspeed 0
	if (client->pers.pitchspeed != 0) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use cl_pitchspeed 0.\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "resetPitchspeed");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, force auto demo record in cup mode
	if (g_cupMode.integer != 0 && client->pers.autoDemo == 0) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use cg_autoDemo 1.\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "autoDemoOn");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// Nico, force hide me in cup mode
	if (g_cupMode.integer != 0 && client->pers.hideme == 0) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use cg_hideMe 1.\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "hideMeOn");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// suburb, force CGaz if disabled on server
	if (g_disableCGaz.integer != 0 && client->pers.cgaz != 0) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use cg_drawCGaz 0.\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "CGazOff");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// suburb, force snapping hud if disabled on server or logged in
	if ((g_disableSnappingHUD.integer != 0 || (client->sess.logged && (client->sess.sessionTeam == TEAM_AXIS || client->sess.sessionTeam == TEAM_ALLIES))) && client->pers.snapping != 0) {
		CP(va("cpm \"%s^w: ^1You were removed from teams because you must use cg_drawVelocitySnapping 0.\n\"", GAME_VERSION_COLORED));
		trap_SendServerCommand(ent - g_entities, "SnappingOff");
		SetTeam(ent, "s", -1, -1, qfalse);
	}

	// suburb, prevent pronebug & wallbug
	counter = 0;

	for (i = 0; i < 3; ++i) {
		if (client->pers.oldPosition[i] == (int) pm.ps->origin[i]) {
			counter++;
		}
	}

	Zaccel = (int) pm.ps->velocity[2] - client->pers.oldZvelocity;
	speed  = sqrt(pm.ps->velocity[0] * pm.ps->velocity[0] + pm.ps->velocity[1] * pm.ps->velocity[1]);

	if (client->sess.logged && ((!client->sess.timerunActive && speed > BUGGING_MAX_SPEED && counter == 3) || // prevent accelerating in brushes
	                            (pm.ps->eFlags & EF_PRONE && Zaccel > -6 && Zaccel < 0 && client->ps.groundEntityNum == ENTITYNUM_NONE && !client->pers.isTouchingJumppad))) { // prevent accelerating on steep slopes
		if (!client->pers.buggedLastFrame) { // only do something the second frame not to break jumppads
			client->pers.buggedLastFrame = qtrue;
			return;
		}
		if (!client->pers.loadKillNeeded) {
			CP(va("cpm \"%s^w: ^1Bugging detected, load or kill required.\n\"", GAME_VERSION_COLORED));
			client->pers.loadKillNeeded = qtrue;
		}
	}

	// checking acceleration in brushes every frame would break corner skimming
	if (level.time - client->pers.lastBuggingCheck > BUGGING_CHECK_FREQUENCY) {
		for (i = 0; i < 3; ++i) {
			client->pers.oldPosition[i]   = (int) pm.ps->origin[i];
			client->pers.lastBuggingCheck = level.time;
		}
	}

	client->pers.oldZvelocity    = (int) pm.ps->velocity[2];
	client->pers.buggedLastFrame = qfalse;
}
Exemple #8
0
/*
===========
ClientUserInfoChanged

Called from ClientConnect when the player first connects and
directly by the server system when the player updates a userinfo variable.

The game can override any of the settings and call trap_SetUserinfo
if desired.
============
*/
char *ClientUserinfoChanged( int clientNum, qboolean forceName )
{
    gentity_t *ent;
    char      *s;
    char      model[ MAX_QPATH ];
    char      buffer[ MAX_QPATH ];
    char      filename[ MAX_QPATH ];
    char      oldname[ MAX_NAME_LENGTH ];
    char      newname[ MAX_NAME_LENGTH ];
    char      err[ MAX_STRING_CHARS ];
    qboolean  revertName = qfalse;
    gclient_t *client;
    char      userinfo[ MAX_INFO_STRING ];

    ent = g_entities + clientNum;
    client = ent->client;

    trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );

    // check for malformed or illegal info strings
    if( !Info_Validate(userinfo) )
    {
        trap_SendServerCommand( ent - g_entities,
                                "disconnect \"illegal or malformed userinfo\n\"" );
        trap_DropClient( ent - g_entities,
                         "dropped: illegal or malformed userinfo");
        return "Illegal or malformed userinfo";
    }
    // If their userinfo overflowed, tremded is in the process of disconnecting them.
    // If we send our own disconnect, it won't work, so just return to prevent crashes later
    //  in this function. This check must come after the Info_Validate call.
    else if( !userinfo[ 0 ] )
        return "Empty (overflowed) userinfo";

    // stickyspec toggle
    s = Info_ValueForKey( userinfo, "cg_stickySpec" );
    client->pers.stickySpec = atoi( s ) != 0;

    // set name
    Q_strncpyz( oldname, client->pers.netname, sizeof( oldname ) );
    s = Info_ValueForKey( userinfo, "name" );
    G_ClientCleanName( s, newname, sizeof( newname ) );

    if( strcmp( oldname, newname ) )
    {
        if( !forceName && client->pers.namelog->nameChangeTime &&
                level.time - client->pers.namelog->nameChangeTime <=
                g_minNameChangePeriod.value * 1000 )
        {
            trap_SendServerCommand( ent - g_entities, va(
                                        "print \"Name change spam protection (g_minNameChangePeriod = %d)\n\"",
                                        g_minNameChangePeriod.integer ) );
            revertName = qtrue;
        }
        else if( !forceName && g_maxNameChanges.integer > 0 &&
                 client->pers.namelog->nameChanges >= g_maxNameChanges.integer  )
        {
            trap_SendServerCommand( ent - g_entities, va(
                                        "print \"Maximum name changes reached (g_maxNameChanges = %d)\n\"",
                                        g_maxNameChanges.integer ) );
            revertName = qtrue;
        }
        else if( !forceName && client->pers.namelog->muted )
        {
            trap_SendServerCommand( ent - g_entities,
                                    "print \"You cannot change your name while you are muted\n\"" );
            revertName = qtrue;
        }
        else if( !G_admin_name_check( ent, newname, err, sizeof( err ) ) )
        {
            trap_SendServerCommand( ent - g_entities, va( "print \"%s\n\"", err ) );
            revertName = qtrue;
        }

        if( revertName )
        {
            Q_strncpyz( client->pers.netname, *oldname ? oldname : "UnnamedPlayer",
                        sizeof( client->pers.netname ) );
            Info_SetValueForKey( userinfo, "name", oldname );
            trap_SetUserinfo( clientNum, userinfo );
        }
        else
        {
            G_CensorString( client->pers.netname, newname,
                            sizeof( client->pers.netname ), ent );
            if( !forceName && client->pers.connected == CON_CONNECTED )
            {
                client->pers.namelog->nameChangeTime = level.time;
                client->pers.namelog->nameChanges++;
            }
            if( *oldname )
            {
                G_LogPrintf( "ClientRename: %i [%s] (%s) \"%s^7\" -> \"%s^7\" \"%c%s%c^7\"\n",
                             clientNum, client->pers.ip.str, client->pers.guid,
                             oldname, client->pers.netname,
                             DECOLOR_OFF, client->pers.netname, DECOLOR_ON );
            }
        }
        G_namelog_update_name( client );
    }

    if( client->pers.classSelection == PCL_NONE )
    {
        //This looks hacky and frankly it is. The clientInfo string needs to hold different
        //model details to that of the spawning class or the info change will not be
        //registered and an axis appears instead of the player model. There is zero chance
        //the player can spawn with the battlesuit, hence this choice.
        Com_sprintf( buffer, MAX_QPATH, "%s/%s",  BG_ClassConfig( PCL_HUMAN_BSUIT )->modelName,
                     BG_ClassConfig( PCL_HUMAN_BSUIT )->skinName );
    }
    else
    {
        Com_sprintf( buffer, MAX_QPATH, "%s/%s",  BG_ClassConfig( client->pers.classSelection )->modelName,
                     BG_ClassConfig( client->pers.classSelection )->skinName );

        //model segmentation
        Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg",
                     BG_ClassConfig( client->pers.classSelection )->modelName );

        if( G_NonSegModel( filename ) )
            client->ps.persistant[ PERS_STATE ] |= PS_NONSEGMODEL;
        else
            client->ps.persistant[ PERS_STATE ] &= ~PS_NONSEGMODEL;
    }
    Q_strncpyz( model, buffer, sizeof( model ) );

    // wallwalk follow
    s = Info_ValueForKey( userinfo, "cg_wwFollow" );

    if( atoi( s ) )
        client->ps.persistant[ PERS_STATE ] |= PS_WALLCLIMBINGFOLLOW;
    else
        client->ps.persistant[ PERS_STATE ] &= ~PS_WALLCLIMBINGFOLLOW;

    // wallwalk toggle
    s = Info_ValueForKey( userinfo, "cg_wwToggle" );

    if( atoi( s ) )
        client->ps.persistant[ PERS_STATE ] |= PS_WALLCLIMBINGTOGGLE;
    else
        client->ps.persistant[ PERS_STATE ] &= ~PS_WALLCLIMBINGTOGGLE;

    // always sprint
    s = Info_ValueForKey( userinfo, "cg_sprintToggle" );

    if( atoi( s ) )
        client->ps.persistant[ PERS_STATE ] |= PS_SPRINTTOGGLE;
    else
        client->ps.persistant[ PERS_STATE ] &= ~PS_SPRINTTOGGLE;

    // fly speed
    s = Info_ValueForKey( userinfo, "cg_flySpeed" );

    if( *s )
        client->pers.flySpeed = atoi( s );
    else
        client->pers.flySpeed = BG_Class( PCL_NONE )->speed;

    // disable blueprint errors
    s = Info_ValueForKey( userinfo, "cg_disableBlueprintErrors" );

    if( atoi( s ) )
        client->pers.disableBlueprintErrors = qtrue;
    else
        client->pers.disableBlueprintErrors = qfalse;

    // teamInfo
    s = Info_ValueForKey( userinfo, "teamoverlay" );

    if( atoi( s ) != 0 )
    {
        // teamoverlay was enabled so we need an update
        if( client->pers.teamInfo == 0 )
            client->pers.teamInfo = 1;
    }
    else
        client->pers.teamInfo = 0;

    s = Info_ValueForKey( userinfo, "cg_unlagged" );
    if( !s[0] || atoi( s ) != 0 )
        client->pers.useUnlagged = qtrue;
    else
        client->pers.useUnlagged = qfalse;

    Q_strncpyz( client->pers.voice, Info_ValueForKey( userinfo, "voice" ),
                sizeof( client->pers.voice ) );

    // send over a subset of the userinfo keys so other clients can
    // print scoreboards, display models, and play custom sounds

    Com_sprintf( userinfo, sizeof( userinfo ),
                 "n\\%s\\t\\%i\\model\\%s\\ig\\%16s\\v\\%s",
                 client->pers.netname, client->pers.teamSelection, model,
                 Com_ClientListString( &client->sess.ignoreList ),
                 client->pers.voice );

    trap_SetConfigstring( CS_PLAYERS + clientNum, userinfo );

    /*G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, userinfo );*/

    return NULL;
}
Exemple #9
0
void CheckTeamStatus( void )
{
	int       i;
	gentity_t *loc, *ent;

	if ( level.time - level.lastTeamLocationTime > TEAM_LOCATION_UPDATE_TIME )
	{
		level.lastTeamLocationTime = level.time;

		for ( i = 0; i < g_maxclients.integer; i++ )
		{
			ent = g_entities + i;

			if ( ent->client->pers.connected != CON_CONNECTED )
			{
				continue;
			}

			if ( ent->inuse && ( ent->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ||
			                     ent->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) )
			{
				loc = Team_GetLocation( ent );

				if ( loc )
				{
					ent->client->pers.location = loc->s.generic1;
				}
				else
				{
					ent->client->pers.location = 0;
				}
			}
		}

		for ( i = 0; i < g_maxclients.integer; i++ )
		{
			ent = g_entities + i;

			if ( ent->client->pers.connected != CON_CONNECTED )
			{
				continue;
			}

			if ( ent->inuse )
			{
				TeamplayInfoMessage( ent );
			}
		}
	}

	// Warn on imbalanced teams
	if ( g_teamImbalanceWarnings.integer && !level.intermissiontime &&
	     ( level.time - level.lastTeamImbalancedTime >
	       ( g_teamImbalanceWarnings.integer * 1000 ) ) &&
	     level.numTeamImbalanceWarnings < 3 && !level.restarted )
	{
		level.lastTeamImbalancedTime = level.time;

		if ( level.numAlienSpawns > 0 &&
		     level.numHumanClients - level.numAlienClients > 2 )
		{
			trap_SendServerCommand( -1, "print_tr \"" N_("Teams are imbalanced. "
			                        "Humans have more players.\n") "\"" );
			level.numTeamImbalanceWarnings++;
		}
		else if ( level.numHumanSpawns > 0 &&
		          level.numAlienClients - level.numHumanClients > 2 )
		{
			trap_SendServerCommand( -1, "print_tr \"" N_("Teams are imbalanced. "
			                        "Aliens have more players.\n") "\"" );
			level.numTeamImbalanceWarnings++;
		}
		else
		{
			level.numTeamImbalanceWarnings = 0;
		}
	}
}
Exemple #10
0
/*
==================
TeamplayInfoMessage

Format:
  clientNum location health weapon upgrade

==================
*/
void TeamplayInfoMessage( gentity_t *ent )
{
	char      entry[ 19 ], string[ 1143 ];
	int       i, j;
	int       team, stringlength;
	int       sent = 0;
	gentity_t *player;
	gclient_t *cl;
	upgrade_t upgrade = UP_NONE;
	int       curWeaponClass = WP_NONE; // sends weapon for humans, class for aliens
	char      *tmp;

	if ( !g_allowTeamOverlay.integer )
	{
		return;
	}

	if ( !ent->client->pers.teamInfo )
	{
		return;
	}

	if ( ent->client->pers.teamSelection == TEAM_NONE )
	{
		if ( ent->client->sess.spectatorState == SPECTATOR_FREE ||
		     ent->client->sess.spectatorClient < 0 )
		{
			return;
		}

		team = g_entities[ ent->client->sess.spectatorClient ].client->
		       pers.teamSelection;
	}
	else
	{
		team = ent->client->pers.teamSelection;
	}

	string[ 0 ] = '\0';
	stringlength = 0;

	for ( i = 0; i < MAX_CLIENTS; i++ )
	{
		player = g_entities + i;
		cl = player->client;

		if ( ent == player || !cl || team != cl->pers.teamSelection ||
		     !player->inuse )
		{
			continue;
		}

		if ( cl->sess.spectatorState != SPECTATOR_NOT )
		{
			curWeaponClass = WP_NONE;
			upgrade = UP_NONE;
		}
		else if ( cl->pers.teamSelection == TEAM_HUMANS )
		{
			curWeaponClass = cl->ps.weapon;

			if ( BG_InventoryContainsUpgrade( UP_BATTLESUIT, cl->ps.stats ) )
			{
				upgrade = UP_BATTLESUIT;
			}
			else if ( BG_InventoryContainsUpgrade( UP_JETPACK, cl->ps.stats ) )
			{
				upgrade = UP_JETPACK;
			}
			else if ( BG_InventoryContainsUpgrade( UP_BATTPACK, cl->ps.stats ) )
			{
				upgrade = UP_BATTPACK;
			}
			else if ( BG_InventoryContainsUpgrade( UP_HELMET, cl->ps.stats ) )
			{
				upgrade = UP_HELMET;
			}
			else if ( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, cl->ps.stats ) )
			{
				upgrade = UP_LIGHTARMOUR;
			}
			else
			{
				upgrade = UP_NONE;
			}
		}
		else if ( cl->pers.teamSelection == TEAM_ALIENS )
		{
			curWeaponClass = cl->ps.stats[ STAT_CLASS ];
			upgrade = UP_NONE;
		}

		tmp = va( "%i %i %i %i",
		          player->client->pers.location,
		          player->client->ps.stats[ STAT_HEALTH ] < 1 ? 0 :
		          player->client->ps.stats[ STAT_HEALTH ],
		          curWeaponClass,
		          upgrade );

		if ( !strcmp( ent->client->pers.cinfo[ i ], tmp ) )
		{
			continue;
		}

		Q_strncpyz( ent->client->pers.cinfo[ i ], tmp,
		            sizeof( ent->client->pers.cinfo[ i ] ) );

		Com_sprintf( entry, sizeof( entry ), " %i %s", i, tmp );

		j = strlen( entry );

		if ( stringlength + j >= sizeof( string ) )
		{
			break;
		}

		strcpy( string + stringlength, entry );
		stringlength += j;
		sent++;
	}

	if ( !sent )
	{
		return;
	}

	trap_SendServerCommand( ent - g_entities, va( "tinfo%s", string ) );
}
Exemple #11
0
/*
=======================================================================================================================================
Team_TouchOurFlag
=======================================================================================================================================
*/
int Team_TouchOurFlag(gentity_t *ent, gentity_t *other, int team) {
	int i;
	gentity_t *player;
	gclient_t *cl = other->client;
	int enemy_flag;

	if (g_gametype.integer == GT_1FCTF) {
		enemy_flag = PW_NEUTRALFLAG;
	} else {
		if (cl->sess.sessionTeam == TEAM_RED) {
			enemy_flag = PW_BLUEFLAG;
		} else {
			enemy_flag = PW_REDFLAG;
		}

		if (ent->flags & FL_DROPPED_ITEM) {
			// hey, it's not home. return it by teleporting it back
			PrintMsg(NULL, "%s" S_COLOR_WHITE " returned the %s flag!\n", cl->pers.netname, TeamName(team));
			AddScore(other, ent->r.currentOrigin, CTF_RECOVERY_BONUS);

			other->client->pers.teamState.lastreturnedflag = level.time;
			// 'ResetFlag' will remove this entity! We must return zero
			Team_ReturnFlagSound(Team_ResetFlag(team), team);
			return 0;
		}
	}
	// the flag is at home base. if the player has the enemy flag, he's just won!
	if (!cl->ps.powerups[enemy_flag]) {
		return 0; // we don't have the flag
	}

	if (g_gametype.integer == GT_1FCTF) {
		trap_SendServerCommand(-1, va("cp \"%s" S_COLOR_WHITE "\ncaptured the flag!\n\"", cl->pers.netname));
	} else {
		trap_SendServerCommand(-1, va("cp \"%s" S_COLOR_WHITE "\ncaptured the %s flag!\n\"", cl->pers.netname, TeamName(OtherTeam(team))));
	}

	cl->ps.powerups[enemy_flag] = 0;

	other->client->rewardTime = level.time + REWARD_TIME;
	other->client->ps.persistant[PERS_CAPTURES]++;
	// other gets another 10 frag bonus
	AddScore(other, ent->r.currentOrigin, CTF_CAPTURE_BONUS);
	// ok, let's do the player loop, hand out the bonuses
	for (i = 0; i < g_maxclients.integer; i++) {
		player = &g_entities[i];
		// also make sure we don't award assist bonuses to the flag carrier himself.
		if (!player->inuse || player == other) {
			continue;
		}

		if (player->client->sess.sessionTeam != cl->sess.sessionTeam) {
			player->client->pers.teamState.lasthurtcarrier = -5;
		} else if (player->client->sess.sessionTeam == cl->sess.sessionTeam) {
			AddScore(player, ent->r.currentOrigin, CTF_TEAM_BONUS);
			// award extra points for capture assists
			if (player->client->pers.teamState.lastreturnedflag + CTF_RETURN_FLAG_ASSIST_TIMEOUT > level.time) {
				AddScore(player, ent->r.currentOrigin, CTF_RETURN_FLAG_ASSIST_BONUS);

				player->client->ps.persistant[PERS_ASSIST_COUNT]++;
				player->client->rewardTime = level.time + REWARD_TIME;
			}

			if (player->client->pers.teamState.lastfraggedcarrier + CTF_FRAG_CARRIER_ASSIST_TIMEOUT > level.time) {
				AddScore(player, ent->r.currentOrigin, CTF_FRAG_CARRIER_ASSIST_BONUS);

				player->client->ps.persistant[PERS_ASSIST_COUNT]++;
				player->client->rewardTime = level.time + REWARD_TIME;
			}
		}
	}

	teamgame.last_flag_capture = level.time;
	teamgame.last_capture_team = team;
	// increase the team's score
	AddTeamScore(ent->s.pos.trBase, other->client->sess.sessionTeam, 1);
	CalculateRanks();
	Team_ResetFlags();
	Team_CaptureFlagSound(ent, team);
	Team_ForceGesture(other->client->sess.sessionTeam);

	return 0; // do not respawn this automatically
}
Exemple #12
0
/*
=================
ConsoleCommand

=================
*/
qboolean    ConsoleCommand( void ) {
	char cmd[MAX_TOKEN_CHARS];

	trap_Argv( 0, cmd, sizeof( cmd ) );

	if ( Q_stricmp( cmd, "entitylist" ) == 0 ) {
		Svcmd_EntityList_f();
		return qtrue;
	}

	if ( Q_stricmp( cmd, "forceteam" ) == 0 ) {
		Svcmd_ForceTeam_f();
		return qtrue;
	}

	if ( Q_stricmp( cmd, "game_memory" ) == 0 ) {
		Svcmd_GameMem_f();
		return qtrue;
	}

	if ( Q_stricmp( cmd, "addbot" ) == 0 ) {
		Svcmd_AddBot_f();
		return qtrue;
	}

	if ( Q_stricmp( cmd, "addip" ) == 0 ) {
		Svcmd_AddIP_f();
		return qtrue;
	}

	if ( Q_stricmp( cmd, "removeip" ) == 0 ) {
		Svcmd_RemoveIP_f();
		return qtrue;
	}

	if ( Q_stricmp( cmd, "listip" ) == 0 ) {
		trap_SendConsoleCommand( EXEC_INSERT, "g_banIPs\n" );
		return qtrue;
	}

	if ( Q_stricmp( cmd, "listmaxlivesip" ) == 0 ) {
		PrintMaxLivesGUID();
		return qtrue;
	}


	// NERVE - SMF
	if ( Q_stricmp( cmd, "start_match" ) == 0 ) {
		Svcmd_StartMatch_f();
		return qtrue;
	}

	if ( Q_stricmp( cmd, "reset_match" ) == 0 ) {
		Svcmd_ResetMatch_f();
		return qtrue;
	}

	if ( Q_stricmp( cmd, "swap_teams" ) == 0 ) {
		Svcmd_SwapTeams_f();
		return qtrue;
	}
	// -NERVE - SMF

	if ( g_dedicated.integer ) {
		if ( Q_stricmp( cmd, "say" ) == 0 ) {
			trap_SendServerCommand( -1, va( "print \"server:[lof] %s\"", ConcatArgs( 1 ) ) );
			return qtrue;
		}
		// everything else will also be printed as a say command
		trap_SendServerCommand( -1, va( "print \"server:[lof] %s\"", ConcatArgs( 0 ) ) );
		return qtrue;
	}

	return qfalse;
}
Exemple #13
0
/*
=================
G_TimeShiftClient

Move a client back to where he was at the specified "time"
=================
*/
void G_TimeShiftClient( gentity_t *ent, int time, qboolean debug, gentity_t *debugger ) {
	int		j, k;
	char msg[2048];

	// this will dump out the head index, and the time for all the stored positions
/*
	if ( debug ) {
		char	str[MAX_STRING_CHARS];

		Com_sprintf(str, sizeof(str), "print \"head: %d, %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n\"",
			ent->client->historyHead,
			ent->client->history[0].leveltime,
			ent->client->history[1].leveltime,
			ent->client->history[2].leveltime,
			ent->client->history[3].leveltime,
			ent->client->history[4].leveltime,
			ent->client->history[5].leveltime,
			ent->client->history[6].leveltime,
			ent->client->history[7].leveltime,
			ent->client->history[8].leveltime,
			ent->client->history[9].leveltime,
			ent->client->history[10].leveltime,
			ent->client->history[11].leveltime,
			ent->client->history[12].leveltime,
			ent->client->history[13].leveltime,
			ent->client->history[14].leveltime,
			ent->client->history[15].leveltime,
			ent->client->history[16].leveltime);

		trap_SendServerCommand( debugger - g_entities, str );
	}
*/

	// find two entries in the history whose times sandwich "time"
	// assumes no two adjacent records have the same timestamp
	j = k = ent->client->historyHead;
	do {
		if ( ent->client->history[j].leveltime <= time )
			break;

		k = j;
		j--;
		if ( j < 0 ) {
			j = NUM_CLIENT_HISTORY - 1;
		}
	}
	while ( j != ent->client->historyHead );

	// if we got past the first iteration above, we've sandwiched (or wrapped)
	if ( j != k ) {
		// make sure it doesn't get re-saved
		if ( ent->client->saved.leveltime != level.time ) {
			// save the current origin and bounding box
			VectorCopy( ent->r.mins, ent->client->saved.mins );
			VectorCopy( ent->r.maxs, ent->client->saved.maxs );
			VectorCopy( ent->r.currentOrigin, ent->client->saved.currentOrigin );
			ent->client->saved.leveltime = level.time;
		}

		// if we haven't wrapped back to the head, we've sandwiched, so
		// we shift the client's position back to where he was at "time"
		if ( j != ent->client->historyHead ) {
			float	frac = (float)(time - ent->client->history[j].leveltime) /
				(float)(ent->client->history[k].leveltime - ent->client->history[j].leveltime);

			// interpolate between the two origins to give position at time index "time"
			TimeShiftLerp( frac,
				ent->client->history[j].currentOrigin, ent->client->history[k].currentOrigin,
				ent->r.currentOrigin );

			// lerp these too, just for fun (and ducking)
			TimeShiftLerp( frac,
				ent->client->history[j].mins, ent->client->history[k].mins,
				ent->r.mins );

			TimeShiftLerp( frac,
				ent->client->history[j].maxs, ent->client->history[k].maxs,
				ent->r.maxs );

			if ( debug && debugger != NULL ) {
				// print some debugging stuff exactly like what the client does

				// it starts with "Rec:" to let you know it backward-reconciled
				Com_sprintf( msg, sizeof(msg),
					"print \"^1Rec: time: %d, j: %d, k: %d, origin: %0.2f %0.2f %0.2f\n"
					"^2frac: %0.4f, origin1: %0.2f %0.2f %0.2f, origin2: %0.2f %0.2f %0.2f\n"
					"^7level.time: %d, est time: %d, level.time delta: %d, est real ping: %d\n\"",
					time, ent->client->history[j].leveltime, ent->client->history[k].leveltime,
					ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2],
					frac,
					ent->client->history[j].currentOrigin[0],
					ent->client->history[j].currentOrigin[1],
					ent->client->history[j].currentOrigin[2], 
					ent->client->history[k].currentOrigin[0],
					ent->client->history[k].currentOrigin[1],
					ent->client->history[k].currentOrigin[2],
					level.time, level.time + debugger->client->frameOffset,
					level.time - time, level.time + debugger->client->frameOffset - time);

				trap_SendServerCommand( debugger - g_entities, msg );
			}

			// this will recalculate absmin and absmax
			trap_LinkEntity( ent );
		} else {
			// we wrapped, so grab the earliest
			VectorCopy( ent->client->history[k].currentOrigin, ent->r.currentOrigin );
			VectorCopy( ent->client->history[k].mins, ent->r.mins );
			VectorCopy( ent->client->history[k].maxs, ent->r.maxs );

			// this will recalculate absmin and absmax
			trap_LinkEntity( ent );
		}
	}
	else {
		// this only happens when the client is using a negative timenudge, because that
		// number is added to the command time

		// print some debugging stuff exactly like what the client does

		// it starts with "No rec:" to let you know it didn't backward-reconcile
		if ( debug && debugger != NULL ) {
			Com_sprintf( msg, sizeof(msg),
				"print \"^1No rec: time: %d, j: %d, k: %d, origin: %0.2f %0.2f %0.2f\n"
				"^2frac: %0.4f, origin1: %0.2f %0.2f %0.2f, origin2: %0.2f %0.2f %0.2f\n"
				"^7level.time: %d, est time: %d, level.time delta: %d, est real ping: %d\n\"",
				time, level.time, level.time,
				ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2],
				0.0f,
				ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2], 
				ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2],
				level.time, level.time + debugger->client->frameOffset,
				level.time - time, level.time + debugger->client->frameOffset - time);

			trap_SendServerCommand( debugger - g_entities, msg );
		}
	}
}
Exemple #14
0
void ThinkBalloonzone( gentity_t *self ) {
	//"(team == 0) ? TEAM_RED : TEAM_BLUE" => ! in this code red=0, blue=1 ! (unlike TEAM_RED(1), TEAM_BLUE(2) from team_t)
	// FIXME: Remove that offset team uglyness or at least make it readable!!1!
	int team, opponent;
	int numPlayers;
	team_t tteam;
	char *msg;

	if ( !self->message ) {
		msg = "Balloon";
	}
	else {
		msg = self->message;
	}

	if ( self->target_ent->s.frame ) {
		// get teams
		team = ( self->target_ent->s.generic1 - 1 );
		opponent = ( team ^ 1 );
		tteam = ( team + 1 );

		// capturing
		if ( ( self->target_ent->s.frame < 11 ) &&
		     ( self->teamMask & ( 1 << team ) ) &&
		     !( self->teamMask & (1 << opponent ) ) ) {

			numPlayers = NumPlayersAtBalloon( self, tteam );
			if ( numPlayers <= 0 ) {
				numPlayers = 1; //... so, we must not check this later
			}

			self->teamTime[team] += ( BALLOON_THINKTIME * numPlayers );
			self->target_ent->s.frame = ( 1 + self->teamTime[team] / ( 100 * self->speed ) );

			if ( self->target_ent->s.frame >= 11 ) {
				// captured
				self->last_move_time = 0;
				self->teamTime[team] = 0;
				level.balloonState[self->count] = ( '1' + team );
				trap_SetConfigstring( CS_BALLOONS, level.balloonState );

				// TODO: Give more points for capturing than for owning?
				//       Need to test balance!
				AddTeamScore( self->s.pos.trBase, tteam, ( BalloonScore() * 2 ), SCORE_BONUS_CAPTURE_S );
				AddBalloonScores( self, tteam, 1 );

				trap_SendServerCommand( -1, va( "mp \"%s captured by %s Team\"", msg, TeamName( tteam ) ) );
			}
		}

		// balloon is fully raised
		if ( self->target_ent->s.frame >= 11 ) {
			// animate
			self->last_move_time += BALLOON_THINKTIME;
			if ( self->last_move_time >= ( 700 * self->speed ) ) {
				self->last_move_time -= ( 700 * self->speed );
			}
			self->target_ent->s.frame = ( 11 + self->last_move_time / ( 100 * self->speed ) );

			// give points
			if ( !level.intermissiontime ) {
				self->teamTime[team] += BALLOON_THINKTIME;
				while ( self->teamTime[team] >= BALLOON_POINTTIME ) {
					self->teamTime[team] -= BALLOON_POINTTIME;

					AddTeamScore( self->s.pos.trBase, tteam, ( BalloonScore() * 2 ), SCORE_BONUS_CAPTURE_TEAM_S );
				}
			}
		}

		// countering capture
		if ( self->teamMask & (1 << opponent ) ) {
			numPlayers = NumPlayersAtBalloon( self, tteam );
			if ( numPlayers <= 0 ) {
				numPlayers = 1; //... so, we must not check this later
			}

			if ( !self->teamTime[opponent] ) {
				self->teamTime[opponent] = level.time;
			}
			// FIXME: If some players come "later", they will also be calculated for the full time.
			else if ( level.time > ( self->teamTime[opponent] + ( self->wait * 1000 / numPlayers ) ) ) {
				// countered
				self->teamTime[0] = 0;
				self->teamTime[1] = 0;
				self->target_ent->s.frame = 0;
				level.balloonState[self->count] = '0';
				trap_SetConfigstring( CS_BALLOONS, level.balloonState );

				// TODO: Also give players//&team points for destroying a balloon?

				trap_SendServerCommand( -1, va( "mp \"%s destroyed by %s Team\"", msg, TeamName( OtherTeam( tteam ) ) ) );
			}
		}
		else {
			self->teamTime[opponent] = 0;
		}
	}
	else {
		if ( ( self->teamMask & BT_RED ) && ( self->teamMask & BT_BLUE ) ) {
			// reset timer if both teams are trying to capture
			self->teamTime[0] = 0;
			self->teamTime[1] = 0;
		}
		else {
			for ( team = 0; team < 2; team++ ) {
				if ( self->teamMask & ( 1 << team ) ) {
					// start capture timer or test for capture
					if ( !self->teamTime[team] ) {
						self->teamTime[team] = level.time;
					}
					else if ( level.time > ( self->teamTime[team] + 1000 ) ) {
						self->teamTime[team] = 0;
						self->teamTime[team^1] = level.time;
						self->target_ent->s.generic1 = ( team + 1 );
						self->target_ent->s.frame = 1;
						level.balloonState[self->count] = ( 'a' + team );
						trap_SetConfigstring( CS_BALLOONS, level.balloonState );

						trap_SendServerCommand( -1, va( "mp \"%s under attack by %s Team\"", msg, TeamName( team + 1 ) ) );
					}
				} 
				else {
					self->teamTime[team] = 0;
				}
			}
		}
	}

	// prepare next think

	//#@070329: some delay ... i think there isn't always a touch-call (with laging clients)
	// "TEAM_RED ? 0 : 1" @ teamTime[...]
	if ( ( self->target_ent->teamTime[0] + BALLOON_TOUCHDELAY ) < level.time ) {
		self->teamMask &= ~BT_RED;
	}
	if ( ( self->target_ent->teamTime[1] + BALLOON_TOUCHDELAY ) < level.time ) {
		self->teamMask &= ~BT_BLUE;
	}

	self->nextthink = ( level.time + BALLOON_THINKTIME );
}
Exemple #15
0
void trigger_teleporter_touch( gentity_t *self, gentity_t *other, trace_t *trace ) {
	gentity_t	*dest;

	if ( !other->client ) {
		return;
	}
	if ( other->client->ps.pm_type == PM_DEAD ) {
		return;
	}
	// Spectators only?
	if ( ( self->spawnflags & 1 ) && 
		( ( other->client->sess.sessionTeam != TEAM_SPECTATOR ) && !LPSDeadSpec( other->client ) ) ) {
		return;
	}

	// FIXME: Use defines for spawnflags
	if ( ( self->spawnflags & 0x2 ) && !IsSyc() ) {
		// No need to check for sprayroom teleporter out
		return;
	}

	if ( ( other->client->sess.sessionTeam != TEAM_SPECTATOR ) && !LPSDeadSpec( other->client ) ) {
		// sprayroom teleporter in
		if ( self->spawnflags & 0x2 ) {
			if ( other->client->ps.ammo[WP_SPRAYPISTOL] <= 0 ) {
				return;
			}

			other->client->logocounter = 0;

			other->client->sprayroomleavetime = ( ( level.maxsprayroomtime * 1000 ) + level.time );
			other->client->sprayroomsoundflags = 0;
			other->client->ps.stats[STAT_SPRAYROOMSECS] = ( level.maxsprayroomtime + 1 );

			if ( other->client->ps.weapon != WP_SPRAYPISTOL ) {
				other->client->last_nonspray_weapon = other->client->ps.weapon;
			}
			if ( other->client->ps.weaponstate == WEAPON_CHARGING ) {
				other->client->ps.weaponstate = WEAPON_READY;
				other->client->ps.weaponTime = 0;
			}
			trap_SendServerCommand( other->client->ps.clientNum, va( "srwc %i", WP_SPRAYPISTOL ) );
			other->client->pers.cmd.weapon = WP_SPRAYPISTOL;
			other->client->ps.weapon = WP_SPRAYPISTOL;

			G_BackupPowerups( other->client );
		}
		// sprayroom teleporter out
		else if ( self->spawnflags & 0x4 ) {
			other->client->ps.stats[STAT_SPRAYROOMSECS] = 0;
			trap_SendServerCommand( other->client->ps.clientNum, va( "srwc %i", other->client->last_nonspray_weapon ) );
			other->client->pers.cmd.weapon = other->client->last_nonspray_weapon;
			other->client->ps.weapon = other->client->last_nonspray_weapon;

			G_RestorePowerups( other->client );
		}
	}

	dest = 	G_PickTarget( self->target );
	if (!dest) {
		G_Printf ("Couldn't find teleporter destination\n");
		return;
	}

	TeleportPlayer( other, dest->s.origin, dest->s.angles );

}
/*
=================
ConsoleCommand

=================
*/
qboolean	ConsoleCommand( void ) {
	char	cmd[MAX_TOKEN_CHARS];

	trap_Argv( 0, cmd, sizeof( cmd ) );

	//	all commands prefixed with st_ are destined for the rules engine.
	if (	cmd[ 0 ] == 's' &&
			cmd[ 1 ] == 't' &&
			cmd[ 2 ] == '_' )
	{
		if ( G_ST_exec( ST_CONSOLECOMMAND, cmd+3 ) )
			return qtrue;
	}

	switch( SWITCHSTRING( cmd ) )
	{
#ifdef DEVELOPER
	case CS('b','u','y',0):
	case CS('s','e','l','l'):
	case CS('v','i','s','i'):
	case CS('b','e','g','i'):
	case CS('a','s','s','e'):
	case CS('i','n','t','e'):
	case CS('e','n','d','i'):
	case CS('l','o','o','k'):
	case CS('p','l','a','n'):
		G_ST_exec( ST_CLIENTCOMMAND, 0, cmd );
		trap_SendConsoleCommand( EXEC_INSERT, "wait 50 ;" );
		return qtrue;

		//	cl0_
	case CS('c','l','0','_'):
		ClientCommand( 0, cmd + 4 );
		return 0;
#endif

		//	entitylist
	case CS('e','n','t','i'):
		Svcmd_EntityList_f();
		return qtrue;

		//	forceteam
	case CS('f','o','r','c'):
		Svcmd_ForceTeam_f();
		return qtrue;

		//	game_memory
	case CS('g','a','m','e'):
		Svcmd_GameMem_f();
		return qtrue;

		//	addbot
	case CS('a','d','d','b'):
		Svcmd_AddBot_f();
		return qtrue;

		//	botlist
	case CS('b','o','t','l'):
		Svcmd_BotList_f();
		return qtrue;

		//	addip
	case CS('a','d','d','i'):
		Svcmd_AddIP_f();
		return qtrue;

		//	removeip
	case CS('r','e','m','o'):
		Svcmd_RemoveIP_f();
		return qtrue;

		//	listip
	case CS('l','i','s','t'):
		trap_SendConsoleCommand( EXEC_NOW, "g_banIPs\n" );
		return qtrue;

		//	abort
	case CS('a','b','o','r'):
		G_ST_exec( ST_CONSOLECOMMAND, cmd );
		return qtrue;
	}

	if (g_dedicated.integer) {
		if (Q_stricmp (cmd, "say") == 0) {

			trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(1) ) );
			return qtrue;
		}
		// everything else will also be printed as a say command
		trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(0) ) );
		return qtrue;
	}

	return qfalse;
}
Exemple #17
0
/*
===========
ClientConnect

Called when a player begins connecting to the server.
Called again for every map change or tournement restart.

The session information will be valid after exit.

Return NULL if the client should be allowed, otherwise return
a string with the reason for denial.

Otherwise, the client will be sent the current gamestate
and will eventually get to ClientBegin.

firstTime will be qtrue the very first time a client connects
to the server machine, but qfalse on map changes and tournement
restarts.
============
*/
char *ClientConnect( int clientNum, qboolean firstTime )
{
    char      *value;
    char      *userInfoError;
    gclient_t *client;
    char      userinfo[ MAX_INFO_STRING ];
    gentity_t *ent;
    char      reason[ MAX_STRING_CHARS ] = {""};
    int       i;

    ent = &g_entities[ clientNum ];
    client = &level.clients[ clientNum ];

    // ignore if client already connected
    if( client->pers.connected != CON_DISCONNECTED )
        return NULL;

    ent->client = client;
    memset( client, 0, sizeof( *client ) );

    trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );

    value = Info_ValueForKey( userinfo, "cl_guid" );
    Q_strncpyz( client->pers.guid, value, sizeof( client->pers.guid ) );

    value = Info_ValueForKey( userinfo, "ip" );
    // check for local client
    if( !strcmp( value, "localhost" ) )
        client->pers.localClient = qtrue;
    G_AddressParse( value, &client->pers.ip );

    client->pers.admin = G_admin_admin( client->pers.guid );

    // check for admin ban
    if( G_admin_ban_check( ent, reason, sizeof( reason ) ) )
    {
        return va( "%s", reason );
    }

    // check for a password
    value = Info_ValueForKey( userinfo, "password" );

    if( g_password.string[ 0 ] && Q_stricmp( g_password.string, "none" ) &&
            strcmp( g_password.string, value ) != 0 )
        return "Invalid password";

    // add guid to session so we don't have to keep parsing userinfo everywhere
    for( i = 0; i < sizeof( client->pers.guid ) - 1 &&
            isxdigit( client->pers.guid[ i ] ); i++ );

    if( i < sizeof( client->pers.guid ) - 1 )
        return "Invalid GUID";

    for( i = 0; i < level.maxclients; i++ )
    {
        if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
            continue;

        if( !Q_stricmp( client->pers.guid, level.clients[ i ].pers.guid ) )
        {
            if( !G_ClientIsLagging( level.clients + i ) )
            {
                trap_SendServerCommand( i, "cp \"Your GUID is not secure\"" );
                return "Duplicate GUID";
            }
            trap_DropClient( i, "Ghost" );
        }
    }

    client->pers.connected = CON_CONNECTING;

    // read or initialize the session data
    if( firstTime || level.newSession )
        G_InitSessionData( client, userinfo );

    G_ReadSessionData( client );

    // get and distribute relevent paramters
    G_namelog_connect( client );
    userInfoError = ClientUserinfoChanged( clientNum, qfalse );
    if( userInfoError != NULL )
        return userInfoError;

    G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\" \"%c%s%c^7\"\n",
                 clientNum, client->pers.ip.str, client->pers.guid,
                 client->pers.netname,
                 DECOLOR_OFF, client->pers.netname, DECOLOR_ON );

    // don't do the "xxx connected" messages if they were caried over from previous level
    if( firstTime )
        trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"",
                                        client->pers.netname ) );

    if( client->pers.admin )
        G_admin_authlog( ent );

    // count current clients and rank for scoreboard
    CalculateRanks( );


    // if this is after !restart keepteams or !restart switchteams, apply said selection
    if ( client->sess.restartTeam != TEAM_NONE )
    {
        G_ChangeTeam( ent, client->sess.restartTeam );
        client->sess.restartTeam = TEAM_NONE;
    }


    return NULL;
}
Exemple #18
0
void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
	gentity_t   *ent;
	// TTimo might be used uninitialized
	int contents = 0;
	int killer;
	int i;
	const char        *killerName, *obit;
	qboolean nogib = qtrue;
	gitem_t     *item = NULL; // JPW NERVE for flag drop
	vec3_t launchvel,launchspot;      // JPW NERVE
	gentity_t   *flag; // JPW NERVE

	if ( self->client->ps.pm_type == PM_DEAD ) {
		return;
	}

	if ( level.intermissiontime ) {
		return;
	}

	self->client->ps.pm_type = PM_DEAD;

	G_AddEvent( self, EV_STOPSTREAMINGSOUND, 0 );

	if ( attacker ) {
		killer = attacker->s.number;
		if ( attacker->client ) {
			killerName = attacker->client->pers.netname;
		} else {
			killerName = "<non-client>";
		}
	} else {
		killer = ENTITYNUM_WORLD;
		killerName = "<world>";
	}

	if ( killer < 0 || killer >= MAX_CLIENTS ) {
		killer = ENTITYNUM_WORLD;
		killerName = "<world>";
	}

	if ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) {
		obit = "<bad obituary>";
	} else {
		obit = modNames[ meansOfDeath ];
	}

	G_LogPrintf( "Kill: %i %i %i: %s killed %s by %s\n",
				 killer, self->s.number, meansOfDeath, killerName,
				 self->client->pers.netname, obit );

	// broadcast the death event to everyone
	ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
	ent->s.eventParm = meansOfDeath;
	ent->s.otherEntityNum = self->s.number;
	ent->s.otherEntityNum2 = killer;
	ent->r.svFlags = SVF_BROADCAST; // send to everyone

	self->enemy = attacker;

	self->client->ps.persistant[PERS_KILLED]++;

// JPW NERVE -- if player is holding ticking grenade, drop it
	if ( g_gametype.integer != GT_SINGLE_PLAYER ) {
		if ( ( self->client->ps.grenadeTimeLeft ) && ( self->s.weapon != WP_DYNAMITE ) ) {
			launchvel[0] = crandom();
			launchvel[1] = crandom();
			launchvel[2] = random();
			VectorScale( launchvel, 160, launchvel );
			VectorCopy( self->r.currentOrigin, launchspot );
			launchspot[2] += 40;
			fire_grenade( self, launchspot, launchvel, self->s.weapon );

		}
	}
// jpw

	if ( attacker && attacker->client ) {
		if ( attacker == self || OnSameTeam( self, attacker ) ) {

			// DHM - Nerve :: Complaint lodging
			if ( attacker != self && level.warmupTime <= 0 ) {
				if ( attacker->client->pers.localClient ) {
					trap_SendServerCommand( self - g_entities, "complaint -4" );
				} else {
					trap_SendServerCommand( self - g_entities, va( "complaint %i", attacker->s.number ) );
					self->client->pers.complaintClient = attacker->s.clientNum;
					self->client->pers.complaintEndTime = level.time + 20500;
				}
			}
			// dhm

			// JPW NERVE
			if ( g_gametype.integer >= GT_WOLF ) { // high penalty to offset medic heal
				AddScore( attacker, WOLF_FRIENDLY_PENALTY );
			} else {
				// jpw
				AddScore( attacker, -1 );
			}
		} else {
			// JPW NERVE -- mostly added as conveneience so we can tweak from the #defines all in one place
			if ( g_gametype.integer >= GT_WOLF ) {
				AddScore( attacker, WOLF_FRAG_BONUS );
			} else {
				// jpw
				AddScore( attacker, 1 );
			}

			attacker->client->lastKillTime = level.time;
		}
	} else {
		AddScore( self, -1 );
	}

	// Add team bonuses
	Team_FragBonuses( self, inflictor, attacker );

	// if client is in a nodrop area, don't drop anything
// JPW NERVE new drop behavior
	if ( g_gametype.integer == GT_SINGLE_PLAYER ) {   // only drop here in single player; in multiplayer, drop @ limbo
		contents = trap_PointContents( self->r.currentOrigin, -1 );
		if ( !( contents & CONTENTS_NODROP ) ) {
			TossClientItems( self );
		}
	}

	// drop flag regardless
	if ( g_gametype.integer != GT_SINGLE_PLAYER ) {
		if ( self->client->ps.powerups[PW_REDFLAG] ) {
			item = BG_FindItem( "Red Flag" );
			if ( !item ) {
				item = BG_FindItem( "Objective" );
			}

			self->client->ps.powerups[PW_REDFLAG] = 0;
		}
		if ( self->client->ps.powerups[PW_BLUEFLAG] ) {
			item = BG_FindItem( "Blue Flag" );
			if ( !item ) {
				item = BG_FindItem( "Objective" );
			}

			self->client->ps.powerups[PW_BLUEFLAG] = 0;
		}

		if ( item ) {
			launchvel[0] = crandom() * 20;
			launchvel[1] = crandom() * 20;
			launchvel[2] = 10 + random() * 10;

			flag = LaunchItem( item,self->r.currentOrigin,launchvel,self->s.number );
			flag->s.modelindex2 = self->s.otherEntityNum2; // JPW NERVE FIXME set player->otherentitynum2 with old modelindex2 from flag and restore here
			flag->message = self->message;  // DHM - Nerve :: also restore item name
			// Clear out player's temp copies
			self->s.otherEntityNum2 = 0;
			self->message = NULL;
		}

		// send a fancy "MEDIC!" scream.  Sissies, ain' they?
		if ( self->client != NULL ) {
			if ( self->health > GIB_HEALTH && meansOfDeath != MOD_SUICIDE ) {

				if ( self->client->sess.sessionTeam == TEAM_RED ) {
					if ( random() > 0.5 ) {
						G_AddEvent( self, EV_GENERAL_SOUND, G_SoundIndex( "sound/multiplayer/axis/g-medic2.wav" ) );
					} else {
						G_AddEvent( self, EV_GENERAL_SOUND, G_SoundIndex( "sound/multiplayer/axis/g-medic3.wav" ) );
					}
				} else {
					if ( random() > 0.5 ) {
						G_AddEvent( self, EV_GENERAL_SOUND, G_SoundIndex( "sound/multiplayer/allies/a-medic3.wav" ) );
					} else {
						G_AddEvent( self, EV_GENERAL_SOUND, G_SoundIndex( "sound/multiplayer/allies/a-medic2.wav" ) );
					}
				}
			}
		}
	}
// jpw

	Cmd_Score_f( self );        // show scores
	// send updated scores to any clients that are following this one,
	// or they would get stale scoreboards
	for ( i = 0 ; i < level.maxclients ; i++ ) {
		gclient_t   *client;

		client = &level.clients[i];
		if ( client->pers.connected != CON_CONNECTED ) {
			continue;
		}
		if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
			continue;
		}
		if ( client->sess.spectatorClient == self->s.number ) {
			Cmd_Score_f( g_entities + i );
		}
	}

	self->takedamage = qtrue;   // can still be gibbed
	self->r.contents = CONTENTS_CORPSE;

	self->s.powerups = 0;
// JPW NERVE -- only corpse in SP; in MP, need CONTENTS_BODY so medic can operate
	if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
		self->s.weapon = WP_NONE;
		self->s.angles[0] = 0;
	} else {
		self->client->limboDropWeapon = self->s.weapon; // store this so it can be dropped in limbo
	}
// jpw
	self->s.angles[2] = 0;
	LookAtKiller( self, inflictor, attacker );

	VectorCopy( self->s.angles, self->client->ps.viewangles );
	self->s.loopSound = 0;

	trap_UnlinkEntity( self );
	self->r.maxs[2] = 0;
	self->client->ps.maxs[2] = 0;
	trap_LinkEntity( self );

	// don't allow respawn until the death anim is done
	// g_forcerespawn may force spawning at some later time
	self->client->respawnTime = level.time + 800;

	// remove powerups
	memset( self->client->ps.powerups, 0, sizeof( self->client->ps.powerups ) );

	// never gib in a nodrop
	if ( self->health <= GIB_HEALTH && !( contents & CONTENTS_NODROP ) ) {
		GibEntity( self, killer );
		nogib = qfalse;
	}

	if ( nogib ) {
		// normal death
		// for the no-blood option, we need to prevent the health
		// from going to gib level
		if ( self->health <= GIB_HEALTH ) {
			self->health = GIB_HEALTH + 1;
		}

// JPW NERVE for medic
		self->client->medicHealAmt = 0;
// jpw

		// DHM - Play death animation, and set pm_time to delay 'fallen' animation
		self->client->ps.pm_time = BG_AnimScriptEvent( &self->client->ps, ANIM_ET_DEATH, qfalse, qtrue );

		G_AddEvent( self, EV_DEATH1 + 1, killer );

		// the body can still be gibbed
		self->die = body_die;
	}

	trap_LinkEntity( self );

	if ( g_gametype.integer >= GT_WOLF && meansOfDeath == MOD_SUICIDE ) {
		limbo( self, qtrue );
	}
}
Exemple #19
0
void G_RadarUpdateCS(void) {
	int i, valid_count;
	gentity_t *ent;
	playerState_t *ps;
	char cmd[MAX_TOKEN_CHARS];	// make sure our command string is
								// large enough for all the data

	// do we need to update the positions yet?
	if (level.time - level.lastRadarUpdateTime > RADAR_UPDATE_TIME) {
		//store the current time so we know when to update next
		level.lastRadarUpdateTime = level.time;

		//for each possible client
		valid_count = 0;
		
		for (i = 0; i < g_maxclients.integer; i++) {
			//get a pointer to the entity
			ent = g_entities + i;			

			//see if we have a valid entry
			if ( ent->client->pers.connected != CON_CONNECTED ) {
				g_playerOrigins[i].valid = qfalse;
			} else if ( !(ent->inuse) ) {
				g_playerOrigins[i].valid = qfalse;
			} else if( ent->client->ps.powerLevel[plCurrent] <= 0 ) {
				g_playerOrigins[i].valid = qfalse;
			} else {
				// get the client's player info
				ps = &ent->client->ps;

				//get and store the client position and information
				VectorCopy( ps->origin, g_playerOrigins[i].pos );

				g_playerOrigins[i].pl = ps->powerLevel[plCurrent];
				g_playerOrigins[i].plMax = ps->powerLevel[plMaximum];
				g_playerOrigins[i].clientNum = ps->clientNum;

				g_playerOrigins[i].properties = 0;
				if ( ( ps->stats[stChargePercentPrimary] >= 50 ) || ( ps->stats[stChargePercentSecondary] >= 50 ) ) {
					g_playerOrigins[i].properties |= RADAR_WARN;
				}
				if ( ( ps->eFlags & EF_AURA ) || ps->powerups[PW_BOOST] ) {
					g_playerOrigins[i].properties |= RADAR_BURST;
				}

				g_playerOrigins[i].team = ps->persistant[ PERS_TEAM ];
				if ( g_playerOrigins[i].team >= TEAM_SPECTATOR ) {
					// mark as invalid entry for a spectator
					g_playerOrigins[i].valid = qfalse;
				
				} else {
					//mark as valid entry
					g_playerOrigins[i].valid = qtrue;

					//increase the valid counter
					valid_count++;
				}
			}
		} 

		//build the command string to send
		Com_sprintf( cmd, sizeof(cmd), "radar %i", valid_count );
		for( i = 0; i < g_maxclients.integer; i++ ) {
			//if weve got a valid entry then add the position to the command string
			if( g_playerOrigins[i].valid ) {
				strcat(cmd, va(" %i,", g_playerOrigins[i].clientNum));
				strcat(cmd, va("%i,",  g_playerOrigins[i].pl));
				strcat(cmd, va("%i,",  g_playerOrigins[i].plMax));
				strcat(cmd, va("%i,",  g_playerOrigins[i].team));
				strcat(cmd, va("%i,",  g_playerOrigins[i].properties));
				strcat(cmd, va("%i,",  (int)ceil(g_playerOrigins[i].pos[0])));
				strcat(cmd, va("%i,",  (int)ceil(g_playerOrigins[i].pos[1])));
				strcat(cmd, va("%i",   (int)ceil(g_playerOrigins[i].pos[2])));
			}
		}

		// broadcast the command seperately to only connected clients.
		
		// FIXME: Does this prevent overflows that otherwise have to
		//        wait for a time-out message from unconnected clients?
		// NOTE:  Yep, seems to fix it.
		for ( i = 0; i < g_maxclients.integer; i++ ) {
			ent = g_entities + i;

			if ( ent->client->pers.connected != CON_CONNECTED ) {
				continue;
			}

			if ( ent->inuse ) {
				trap_SendServerCommand( ent-g_entities, cmd );
			}
		}
    
		/*
		//finally broadcast the command
		trap_SendServerCommand( -1, cmd );
		*/
	}
}
Exemple #20
0
/*
 * Format:
 *      clientNum location health armor weapon powerups
 */
void
TeamplayInfoMessage(Gentity *ent)
{
	char	entry[1024];
	char	string[8192];
	int	stringlength;
	int	i, j;
	Gentity *player;
	int	cnt;
	int	h, a;
	int	clients[TEAM_MAXOVERLAY];
	int team;

	if(!ent->client->pers.teamInfo)
		return;

	/* send info about followed client's team to spectator */
	if(ent->client->sess.team == TEAM_SPECTATOR){
		if(ent->client->sess.specclient != SPECTATOR_FOLLOW
		   || ent->client->sess.specclient < 0)
			return;
		team = g_entities[ent->client->sess.specclient].client->sess.team;
	}else
		team = ent->client->sess.team;
	if(team != TEAM_RED && team != TEAM_BLUE)
		return;

	/* 
	 * figure out what client should be on the display
	 * we are limited to 8, but we want to use the top eight players
	 * but in client order (so they don't keep changing position on the overlay) 
	 */
	for(i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY; i++){
		player = g_entities + level.sortedClients[i];
		if(player->inuse && player->client->sess.team == team)
			clients[cnt++] = level.sortedClients[i];
	}

	/* We have the top eight players, sort them by clientNum */
	qsort(clients, cnt, sizeof(clients[0]), SortClients);

	/* send the latest information on all clients */
	string[0] = 0;
	stringlength = 0;

	for(i = 0, cnt = 0; i < g_maxclients.integer && cnt < TEAM_MAXOVERLAY;
	    i++){
		player = g_entities + i;
		if(player->inuse && player->client->sess.team == team){
			h = player->client->ps.stats[STAT_HEALTH];
			a = player->client->ps.stats[STAT_SHIELD];
			if(h < 0) h = 0;
			if(a < 0) a = 0;

			Q_sprintf (entry, sizeof(entry), " %i %i %i %i %i %i",
/*				level.sortedClients[i], player->client->pers.teamState.location, h, a, */
				i, player->client->pers.teamState.location, h, a,
				player->client->ps.weap[WSpri], player->s.powerups);
			j = strlen(entry);
			if(stringlength + j >= sizeof(string))
				break;
			strcpy (string + stringlength, entry);
			stringlength += j;
			cnt++;
		}
	}
	trap_SendServerCommand(ent-g_entities, va("tinfo %i %s", cnt, string));
}
void AICast_ScriptParse( cast_state_t *cs ) {
	#define MAX_SCRIPT_EVENTS   64
	gentity_t   *ent;
	char        *pScript;
	char        *token;
	qboolean wantName;
	qboolean inScript;
	int eventNum;
	cast_script_event_t events[MAX_SCRIPT_EVENTS];
	int numEventItems;
	cast_script_event_t *curEvent;
	char params[MAX_QPATH];
	cast_script_stack_action_t  *action;
	int i;
	int bracketLevel;
	qboolean buildScript;       //----(SA)	added

	if ( !level.scriptAI ) {
		return;
	}

	ent = &g_entities[cs->entityNum];
	if ( !ent->aiName ) {
		return;
	}

	buildScript = trap_Cvar_VariableIntegerValue( "com_buildScript" );
	buildScript = qtrue;

	pScript = level.scriptAI;
	wantName = qtrue;
	inScript = qfalse;
	COM_BeginParseSession( "AICast_ScriptParse" );
	bracketLevel = 0;
	numEventItems = 0;

	memset( events, 0, sizeof( events ) );

	while ( 1 )
	{
		token = COM_Parse( &pScript );

		if ( !token[0] ) {
			if ( !wantName ) {
				G_Error( "AICast_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine() );
			}
			break;
		}

		// end of script
		if ( token[0] == '}' ) {
			if ( inScript ) {
				break;
			}
			if ( wantName ) {
				G_Error( "AICast_ScriptParse(), Error (line %d): '}' found, but not expected.\n", COM_GetCurrentParseLine() );
			}
			wantName = qtrue;
		} else if ( token[0] == '{' )    {
			if ( wantName ) {
				G_Error( "AICast_ScriptParse(), Error (line %d): '{' found, NAME expected.\n", COM_GetCurrentParseLine() );
			}
		} else if ( wantName )   {
			if ( !Q_strcasecmp( ent->aiName, token ) ) {
				inScript = qtrue;
				numEventItems = 0;
			}
			wantName = qfalse;
		} else if ( inScript )   {
			if ( !Q_strcasecmp( token, "attributes" ) ) {
				// read in all the attributes
				AICast_CheckLevelAttributes( cs, ent, &pScript );
				continue;
			}
			eventNum = AICast_EventForString( token );
			if ( eventNum < 0 ) {
				G_Error( "AICast_ScriptParse(), Error (line %d): unknown event: %s.\n", COM_GetCurrentParseLine(), token );
			}
			if ( numEventItems >= MAX_SCRIPT_EVENTS ) {
				G_Error( "AICast_ScriptParse(), Error (line %d): MAX_SCRIPT_EVENTS reached (%d)\n", COM_GetCurrentParseLine(), MAX_SCRIPT_EVENTS );
			}

			// if this is a "friendlysightcorpse" event, then disable corpse vis sharing
			if ( !Q_stricmp( token, "friendlysightcorpse" ) ) {
				cs->aiFlags &= ~AIFL_CORPSESIGHTING;
			}

			curEvent = &events[numEventItems];
			curEvent->eventNum = eventNum;
			memset( params, 0, sizeof( params ) );

			// parse any event params before the start of this event's actions
			while ( ( token = COM_Parse( &pScript ) ) && ( token[0] != '{' ) )
			{
				if ( !token[0] ) {
					G_Error( "AICast_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine() );
				}

				if ( eventNum == 13 ) {   // statechange event, check params
					if ( strlen( token ) > 1 ) {
						if ( BG_IndexForString( token, animStateStr, qtrue ) < 0 ) {
							G_Error( "AICast_ScriptParse(), Error (line %d): unknown state type '%s'.\n", COM_GetCurrentParseLine(), token );
						}
					}
				}

				if ( strlen( params ) ) { // add a space between each param
					Q_strcat( params, sizeof( params ), " " );
				}
				Q_strcat( params, sizeof( params ), token );
			}

			if ( strlen( params ) ) { // copy the params into the event
				curEvent->params = G_Alloc( strlen( params ) + 1 );
				Q_strncpyz( curEvent->params, params, strlen( params ) + 1 );
			}

			// parse the actions for this event
			while ( ( token = COM_Parse( &pScript ) ) && ( token[0] != '}' ) )
			{
				if ( !token[0] ) {
					G_Error( "AICast_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine() );
				}

				action = AICast_ActionForString( cs, token );
				if ( !action ) {
					G_Error( "AICast_ScriptParse(), Error (line %d): unknown action: %s.\n", COM_GetCurrentParseLine(), token );
				}

				curEvent->stack.items[curEvent->stack.numItems].action = action;

				memset( params, 0, sizeof( params ) );
				token = COM_ParseExt( &pScript, qfalse );
				for ( i = 0; token[0]; i++ )
				{
					if ( strlen( params ) ) { // add a space between each param
						Q_strcat( params, sizeof( params ), " " );
					}

					if ( i == 0 ) {
						// Special case: playsound's need to be cached on startup to prevent in-game pauses
						if ( !Q_stricmp( action->actionString, "playsound" ) ) {
							G_SoundIndex( token );
						}

//----(SA)	added a bit more
						if (    buildScript && (
									!Q_stricmp( action->actionString, "mu_start" ) ||
									!Q_stricmp( action->actionString, "mu_play" ) ||
									!Q_stricmp( action->actionString, "mu_queue" ) ||
									!Q_stricmp( action->actionString, "startcam" ) ||
									!Q_stricmp( action->actionString, "startcamblack" ) )
								) {
							if ( strlen( token ) ) { // we know there's a [0], but don't know if it's '0'
								trap_SendServerCommand( cs->entityNum, va( "addToBuild %s\n", token ) );
							}
						}

						if ( !Q_stricmp( action->actionString, "giveweapon" ) ) { // register weapon for client pre-loading
							gitem_t *weap = BG_FindItem2( token );    // (SA) FIXME: rats, need to fix this for weapon names with spaces: 'mauser rifle'
//							if(weap)
							RegisterItem( weap );   // don't be nice, just do it.  if it can't find it, you'll bomb out to the error menu
						}
//----(SA)	end
					}

					if ( strrchr( token,' ' ) ) { // need to wrap this param in quotes since it has more than one word
						Q_strcat( params, sizeof( params ), "\"" );
					}

					Q_strcat( params, sizeof( params ), token );

					if ( strrchr( token,' ' ) ) { // need to wrap this param in quotes since it has more than one word
						Q_strcat( params, sizeof( params ), "\"" );
					}

					token = COM_ParseExt( &pScript, qfalse );
				}

				if ( strlen( params ) ) { // copy the params into the event
					curEvent->stack.items[curEvent->stack.numItems].params = G_Alloc( strlen( params ) + 1 );
					Q_strncpyz( curEvent->stack.items[curEvent->stack.numItems].params, params, strlen( params ) + 1 );
				}

				curEvent->stack.numItems++;

				if ( curEvent->stack.numItems >= AICAST_MAX_SCRIPT_STACK_ITEMS ) {
					G_Error( "AICast_ScriptParse(): script exceeded MAX_SCRIPT_ITEMS (%d), line %d\n", AICAST_MAX_SCRIPT_STACK_ITEMS, COM_GetCurrentParseLine() );
				}
			}

			numEventItems++;
		} else    // skip this character completely
		{
			// TTimo: gcc: suggest () around assignment used as truth value
			while ( ( token = COM_Parse( &pScript ) ) )
			{
				if ( !token[0] ) {
					G_Error( "AICast_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine() );
				} else if ( token[0] == '{' ) {
					bracketLevel++;
				} else if ( token[0] == '}' ) {
					if ( !--bracketLevel ) {
						break;
					}
				}
			}
		}
	}

	// alloc and copy the events into the cast_state_t for this cast
	if ( numEventItems > 0 ) {
		cs->castScriptEvents = G_Alloc( sizeof( cast_script_event_t ) * numEventItems );
		memcpy( cs->castScriptEvents, events, sizeof( cast_script_event_t ) * numEventItems );
		cs->numCastScriptEvents = numEventItems;

		cs->castScriptStatus.castScriptEventIndex = -1;
	}
}
void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,  vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
	gclient_t	*client;
	int			take;
	int			save;
	int			knockback;
	qboolean	headShot;
	qboolean	wasAlive;
	hitRegion_t	hr = HR_NUM_HITREGIONS;

	if (!targ->takedamage) {
		return;
	}

#ifdef SAVEGAME_SUPPORT
	if( g_gametype.integer == GT_SINGLE_PLAYER && ( g_reloading.integer || saveGamePending ) )
		return;
#endif // SAVEGAME_SUPPORT

//	trap_SendServerCommand( -1, va("print \"%i\n\"\n", targ->health) );

	// the intermission has allready been qualified for, so don't
	// allow any extra scoring
	if ( level.intermissionQueued || (g_gamestate.integer != GS_PLAYING && match_warmupDamage.integer == 0)) {
		return;
	}

	if ( !inflictor ) {
		inflictor = &g_entities[ENTITYNUM_WORLD];
	}
	if ( !attacker ) {
		attacker = &g_entities[ENTITYNUM_WORLD];
	}

	// Arnout: invisible entities can't be damaged
	if( targ->entstate == STATE_INVISIBLE ||
		targ->entstate == STATE_UNDERCONSTRUCTION ) {
		return;
	}

	// xkan, 12/23/2002 - was the bot alive before applying any damage?
	wasAlive = (targ->health > 0);

	// Arnout: combatstate
	if( targ->client && attacker && attacker->client && attacker != targ ) {
		/*vec_t dist = -1.f;

		if( targ->client->combatState < COMBATSTATE_HOT ) {
			vec3_t shotvec;

			VectorSubtract( targ->r.currentOrigin, attacker->r.currentOrigin, shotvec );
			dist = VectorLengthSquared( shotvec );

			if( dist < Square(1500.f) && targ->client->combatState == COMBATSTATE_WARM )
				targ->client->combatState = COMBATSTATE_HOT;
		}

		if( attacker->client->combatState < COMBATSTATE_HOT ) {
			if( dist < 0.f ) {
				vec3_t shotvec;

				VectorSubtract( targ->r.currentOrigin, attacker->r.currentOrigin, shotvec );
				dist = VectorLengthSquared( shotvec );
			}

			if( dist > Square(1500.f) )
				attacker->client->combatState = COMBATSTATE_WARM;
			else if( attacker->client->combatState == COMBATSTATE_WARM )
				attacker->client->combatState = COMBATSTATE_HOT;
		}*/

		if( g_gamestate.integer == GS_PLAYING ) {
			if( !OnSameTeam( attacker, targ ) ) {
				targ->client->combatState |= (1<<COMBATSTATE_DAMAGERECEIVED);
				attacker->client->combatState |= (1<<COMBATSTATE_DAMAGEDEALT);
			}
		}
	}

// JPW NERVE
	if ((targ->waterlevel >= 3) && (mod == MOD_FLAMETHROWER))
		return;
// jpw

	// shootable doors / buttons don't actually have any health
	if ( targ->s.eType == ET_MOVER && !(targ->isProp) && !targ->scriptName) {
		if ( targ->use && targ->moverState == MOVER_POS1 ) {
			G_UseEntity( targ, inflictor, attacker );
		}
		return;
	}


	// TAT 11/22/2002
	//		In the old code, this check wasn't done for props, so I put that check back in to make props_statue properly work	
	// 4 means destructible
	if ( targ->s.eType == ET_MOVER && (targ->spawnflags & 4) && !targ->isProp ) 
	{
		/*switch (mod) {
		case MOD_GRENADE:
		case MOD_GRENADE_LAUNCHER:
		case MOD_ROCKET:
		case MOD_AIRSTRIKE:
		case MOD_ARTY:
		case MOD_GRENADE_PINEAPPLE:
		case MOD_MAPMORTAR:
		case MOD_EXPLOSIVE:
		case MOD_DYNAMITE:
		case MOD_LANDMINE:
		case MOD_GPG40:
		case MOD_M7:
		case MOD_TELEFRAG:
		case MOD_PANZERFAUST:
		case MOD_SATCHEL:
			break;
		default:
			return;	// no damage from other weapons
		}*/
		if( !G_WeaponIsExplosive( mod ) ) {
			return;
		}

		// check for team
		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}
	} else if ( targ->s.eType == ET_EXPLOSIVE ) {
		/*// 32 Explosive
		// 64 Dynamite only
		// 256 Airstrike/artillery only
		// 512 Satchel only
		if ((targ->spawnflags & 32) || (targ->spawnflags & 64) || (targ->spawnflags & 256) || (targ->spawnflags & 512))
		{
			switch (mod) {
			case MOD_GRENADE:
			case MOD_GRENADE_LAUNCHER:
			case MOD_ROCKET:
			case MOD_GRENADE_PINEAPPLE:
			case MOD_MAPMORTAR:
			case MOD_EXPLOSIVE:
			case MOD_LANDMINE:
			case MOD_GPG40:
			case MOD_M7:
				if( !(targ->spawnflags & 32) )
					return;
				break;
			case MOD_SATCHEL:
				if( !(targ->spawnflags & 512) )
					return;
				break;
			case MOD_ARTY:
			case MOD_AIRSTRIKE:
				if( !(targ->spawnflags & 256) )
					return;
				break;
			case MOD_DYNAMITE:
				if( !(targ->spawnflags & 64) )
					return;
				break;
			default: 
				return;
			}

			// check for team
			if( targ->s.teamNum == inflictor->s.teamNum ) {
				return;
			}
		}*/
		
		if( targ->parent && G_GetWeaponClassForMOD( mod ) == 2 ) {
			return;
		}

		// check for team
//		if( G_GetWeaponClassForMOD( mod ) != -1 && targ->s.teamNum == inflictor->s.teamNum ) {
//			return;
//		}
		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}

		if( G_GetWeaponClassForMOD( mod ) < targ->constructibleStats.weaponclass ) {
			return;
		}
	}
	else if ( targ->s.eType == ET_MISSILE && targ->methodOfDeath == MOD_LANDMINE ) {
		if( targ->s.modelindex2 ) {
			if( G_WeaponIsExplosive( mod ) ) {
				mapEntityData_t	*mEnt;

				if((mEnt = G_FindMapEntityData(&mapEntityData[0], targ-g_entities)) != NULL) {
					G_FreeMapEntityData( &mapEntityData[0], mEnt );
				}

				if((mEnt = G_FindMapEntityData(&mapEntityData[1], targ-g_entities)) != NULL) {
					G_FreeMapEntityData( &mapEntityData[1], mEnt );
				}

				if( attacker && attacker->client ) {
					AddScore( attacker, 1 );
					//G_AddExperience( attacker, 1.f );
				}

				G_ExplodeMissile(targ);
			}
		}
		return;
	} else if ( targ->s.eType == ET_CONSTRUCTIBLE ) {

		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}

		if( G_GetWeaponClassForMOD( mod ) < targ->constructibleStats.weaponclass ) {
			return;
		}
	}

	client = targ->client;

	if ( client ) {
		if ( client->noclip || client->ps.powerups[PW_INVULNERABLE] ) {
			return;
		}
	}

	// check for godmode
	if ( targ->flags & FL_GODMODE ) {
		return;
	}

	if ( !dir ) {
		dflags |= DAMAGE_NO_KNOCKBACK;
	} else {
		VectorNormalize(dir);
	}

	knockback = damage;
	if ( knockback > 200 ) {
		knockback = 200;
	}
	if ( targ->flags & FL_NO_KNOCKBACK ) {
		knockback = 0;
	}
	if ( dflags & DAMAGE_NO_KNOCKBACK ) {
		knockback = 0;
	} else if( dflags & DAMAGE_HALF_KNOCKBACK ) {
		knockback *= 0.5f;
	}
	
	// ydnar: set weapons means less knockback
	if( client && (client->ps.weapon == WP_MORTAR_SET || client->ps.weapon == WP_MOBILE_MG42_SET) )
		knockback *= 0.5;

	if( targ->client && g_friendlyFire.integer && OnSameTeam(targ, attacker) ) {
		knockback = 0;
	}
	
	// figure momentum add, even if the damage won't be taken
	if ( knockback && targ->client ) {
		vec3_t	kvel;
		float	mass;

		mass = 200;

		VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
		VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);

		/*if( mod == MOD_GRENADE ||
			mod == MOD_GRENADE_LAUNCHER ||
			mod == MOD_DYNAMITE ||
			mod == MOD_GPG40 ||
			mod == MOD_M7 ||
 			mod == MOD_LANDMINE ) {
			targ->client->ps.velocity[2] *= 2.f;				// gimme air baby!
			targ->client->ps.groundEntityNum = ENTITYNUM_NONE;	// flying high!
		} else if( mod == MOD_ROCKET ) {
			targ->client->ps.velocity[2] *= .75f;				// but not to the moon please!
			targ->client->ps.groundEntityNum = ENTITYNUM_NONE;	// flying high!
		}*/

		if (targ == attacker && !(	mod != MOD_ROCKET &&
									mod != MOD_GRENADE &&
									mod != MOD_GRENADE_LAUNCHER &&
									mod != MOD_DYNAMITE
									&& mod != MOD_GPG40
									&& mod != MOD_M7
									&& mod != MOD_LANDMINE
									))
		{
			targ->client->ps.velocity[2] *= 0.25;
		}

		// set the timer so that the other client can't cancel
		// out the movement immediately
		if ( !targ->client->ps.pm_time ) {
			int		t;

			t = knockback * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			targ->client->ps.pm_time = t;
			targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}
	}

	// check for completely getting out of the damage
	if ( !(dflags & DAMAGE_NO_PROTECTION) ) {

		// if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
		// if the attacker was on the same team
		if ( targ != attacker && OnSameTeam (targ, attacker)  ) {
			if ( (g_gamestate.integer != GS_PLAYING && match_warmupDamage.integer == 1)) {
				return;
			}
			else if (!g_friendlyFire.integer)
			{
				return;
			}
		}
	}

	// add to the attacker's hit counter
	if ( attacker->client && targ != attacker && targ->health > 0 ) {
		if ( OnSameTeam( targ, attacker ) ) {
			attacker->client->ps.persistant[PERS_HITS] -= damage;
		} else {
			attacker->client->ps.persistant[PERS_HITS] += damage;
		}
	}

	if ( damage < 1 ) {
		damage = 1;
	}
	take = damage;
	save = 0;

	// adrenaline junkie!
	if( targ->client && targ->client->ps.powerups[PW_ADRENALINE] ) {
		take *= .5f;
	}

	// save some from flak jacket
	if( targ->client && targ->client->sess.skill[SK_EXPLOSIVES_AND_CONSTRUCTION] >= 4 && targ->client->sess.playerType == PC_ENGINEER ) {
		if( mod == MOD_GRENADE ||
			mod == MOD_GRENADE_LAUNCHER ||
			mod == MOD_ROCKET ||
			mod == MOD_GRENADE_PINEAPPLE ||
			mod == MOD_MAPMORTAR ||
			mod == MOD_MAPMORTAR_SPLASH || 
			mod == MOD_EXPLOSIVE ||
			mod == MOD_LANDMINE ||
			mod == MOD_GPG40 ||
			mod == MOD_M7 ||
			mod == MOD_SATCHEL ||
			mod == MOD_ARTY ||
			mod == MOD_AIRSTRIKE ||
			mod == MOD_DYNAMITE ||
			mod == MOD_MORTAR ||
			mod == MOD_PANZERFAUST ||
			mod == MOD_MAPMORTAR ) {
			take -= take * .5f;
		}
	}

	headShot = IsHeadShot(targ, dir, point, mod);
	if ( headShot ) {
		if( take * 2 < 50 ) // head shots, all weapons, do minimum 50 points damage
			take = 50;
		else
			take *= 2; // sniper rifles can do full-kill (and knock into limbo)

		if( dflags & DAMAGE_DISTANCEFALLOFF ) {
			vec_t dist;
			vec3_t shotvec;

			VectorSubtract( point, muzzleTrace, shotvec );
			dist = VectorLength( shotvec );

			if( dist > 1500.f ) {
				if( dist > 2500.f ) {
					take *= 0.2f;
				} else {
					float scale = 1.f - 0.2f * (1000.f / (dist - 1000.f));

					take *= scale;
				}
			}
		}

		if( !(targ->client->ps.eFlags & EF_HEADSHOT) ) {	// only toss hat on first headshot
			G_AddEvent( targ, EV_LOSE_HAT, DirToByte(dir) );

			if( mod != MOD_K43_SCOPE &&
				mod != MOD_GARAND_SCOPE ) {
				take *= .8f;	// helmet gives us some protection
			}
		}

		targ->client->ps.eFlags |= EF_HEADSHOT;

		// OSP - Record the headshot
		if(client && attacker && attacker->client
#ifndef DEBUG_STATS
		  && attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam
#endif
		  ) {
			G_addStatsHeadShot(attacker, mod);
		}

		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Head Shot\n\"\n");
		}
		G_LogRegionHit( attacker, HR_HEAD );
		hr = HR_HEAD;
	} else if ( IsLegShot(targ, dir, point, mod) ) {
		G_LogRegionHit( attacker, HR_LEGS );
		hr = HR_LEGS;
		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Leg Shot\n\"\n");
		}
	} else if ( IsArmShot(targ, attacker, point, mod) ) {
		G_LogRegionHit( attacker, HR_ARMS );
		hr = HR_ARMS;
		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Arm Shot\n\"\n");
		}
	} else if (targ->client && targ->health > 0 && IsHeadShotWeapon( mod ) ) {
		G_LogRegionHit( attacker, HR_BODY );
		hr = HR_BODY;
		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Body Shot\n\"\n");
		}
	}

#ifndef DEBUG_STATS
	if ( g_debugDamage.integer )
#endif
	{
		G_Printf( "client:%i health:%i damage:%i mod:%s\n", targ->s.number, targ->health, take, modNames[mod] );
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if ( client ) {
		if ( attacker ) {
			client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
		} else {
			client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
		}
		client->damage_blood += take;
		client->damage_knockback += knockback;

		if ( dir ) {
			VectorCopy ( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		} else {
			VectorCopy ( targ->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}
	}

	// See if it's the player hurting the emeny flag carrier
//	Team_CheckHurtCarrier(targ, attacker);

	if (targ->client) {
		// set the last client who damaged the target
		targ->client->lasthurt_client = attacker->s.number;
		targ->client->lasthurt_mod = mod;
	}

	// do the damage
	if( take ) {
		targ->health -= take;

		// Gordon: don't ever gib POWS
		if( ( targ->health <= 0 ) && ( targ->r.svFlags & SVF_POW ) ) {
			targ->health = -1;
		}

		// Ridah, can't gib with bullet weapons (except VENOM)
		// Arnout: attacker == inflictor can happen in other cases as well! (movers trying to gib things)
		//if ( attacker == inflictor && targ->health <= GIB_HEALTH) {
		if( targ->health <= GIB_HEALTH ) {
			if( !G_WeaponIsExplosive( mod ) ) {
				targ->health = GIB_HEALTH + 1;
			}
		}

// JPW NERVE overcome previous chunk of code for making grenades work again
//		if ((take > 190)) // 190 is greater than 2x mauser headshot, so headshots don't gib
		// Arnout: only player entities! messes up ents like func_constructibles and func_explosives otherwise
		if( ( (targ->s.number < MAX_CLIENTS) && (take > 190) ) && !(targ->r.svFlags & SVF_POW) ) {
			targ->health = GIB_HEALTH - 1;
		}

		if( targ->s.eType == ET_MOVER && !Q_stricmp( targ->classname, "script_mover" ) ) {
			targ->s.dl_intensity = 255.f * (targ->health / (float)targ->count);	// send it to the client
		}

		//G_Printf("health at: %d\n", targ->health);
		if( targ->health <= 0 ) {
			if( client && !wasAlive ) {
				targ->flags |= FL_NO_KNOCKBACK;
				// OSP - special hack to not count attempts for body gibbage
				if( targ->client->ps.pm_type == PM_DEAD ) {
					G_addStats(targ, attacker, take, mod);
				}

				if( (targ->health < FORCE_LIMBO_HEALTH) && (targ->health > GIB_HEALTH) ) {
					limbo(targ, qtrue);
				}

				// xkan, 1/13/2003 - record the time we died.
				if (!client->deathTime)
					client->deathTime = level.time;
			} else {


				targ->sound1to2 = hr;
				targ->sound2to1 = mod;
				targ->sound2to3 = (dflags & DAMAGE_RADIUS) ? 1 : 0;

				if( client ) {
					if( G_GetTeamFromEntity( inflictor ) != G_GetTeamFromEntity( targ ) ) {
						G_AddKillSkillPoints( attacker, mod, hr, (dflags & DAMAGE_RADIUS) );
					}
				}

				if( targ->health < -999 ) {
					targ->health = -999;
				}


				targ->enemy = attacker;
				targ->deathType = mod;

				// Ridah, mg42 doesn't have die func (FIXME)
				if( targ->die ) {	
					// Kill the entity.  Note that this funtion can set ->die to another
					// function pointer, so that next time die is applied to the dead body.
					targ->die( targ, inflictor, attacker, take, mod );
					// OSP - kill stats in player_die function
				}

				if( targ->s.eType == ET_MOVER && !Q_stricmp( targ->classname, "script_mover" ) && (targ->spawnflags & 8) ) {
					return;	// reseructable script mover doesn't unlink itself but we don't want a second death script to be called
				}

				// if we freed ourselves in death function
				if (!targ->inuse)
					return;

				// RF, entity scripting
				if (targ->health <= 0)
				{	// might have revived itself in death function
					if ((targ->s.eType != ET_CONSTRUCTIBLE && targ->s.eType != ET_EXPLOSIVE) ||	(targ->s.eType == ET_CONSTRUCTIBLE && !targ->desstages))
					{ // call manually if using desstages
						G_Script_ScriptEvent( targ, "death", "" );
					}
				}
			}

		}
		else if ( targ->pain )
		{
			if (dir) {	// Ridah, had to add this to fix NULL dir crash
				VectorCopy (dir, targ->rotate);
				VectorCopy (point, targ->pos3); // this will pass loc of hit
			} else {
				VectorClear( targ->rotate );
				VectorClear( targ->pos3 );
			}

			targ->pain (targ, attacker, take, point);
		} else {
			// OSP - update weapon/dmg stats
			G_addStats(targ, attacker, take, mod);
			// OSP
		}

		// RF, entity scripting
		G_Script_ScriptEvent( targ, "pain", va("%d %d", targ->health, targ->health+take) );

		// Ridah, this needs to be done last, incase the health is altered in one of the event calls
		if ( targ->client ) {
			targ->client->ps.stats[STAT_HEALTH] = targ->health;
		}
	}
}
/*
=================
ConsoleCommand

=================
*/
qboolean	ConsoleCommand( void ) {
    char	cmd[MAX_TOKEN_CHARS];

    trap_Argv( 0, cmd, sizeof( cmd ) );

    if ( Q_stricmp (cmd, "entitylist") == 0 ) {
        Svcmd_EntityList_f();
        return qtrue;
    }

    if ( Q_stricmp (cmd, "forceteam") == 0 ) {
        Svcmd_ForceTeam_f();
        return qtrue;
    }

    if (Q_stricmp (cmd, "game_memory") == 0) {
        Svcmd_GameMem_f();
        return qtrue;
    }

    if (Q_stricmp (cmd, "addbot") == 0) {
        Svcmd_AddBot_f();
        return qtrue;
    }

    if (Q_stricmp (cmd, "botlist") == 0) {
        Svcmd_BotList_f();
        return qtrue;
    }

    if (Q_stricmp (cmd, "abort_podium") == 0) {
        Svcmd_AbortPodium_f();
        return qtrue;
    }

    if (Q_stricmp (cmd, "addip") == 0) {
        Svcmd_AddIP_f();
        return qtrue;
    }

    if (Q_stricmp (cmd, "removeip") == 0) {
        Svcmd_RemoveIP_f();
        return qtrue;
    }

    if (Q_stricmp (cmd, "listip") == 0) {
        trap_SendConsoleCommand( EXEC_NOW, "g_banIPs\n" );
        return qtrue;
    }

    if(Q_stricmp (cmd, "setGametype") == 0)
    {
        Svcmd_SetGameType_f();
        return qtrue;
    }
    if(Q_stricmp (cmd, "startcam") == 0) {
        Svcmd_StartCam();
        return qtrue;
    }
    if(Q_stricmp (cmd, "stopcam") == 0) {
        Svcmd_StopCam();
        return qtrue;
    }
    if(Q_stricmp (cmd, "camcmd") == 0) {
        Svcmd_CamCmd();
        return qtrue;
    }
    if( !Q_stricmp( cmd, "initwp") ) {
        WaypointInit();
        return qtrue;
    }

    if ( Q_stricmp( cmd, "blibset") == 0 ) {
        char key[MAX_TOKEN_CHARS];
        char value[MAX_TOKEN_CHARS];

        trap_Argv(1, key, sizeof(key) );
        trap_Argv(2, value, sizeof(value) );
        if(!strlen(key))
        {
            G_Printf("missing key\n");
            return qtrue;
        }

        if( !strlen(value) )	// use "1" as default
            strcpy( value, "1" );

        trap_BotLibVarSet( key, value );
        return qtrue;
    }

    if(wopSP_cmdCheck(cmd))
        return qtrue;

    if (g_dedicated.integer) {
        if ( Q_stricmp( cmd, "ssay" ) == 0 ) {
            Svcmd_Say_f();
            return qtrue;
        }
        if ( Q_stricmp( cmd, "stell" ) == 0 ) {
            Svcmd_Tell_f();
            return qtrue;
        }

        if ( Q_stricmp( cmd, "scp" ) == 0 ) {
            Svcmd_ClientCommand_f( CCMD_CP );
            return qtrue;
        }
        if ( Q_stricmp( cmd, "smp" ) == 0 ) {
            Svcmd_ClientCommand_f( CCMD_MP );
            return qtrue;
        }
        if ( Q_stricmp( cmd, "sprint" ) == 0 ) {
            Svcmd_ClientCommand_f( CCMD_PRINT );
            return qtrue;
        }

        // everything else will also be printed to clients
        trap_SendServerCommand( -1, va("print \"server: %s\n\"", ConcatArgs(0) ) );
        return qtrue;
    }

    return qfalse;
}
void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
	int			contents = 0, i, killer = ENTITYNUM_WORLD;
	char		*killerName = "<world>";
	qboolean	nogib = qtrue;
	gitem_t		*item = NULL;
	gentity_t	*ent;
	qboolean	killedintank = qfalse;

	//float			timeLived;
	weapon_t	weap = BG_WeaponForMOD( meansOfDeath );

//	G_Printf( "player_die\n" );

	if(attacker == self) {
		if(self->client) {
			self->client->pers.playerStats.suicides++;
			trap_PbStat ( self - g_entities , "suicide" , 
				va ( "%d %d %d" , self->client->sess.sessionTeam , self->client->sess.playerType , weap ) ) ;
		}
	} else if(OnSameTeam( self, attacker )) {
		G_LogTeamKill(	attacker,	weap );
	} else {
		G_LogDeath( self,		weap );
		G_LogKill(	attacker,	weap );

		if( g_gamestate.integer == GS_PLAYING ) {
			if( attacker->client ) {
				attacker->client->combatState |= (1<<COMBATSTATE_KILLEDPLAYER);
			}
		}
	}

	// RF, record this death in AAS system so that bots avoid areas which have high death rates
	if( !OnSameTeam( self, attacker ) )
	{
// LC - not needed
//		BotRecordTeamDeath( self->s.number );

		self->isProp = qfalse;	// were we teamkilled or not?
	} else {
		self->isProp = qtrue;
	}	

	// if we got killed by a landmine, update our map
	if( self->client && meansOfDeath == MOD_LANDMINE ) {
		// if it's an enemy mine, update both teamlists
		/*int teamNum;
		mapEntityData_t	*mEnt;
		mapEntityData_Team_t *teamList;
	
		teamNum = inflictor->s.teamNum % 4;

		teamList = self->client->sess.sessionTeam == TEAM_AXIS ? &mapEntityData[0] : &mapEntityData[1];
		if((mEnt = G_FindMapEntityData(teamList, inflictor-g_entities)) != NULL) {
			G_FreeMapEntityData( teamList, mEnt );
		}

		if( teamNum != self->client->sess.sessionTeam ) {
			teamList = self->client->sess.sessionTeam == TEAM_AXIS ? &mapEntityData[1] : &mapEntityData[0];
			if((mEnt = G_FindMapEntityData(teamList, inflictor-g_entities)) != NULL) {
				G_FreeMapEntityData( teamList, mEnt );
			}
		}*/
		mapEntityData_t	*mEnt;

		if((mEnt = G_FindMapEntityData(&mapEntityData[0], inflictor-g_entities)) != NULL) {
			G_FreeMapEntityData( &mapEntityData[0], mEnt );
		}

		if((mEnt = G_FindMapEntityData(&mapEntityData[1], inflictor-g_entities)) != NULL) {
			G_FreeMapEntityData( &mapEntityData[1], mEnt );
		}
	}

	{
		mapEntityData_t	*mEnt;
		mapEntityData_Team_t *teamList = self->client->sess.sessionTeam == TEAM_AXIS ? &mapEntityData[1] : &mapEntityData[0];	// swapped, cause enemy team

		mEnt = G_FindMapEntityDataSingleClient( teamList, NULL, self->s.number, -1 );
		
		while( mEnt ) {
			if( mEnt->type == ME_PLAYER_DISGUISED ) {
				mapEntityData_t* mEntFree = mEnt;

				mEnt = G_FindMapEntityDataSingleClient( teamList, mEnt, self->s.number, -1 );

				G_FreeMapEntityData( teamList, mEntFree );
			} else {
				mEnt = G_FindMapEntityDataSingleClient( teamList, mEnt, self->s.number, -1 );
			}
		}
	}

	if( self->tankLink ) {
		G_LeaveTank( self, qfalse );

		killedintank = qtrue;
	}

	if( self->client->ps.pm_type == PM_DEAD || g_gamestate.integer == GS_INTERMISSION ) {
		return;
	}

	// OSP - death stats handled out-of-band of G_Damage for external calls
	G_addStats(self, attacker, damage, meansOfDeath);
	// OSP

	self->client->ps.pm_type = PM_DEAD;

	G_AddEvent( self, EV_STOPSTREAMINGSOUND, 0);

	if(attacker) {
		killer = attacker->s.number;
		killerName = (attacker->client) ? attacker->client->pers.netname : "<non-client>";
	}

	if(attacker == 0 || killer < 0 || killer >= MAX_CLIENTS) {
		killer = ENTITYNUM_WORLD;
		killerName = "<world>";
	}

	if(g_gamestate.integer == GS_PLAYING) {
		char *obit;

		if(meansOfDeath < 0 || meansOfDeath >= sizeof(modNames) / sizeof(modNames[0])) {
			obit = "<bad obituary>";
		} else {
			obit = modNames[meansOfDeath];
		}

		G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n", killer, self->s.number, meansOfDeath, killerName, self->client->pers.netname, obit );
	}


	// broadcast the death event to everyone
	ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
	ent->s.eventParm = meansOfDeath;
	ent->s.otherEntityNum = self->s.number;
	ent->s.otherEntityNum2 = killer;
	ent->r.svFlags = SVF_BROADCAST;	// send to everyone

	self->enemy = attacker;

	self->client->ps.persistant[PERS_KILLED]++;

	// JPW NERVE -- if player is holding ticking grenade, drop it
	if ((self->client->ps.grenadeTimeLeft) && (self->s.weapon != WP_DYNAMITE) && (self->s.weapon != WP_LANDMINE) && (self->s.weapon != WP_SATCHEL) && (self->s.weapon != WP_TRIPMINE)) {
		vec3_t launchvel, launchspot;

		launchvel[0] = crandom();
		launchvel[1] = crandom();
		launchvel[2] = random();
		VectorScale( launchvel, 160, launchvel );
		VectorCopy(self->r.currentOrigin, launchspot);
		launchspot[2] += 40;
		
		{
			// Gordon: fixes premature grenade explosion, ta bani ;)
			gentity_t *m = fire_grenade(self, launchspot, launchvel, self->s.weapon);
			m->damage = 0;
		}
	}

	if (attacker && attacker->client) {
		if ( attacker == self || OnSameTeam (self, attacker ) ) {

			// DHM - Nerve :: Complaint lodging
			if( attacker != self && level.warmupTime <= 0 && g_gamestate.integer == GS_PLAYING) {
				if( attacker->client->pers.localClient ) {
					trap_SendServerCommand( self-g_entities, "complaint -4" );
				} else {
					if( meansOfDeath != MOD_CRUSH_CONSTRUCTION && meansOfDeath != MOD_CRUSH_CONSTRUCTIONDEATH && meansOfDeath != MOD_CRUSH_CONSTRUCTIONDEATH_NOATTACKER ) {
						if( g_complaintlimit.integer ) {

							if( !(meansOfDeath == MOD_LANDMINE && g_disableComplaints.integer & TKFL_MINES ) &&
								!((meansOfDeath == MOD_ARTY || meansOfDeath == MOD_AIRSTRIKE) && g_disableComplaints.integer & TKFL_AIRSTRIKE ) &&
								!(meansOfDeath == MOD_MORTAR && g_disableComplaints.integer & TKFL_MORTAR ) ) {
								trap_SendServerCommand( self-g_entities, va( "complaint %i", attacker->s.number ) );
								self->client->pers.complaintClient = attacker->s.clientNum;
								self->client->pers.complaintEndTime = level.time + 20500;
							}
						}
					}
				}
			}

			// high penalty to offset medic heal
/*			AddScore( attacker, WOLF_FRIENDLY_PENALTY ); */

			if( g_gametype.integer == GT_WOLF_LMS ) {
				AddKillScore( attacker, WOLF_FRIENDLY_PENALTY );
			}
		} else {

			//G_AddExperience( attacker, 1 );

			// JPW NERVE -- mostly added as conveneience so we can tweak from the #defines all in one place
			AddScore(attacker, WOLF_FRAG_BONUS);

			if( g_gametype.integer == GT_WOLF_LMS ) {
				if( level.firstbloodTeam == -1 )
					level.firstbloodTeam = attacker->client->sess.sessionTeam;

				AddKillScore( attacker, WOLF_FRAG_BONUS );
			}

			attacker->client->lastKillTime = level.time;
		}
	} else {
		AddScore( self, -1 );

		if( g_gametype.integer == GT_WOLF_LMS )
			AddKillScore( self, -1 );
	}

	// Add team bonuses
	Team_FragBonuses(self, inflictor, attacker);

	// drop flag regardless
	if (self->client->ps.powerups[PW_REDFLAG]) {
		item = BG_FindItem("Red Flag");
		if (!item)
			item = BG_FindItem("Objective");

		self->client->ps.powerups[PW_REDFLAG] = 0;
	}
	if (self->client->ps.powerups[PW_BLUEFLAG]) {
		item = BG_FindItem("Blue Flag");
		if (!item)
			item = BG_FindItem("Objective");

		self->client->ps.powerups[PW_BLUEFLAG] = 0;
	}

	if (item) {
		vec3_t launchvel = { 0, 0, 0 };
		gentity_t *flag = LaunchItem(item, self->r.currentOrigin, launchvel, self->s.number);

		flag->s.modelindex2 = self->s.otherEntityNum2;// JPW NERVE FIXME set player->otherentitynum2 with old modelindex2 from flag and restore here
		flag->message = self->message;	// DHM - Nerve :: also restore item name
		// Clear out player's temp copies
		self->s.otherEntityNum2 = 0;
		self->message = NULL;
	}

	// send a fancy "MEDIC!" scream.  Sissies, ain' they?
	if (self->client != NULL) {
		if( self->health > GIB_HEALTH && meansOfDeath != MOD_SUICIDE && meansOfDeath != MOD_SWITCHTEAM ) {
			G_AddEvent( self, EV_MEDIC_CALL, 0 );
		}
	}

	Cmd_Score_f( self );		// show scores

	// send updated scores to any clients that are following this one,
	// or they would get stale scoreboards
	for(i=0; i<level.numConnectedClients; i++) {
		gclient_t *client = &level.clients[level.sortedClients[i]];

		if(client->pers.connected != CON_CONNECTED) continue;
		if(client->sess.sessionTeam != TEAM_SPECTATOR) continue;

		if(client->sess.spectatorClient == self->s.number) {
			Cmd_Score_f(g_entities + level.sortedClients[i]);
		}
	}

	self->takedamage = qtrue;	// can still be gibbed
	self->r.contents = CONTENTS_CORPSE;

	//self->s.angles[2] = 0;
	self->s.powerups = 0;
	self->s.loopSound = 0;
	
	self->client->limboDropWeapon = self->s.weapon; // store this so it can be dropped in limbo

	LookAtKiller( self, inflictor, attacker );
	self->client->ps.viewangles[0] = 0;
	self->client->ps.viewangles[2] = 0;
	//VectorCopy( self->s.angles, self->client->ps.viewangles );

//	trap_UnlinkEntity( self );
	self->r.maxs[2] = self->client->ps.crouchMaxZ;	//%	0;			// ydnar: so bodies don't clip into world
	self->client->ps.maxs[2] = self->client->ps.crouchMaxZ;	//%	0;	// ydnar: so bodies don't clip into world
	trap_LinkEntity( self );

	// don't allow respawn until the death anim is done
	// g_forcerespawn may force spawning at some later time
	self->client->respawnTime = level.timeCurrent + 800;

	// remove powerups
	memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) );

	// never gib in a nodrop
	// FIXME: contents is always 0 here
	if ( self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) ) {
		GibEntity( self, killer );
		nogib = qfalse;
	}

	if(nogib){
		// normal death
		// for the no-blood option, we need to prevent the health
		// from going to gib level
		if ( self->health <= GIB_HEALTH ) {
			self->health = GIB_HEALTH + 1;
		}

		// Arnout: re-enable this for flailing
/*		if( self->client->ps.groundEntityNum == ENTITYNUM_NONE ) {
			self->client->ps.pm_flags |= PMF_FLAILING;
			self->client->ps.pm_time = 750;
			BG_AnimScriptAnimation( &self->client->ps, ANIM_MT_FLAILING, qtrue );

			// Face explosion directory
			{
				vec3_t angles;

				vectoangles( self->client->ps.velocity, angles );
				self->client->ps.viewangles[YAW] = angles[YAW];
				SetClientViewAngle( self, self->client->ps.viewangles );
			}
		} else*/

			// DHM - Play death animation, and set pm_time to delay 'fallen' animation
			//if( G_IsSinglePlayerGame() && self->client->sess.sessionTeam == TEAM_ALLIES ) {
			//	// play "falldown" animation since allies bots won't ever die completely
			//	self->client->ps.pm_time = BG_AnimScriptEvent( &self->client->ps, self->client->pers.character->animModelInfo, ANIM_ET_FALLDOWN, qfalse, qtrue );
			//	G_StartPlayerAppropriateSound(self, "death");
			//} else {
				self->client->ps.pm_time = BG_AnimScriptEvent( &self->client->ps, self->client->pers.character->animModelInfo, ANIM_ET_DEATH, qfalse, qtrue );
				// death animation script already contains sound
			//}

			// record the death animation to be used later on by the corpse
			self->client->torsoDeathAnim = self->client->ps.torsoAnim;
			self->client->legsDeathAnim = self->client->ps.legsAnim;

			G_AddEvent( self, EV_DEATH1 + 1, killer );

		// the body can still be gibbed
		self->die = body_die;
	}

	if( meansOfDeath == MOD_MACHINEGUN ) {
		switch( self->client->sess.sessionTeam ) {
			case TEAM_AXIS:
				level.axisMG42Counter = level.time;
				break;
			case TEAM_ALLIES:
				level.alliesMG42Counter = level.time;
				break;
		}
	}

	G_FadeItems( self, MOD_SATCHEL );

	CalculateRanks();

	if( killedintank /*Gordon: automatically go to limbo from tank*/ ) {
		limbo( self, qfalse ); // but no corpse
	} else if ( (meansOfDeath == MOD_SUICIDE && g_gamestate.integer == GS_PLAYING) ) {
		limbo( self, qtrue );
	} else if( g_gametype.integer == GT_WOLF_LMS ) {
		if( !G_CountTeamMedics( self->client->sess.sessionTeam, qtrue ) ) {
			limbo( self, qtrue );
		}
	}
}
/*
=================
CheckExitRules

There will be a delay between the time the exit is qualified for
and the time everyone is moved to the intermission spot, so you
can see the last frag.
=================
*/
void CheckExitRules( void ) {
 	int			i;
	gclient_t	*cl;
	// if at the intermission, wait for all non-bots to
	// signal ready, then go to next level
	if ( level.intermissiontime ) {
		CheckIntermissionExit ();
		return;
	}

	if ( level.intermissionQueued ) {
#ifdef MISSIONPACK
		int time = (g_singlePlayer.integer) ? SP_INTERMISSION_DELAY_TIME : INTERMISSION_DELAY_TIME;
		if ( level.time - level.intermissionQueued >= time ) {
			level.intermissionQueued = 0;
			BeginIntermission();
		}
#else
		if ( level.time - level.intermissionQueued >= INTERMISSION_DELAY_TIME ) {
			level.intermissionQueued = 0;
			BeginIntermission();
		}
#endif
		return;
	}

	// check for sudden death
	if ( ScoreIsTied() ) {
		// always wait for sudden death
		return;
	}

	if ( g_timelimit.integer && !level.warmupTime ) {
		if ( level.time - level.startTime >= g_timelimit.integer*60000 ) {
			trap_SendServerCommand( -1, "print \"Timelimit hit.\n\"");
			LogExit( "Timelimit hit." );
			return;
		}
	}

	if ( g_gametype.integer < GT_CTF && g_fraglimit.integer ) {
		if ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) {
			trap_SendServerCommand( -1, "print \"Red hit the fraglimit.\n\"" );
			LogExit( "Fraglimit hit." );
			return;
		}

		if ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) {
			trap_SendServerCommand( -1, "print \"Blue hit the fraglimit.\n\"" );
			LogExit( "Fraglimit hit." );
			return;
		}

		for ( i=0 ; i< g_maxclients.integer ; i++ ) {
			cl = level.clients + i;
			if ( cl->pers.connected != CON_CONNECTED ) {
				continue;
			}
			if ( cl->sess.sessionTeam != TEAM_FREE ) {
				continue;
			}

			if ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) {
				LogExit( "Fraglimit hit." );
				trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the fraglimit.\n\"",
					cl->pers.netname ) );
				return;
			}
		}
	}

	if ( g_gametype.integer >= GT_CTF && g_capturelimit.integer ) {

		if ( level.teamScores[TEAM_RED] >= g_capturelimit.integer ) {
			trap_SendServerCommand( -1, "print \"Red hit the capturelimit.\n\"" );
			LogExit( "Capturelimit hit." );
			return;
		}

		if ( level.teamScores[TEAM_BLUE] >= g_capturelimit.integer ) {
			trap_SendServerCommand( -1, "print \"Blue hit the capturelimit.\n\"" );
			LogExit( "Capturelimit hit." );
			return;
		}
	}
}
Exemple #26
0
/*
=================
ConsoleCommand

=================
*/
qboolean	ConsoleCommand( void ) {
	char	cmd[MAX_TOKEN_CHARS];

	trap_Argv( 0, cmd, sizeof( cmd ) );

	if ( Q_stricmp (cmd, "entitylist") == 0 ) {
		Svcmd_EntityList_f();
		return qtrue;
	}

	if ( Q_stricmp (cmd, "forceteam") == 0 ) {
		Svcmd_ForceTeam_f();
		return qtrue;
	}

	if (Q_stricmp (cmd, "game_memory") == 0) {
		Svcmd_GameMem_f();
		return qtrue;
	}

	if (Q_stricmp (cmd, "addbot") == 0) {
		Svcmd_AddBot_f();
		return qtrue;
	}

	if (Q_stricmp (cmd, "botlist") == 0) {
		Svcmd_BotList_f();
		return qtrue;
	}

/*	if (Q_stricmp (cmd, "abort_podium") == 0) {
		Svcmd_AbortPodium_f();
		return qtrue;
	}
*/
	if (Q_stricmp (cmd, "addip") == 0) {
		Svcmd_AddIP_f();
		return qtrue;
	}

	if (Q_stricmp (cmd, "removeip") == 0) {
		Svcmd_RemoveIP_f();
		return qtrue;
	}

	if (Q_stricmp (cmd, "listip") == 0) {
		trap_SendConsoleCommand( EXEC_NOW, "g_banIPs\n" );
		return qtrue;
	}

	if (g_dedicated.integer) {
		if (Q_stricmp (cmd, "say") == 0) {
			trap_SendServerCommand( -1, va("print \"server: %s\n\"", ConcatArgs(1) ) );
			return qtrue;
		}
		// everything else will also be printed as a say command
		trap_SendServerCommand( -1, va("print \"server: %s\n\"", ConcatArgs(0) ) );
		return qtrue;
	}

	return qfalse;
}
Exemple #27
0
/*
================
G_RankRunFrame
================
*/
void G_RankRunFrame()
{
	gentity_t*		ent;
	gentity_t*		ent2;
	grank_status_t	old_status;
	grank_status_t	status;
	int				time;
	int				i;
	int				j;

	if( !trap_RankCheckInit() ) 
	{
		trap_RankBegin( GR_GAMEKEY );
	}

	trap_RankPoll();
	
	if( trap_RankActive() )
	{
		for( i = 0; i < level.maxclients; i++ )
		{
			ent = &(g_entities[i]);
			if ( !ent->inuse )
				continue;
			if ( ent->client == NULL )
				continue;
			if ( ent->r.svFlags & SVF_BOT)
			{
				// no bots in ranked games
				trap_SendConsoleCommand( EXEC_INSERT, va("kick %s\n", 
					ent->client->pers.netname) );
				continue;
			}

			old_status = ent->client->client_status;
			status = trap_RankUserStatus( i );
			
			if( ent->client->client_status != status )
			{
				// inform client of current status
				// not needed for client side log in
				trap_SendServerCommand( i, va("rank_status %i\n",status) );
				if ( i == 0 )
				{
					int j = 0;
				}
				ent->client->client_status = status;
			}
			
			switch( status )
			{
			case QGR_STATUS_NEW:
			case QGR_STATUS_SPECTATOR:
				if( ent->client->sess.sessionTeam != TEAM_SPECTATOR )
				{
					ent->client->sess.sessionTeam = TEAM_SPECTATOR;
					ent->client->sess.spectatorState = SPECTATOR_FREE;
					ClientSpawn( ent );
					// make sure by now CS_GRAND rankingsGameID is ready
					trap_SendServerCommand( i, va("rank_status %i\n",status) );
					trap_SendServerCommand( i, "rank_menu\n" );
				}
				break;
			case QGR_STATUS_NO_USER:
			case QGR_STATUS_BAD_PASSWORD:
			case QGR_STATUS_TIMEOUT:
			case QGR_STATUS_NO_MEMBERSHIP:
			case QGR_STATUS_INVALIDUSER:
			case QGR_STATUS_ERROR:
				if( (ent->r.svFlags & SVF_BOT) == 0 )
				{
					trap_RankUserReset( ent->s.clientNum );
				}
				break;
			case QGR_STATUS_ACTIVE:
				if( (ent->client->sess.sessionTeam == TEAM_SPECTATOR) &&
					(g_gametype.integer < GT_TEAM) )
				{
					SetTeam( ent, "free" );
				}

				if( old_status != QGR_STATUS_ACTIVE )
				{
					// player has just become active
					for( j = 0; j < level.maxclients; j++ )
					{
						ent2 = &(g_entities[j]);
						if ( !ent2->inuse )
							continue;
						if ( ent2->client == NULL )
							continue;
						if ( ent2->r.svFlags & SVF_BOT)
							continue;

						if( (i != j) && (trap_RankUserStatus( j ) == QGR_STATUS_ACTIVE) )
						{
							trap_RankReportInt( i, j, QGR_KEY_PLAYED_WITH, 1, 0 );
						}

						// send current scores so the player's rank will show 
						// up under the crosshair immediately
						DeathmatchScoreboardMessage( ent2 );
					}
				}
				break;
			default:
				break;
			}
		}

		// don't let ranked games last forever
		if( ((g_fraglimit.integer == 0) || (g_fraglimit.integer > 100)) && 
			((g_timelimit.integer == 0) || (g_timelimit.integer > 1000)) )
		{
			trap_Cvar_Set( "timelimit", "1000" );
		}
	}

	// tell time to clients so they can show current match rating
	if( level.intermissiontime == 0 )
	{
		for( i = 0; i < level.maxclients; i++ )
		{
			ent = &(g_entities[i]);
			if( ent->client == NULL )
			{
				continue;
			}

			time = (level.time - ent->client->pers.enterTime) / 1000;
			ent->client->ps.persistant[PERS_MATCH_TIME] = time;
		}
	}
}
Exemple #28
0
/*
===============
G_AddBot
===============
*/
static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) {
	int				clientNum;
	char			*botinfo;
	gentity_t		*bot;
	char			*key;
	char			*s;
	char			*botname;
	char			*model;
//	char			*headmodel;
	char			userinfo[MAX_INFO_STRING];
	int				preTeam = 0;

	// get the botinfo from bots.txt
	botinfo = G_GetBotInfoByName( name );
	if ( !botinfo ) {
		G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name );
		return;
	}

	// create the bot's userinfo
	userinfo[0] = '\0';

	botname = Info_ValueForKey( botinfo, "funname" );
	if( !botname[0] ) {
		botname = Info_ValueForKey( botinfo, "name" );
	}
	// check for an alternative name
	if (altname && altname[0]) {
		botname = altname;
	}
	Info_SetValueForKey( userinfo, "name", botname );
	Info_SetValueForKey( userinfo, "rate", "25000" );
	Info_SetValueForKey( userinfo, "snaps", "20" );
	Info_SetValueForKey( userinfo, "skill", va("%1.2f", skill) );

	if ( skill >= 1 && skill < 2 ) {
		Info_SetValueForKey( userinfo, "handicap", "50" );
	}
	else if ( skill >= 2 && skill < 3 ) {
		Info_SetValueForKey( userinfo, "handicap", "70" );
	}
	else if ( skill >= 3 && skill < 4 ) {
		Info_SetValueForKey( userinfo, "handicap", "90" );
	}

	key = "model";
	model = Info_ValueForKey( botinfo, key );
	if ( !*model ) {
		model = "kyle/default";
	}
	Info_SetValueForKey( userinfo, key, model );

/*	key = "headmodel";
	headmodel = Info_ValueForKey( botinfo, key );
	if ( !*headmodel ) {
		headmodel = model;
	}
	Info_SetValueForKey( userinfo, key, headmodel );
	key = "team_headmodel";
	Info_SetValueForKey( userinfo, key, headmodel );
*/
	key = "gender";
	s = Info_ValueForKey( botinfo, key );
	if ( !*s ) {
		s = "male";
	}
	Info_SetValueForKey( userinfo, "sex", s );

	key = "color1";
	s = Info_ValueForKey( botinfo, key );
	if ( !*s ) {
		s = "4";
	}
	Info_SetValueForKey( userinfo, key, s );

	key = "color2";
	s = Info_ValueForKey( botinfo, key );
	if ( !*s ) {
		s = "4";
	}
	Info_SetValueForKey( userinfo, key, s );

	key = "saber1";
	s = Info_ValueForKey( botinfo, key );
	if ( !*s ) {
		s = "single_1";
	}
	Info_SetValueForKey( userinfo, key, s );

	key = "saber2";
	s = Info_ValueForKey( botinfo, key );
	if ( !*s ) {
		s = "none";
	}
	Info_SetValueForKey( userinfo, key, s );

	s = Info_ValueForKey(botinfo, "personality");
	if (!*s )
	{
		Info_SetValueForKey( userinfo, "personality", "botfiles/default.jkb" );
	}
	else
	{
		Info_SetValueForKey( userinfo, "personality", s );
	}

	// have the server allocate a client slot
	clientNum = trap_BotAllocateClient();
	if ( clientNum == -1 ) {
//		G_Printf( S_COLOR_RED "Unable to add bot.  All player slots are in use.\n" );
//		G_Printf( S_COLOR_RED "Start server with more 'open' slots.\n" );
		trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "UNABLE_TO_ADD_BOT")));
		return;
	}

	// initialize the bot settings
	if( !team || !*team ) {
		if( g_gametype.integer >= GT_TEAM ) {
			if( PickTeam(clientNum) == TEAM_RED) {
				team = "red";
			}
			else {
				team = "blue";
			}
		}
		else {
			team = "red";
		}
	}
//	Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) );
	Info_SetValueForKey( userinfo, "skill", va( "%5.2f", skill ) );
	Info_SetValueForKey( userinfo, "team", team );

	bot = &g_entities[ clientNum ];
	bot->r.svFlags |= SVF_BOT;
	bot->inuse = qtrue;

	// register the userinfo
	trap_SetUserinfo( clientNum, userinfo );

	if (g_gametype.integer >= GT_TEAM)
	{
		if (team && Q_stricmp(team, "red") == 0)
		{
			bot->client->sess.sessionTeam = TEAM_RED;
		}
		else if (team && Q_stricmp(team, "blue") == 0)
		{
			bot->client->sess.sessionTeam = TEAM_BLUE;
		}
		else
		{
			bot->client->sess.sessionTeam = PickTeam( -1 );
		}
	}

	if (g_gametype.integer == GT_SIEGE)
	{
		bot->client->sess.siegeDesiredTeam = bot->client->sess.sessionTeam;
		bot->client->sess.sessionTeam = TEAM_SPECTATOR;
	}

	preTeam = bot->client->sess.sessionTeam;

	// have it connect to the game as a normal client
	if ( ClientConnect( clientNum, qtrue, qtrue ) ) {
		return;
	}

	if (bot->client->sess.sessionTeam != preTeam)
	{
		trap_GetUserinfo(clientNum, userinfo, MAX_INFO_STRING);

		if (bot->client->sess.sessionTeam == TEAM_SPECTATOR)
		{
			bot->client->sess.sessionTeam = preTeam;
		}

		if (bot->client->sess.sessionTeam == TEAM_RED)
		{
			team = "Red";
		}
		else
		{
			if (g_gametype.integer == GT_SIEGE)
			{
				if (bot->client->sess.sessionTeam == TEAM_BLUE)
				{
					team = "Blue";
				}
				else
				{
					team = "s";
				}
			}
			else
			{
				team = "Blue";
			}
		}

		Info_SetValueForKey( userinfo, "team", team );

		trap_SetUserinfo( clientNum, userinfo );

		bot->client->ps.persistant[ PERS_TEAM ] = bot->client->sess.sessionTeam;

		G_ReadSessionData( bot->client );
		ClientUserinfoChanged( clientNum );
	}

	if (g_gametype.integer == GT_DUEL ||
		g_gametype.integer == GT_POWERDUEL)
	{
		int loners = 0;
		int doubles = 0;

		bot->client->sess.duelTeam = 0;
		G_PowerDuelCount(&loners, &doubles, qtrue);

		if (!doubles || loners > (doubles/2))
		{
            bot->client->sess.duelTeam = DUELTEAM_DOUBLE;
		}
		else
		{
            bot->client->sess.duelTeam = DUELTEAM_LONE;
		}

		bot->client->sess.sessionTeam = TEAM_SPECTATOR;
		SetTeam(bot, "s");
	}
	else
	{
		if( delay == 0 ) {
			ClientBegin( clientNum, qfalse );
			return;
		}		
		AddBotToSpawnQueue( clientNum, delay );
	}
}
Exemple #29
0
/*
==============
G_Script_ScriptParse

  Parses the script for the given entity
==============
*/
void G_Script_ScriptParse(gentity_t *ent) {
	char                    *pScript;
	qboolean                wantName;
	qboolean                inScript;
	int                     eventNum;
	g_script_event_t        events[G_MAX_SCRIPT_STACK_ITEMS];
	int                     numEventItems;
	g_script_event_t        *curEvent;
	char                    params[MAX_INFO_STRING];
	g_script_stack_action_t *action;
	int                     i;
	int                     bracketLevel;
	qboolean                buildScript;

	if (!ent->scriptName) {
		return;
	}
	if (!level.scriptEntity) {
		return;
	}

	buildScript = trap_Cvar_VariableIntegerValue("com_buildScript");

	pScript  = level.scriptEntity;
	wantName = qtrue;
	inScript = qfalse;
	COM_BeginParseSession("G_Script_ScriptParse");
	bracketLevel  = 0;
	numEventItems = 0;

	memset(events, 0, sizeof (events));

	for (;;) {
		char *token;

		token = COM_Parse(&pScript);

		if (!token[0]) {
			if (!wantName) {
				G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine());
			}
			break;
		}

		// end of script
		if (token[0] == '}') {
			if (inScript) {
				break;
			}
			if (wantName) {
				G_Error("G_Script_ScriptParse(), Error (line %d): '}' found, but not expected.\n", COM_GetCurrentParseLine());
			}
			wantName = qtrue;
		} else if (token[0] == '{') {
			if (wantName) {
				G_Error("G_Script_ScriptParse(), Error (line %d): '{' found, NAME expected.\n", COM_GetCurrentParseLine());
			}
		} else if (wantName) {
			if (!Q_stricmp(token, "bot")) {
				// a bot, skip this whole entry
				SkipRestOfLine(&pScript);
				// skip this section
				SkipBracedSection(&pScript);
				//
				continue;
			}
			if (!Q_stricmp(token, "entity")) {
				// this is an entity, so go back to look for a name
				continue;
			}
			if (!Q_stricmp(ent->scriptName, token)) {
				inScript      = qtrue;
				numEventItems = 0;
			}
			wantName = qfalse;
		} else if (inScript) {
			Q_strlwr(token);
			eventNum = G_Script_EventForString(token);
			if (eventNum < 0) {
				G_Error("G_Script_ScriptParse(), Error (line %d): unknown event: %s.\n", COM_GetCurrentParseLine(), token);
			}

			if (numEventItems >= G_MAX_SCRIPT_STACK_ITEMS) {
				G_Error("G_Script_ScriptParse(), Error (line %d): G_MAX_SCRIPT_STACK_ITEMS reached (%d)\n", COM_GetCurrentParseLine(), G_MAX_SCRIPT_STACK_ITEMS);
			}

			curEvent           = &events[numEventItems];
			curEvent->eventNum = eventNum;
			memset(params, 0, sizeof (params));

			// parse any event params before the start of this event's actions
			while ((token = COM_Parse(&pScript)) != NULL && (token[0] != '{')) {
				if (!token[0]) {
					G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine());
				}

				if (strlen(params)) {      // add a space between each param
					Q_strcat(params, sizeof (params), " ");
				}
				Q_strcat(params, sizeof (params), token);
			}

			if (strlen(params)) {        // copy the params into the event
				curEvent->params = G_Alloc(strlen(params) + 1);
				Q_strncpyz(curEvent->params, params, strlen(params) + 1);
			}

			// parse the actions for this event
			while ((token = COM_Parse(&pScript)) != NULL && (token[0] != '}')) {
				if (!token[0]) {
					G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine());
				}

				action = G_Script_ActionForString(token);
				if (!action) {
					G_Error("G_Script_ScriptParse(), Error (line %d): unknown action: %s.\n", COM_GetCurrentParseLine(), token);
				}

				curEvent->stack.items[curEvent->stack.numItems].action = action;

				memset(params, 0, sizeof (params));

				// Ikkyo - Parse for {}'s if this is a set command
				// Nico, added "create" & "delete" condition
				if (!Q_stricmp(action->actionString, "set") ||
				    !Q_stricmp(action->actionString, "create") ||
				    !Q_stricmp(action->actionString, "delete")) {
					token = COM_Parse(&pScript);
					if (token[0] != '{') {
						COM_ParseError("'{' expected, found: %s.\n", token);
					}

					while ((token = COM_Parse(&pScript)) != NULL && (token[0] != '}')) {
						if (strlen(params)) {     // add a space between each param
							Q_strcat(params, sizeof (params), " ");
						}

						if (strrchr(token, ' ')) {    // need to wrap this param in quotes since it has more than one word
							Q_strcat(params, sizeof (params), "\"");
						}

						Q_strcat(params, sizeof (params), token);

						if (strrchr(token, ' ')) {    // need to wrap this param in quotes since it has mor
							Q_strcat(params, sizeof (params), "\"");
						}
					}
				} else
				// hackly precaching of custom characters
				if (!Q_stricmp(token, "spawnbot")) {
					// this is fairly indepth, so I'll move it to a separate function for readability
					G_Script_ParseSpawnbot(&pScript, params, MAX_INFO_STRING);
				} else {
					token = COM_ParseExt(&pScript, qfalse);
					for (i = 0; token[0]; ++i) {
						if (strlen(params)) {     // add a space between each param
							Q_strcat(params, sizeof (params), " ");
						}

						if (i == 0) {
							// Special case: playsound's need to be cached on startup to prevent in-game pauses
							if (!Q_stricmp(action->actionString, "playsound")) {
								G_SoundIndex(token);
							} else if (!Q_stricmp(action->actionString, "changemodel")) {
								G_ModelIndex(token);
							} else if (buildScript &&
							           (!Q_stricmp(action->actionString, "mu_start") ||
							            !Q_stricmp(action->actionString, "mu_play") ||
							            !Q_stricmp(action->actionString, "mu_queue") ||
							            !Q_stricmp(action->actionString, "startcam")) &&
							           strlen(token)) {
								trap_SendServerCommand(-1, va("addToBuild %s\n", token));
							}
						}

						if ((i == 0 || i == 1) && !Q_stricmp(action->actionString, "remapshader")) {
							G_ShaderIndex(token);
						}

						if (strrchr(token, ' ')) {    // need to wrap this param in quotes since it has more than one word
							Q_strcat(params, sizeof (params), "\"");
						}

						Q_strcat(params, sizeof (params), token);

						if (strrchr(token, ' ')) {    // need to wrap this param in quotes since it has more than one word
							Q_strcat(params, sizeof (params), "\"");
						}

						token = COM_ParseExt(&pScript, qfalse);
					}
				}

				if (strlen(params)) {     // copy the params into the event
					curEvent->stack.items[curEvent->stack.numItems].params = G_Alloc(strlen(params) + 1);
					Q_strncpyz(curEvent->stack.items[curEvent->stack.numItems].params, params, strlen(params) + 1);
				}

				curEvent->stack.numItems++;

				if (curEvent->stack.numItems >= G_MAX_SCRIPT_STACK_ITEMS) {
					G_Error("G_Script_ScriptParse(): script exceeded G_MAX_SCRIPT_STACK_ITEMS (%d), line %d\n", G_MAX_SCRIPT_STACK_ITEMS, COM_GetCurrentParseLine());
				}
			}

			numEventItems++;
		} else {   // skip this character completely
			// TTimo gcc: suggest parentheses around assignment used as truth value
			while ((token = COM_Parse(&pScript)) != NULL) {
				if (!token[0]) {
					G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine());
				} else if (token[0] == '{') {
					bracketLevel++;
				} else if (token[0] == '}' && !--bracketLevel) {
					break;
				}
			}
		}
	}

	// alloc and copy the events into the gentity_t for this cast
	if (numEventItems > 0) {
		ent->scriptEvents = G_Alloc(sizeof (g_script_event_t) * numEventItems);
		memcpy(ent->scriptEvents, events, sizeof (g_script_event_t) * numEventItems);
		ent->numScriptEvents = numEventItems;
	}
}
Exemple #30
0
void UpdateTournamentInfo( void ) {
	int			i = 0, j = 0, k = 0;
	gentity_t	*player = NULL;
	int			playerClientNum;
	int			n;
	char		msg[AWARDS_MSG_LENGTH], msg2[AWARDS_MSG_LENGTH];
	int			playerRank=level.numNonSpectatorClients-1, highestTiedRank = 0;
	gentity_t	*MVP = NULL;
	int			mvpNum = -1, mvpPoints = 0, winningCaptures = 0, winningPoints = 0;
	int			winningTeam=0;
	int			loseCaptures = 0, losePoints = 0;
	char		*mvpName = "";
	gclient_t	*cl = NULL;
	gclient_t	*cl2= NULL;
	int			secondPlaceTied=0;

	memset(msg, 0, AWARDS_MSG_LENGTH);
	memset(msg2, 0, AWARDS_MSG_LENGTH);

	player = NULL;

	// Was there a tie for second place on the podium?
	cl = &level.clients[level.sortedClients[1]];
	cl2= &level.clients[level.sortedClients[2]];
	if (cl->ps.persistant[PERS_SCORE] == cl2->ps.persistant[PERS_SCORE])
		secondPlaceTied=1;

	winningTeam = level.clients[0].ps.persistant[PERS_RANK]+1;
	if ( winningTeam != TEAM_BLUE && winningTeam != TEAM_RED )
	{//tie or not a team game
		winningTeam = 0;
	}

	if (mvpNum < 0)
	{//ah, crap no MVP, pick the first player on the winning team
		for (i = 0; i < level.maxclients; i++ )
		{
			if ( !&g_entities[i] ) continue;
			if ( !(&g_entities[i])->client) continue;
			if ( g_entities[i].client->ps.persistant[PERS_TEAM] == winningTeam )
			{
				mvpNum = i;
				break;
			}
		}
	}
	if (mvpNum >= 0)
	{//still no MVP, so skip it
		MVP = &g_entities[mvpNum];
		mvpName = MVP->client->pers.netname;
		mvpPoints = MVP->client->ps.persistant[PERS_SCORE];
		winningTeam = MVP->client->ps.persistant[PERS_TEAM];
	}

	if ( winningTeam )
	{//one of the teams won
		winningCaptures = level.teamScores[winningTeam];
		if (winningTeam == TEAM_RED)
			loseCaptures = level.teamScores[TEAM_BLUE];
		else
			loseCaptures = level.teamScores[TEAM_RED];

		for (i = 0; i < level.maxclients; i++ )
		{
			if ( !&g_entities[i] ) continue;
			if ( !(&g_entities[i])->client ) continue;
			if ( g_entities[i].client->ps.persistant[PERS_TEAM] == winningTeam )
				winningPoints += g_entities[i].client->ps.persistant[PERS_SCORE];
			else
				losePoints += g_entities[i].client->ps.persistant[PERS_SCORE];
		}
	}

	for (i = 0; i < level.maxclients; i++ )
	{
		player = &g_entities[i];
		if ( !player->inuse || (player->r.svFlags & SVF_BOT))
		{
			continue;
		}
		playerClientNum = i;

		G_Client_CalculateRanks( qfalse );
		// put info for the top three players into the msg
		Com_sprintf(msg, AWARDS_MSG_LENGTH, "awards %d", level.numNonSpectatorClients);
		for( j = 0; j < level.numNonSpectatorClients; j++ )
		{
			if (j > 2)
			{
				break;
			}
			n = level.sortedClients[j];
			strcpy(msg2, msg);
			Com_sprintf(msg, AWARDS_MSG_LENGTH, "%s %d", msg2, n);
		}

		// put this guy's awards into the msg
		if ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR )
		{
			strcpy(msg2, msg);
			Com_sprintf( msg, sizeof(msg), "%s 0", msg2);
		}

		// now supply...
		//
		// 1) winning team's MVP's name
		// 2) winning team's MVP's score
		// 3) winning team's total captures
		// 4) winning team's total points
		// 5) this player's rank
		// 6) the highest rank for which this player tied
		// 7) losing team's total captures
		// 8) losing team's total points
		// 9) if second place was tied
		// 10) intermission point
		// 11) intermission angles
		//
		for (k = 0; k < level.numNonSpectatorClients; k++)
		{
			if (level.sortedClients[k] == playerClientNum)
			{
				playerRank = k;
				break;
			}
		}
		highestTiedRank = 0;
		for (k = playerRank-1; k >= 0; k--)
		{
			cl = &level.clients[level.sortedClients[k]];
			if (cl->ps.persistant[PERS_SCORE] > level.clients[level.sortedClients[playerRank]].ps.persistant[PERS_SCORE])
			{
				break;
			}
			highestTiedRank = k+1;
		}
		strcpy(msg2, msg);
		Com_sprintf(msg, AWARDS_MSG_LENGTH, "%s \"%s\" %d %d %d %d %d %d %d %d %f %f %f %f %f %f",
			msg2, mvpName, mvpPoints, winningCaptures, winningPoints, playerRank, highestTiedRank,
			loseCaptures, losePoints, secondPlaceTied, level.intermission_origin[0], level.intermission_origin[1],
			level.intermission_origin[2], level.intermission_angle[0], level.intermission_angle[1],
			level.intermission_angle[2]);

		trap_SendServerCommand(player-g_entities, msg);
	}

	if (g_gametype.integer == GT_SINGLE_PLAYER)
	{
		Com_sprintf( msg, sizeof(msg), "postgame %i", playerRank);
		trap_SendConsoleCommand( EXEC_APPEND, msg); 
	}

}