Esempio n. 1
0
//------------------------------------
void Seeker_Strafe( void )
{
    int		side;
    vec3_t	end, right, dir;
    trace_t	tr;

    if ( random() > 0.7f || !NPC->enemy || !NPC->enemy->client )
    {
        // Do a regular style strafe
        AngleVectors( NPC->client->renderInfo.eyeAngles, NULL, right, NULL );

        // Pick a random strafe direction, then check to see if doing a strafe would be
        //	reasonably valid
        side = ( rand() & 1 ) ? -1 : 1;
        VectorMA( NPC->r.currentOrigin, SEEKER_STRAFE_DIS * side, right, end );

        trap_Trace( &tr, NPC->r.currentOrigin, NULL, NULL, end, NPC->s.number, MASK_SOLID );

        // Close enough
        if ( tr.fraction > 0.9f )
        {
            float vel = SEEKER_STRAFE_VEL;
            float upPush = SEEKER_UPWARD_PUSH;
            if ( NPC->client->NPC_class != CLASS_BOBAFETT )
            {
                G_Sound( NPC, CHAN_AUTO, G_SoundIndex( "sound/chars/seeker/misc/hiss" ));
            }
            else
            {
                vel *= 3.0f;
                upPush *= 4.0f;
            }
            VectorMA( NPC->client->ps.velocity, vel*side, right, NPC->client->ps.velocity );
            // Add a slight upward push
            NPC->client->ps.velocity[2] += upPush;

            NPCInfo->standTime = level.time + 1000 + random() * 500;
        }
    }
    else
    {
        float stDis;

        // Do a strafe to try and keep on the side of their enemy
        AngleVectors( NPC->enemy->client->renderInfo.eyeAngles, dir, right, NULL );

        // Pick a random side
        side = ( rand() & 1 ) ? -1 : 1;
        stDis = SEEKER_STRAFE_DIS;
        if ( NPC->client->NPC_class == CLASS_BOBAFETT )
        {
            stDis *= 2.0f;
        }
        VectorMA( NPC->enemy->r.currentOrigin, stDis * side, right, end );

        // then add a very small bit of random in front of/behind the player action
        VectorMA( end, crandom() * 25, dir, end );

        trap_Trace( &tr, NPC->r.currentOrigin, NULL, NULL, end, NPC->s.number, MASK_SOLID );

        // Close enough
        if ( tr.fraction > 0.9f )
        {
            float dis, upPush;

            VectorSubtract( tr.endpos, NPC->r.currentOrigin, dir );
            dir[2] *= 0.25; // do less upward change
            dis = VectorNormalize( dir );

            // Try to move the desired enemy side
            VectorMA( NPC->client->ps.velocity, dis, dir, NPC->client->ps.velocity );

            upPush = SEEKER_UPWARD_PUSH;
            if ( NPC->client->NPC_class != CLASS_BOBAFETT )
            {
                G_Sound( NPC, CHAN_AUTO, G_SoundIndex( "sound/chars/seeker/misc/hiss" ));
            }
            else
            {
                upPush *= 4.0f;
            }

            // Add a slight upward push
            NPC->client->ps.velocity[2] += upPush;

            NPCInfo->standTime = level.time + 2500 + random() * 500;
        }
    }
}
Esempio n. 2
0
/*
=============
P_WorldEffects

Check for lava / slime contents and drowning
=============
*/
void P_WorldEffects( gentity_t *ent ) {
	qboolean	envirosuit;
	int			waterlevel;

	if ( ent->client->noclip ) {
		ent->client->airOutTime = level.time + 12000;	// don't need air
		return;
	}

	waterlevel = ent->waterlevel;

	envirosuit = ent->client->ps.powerups[PW_BATTLESUIT] > level.time;

	//
	// check for drowning
	//
	if ( waterlevel == 3 ) {
		// envirosuit give air
		if ( envirosuit ) {
			ent->client->airOutTime = level.time + 10000;
		}

		// if out of air, start drowning
		if ( ent->client->airOutTime < level.time) {
			// drown!
			ent->client->airOutTime += 1000;
			if ( ent->health > 0 ) {
				// take more damage the longer underwater
				ent->damage += 2;
				if (ent->damage > 15)
					ent->damage = 15;

				// play a gurp sound instead of a normal pain sound
				if (ent->health <= ent->damage) {
					G_Sound(ent, CHAN_VOICE, G_SoundIndex(/*"*drown.wav"*/"sound/player/gurp1.wav"));
				} else if (rand()&1) {
					G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp1.wav"));
				} else {
					G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp2.wav"));
				}

				// don't play a normal pain sound
				ent->pain_debounce_time = level.time + 200;

				G_Damage (ent, NULL, NULL, NULL, NULL, 
					ent->damage, DAMAGE_NO_ARMOR, MOD_WATER);
			}
		}
	} else {
		ent->client->airOutTime = level.time + 12000;
		ent->damage = 2;
	}

	//
	// check for sizzle damage (move to pmove?)
	//
	if (waterlevel && 
		(ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) {
		if (ent->health > 0
			&& ent->pain_debounce_time <= level.time	) {

			if ( envirosuit ) {
				G_AddEvent( ent, EV_POWERUP_BATTLESUIT, 0 );
			} else {
				if (ent->watertype & CONTENTS_LAVA) {
					G_Damage (ent, NULL, NULL, NULL, NULL, 
						30*waterlevel, 0, MOD_LAVA);
				}

				if (ent->watertype & CONTENTS_SLIME) {
					G_Damage (ent, NULL, NULL, NULL, NULL, 
						10*waterlevel, 0, MOD_SLIME);
				}
			}
		}
	}
}
Esempio n. 3
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 ) {
	gclient_t	*client;
	pmove_t		pm;
	int			oldEventSequence;
	int			msec;
	int			i;
	usercmd_t	*ucmd;

	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;
	}
	// mark the time, so the connection sprite can be removed
	ucmd = &ent->client->pers.cmd;

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

	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;
	}

	if ( pmove_msec.integer < 8 ) {
		trap_Cvar_Set("pmove_msec", "8");
	}
	else if (pmove_msec.integer > 33) {
		trap_Cvar_Set("pmove_msec", "33");
	}

	if ( pmove_fixed.integer || client->pers.pmoveFixed ) {
		ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
		//if (ucmd->serverTime - client->ps.commandTime <= 0)
		//	return;
	}

	//
	// check for exiting intermission
	//
	if ( level.intermissiontime ) {
		ClientIntermissionThink( client );
		return;
	}

	// spectators don't do much
	if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
		if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
			return;
		}
		SpectatorThink( ent, ucmd );
		return;
	}

	if (ent && ent->client && (ent->client->ps.eFlags & EF_INVULNERABLE))
	{
		if (ent->client->invulnerableTimer <= level.time)
		{
			ent->client->ps.eFlags &= ~EF_INVULNERABLE;
		}
	}

	// check for inactivity timer, but never drop the local client of a non-dedicated server
	if ( !ClientInactivityTimer( client ) ) {
		return;
	}

	// clear the rewards if time
	if ( level.time > client->rewardTime ) {
		client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
	}

	if ( client->noclip ) {
		client->ps.pm_type = PM_NOCLIP;
	} else if ( client->ps.eFlags & EF_DISINTEGRATION ) {
		client->ps.pm_type = PM_NOCLIP;
	} else if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
		client->ps.pm_type = PM_DEAD;
	} else {
		if (client->ps.forceGripChangeMovetype)
		{
			client->ps.pm_type = client->ps.forceGripChangeMovetype;
		}
		else
		{
			client->ps.pm_type = PM_NORMAL;
		}
	}

	client->ps.gravity = g_gravity.value;

	// set speed
	client->ps.speed = g_speed.value;
	client->ps.basespeed = g_speed.value;

	if (ent->client->ps.duelInProgress)
	{
		gentity_t *duelAgainst = &g_entities[ent->client->ps.duelIndex];

		//Keep the time updated, so once this duel ends this player can't engage in a duel for another
		//10 seconds. This will give other people a chance to engage in duels in case this player wants
		//to engage again right after he's done fighting and someone else is waiting.
		ent->client->ps.fd.privateDuelTime = level.time + 10000;

		if (ent->client->ps.duelTime < level.time)
		{
			//Bring out the sabers
			if (ent->client->ps.weapon == WP_SABER && ent->client->ps.saberHolstered &&
				ent->client->ps.duelTime)
			{
				if (!saberOffSound || !saberOnSound)
				{
					saberOffSound = G_SoundIndex("sound/weapons/saber/saberoffquick.wav");
					saberOnSound = G_SoundIndex("sound/weapons/saber/saberon.wav");
				}

				ent->client->ps.saberHolstered = qfalse;
				G_Sound(ent, CHAN_AUTO, saberOnSound);

				G_AddEvent(ent, EV_PRIVATE_DUEL, 2);

				ent->client->ps.duelTime = 0;
			}

			if (duelAgainst && duelAgainst->client && duelAgainst->inuse &&
				duelAgainst->client->ps.weapon == WP_SABER && duelAgainst->client->ps.saberHolstered &&
				duelAgainst->client->ps.duelTime)
			{
				if (!saberOffSound || !saberOnSound)
				{
					saberOffSound = G_SoundIndex("sound/weapons/saber/saberoffquick.wav");
					saberOnSound = G_SoundIndex("sound/weapons/saber/saberon.wav");
				}

				duelAgainst->client->ps.saberHolstered = qfalse;
				G_Sound(duelAgainst, CHAN_AUTO, saberOnSound);

				G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 2);

				duelAgainst->client->ps.duelTime = 0;
			}
		}
		else
		{
			client->ps.speed = 0;
			client->ps.basespeed = 0;
			ucmd->forwardmove = 0;
			ucmd->rightmove = 0;
			ucmd->upmove = 0;
		}

		if (!duelAgainst || !duelAgainst->client || !duelAgainst->inuse ||
			duelAgainst->client->ps.duelIndex != ent->s.number)
		{
			ent->client->ps.duelInProgress = 0;
			G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
		}
		else if (duelAgainst->health < 1 || duelAgainst->client->ps.stats[STAT_HEALTH] < 1)
		{
			ent->client->ps.duelInProgress = 0;
			duelAgainst->client->ps.duelInProgress = 0;

			G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
			G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 0);

			//Winner gets full health.. providing he's still alive
			if (ent->health > 0 && ent->client->ps.stats[STAT_HEALTH] > 0)
			{
				if (ent->health < ent->client->ps.stats[STAT_MAX_HEALTH])
				{
					ent->client->ps.stats[STAT_HEALTH] = ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
				}

				if (g_spawnInvulnerability.integer)
				{
					ent->client->ps.eFlags |= EF_INVULNERABLE;
					ent->client->invulnerableTimer = level.time + g_spawnInvulnerability.integer;
				}
			}

			/*
			trap_SendServerCommand( ent-g_entities, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStripEdString("SVINGAME", "PLDUELWINNER")) );
			trap_SendServerCommand( duelAgainst-g_entities, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStripEdString("SVINGAME", "PLDUELWINNER")) );
			*/
			//Private duel announcements are now made globally because we only want one duel at a time.
			if (ent->health > 0 && ent->client->ps.stats[STAT_HEALTH] > 0)
			{
				trap_SendServerCommand( -1, va("cp \"%s %s %s!\n\"", ent->client->pers.netname, G_GetStripEdString("SVINGAME", "PLDUELWINNER"), duelAgainst->client->pers.netname) );
			}
			else
			{ //it was a draw, because we both managed to die in the same frame
				trap_SendServerCommand( -1, va("cp \"%s\n\"", G_GetStripEdString("SVINGAME", "PLDUELTIE")) );
			}
		}
		else
		{
			vec3_t vSub;
			float subLen = 0;

			VectorSubtract(ent->client->ps.origin, duelAgainst->client->ps.origin, vSub);
			subLen = VectorLength(vSub);

			if (subLen >= 1024)
			{
				ent->client->ps.duelInProgress = 0;
				duelAgainst->client->ps.duelInProgress = 0;

				G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
				G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 0);

				trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "PLDUELSTOP")) );
			}
		}
	}

	/*
	if ( client->ps.powerups[PW_HASTE] ) {
		client->ps.speed *= 1.3;
	}
	*/

	if (client->ps.usingATST && ent->health > 0)
	{ //we have special shot clip boxes as an ATST
		ent->r.contents |= CONTENTS_NOSHOT;
		ATST_ManageDamageBoxes(ent);
	}
	else
	{
		ent->r.contents &= ~CONTENTS_NOSHOT;
		client->damageBoxHandle_Head = 0;
		client->damageBoxHandle_RLeg = 0;
		client->damageBoxHandle_LLeg = 0;
	}

	//rww - moved this stuff into the pmove code so that it's predicted properly
	//BG_AdjustClientSpeed(&client->ps, &client->pers.cmd, level.time);

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

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

	if ( ent->flags & FL_FORCE_GESTURE ) {
		ent->flags &= ~FL_FORCE_GESTURE;
		ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
	}

	if (ent->client && ent->client->ps.fallingToDeath &&
		(level.time - FALL_FADE_TIME) > ent->client->ps.fallingToDeath)
	{ //die!
		player_die(ent, ent, ent, 100000, MOD_FALLING);
		respawn(ent);
		ent->client->ps.fallingToDeath = 0;

		G_MuteSound(ent->s.number, CHAN_VOICE); //stop screaming, because you are dead!
	}

	if (ent->client->ps.otherKillerTime > level.time &&
		ent->client->ps.groundEntityNum != ENTITYNUM_NONE &&
		ent->client->ps.otherKillerDebounceTime < level.time)
	{
		ent->client->ps.otherKillerTime = 0;
		ent->client->ps.otherKiller = ENTITYNUM_NONE;
	}
	else if (ent->client->ps.otherKillerTime > level.time &&
		ent->client->ps.groundEntityNum == ENTITYNUM_NONE)
	{
		if (ent->client->ps.otherKillerDebounceTime < (level.time + 100))
		{
			ent->client->ps.otherKillerDebounceTime = level.time + 100;
		}
	}

//	WP_ForcePowersUpdate( ent, msec, ucmd); //update any active force powers
//	WP_SaberPositionUpdate(ent, ucmd); //check the server-side saber point, do apprioriate server-side actions (effects are cs-only)

	if ((ent->client->pers.cmd.buttons & BUTTON_USE) && ent->client->ps.useDelay < level.time)
	{
		TryUse(ent);
		ent->client->ps.useDelay = level.time + 100;
	}

	pm.ps = &client->ps;
	pm.cmd = *ucmd;
	if ( pm.ps->pm_type == PM_DEAD ) {
		pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
	}
	else if ( ent->r.svFlags & SVF_BOT ) {
		pm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP;
	}
	else {
		pm.tracemask = MASK_PLAYERSOLID;
	}
	pm.trace = trap_Trace;
	pm.pointcontents = trap_PointContents;
	pm.debugLevel = g_debugMove.integer;
	pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0;

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

	pm.animations = bgGlobalAnimations;//NULL;

	pm.gametype = g_gametype.integer;

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

	if (level.intermissionQueued != 0 && g_singlePlayer.integer) {
		if ( level.time - level.intermissionQueued >= 1000  ) {
			pm.cmd.buttons = 0;
			pm.cmd.forwardmove = 0;
			pm.cmd.rightmove = 0;
			pm.cmd.upmove = 0;
			if ( level.time - level.intermissionQueued >= 2000 && level.time - level.intermissionQueued <= 2500 ) {
				trap_SendConsoleCommand( EXEC_APPEND, "centerview\n");
			}
			ent->client->ps.pm_type = PM_SPINTERMISSION;
		}
	}

	for ( i = 0 ; i < MAX_CLIENTS ; i++ )
	{
		if (g_entities[i].inuse && g_entities[i].client)
		{
			pm.bgClients[i] = &g_entities[i].client->ps;
		}
	}

	if (ent->client->ps.saberLockTime > level.time)
	{
		gentity_t *blockOpp = &g_entities[ent->client->ps.saberLockEnemy];

		if (blockOpp && blockOpp->inuse && blockOpp->client)
		{
			vec3_t lockDir, lockAng;

			//VectorClear( ent->client->ps.velocity );
			VectorSubtract( blockOpp->r.currentOrigin, ent->r.currentOrigin, lockDir );
			//lockAng[YAW] = vectoyaw( defDir );
			vectoangles(lockDir, lockAng);
			SetClientViewAngle( ent, lockAng );
		}

		if ( ( ent->client->buttons & BUTTON_ATTACK ) && ! ( ent->client->oldbuttons & BUTTON_ATTACK ) )
		{
			ent->client->ps.saberLockHits++;
		}
		if (ent->client->ps.saberLockHits > 2)
		{
			if (!ent->client->ps.saberLockAdvance)
			{
				ent->client->ps.saberLockHits -= 3;
			}
			ent->client->ps.saberLockAdvance = qtrue;
		}
	}
	else
	{
		ent->client->ps.saberLockFrame = 0;
	}

	Pmove (&pm);

	switch(pm.cmd.generic_cmd)
	{
	case 0:
		break;
	case GENCMD_SABERSWITCH:
		Cmd_ToggleSaber_f(ent);
		break;
	case GENCMD_ENGAGE_DUEL:
		Cmd_EngageDuel_f(ent);
		break;
	case GENCMD_FORCE_HEAL:
		ForceHeal(ent);
		break;
	case GENCMD_FORCE_SPEED:
		ForceSpeed(ent, 0);
		break;
	case GENCMD_FORCE_THROW:
		ForceThrow(ent, qfalse);
		break;
	case GENCMD_FORCE_PULL:
		ForceThrow(ent, qtrue);
		break;
	case GENCMD_FORCE_DISTRACT:
		ForceTelepathy(ent);
		break;
	case GENCMD_FORCE_RAGE:
		ForceRage(ent);
		break;
	case GENCMD_FORCE_PROTECT:
		ForceProtect(ent);
		break;
	case GENCMD_FORCE_ABSORB:
		ForceAbsorb(ent);
		break;
	case GENCMD_FORCE_HEALOTHER:
		ForceTeamHeal(ent);
		break;
	case GENCMD_FORCE_FORCEPOWEROTHER:
		ForceTeamForceReplenish(ent);
		break;
	case GENCMD_FORCE_SEEING:
		ForceSeeing(ent);
		break;
	case GENCMD_USE_SEEKER:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SEEKER)) &&
			G_ItemUsable(&ent->client->ps, HI_SEEKER) )
		{
			ItemUse_Seeker(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_SEEKER, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SEEKER);
		}
		break;
	case GENCMD_USE_FIELD:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SHIELD)) &&
			G_ItemUsable(&ent->client->ps, HI_SHIELD) )
		{
			ItemUse_Shield(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_SHIELD, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SHIELD);
		}
		break;
	case GENCMD_USE_BACTA:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_MEDPAC)) &&
			G_ItemUsable(&ent->client->ps, HI_MEDPAC) )
		{
			ItemUse_MedPack(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_MEDPAC, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_MEDPAC);
		}
		break;
	case GENCMD_USE_ELECTROBINOCULARS:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_BINOCULARS)) &&
			G_ItemUsable(&ent->client->ps, HI_BINOCULARS) )
		{
			ItemUse_Binoculars(ent);
			if (ent->client->ps.zoomMode == 0)
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 1);
			}
			else
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 2);
			}
		}
		break;
	case GENCMD_ZOOM:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_BINOCULARS)) &&
			G_ItemUsable(&ent->client->ps, HI_BINOCULARS) )
		{
			ItemUse_Binoculars(ent);
			if (ent->client->ps.zoomMode == 0)
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 1);
			}
			else
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 2);
			}
		}
		break;
	case GENCMD_USE_SENTRY:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SENTRY_GUN)) &&
			G_ItemUsable(&ent->client->ps, HI_SENTRY_GUN) )
		{
			ItemUse_Sentry(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_SENTRY_GUN, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SENTRY_GUN);
		}
		break;
	case GENCMD_SABERATTACKCYCLE:
		Cmd_SaberAttackCycle_f(ent);
		break;
	default:
		break;
	}

	// save results of pmove
	if ( ent->client->ps.eventSequence != oldEventSequence ) {
		ent->eventTime = level.time;
	}
	if (g_smoothClients.integer) {
		BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
	}
	else {
		BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
	}
	SendPendingPredictableEvents( &ent->client->ps );

	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 );

	if ( pm.useEvent )
	{
		//TODO: Use
//		TryUse( ent );
	}

	// 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 );

	//test for solid areas in the AAS file
//	BotTestAAS(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;

	// Did we kick someone in our pmove sequence?
	if (client->ps.forceKickFlip)
	{
		gentity_t *faceKicked = &g_entities[client->ps.forceKickFlip-1];

		if (faceKicked && faceKicked->client && (!OnSameTeam(ent, faceKicked) || g_friendlyFire.integer) &&
			(!faceKicked->client->ps.duelInProgress || faceKicked->client->ps.duelIndex == ent->s.number) &&
			(!ent->client->ps.duelInProgress || ent->client->ps.duelIndex == faceKicked->s.number))
		{
			if ( faceKicked && faceKicked->client && faceKicked->health && faceKicked->takedamage )
			{//push them away and do pain
				vec3_t oppDir;
				int strength = (int)VectorNormalize2( client->ps.velocity, oppDir );

				strength *= 0.05;

				VectorScale( oppDir, -1, oppDir );

				G_Damage( faceKicked, ent, ent, oppDir, client->ps.origin, strength, DAMAGE_NO_ARMOR, MOD_MELEE );

				if (faceKicked->health > 0 &&
					faceKicked->client->ps.stats[STAT_HEALTH] > 0 &&
					faceKicked->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
				{
					if (Q_irand(1, 10) <= 3)
					{ //only actually knock over sometimes, but always do velocity hit
						faceKicked->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
						faceKicked->client->ps.forceHandExtendTime = level.time + 1100;
						faceKicked->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
					}

					faceKicked->client->ps.otherKiller = ent->s.number;
					faceKicked->client->ps.otherKillerTime = level.time + 5000;
					faceKicked->client->ps.otherKillerDebounceTime = level.time + 100;

					faceKicked->client->ps.velocity[0] = oppDir[0]*(strength*40);
					faceKicked->client->ps.velocity[1] = oppDir[1]*(strength*40);
					faceKicked->client->ps.velocity[2] = 200;
				}

				G_Sound( faceKicked, CHAN_AUTO, G_SoundIndex( va("sound/weapons/melee/punch%d", Q_irand(1, 4)) ) );
			}
		}

		client->ps.forceKickFlip = 0;
	}

	// check for respawning
	if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
		// wait for the attack button to be pressed
		if ( level.time > client->respawnTime ) {
			// forcerespawn is to prevent users from waiting out powerups
			if ( g_forcerespawn.integer > 0 && 
				( level.time - client->respawnTime ) > g_forcerespawn.integer * 1000 ) {
				respawn( ent );
				return;
			}
		
			// pressing attack or use is the normal respawn method
			if ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) {
				respawn( ent );
			}
		}
		return;
	}

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

	G_UpdateClientBroadcasts ( ent );
}
Esempio n. 4
0
/**
 * @brief SP_team_WOLF_checkpoint
 * @details QUAKED team_WOLF_checkpoint (.9 .3 .9) (-16 -16 0) (16 16 128) SPAWNPOINT CP_HOLD AXIS_ONLY ALLIED_ONLY
 * This is the flagpole players touch in Capture and Hold game scenarios.
 *
 * It will call specific trigger funtions in the map script for this object.
 * When allies capture, it will call "allied_capture".
 * When axis capture, it will call "axis_capture".
 *
 * if spawnpoint flag is set, think will turn on spawnpoints (specified as targets)
 * for capture team and turn *off* targeted spawnpoints for opposing team
 *
 * @param[in,out] ent
 */
void SP_team_WOLF_checkpoint(gentity_t *ent)
{
	char *capture_sound;

	if (!ent->scriptName)
	{
		G_Error("team_WOLF_checkpoint must have a \"scriptname\"\n");
	}

	// Make sure the ET_TRAP entity type stays valid
	ent->s.eType = ET_TRAP;

	// Model is user assignable, but it will always try and use the animations for flagpole.md3
	if (ent->model)
	{
		ent->s.modelindex = G_ModelIndex(ent->model);
	}
	else
	{
		ent->s.modelindex = G_ModelIndex("models/multiplayer/flagpole/flagpole.md3");
	}

	G_SpawnString("noise", "sound/movers/doors/door6_open.wav", &capture_sound);
	ent->soundPos1 = G_SoundIndex(capture_sound);

	ent->clipmask   = CONTENTS_SOLID;
	ent->r.contents = CONTENTS_SOLID;

	VectorSet(ent->r.mins, -8, -8, 0);
	VectorSet(ent->r.maxs, 8, 8, 128);

	G_SetOrigin(ent, ent->s.origin);
	G_SetAngle(ent, ent->s.angles);

	// s.frame is the animation number
	ent->s.frame = WCP_ANIM_NOFLAG;

	// s.teamNum is which set of animations to use ( only 1 right now )
	ent->s.teamNum = 1;

	// Used later to set animations (and delay between captures)
	ent->nextthink = 0;

	// Used to time how long it must be "held" to switch
	ent->health = -1;
	ent->count2 = -1;

	// 'count' signifies which team holds the checkpoint
	ent->count = -1;

	if (ent->spawnflags & SPAWNPOINT)
	{
		ent->touch = checkpoint_spawntouch;
	}
	else
	{
		if (ent->spawnflags & CP_HOLD)
		{
			ent->use = checkpoint_use;
		}
		else
		{
			ent->touch = checkpoint_touch;
		}
	}

	trap_LinkEntity(ent);
}
Esempio n. 5
0
/*
===============
RespawnItem
===============
*/
void RespawnItem( gentity_t *ent ) {
	// randomly select from teamed entities
	if (ent->team) {
		gentity_t	*master;
		int	count;
		int choice;

		if ( !ent->teammaster ) {
			G_Error( "RespawnItem: bad teammaster");
		}
		master = ent->teammaster;

		for (count = 0, ent = master; ent; ent = ent->teamchain, count++)
			;

		choice = rand() % count;

		for (count = 0, ent = master; count < choice; ent = ent->teamchain, count++)
			;
	}

	ent->r.contents = CONTENTS_TRIGGER;
	ent->s.eFlags &= ~EF_NODRAW;
	ent->r.svFlags &= ~SVF_NOCLIENT;
	trap_LinkEntity (ent);

	if ( ent->item->giType == IT_POWERUP ) {
		// play powerup spawn sound to all clients
		gentity_t	*te;

		// if the powerup respawn sound should Not be global
		if (ent->speed) {
			te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
		}
		else {
			te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
		}
		te->s.eventParm = G_SoundIndex( "sound/items/poweruprespawn.wav" );
		te->r.svFlags |= SVF_BROADCAST;
	}

	if ( ent->item->giType == IT_HOLDABLE && ent->item->giTag == HI_KAMIKAZE ) {
		// play powerup spawn sound to all clients
		gentity_t	*te;

		// if the powerup respawn sound should Not be global
		if (ent->speed) {
			te = G_TempEntity( ent->s.pos.trBase, EV_GENERAL_SOUND );
		}
		else {
			te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_SOUND );
		}
		te->s.eventParm = G_SoundIndex( "sound/items/kamikazerespawn.wav" );
		te->r.svFlags |= SVF_BROADCAST;
	}

	// play the normal respawn sound only to nearby clients
	G_AddEvent( ent, EV_ITEM_RESPAWN, 0 );

	ent->nextthink = 0;
}
Esempio n. 6
0
void eweb_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
	if ( !eweb_can_be_used( self, other, activator ) )
	{
		return;
	}

	int	oldWeapon = activator->s.weapon;

	if ( oldWeapon == WP_SABER )
	{
		self->alt_fire = activator->client->ps.SaberActive();
	}

	// swap the users weapon with the emplaced gun and add the ammo the gun has to the player
	activator->client->ps.weapon = self->s.weapon;
	Add_Ammo( activator, WP_EMPLACED_GUN, self->count );
	activator->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_EMPLACED_GUN );

	// Allow us to point from one to the other
	activator->owner = self; // kind of dumb, but when we are locked to the weapon, we are owned by it.
	self->activator = activator;

	G_RemoveWeaponModels( activator );

extern void ChangeWeapon( gentity_t *ent, int newWeapon );
	if ( activator->NPC )
	{
		ChangeWeapon( activator, WP_EMPLACED_GUN );
	}
	else if ( activator->s.number == 0 )
	{
		// we don't want for it to draw the weapon select stuff
		cg.weaponSelect = WP_EMPLACED_GUN;
		CG_CenterPrint( "@SP_INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.95 );
	}

	VectorCopy( activator->currentOrigin, self->pos4 );//keep this around so we know when to make them play the strafe anim

	// the gun will track which weapon we used to have
	self->s.weapon = oldWeapon;

	// Lock the player
	activator->client->ps.eFlags |= EF_LOCKED_TO_WEAPON;
	activator->owner = self; // kind of dumb, but when we are locked to the weapon, we are owned by it.
	self->activator = activator;
	self->delay = level.time; // can't disconnect from the thing for half a second

	// Let the gun be considered an enemy
	//Ugh, so much AI code seems to assume enemies are clients, maybe this shouldn't be on, but it's too late in the game to change it now without knowing what side-effects this will have
	self->svFlags |= SVF_NONNPC_ENEMY;
	self->noDamageTeam = activator->client->playerTeam;

	//FIXME: should really wait a bit after spawn and get this just once?
	self->waypoint = NAV::GetNearestNode(self);
#ifdef _DEBUG
	if ( self->waypoint == -1 )
	{
		gi.Printf( S_COLOR_RED"ERROR: no waypoint for emplaced_gun %s at %s\n", self->targetname, vtos(self->currentOrigin) );
	}
#endif

	G_Sound( self, G_SoundIndex( "sound/weapons/eweb/eweb_mount.mp3" ));
#ifdef _IMMERSION
	G_Force( self, G_ForceIndex( "fffx/weapons/emplaced/emplaced_mount", FF_CHANNEL_TOUCH ) );
#endif // _IMMERSION

	if ( !(self->spawnflags&EMPLACED_PLAYERUSE) || activator->s.number == 0 )
	{//player-only usescript or any usescript
		// Run use script
		G_ActivateBehavior( self, BSET_USE );
	}
}
Esempio n. 7
0
/*
==============
G_Script_ScriptParse

  Parses the script for the given entity
==============
*/
void G_Script_ScriptParse( gentity_t *ent )
{
	char		*pScript;
	char		*token;
	qboolean	wantName;
	qboolean	inScript;
	int			eventNum;
	g_script_event_t	events[G_MAX_SCRIPT_STACK_ITEMS];
	int			numEventItems;
	g_script_event_t *curEvent;
	// DHM - Nerve :: Some of our multiplayer script commands have longer parameters
	//char		params[MAX_QPATH];
	char		params[MAX_INFO_STRING];
	// dhm - end
	g_script_stack_action_t	*action;
	int			i;
	int			bracketLevel;
	qboolean	buildScript;

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

	buildScript = (qboolean)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) );

	while (1)
	{
		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 = (char*)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
				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 ) ) && ( 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"))
								) {
								if(strlen(token))	// we know there's a [0], but don't know if it's '0'
									trap_SendServerCommand(-1, va("addToBuild %s\n", token) );
							}
						}

						if(i == 0 || i == 1) {
							if (!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 = (char*)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] == '}') {
					if (!--bracketLevel)
						break;
				}
			}
		}
	}

	// alloc and copy the events into the gentity_t for this cast
	if (numEventItems > 0)
	{
		ent->scriptEvents = (g_script_event_t*)G_Alloc( sizeof(g_script_event_t) * numEventItems );
		memcpy( ent->scriptEvents, events, sizeof(g_script_event_t) * numEventItems );
		ent->numScriptEvents = numEventItems;
	}
}
Esempio n. 8
0
/*
-------------------------
Remote_MaintainHeight
-------------------------
*/
void Remote_MaintainHeight( void )
{	
	float	dif;

	// Update our angles regardless
	NPC_UpdateAngles( qtrue, qtrue );

	if ( NPC->client->ps.velocity[2] )
	{
		NPC->client->ps.velocity[2] *= VELOCITY_DECAY;

		if ( fabs( NPC->client->ps.velocity[2] ) < 2 )
		{
			NPC->client->ps.velocity[2] = 0;
		}
	}
	// If we have an enemy, we should try to hover at or a little below enemy eye level
	if ( NPC->enemy )
	{
		if (TIMER_Done( NPC, "heightChange"))
		{
			TIMER_Set( NPC,"heightChange",Q_irand( 1000, 3000 ));

			// Find the height difference
			dif = (NPC->enemy->r.currentOrigin[2] +  Q_irand( 0, NPC->enemy->r.maxs[2]+8 )) - NPC->r.currentOrigin[2]; 

			// cap to prevent dramatic height shifts
			if ( fabs( dif ) > 2 )
			{
				if ( fabs( dif ) > 24 )
				{
					dif = ( dif < 0 ? -24 : 24 );
				}
				dif *= 10;
				NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
				G_Sound( NPC, CHAN_AUTO, G_SoundIndex("sound/chars/remote/misc/hiss.wav"));
			}
		}
	}
	else
	{
		gentity_t *goal = NULL;

		if ( NPCInfo->goalEntity )	// Is there a goal?
		{
			goal = NPCInfo->goalEntity;
		}
		else
		{
			goal = NPCInfo->lastGoalEntity;
		}
		if ( goal )
		{
			dif = goal->r.currentOrigin[2] - NPC->r.currentOrigin[2];

			if ( fabs( dif ) > 24 )
			{
				dif = ( dif < 0 ? -24 : 24 );
				NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
			}
		}
	}

	// Apply friction
	if ( NPC->client->ps.velocity[0] )
	{
		NPC->client->ps.velocity[0] *= VELOCITY_DECAY;

		if ( fabs( NPC->client->ps.velocity[0] ) < 1 )
		{
			NPC->client->ps.velocity[0] = 0;
		}
	}

	if ( NPC->client->ps.velocity[1] )
	{
		NPC->client->ps.velocity[1] *= VELOCITY_DECAY;

		if ( fabs( NPC->client->ps.velocity[1] ) < 1 )
		{
			NPC->client->ps.velocity[1] = 0;
		}
	}
}
Esempio n. 9
0
/*
-------------------------
NPC_Protocol_Precache
-------------------------
*/
void NPC_Protocol_Precache( void )
{
	G_SoundIndex( "sound/chars/mark2/misc/mark2_explo" );
	G_EffectIndex( "env/med_explode");
}
Esempio n. 10
0
void charge_stick (gentity_t *self, gentity_t *other, trace_t *trace)
{
	gentity_t	*tent;

	if ( other 
		&& (other->flags&FL_BBRUSH)
		&& other->s.pos.trType == TR_STATIONARY
		&& other->s.apos.trType == TR_STATIONARY )
	{//a perfectly still breakable brush, let us attach directly to it!
		self->target_ent = other;//remember them when we blow up
	}
	else if ( other 
		&& other->s.number < ENTITYNUM_WORLD
		&& other->s.eType == ET_MOVER
		&& trace->plane.normal[2] > 0 )
	{//stick to it?
		self->s.groundEntityNum = other->s.number;
	}
	else if (other && other->s.number < ENTITYNUM_WORLD &&
		(other->client || !other->s.weapon))
	{ //hit another entity that is not stickable, "bounce" off
		//self->target_ent = other;

		vec3_t vNor, tN;

		VectorCopy(trace->plane.normal, vNor);
		VectorNormalize(vNor);
		VectorNPos(self->s.pos.trDelta, tN);
		self->s.pos.trDelta[0] += vNor[0]*(tN[0]*(((float)Q_irand(1, 10))*0.1));
		self->s.pos.trDelta[1] += vNor[1]*(tN[1]*(((float)Q_irand(1, 10))*0.1));
		self->s.pos.trDelta[2] += vNor[1]*(tN[2]*(((float)Q_irand(1, 10))*0.1));

		vectoangles(vNor, self->s.angles);
		vectoangles(vNor, self->s.apos.trBase);
		self->touch = charge_stick;

		return;

	}
	else if (other && other->s.number < ENTITYNUM_WORLD)
	{ //hit an entity that we just want to explode on (probably another projectile or something)
		vec3_t v;

		self->touch = 0;
		self->think = 0;
		self->nextthink = 0;

		self->takedamage = qfalse;

		VectorClear(self->s.apos.trDelta);
		self->s.apos.trType = TR_STATIONARY;

		G_RadiusDamage( self->r.currentOrigin, self->parent, self->splashDamage, self->splashRadius, self, self, MOD_DET_PACK_SPLASH );
		VectorCopy(trace->plane.normal, v);
		VectorCopy(v, self->pos2);
		self->count = -1;
		G_PlayEffect(EFFECT_EXPLOSION_DETPACK, self->r.currentOrigin, v);

		self->think = G_FreeEntity;
		self->nextthink = level.time;
		return;
	}

	//JAC Bugfix
	//if we get here I guess we hit hte world so we can stick to it
	//Raz: This fix requires a bit of explaining..
	//	When you suicide, all of the detpacks you have placed (either on a wall, or still falling in the air) will
	//		have their ent->think() set to DetPackBlow and ent->nextthink will be between 100 <-> 300
	//	If your detpacks land on a surface (i.e. charge_stick gets called) within that 100<->300 ms then ent->think()
	//		will be overwritten (set to DetpackBlow) and ent->nextthink will be 30000
	//	The end result is your detpacks won't explode, but will be stuck to the wall for 30 seconds without
	//		being able to detonate them (or shoot them)
	//	The fix Sil came up with is to check the think() function in charge_stick, and only overwrite it
	//		if they haven't been primed to detonate
	if ( self->think == G_RunObject )
	{
		self->touch = 0;
		self->think = DetPackBlow;
		//[OpenRP - Detpacks last forever]
		self->nextthink = level.time + Q3_INFINITE; //make them last forever
		//[/OpenRP - Detpacks last forever]
	}

	VectorClear(self->s.apos.trDelta);
	self->s.apos.trType = TR_STATIONARY;

	self->s.pos.trType = TR_STATIONARY;
	VectorCopy( self->r.currentOrigin, self->s.origin );
	VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
	VectorClear( self->s.pos.trDelta );

	VectorClear( self->s.apos.trDelta );

	VectorNormalize(trace->plane.normal);

	vectoangles(trace->plane.normal, self->s.angles);
	VectorCopy(self->s.angles, self->r.currentAngles );
	VectorCopy(self->s.angles, self->s.apos.trBase);

	VectorCopy(trace->plane.normal, self->pos2);
	self->count = -1;

	G_Sound(self, CHAN_WEAPON, G_SoundIndex("sound/weapons/detpack/stick.wav"));

	tent = G_TempEntity( self->r.currentOrigin, EV_MISSILE_MISS );
	tent->s.weapon = 0;
	tent->parent = self;
	tent->r.ownerNum = self->s.number;

	//so that the owner can blow it up with projectiles
	self->r.svFlags |= SVF_OWNERNOTSHARED;
}
Esempio n. 11
0
void NPC_Remote_Precache(void)
{
	G_SoundIndex("sound/chars/remote/misc/fire.wav");
	G_SoundIndex( "sound/chars/remote/misc/hiss.wav");
	G_EffectIndex( "env/small_explode");
}
Esempio n. 12
0
//----------------------------------------------------------
void SP_emplaced_gun( gentity_t *ent )
{
	char name[] = "models/map_objects/imp_mine/turret_chair.glm";

	ent->svFlags |= SVF_PLAYER_USABLE;
	ent->contents = CONTENTS_BODY;//CONTENTS_SHOTCLIP|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP;//CONTENTS_SOLID;

	if ( ent->spawnflags & EMPLACED_INACTIVE )
	{
		ent->svFlags |= SVF_INACTIVE;
	}

	VectorSet( ent->mins, -30, -30, -5 );
	VectorSet( ent->maxs, 30, 30, 60 );

	ent->takedamage = qtrue;

	if ( !( ent->spawnflags & EMPLACED_VULNERABLE ))
	{
		ent->flags |= FL_GODMODE;
	}

	ent->s.radius = 110;
	ent->spawnflags |= 4; // deadsolid

	//ent->e_ThinkFunc = thinkF_NULL;
	ent->e_PainFunc = painF_emplaced_gun_pain;
	ent->e_DieFunc  = dieF_emplaced_gun_die;

	G_EffectIndex( "emplaced/explode" );
	G_EffectIndex( "emplaced/dead_smoke" );

	G_SoundIndex( "sound/weapons/emplaced/emplaced_mount.mp3" );
	G_SoundIndex( "sound/weapons/emplaced/emplaced_dismount.mp3" );
	G_SoundIndex( "sound/weapons/emplaced/emplaced_move_lp.wav" );

	// Set up our defaults and override with custom amounts as necessary
	G_SpawnInt( "count", "999", &ent->count );
	G_SpawnInt( "health", "250", &ent->health );
	G_SpawnInt( "splashDamage", "80", &ent->splashDamage );
	G_SpawnInt( "splashRadius", "128", &ent->splashRadius );
	G_SpawnFloat( "delay", "200", &ent->random ); // NOTE: spawning into a different field!!
	G_SpawnFloat( "wait", "800", &ent->wait );

	ent->max_health = ent->health;
	ent->dflags |= DAMAGE_CUSTOM_HUD; // dumb, but we draw a custom hud

	ent->s.modelindex = G_ModelIndex( name );
	ent->playerModel = gi.G2API_InitGhoul2Model( ent->ghoul2, name, ent->s.modelindex );

	// Activate our tags and bones
	ent->headBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*seat" );
	ent->handLBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*flash01" );
	ent->handRBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*flash02" );
	ent->rootBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "base_bone", qtrue );
	ent->lowerLumbarBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "swivel_bone", qtrue );
	gi.G2API_SetBoneAnglesIndex( &ent->ghoul2[ent->playerModel], ent->lowerLumbarBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL); 

	RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN ));
	ent->s.weapon = WP_EMPLACED_GUN;

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );
	VectorCopy( ent->s.angles, ent->lastAngles );

	// store base angles for later
	VectorCopy( ent->s.angles, ent->pos1 );

	ent->e_UseFunc = useF_emplaced_gun_use;
	ent->bounceCount = 0;//to distinguish it from the eweb

	gi.linkentity (ent);
}
Esempio n. 13
0
//----------------------------------------------------------
void emplaced_gun_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
	vec3_t fwd1, fwd2;

	if ( self->health <= 0 )
	{
		// can't use a dead gun.
		return;
	}

	if ( self->svFlags & SVF_INACTIVE )
	{
		return; // can't use inactive gun
	}

	if ( !activator->client )
	{
		return; // only a client can use it.
	}

	if ( self->activator )
	{
		// someone is already in the gun.
		return;
	}

	if ( other && other->client && G_IsRidingVehicle( other ) )
	{//can't use eweb when on a vehicle
		return;
	}

	if ( activator && activator->client && G_IsRidingVehicle( activator ) )
	{//can't use eweb when on a vehicle
		return;
	}

	// We'll just let the designers duke this one out....I mean, as to whether they even want to limit such a thing.
	if ( self->spawnflags & EMPLACED_FACING )
	{
		// Let's get some direction vectors for the users
		AngleVectors( activator->client->ps.viewangles, fwd1, NULL, NULL );

		// Get the guns direction vector
		AngleVectors( self->pos1, fwd2, NULL, NULL );

		float dot = DotProduct( fwd1, fwd2 );

		// Must be reasonably facing the way the gun points ( 90 degrees or so ), otherwise we don't allow to use it.
		if ( dot < 0.0f )
		{
			return;
		}
	}

	// don't allow using it again for half a second
	if ( self->delay + 500 < level.time )
	{
		int	oldWeapon = activator->s.weapon;

		if ( oldWeapon == WP_SABER )
		{
			self->alt_fire = activator->client->ps.SaberActive();
		}

		// swap the users weapon with the emplaced gun and add the ammo the gun has to the player
		activator->client->ps.weapon = self->s.weapon;
		Add_Ammo( activator, WP_EMPLACED_GUN, self->count );
		activator->client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_EMPLACED_GUN );

		// Allow us to point from one to the other
		activator->owner = self; // kind of dumb, but when we are locked to the weapon, we are owned by it.
		self->activator = activator;

		G_RemoveWeaponModels( activator );

extern void ChangeWeapon( gentity_t *ent, int newWeapon );
		if ( activator->NPC )
		{
			ChangeWeapon( activator, WP_EMPLACED_GUN );
		}
		else if ( activator->s.number == 0 )
		{
			// we don't want for it to draw the weapon select stuff
			cg.weaponSelect = WP_EMPLACED_GUN;
			CG_CenterPrint( "@SP_INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.95 );
		}
		// Since we move the activator inside of the gun, we reserve a solid spot where they were standing in order to be able to get back out without being in solid
		if ( self->nextTrain )
		{//you never know
			G_FreeEntity( self->nextTrain );
		}
		self->nextTrain = G_Spawn();
		//self->nextTrain->classname = "emp_placeholder";
		self->nextTrain->contents = CONTENTS_MONSTERCLIP|CONTENTS_PLAYERCLIP;//hmm... playerclip too now that we're doing it for NPCs?
		G_SetOrigin( self->nextTrain, activator->client->ps.origin );
		VectorCopy( activator->mins, self->nextTrain->mins );
		VectorCopy( activator->maxs, self->nextTrain->maxs );
		gi.linkentity( self->nextTrain );

		//need to inflate the activator's mins/maxs since the gunsit anim puts them outside of their bbox
		VectorSet( activator->mins, -24, -24, -24 );
		VectorSet( activator->maxs, 24, 24, 40 );

		// Move the activator into the center of the gun.  For NPC's the only way the can get out of the gun is to die.
		VectorCopy( self->s.origin, activator->client->ps.origin );
		activator->client->ps.origin[2] += 30; // move them up so they aren't standing in the floor
		gi.linkentity( activator );

		// the gun will track which weapon we used to have
		self->s.weapon = oldWeapon;

		// Lock the player
		activator->client->ps.eFlags |= EF_LOCKED_TO_WEAPON;
		activator->owner = self; // kind of dumb, but when we are locked to the weapon, we are owned by it.
		self->activator = activator;
		self->delay = level.time; // can't disconnect from the thing for half a second

		// Let the gun be considered an enemy
		//Ugh, so much AI code seems to assume enemies are clients, maybe this shouldn't be on, but it's too late in the game to change it now without knowing what side-effects this will have
		self->svFlags |= SVF_NONNPC_ENEMY;
		self->noDamageTeam = activator->client->playerTeam;

		// FIXME: don't do this, we'll try and actually put the player in this beast
		// move the player to the center of the gun
//		activator->contents = 0;
//		VectorCopy( self->currentOrigin, activator->client->ps.origin );

		SetClientViewAngle( activator, self->pos1 );

		//FIXME: should really wait a bit after spawn and get this just once?
		self->waypoint = NAV::GetNearestNode(self);
#ifdef _DEBUG
		if ( self->waypoint == -1 )
		{
			gi.Printf( S_COLOR_RED"ERROR: no waypoint for emplaced_gun %s at %s\n", self->targetname, vtos(self->currentOrigin) );
		}
#endif

		G_Sound( self, G_SoundIndex( "sound/weapons/emplaced/emplaced_mount.mp3" ));
#ifdef _IMMERSION
		G_Force( self, G_ForceIndex( "fffx/weapons/emplaced/emplaced_mount", FF_CHANNEL_TOUCH ) );
#endif // _IMMERSION

		if ( !(self->spawnflags&EMPLACED_PLAYERUSE) || activator->s.number == 0 )
		{//player-only usescript or any usescript
			// Run use script
			G_ActivateBehavior( self, BSET_USE );
		}
	}
}
Esempio n. 14
0
//----------------------------------------------------------
void SP_emplaced_eweb( gentity_t *ent )
{
	char name[] = "models/map_objects/hoth/eweb_model.glm";

	ent->svFlags |= SVF_PLAYER_USABLE;
	ent->contents = CONTENTS_BODY;

	if ( ent->spawnflags & EMPLACED_INACTIVE )
	{
		ent->svFlags |= SVF_INACTIVE;
	}

	VectorSet( ent->mins, -12, -12, -24 );
	VectorSet( ent->maxs, 12, 12, 24 );

	ent->takedamage = qtrue;

	if ( ( ent->spawnflags & EWEB_INVULNERABLE ))
	{
		ent->flags |= FL_GODMODE;
	}

	ent->s.radius = 80;
	ent->spawnflags |= 4; // deadsolid

	//ent->e_ThinkFunc = thinkF_NULL;
	ent->e_PainFunc = painF_eweb_pain;
	ent->e_DieFunc  = dieF_eweb_die;

	G_EffectIndex( "emplaced/explode" );
	G_EffectIndex( "emplaced/dead_smoke" );

	G_SoundIndex( "sound/weapons/eweb/eweb_aim.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_dismount.mp3" );
	//G_SoundIndex( "sound/weapons/eweb/eweb_empty.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_fire.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_hitplayer.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_hitsurface.wav" );
	//G_SoundIndex( "sound/weapons/eweb/eweb_load.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_mount.mp3" );

	// Set up our defaults and override with custom amounts as necessary
	G_SpawnInt( "count", "999", &ent->count );
	G_SpawnInt( "health", "250", &ent->health );
	G_SpawnInt( "splashDamage", "40", &ent->splashDamage );
	G_SpawnInt( "splashRadius", "100", &ent->splashRadius );
	G_SpawnFloat( "delay", "200", &ent->random ); // NOTE: spawning into a different field!!
	G_SpawnFloat( "wait", "800", &ent->wait );

	ent->max_health = ent->health;
	ent->dflags |= DAMAGE_CUSTOM_HUD; // dumb, but we draw a custom hud

	ent->s.modelindex = G_ModelIndex( name );
	ent->playerModel = gi.G2API_InitGhoul2Model( ent->ghoul2, name, ent->s.modelindex );

	// Activate our tags and bones
	ent->handLBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*cannonflash" ); //muzzle bolt
	ent->headBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "cannon_Xrot" ); //for placing the owner relative to rotation
	ent->rootBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "model_root", qtrue );
	ent->lowerLumbarBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "cannon_Yrot", qtrue );
	ent->upperLumbarBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "cannon_Xrot", qtrue );
	gi.G2API_SetBoneAnglesIndex( &ent->ghoul2[ent->playerModel], ent->lowerLumbarBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_X, NEGATIVE_Y, NULL); 
	gi.G2API_SetBoneAnglesIndex( &ent->ghoul2[ent->playerModel], ent->upperLumbarBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_X, NEGATIVE_Y, NULL); 
	//gi.G2API_SetBoneAngles( &ent->ghoul2[0], "cannon_Yrot", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL); 
	//set the constraints for this guy as an emplaced weapon, and his constraint angles
	//ent->s.origin2[0] = 60.0f; //60 degrees in either direction

	RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN ));
	ent->s.weapon = WP_EMPLACED_GUN;

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );
	VectorCopy( ent->s.angles, ent->lastAngles );

	// store base angles for later
	VectorClear( ent->pos1 );

	ent->e_UseFunc = useF_eweb_use;
	ent->bounceCount = 1;//to distinguish it from the emplaced gun

	gi.linkentity (ent);
}
Esempio n. 15
0
//------------------------------------
void NPC_Seeker_Precache(void)
{
    G_SoundIndex("sound/chars/seeker/misc/fire.wav");
    G_SoundIndex( "sound/chars/seeker/misc/hiss.wav");
    G_EffectIndex( "env/small_explode");
}
Esempio n. 16
0
/*
============
G_InitGame

============
*/
void G_InitGame( int levelTime, int randomSeed, int restart ) {
	int					i;

	G_Printf ("------- Game Initialization -------\n");
	G_Printf ("gamename: %s\n", GAMEVERSION);
	G_Printf ("gamedate: %s\n", __DATE__);

	srand( randomSeed );

	G_RegisterCvars();

	G_ProcessIPBans();

	G_InitMemory();

	// set some level globals
	memset( &level, 0, sizeof( level ) );
	level.time = levelTime;
	level.startTime = levelTime;

	level.snd_fry = G_SoundIndex("sound/player/fry.wav");	// FIXME standing in lava / slime

	if ( g_gametype.integer != GT_SINGLE_PLAYER && g_logfile.string[0] ) {
		if ( g_logfileSync.integer ) {
			trap_FS_FOpenFile( g_logfile.string, &level.logFile, FS_APPEND_SYNC );
		} else {
			trap_FS_FOpenFile( g_logfile.string, &level.logFile, FS_APPEND );
		}
		if ( !level.logFile ) {
			G_Printf( "WARNING: Couldn't open logfile: %s\n", g_logfile.string );
		} else {
			char	serverinfo[MAX_INFO_STRING];

			trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );

			G_LogPrintf("------------------------------------------------------------\n" );
			G_LogPrintf("InitGame: %s\n", serverinfo );
		}
	} else {
		G_Printf( "Not logging to disk.\n" );
	}

	G_InitWorldSession();

	// initialize all entities for this game
	memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) );
	level.gentities = g_entities;

	// initialize all clients for this game
	level.maxclients = g_maxclients.integer;
	memset( g_clients, 0, MAX_CLIENTS * sizeof(g_clients[0]) );
	level.clients = g_clients;

	// set client fields on player ents
	for ( i=0 ; i<level.maxclients ; i++ ) {
		g_entities[i].client = level.clients + i;
	}

	// always leave room for the max number of clients,
	// even if they aren't all used, so numbers inside that
	// range are NEVER anything but clients
	level.num_entities = MAX_CLIENTS;

	for ( i=0 ; i<MAX_CLIENTS ; i++ ) {
		g_entities[i].classname = "clientslot";
	}

	// let the server system know where the entites are
	trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ), 
		&level.clients[0].ps, sizeof( level.clients[0] ) );

	// reserve some spots for dead player bodies
	InitBodyQue();

	ClearRegisteredItems();

	// parse the key/value pairs and spawn gentities
	G_SpawnEntitiesFromString();

	// general initialization
	G_FindTeams();

	// make sure we have flags for CTF, etc
	if( g_gametype.integer >= GT_TEAM ) {
		G_CheckTeamItems();
	}

	SaveRegisteredItems();

	G_Printf ("-----------------------------------\n");

	if( g_gametype.integer == GT_SINGLE_PLAYER || trap_Cvar_VariableIntegerValue( "com_buildScript" ) ) {
		G_ModelIndex( SP_PODIUM_MODEL );
	}

	if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
		BotAISetup( restart );
		BotAILoadMap( restart );
		G_InitBots( restart );
	}

	G_RemapTeamShaders();

	trap_SetConfigstring( CS_INTERMISSION, "" );
}
Esempio n. 17
0
//[CoOp]
//------------------------------------
void Seeker_FollowPlayer( void )
{   //hover around the closest player

    //[SeekerItemNpc]
#if 1
    vec3_t	pt, dir;
    float	dis;
    float	minDistSqr = MIN_DISTANCE_SQR;
    gentity_t *target;

    Seeker_MaintainHeight();

    if(NPC->activator && NPC->activator->client)
    {
        if(NPC->activator->client->remote != NPC || NPC->activator->health <= 0) {
            //have us fall down and explode.
            NPC->NPC->aiFlags |= NPCAI_CUSTOM_GRAVITY;
            return;
        }
        target = NPCInfo->goalEntity;
        if(!target)
            target = NPC->client->leader;
    }
    else {
        target = FindClosestPlayer(NPC->r.currentOrigin, NPC->client->playerTeam);
    }

    if(!target)
    {   //in MP it's actually possible that there's no players on our team at the moment.
        return;
    }

    dis	= DistanceHorizontalSquared( NPC->r.currentOrigin, target->r.currentOrigin );

    if ( NPC->client->NPC_class == CLASS_BOBAFETT )
    {
        if ( TIMER_Done( NPC, "flameTime" ) )
        {
            minDistSqr = 200*200;
        }
    }

    if ( dis < minDistSqr )
    {
        // generally circle the player closely till we take an enemy..this is our target point
        if ( NPC->client->NPC_class == CLASS_BOBAFETT )
        {
            pt[0] = target->r.currentOrigin[0] + cos( level.time * 0.001f + NPC->random ) * 250;
            pt[1] = target->r.currentOrigin[1] + sin( level.time * 0.001f + NPC->random ) * 250;
            if ( NPC->client->jetPackTime < level.time )
            {
                pt[2] = target->r.currentOrigin[2] - 64;
            }
            else
            {
                pt[2] = target->r.currentOrigin[2] + 200;
            }
        }
        else
        {
            pt[0] = target->r.currentOrigin[0] + cos( level.time * 0.001f + NPC->random ) * 56;
            pt[1] = target->r.currentOrigin[1] + sin( level.time * 0.001f + NPC->random ) * 56;
            pt[2] = target->r.currentOrigin[2] + 40;
        }

        VectorSubtract( pt, NPC->r.currentOrigin, dir );
        VectorMA( NPC->client->ps.velocity, 0.8f, dir, NPC->client->ps.velocity );
    }
    else
    {
        if ( NPC->client->NPC_class != CLASS_BOBAFETT )
        {
            if ( TIMER_Done( NPC, "seekerhiss" ))
            {
                TIMER_Set( NPC, "seekerhiss", 1000 + random() * 1000 );
                G_Sound( NPC, CHAN_AUTO, G_SoundIndex( "sound/chars/seeker/misc/hiss" ));
            }
        }

        // Hey come back!
        NPCInfo->goalEntity = target;
        if(target == NPC->enemy)
            NPCInfo->goalRadius = 60;
        else
            NPCInfo->goalRadius = 32;
        if(!NPC_MoveToGoal(qtrue)) {
            //cant go there on our first try, abort.
            //this really isnt the best way... but if it cant reach the point, it will just sit there doing nothing.
            NPCInfo->goalEntity = NPC->client->leader;
            //stop chasing the enemy if we were told to, and return to the player
            NPCInfo->scriptFlags &= ~SCF_CHASE_ENEMIES;
        }
    }

    //call this even if we do have an enemy, for enemy proximity detection
    if ( /*!NPC->enemy && */ NPCInfo->enemyCheckDebounceTime < level.time )
    {
        // check twice a second to find a new enemy
        Seeker_FindEnemy();
        NPCInfo->enemyCheckDebounceTime = level.time + 500;
    }

    //play our proximity beep
    if(NPC->genericValue3 && NPC->fly_sound_debounce_time > 0 && NPC->fly_sound_debounce_time < level.time) {
        G_Sound(NPC, CHAN_AUTO, NPC->genericValue3);
        NPC->fly_sound_debounce_time = -1;
    }


    NPC_UpdateAngles( qtrue, qtrue );

#else
    vec3_t	pt, dir;
    float	dis;
    float	minDistSqr = MIN_DISTANCE_SQR;
    gentity_t *closestPlayer = NULL;

    Seeker_MaintainHeight();

    closestPlayer = FindClosestPlayer(NPC->r.currentOrigin, NPC->client->playerTeam);

    if(!closestPlayer)
    {   //in MP it's actually possible that there's no players on our team at the moment.
        return;
    }


    dis	= DistanceHorizontalSquared( NPC->r.currentOrigin, closestPlayer->r.currentOrigin );

    if ( NPC->client->NPC_class == CLASS_BOBAFETT )
    {
        if ( TIMER_Done( NPC, "flameTime" ) )
        {
            minDistSqr = 200*200;
        }
    }

    if ( dis < minDistSqr )
    {
        // generally circle the player closely till we take an enemy..this is our target point
        if ( NPC->client->NPC_class == CLASS_BOBAFETT )
        {
            pt[0] = closestPlayer->r.currentOrigin[0] + cos( level.time * 0.001f + NPC->random ) * 250;
            pt[1] = closestPlayer->r.currentOrigin[1] + sin( level.time * 0.001f + NPC->random ) * 250;
            if ( NPC->client->jetPackTime < level.time )
            {
                pt[2] = closestPlayer->r.currentOrigin[2] - 64;
            }
            else
            {
                pt[2] = closestPlayer->r.currentOrigin[2] + 200;
            }
        }
        else
        {
            pt[0] = closestPlayer->r.currentOrigin[0] + cos( level.time * 0.001f + NPC->random ) * 56;
            pt[1] = closestPlayer->r.currentOrigin[1] + sin( level.time * 0.001f + NPC->random ) * 56;
            pt[2] = closestPlayer->r.currentOrigin[2] + 40;
        }

        VectorSubtract( pt, NPC->r.currentOrigin, dir );
        VectorMA( NPC->client->ps.velocity, 0.8f, dir, NPC->client->ps.velocity );
    }
    else
    {
        if ( NPC->client->NPC_class != CLASS_BOBAFETT )
        {
            if ( TIMER_Done( NPC, "seekerhiss" ))
            {
                TIMER_Set( NPC, "seekerhiss", 1000 + random() * 1000 );
                G_Sound( NPC, CHAN_AUTO, G_SoundIndex( "sound/chars/seeker/misc/hiss" ));
            }
        }

        // Hey come back!
        NPCInfo->goalEntity = closestPlayer;
        NPCInfo->goalRadius = 32;
        NPC_MoveToGoal( qtrue );
        NPC->s.owner = closestPlayer->s.number;
    }

    if ( NPCInfo->enemyCheckDebounceTime < level.time )
    {
        // check twice a second to find a new enemy
        Seeker_FindEnemy();
        NPCInfo->enemyCheckDebounceTime = level.time + 500;
    }

    NPC_UpdateAngles( qtrue, qtrue );
#endif
    //[/SeekerItemNpc]
}
Esempio n. 18
0
void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd )
{
	if (( (*ucmd)->buttons & BUTTON_USE || (*ucmd)->forwardmove < 0 || (*ucmd)->upmove > 0 ) && ent->owner && ent->owner->delay + 500 < level.time )
	{
		ent->owner->s.loopSound = 0;

		if ( ent->owner->e_UseFunc == useF_eweb_use )//yeah, crappy way to check this, but...
		{
			G_Sound( ent, G_SoundIndex( "sound/weapons/eweb/eweb_dismount.mp3" ));
		}
		else
		{
			G_Sound( ent, G_SoundIndex( "sound/weapons/emplaced/emplaced_dismount.mp3" ));

		}
#ifdef _IMMERSION
		G_Force( ent, G_ForceIndex( "fffx/weapons/emplaced/emplaced_dismount", FF_CHANNEL_TOUCH ) );
#endif // _IMMERSION

		ExitEmplacedWeapon( ent );
		(*ucmd)->buttons &= ~BUTTON_USE;
		if ( (*ucmd)->upmove > 0 )
		{//don't actually jump
			(*ucmd)->upmove = 0;
		}
	}
	else
	{
		// this is a crappy way to put sounds on a moving eweb....
		if ( ent->owner
			&& ent->owner->e_UseFunc == useF_eweb_use )//yeah, crappy way to check this, but...
		{
			if ( !VectorCompare( ent->client->ps.viewangles, ent->owner->movedir ))
			{
				ent->owner->s.loopSound = G_SoundIndex( "sound/weapons/eweb/eweb_aim.wav" );
				ent->owner->fly_sound_debounce_time = level.time;
			}
			else
			{
				if ( ent->owner->fly_sound_debounce_time + 100 <= level.time )
				{
					ent->owner->s.loopSound = 0;
				}
			}

			VectorCopy( ent->client->ps.viewangles, ent->owner->movedir );
		}

		// don't allow movement, weapon switching, and most kinds of button presses
		(*ucmd)->forwardmove = 0;
		(*ucmd)->rightmove = 0;
		(*ucmd)->upmove = 0;
		(*ucmd)->buttons &= (BUTTON_ATTACK|BUTTON_ALT_ATTACK);

		(*ucmd)->weapon = ent->client->ps.weapon; //WP_EMPLACED_GUN;

		if ( ent->health <= 0 )
		{
			ExitEmplacedWeapon( ent );
		}
	}
}