Beispiel #1
0
void	Pilot_Update(void)
{
	mActivePilotCount = 0;
	mRegistered.clear();
	for (int i=0; i<ENTITYNUM_WORLD; i++)
	{
		if (g_entities[i].inuse && 
			g_entities[i].client &&
			g_entities[i].NPC && 
			g_entities[i].NPC->greetEnt &&
			g_entities[i].NPC->greetEnt->owner==(&g_entities[i])
			)
		{
			mActivePilotCount++;
		}
		if ( g_entities[i].inuse && 
			 g_entities[i].client &&
			 g_entities[i].m_pVehicle &&
			!g_entities[i].owner &&
			 g_entities[i].health>0 &&
			 g_entities[i].m_pVehicle->m_pVehicleInfo->type==VH_SPEEDER && 
			!mRegistered.full())
		{
			mRegistered.push_back(&g_entities[i]);
		}

	}


	if (player && 
		player->inuse && 
		TIMER_Done(player, "FlybySoundArchitectureDebounce"))
	{
    	TIMER_Set(player, "FlybySoundArchitectureDebounce", 300);

		Vehicle_t*	pVeh = G_IsRidingVehicle(player);

		if (pVeh && 
			(pVeh->m_pVehicleInfo->soundFlyBy || pVeh->m_pVehicleInfo->soundFlyBy2) &&
			//fabsf(pVeh->m_pParentEntity->currentAngles[2])<15.0f &&
			VectorLength(pVeh->m_pParentEntity->client->ps.velocity)>500.0f)
		{
			vec3_t	projectedPosition;
			vec3_t	projectedDirection;
			vec3_t	projectedRight;
			vec3_t	anglesNoRoll;

			VectorCopy(pVeh->m_pParentEntity->currentAngles, anglesNoRoll);
			anglesNoRoll[2] = 0;
			AngleVectors(anglesNoRoll, projectedDirection, projectedRight, 0);

			VectorMA(player->currentOrigin, 1.2f, pVeh->m_pParentEntity->client->ps.velocity, projectedPosition);
			VectorMA(projectedPosition, Q_flrand(-200.0f, 200.0f), projectedRight, projectedPosition); 

			gi.trace(&mPilotViewTrace, 
				player->currentOrigin, 
				0, 
				0, 
				projectedPosition, 
				player->s.number, 
 				MASK_SHOT, G2_NOCOLLIDE, 0);

			if ((mPilotViewTrace.allsolid==qfalse) && 
				(mPilotViewTrace.startsolid==qfalse) && 
				(mPilotViewTrace.fraction<0.99f) && 
				(mPilotViewTrace.plane.normal[2]<0.5f) &&
				(DotProduct(projectedDirection, mPilotViewTrace.plane.normal)<-0.5f)
				)
			{
 			//	CG_DrawEdge(player->currentOrigin, mPilotViewTrace.endpos, EDGE_IMPACT_POSSIBLE);
 		  		TIMER_Set(player, "FlybySoundArchitectureDebounce", Q_irand(1000, 2000));

				int soundFlyBy = pVeh->m_pVehicleInfo->soundFlyBy;
				if (pVeh->m_pVehicleInfo->soundFlyBy2 && (!soundFlyBy || !Q_irand(0,1)))
				{
					soundFlyBy = pVeh->m_pVehicleInfo->soundFlyBy2;
				}
				G_SoundAtSpot(mPilotViewTrace.endpos, soundFlyBy, qtrue);
			}
			else
			{
 			//	CG_DrawEdge(player->currentOrigin, mPilotViewTrace.endpos, EDGE_IMPACT_SAFE);
			}
		}
	}
}
bool	Boba_Flee()
{
	bool	EnemyRecentlySeen	= ((level.time - NPCInfo->enemyLastSeenTime)<10000);
	bool	ReachedEscapePoint	= (Distance(level.combatPoints[NPCInfo->combatPoint].origin, NPC->currentOrigin)<50.0f);
	bool	HasBeenGoneEnough	= (level.time>NPCInfo->surrenderTime || (level.time - NPCInfo->enemyLastSeenTime)>400000);


	// Is It Time To Come Back For Some More?
	//----------------------------------------
 	if (!EnemyRecentlySeen || ReachedEscapePoint)
	{
		NPC->svFlags |= SVF_NOCLIENT;
		if (HasBeenGoneEnough)
		{
			if ((level.time - NPCInfo->enemyLastSeenTime)>400000)
			{
				Boba_Printf("  Gone Too Long, Attempting Respawn");
			}

			if (Boba_Respawn())
			{
				return true;
			}
		}
	  	else if (ReachedEscapePoint && (NPCInfo->surrenderTime - level.time)>3000)
		{
 			if (TIMER_Done(NPC, "SpookPlayerTimer"))
			{
				vec3_t		testDirection;
				TIMER_Set(NPC, "SpookPlayerTimer", Q_irand(2000, 10000));
				switch(Q_irand(0, 1))
				{
				case 0:
					Boba_Printf("SPOOK: Dust");
					Boba_DustFallNear(NPC->enemy->currentOrigin, Q_irand(1,2));
					break;

				case 1:
					Boba_Printf("SPOOK: Footsteps");
  					testDirection[0] =  (random() * 0.5f) - 1.0f;
	 		 		testDirection[0] += (testDirection[0]>0.0f)?(0.5f):(-0.5f);
					testDirection[1] = (random() * 0.5f) - 1.0f;
					testDirection[1] += (testDirection[1]>0.0f)?(0.5f):(-0.5f);
					testDirection[2] = 1.0f;
		 	 		VectorMA(NPC->enemy->currentOrigin, 400.0f, testDirection, BobaFootStepLoc);

					BobaFootStepCount = Q_irand(3,8);
					break;
				}
			}

			if (BobaFootStepCount && TIMER_Done(NPC, "BobaFootStepFakeTimer"))
			{
				TIMER_Set(NPC, "BobaFootStepFakeTimer", Q_irand(300, 800));
				BobaFootStepCount --;
				G_SoundAtSpot(BobaFootStepLoc, G_SoundIndex(va("sound/player/footsteps/boot%d", Q_irand(1,4))), qtrue);
			}

		 	if (TIMER_Done(NPC, "ResampleEnemyDirection") && NPC->enemy->resultspeed>10.0f)
			{
				TIMER_Set(NPC, "ResampleEnemyDirection", Q_irand(500, 1000));
				AverageEnemyDirectionSamples ++;

				vec3_t	moveDir;
				VectorCopy(NPC->enemy->client->ps.velocity, moveDir);
				VectorNormalize(moveDir);

				VectorAdd(AverageEnemyDirection, moveDir, AverageEnemyDirection);
			}

	 		if (g_bobaDebug->integer && AverageEnemyDirectionSamples)
			{
				vec3_t	endPos;
				VectorMA(NPC->enemy->currentOrigin, 500.0f / (float)AverageEnemyDirectionSamples, AverageEnemyDirection, endPos);
				CG_DrawEdge(NPC->enemy->currentOrigin, endPos, EDGE_IMPACT_POSSIBLE);
			}
		}
	}
	else
	{
		NPCInfo->surrenderTime += 100;
	}

	// Finish The Flame Thrower First...
	//-----------------------------------
	if (NPCInfo->aiFlags&NPCAI_FLAMETHROW)
	{
		Boba_DoFlameThrower( NPC );
		NPC_FacePosition( NPC->enemy->currentOrigin, qtrue);
		NPC_UpdateAngles(qtrue, qtrue);
		return true;
	}

	bool	IsOnAPath = !!NPC_MoveToGoal(qtrue);
	if (!ReachedEscapePoint &&
		NPCInfo->aiFlags&NPCAI_BLOCKED && 
		NPC->client->moveType!=MT_FLYSWIM && 
		((level.time - NPCInfo->blockedDebounceTime)>1000)
		)
	{
		if (!Boba_CanSeeEnemy(NPC) && Distance(NPC->currentOrigin, level.combatPoints[NPCInfo->combatPoint].origin)<200)
		{
			Boba_Printf("BLOCKED: Just Teleporting There");
			G_SetOrigin(NPC, level.combatPoints[NPCInfo->combatPoint].origin);
		}
		else
		{
			Boba_Printf("BLOCKED: Attempting Jump");

			if (IsOnAPath)
			{
				if (NPC_TryJump(NPCInfo->blockedTargetPosition))
				{
				}
				else
				{
					Boba_Printf("  Failed");
				}
			}
			else if (EnemyRecentlySeen)
			{
				if (NPC_TryJump(NPCInfo->enemyLastSeenLocation))
				{
	 			}
				else
				{
					Boba_Printf("  Failed");
				}
			}
		}
	}


	NPC_UpdateAngles( qtrue, qtrue );
	return true;
}
Beispiel #3
0
void NPC_BSGM_Attack( void )
{
	//Don't do anything if we're hurt
	if ( NPC->painDebounceTime > level.time )
	{
		NPC_UpdateAngles( qtrue, qtrue );
		return;
	}

	//FIXME: if killed enemy, use victory anim
	if ( NPC->enemy && NPC->enemy->health <= 0 
		&& !NPC->enemy->s.number )
	{//my enemy is dead
		if ( NPC->client->ps.torsoAnim == BOTH_STAND2TO1 )
		{
			if ( NPC->client->ps.torsoAnimTimer <= 500 )
			{
				G_AddVoiceEvent( NPC, Q_irand( EV_VICTORY1, EV_VICTORY3 ), 3000 );
				NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
				NPC->client->ps.legsAnimTimer += 500;
				NPC->client->ps.torsoAnimTimer += 500;
			}
		}
		else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1START )
		{
			if ( NPC->client->ps.torsoAnimTimer <= 500 )
			{
				NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1STARTGESTURE, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
				NPC->client->ps.legsAnimTimer += 500;
				NPC->client->ps.torsoAnimTimer += 500;
			}
		}
		else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1STARTGESTURE )
		{
			if ( NPC->client->ps.torsoAnimTimer <= 500 )
			{
				NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1STOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
				NPC->client->ps.legsAnimTimer += 500;
				NPC->client->ps.torsoAnimTimer += 500;
			}
		}
		else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1STOP )
		{
			if ( NPC->client->ps.torsoAnimTimer <= 500 )
			{
				NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
				NPC->client->ps.legsAnimTimer = -1;
				NPC->client->ps.torsoAnimTimer = -1;
			}
		}
		else if ( NPC->wait )
		{
			if ( TIMER_Done( NPC, "gloatTime" ) )
			{
				GM_StartGloat();
			}
			else if ( DistanceHorizontalSquared( NPC->client->renderInfo.eyePoint, NPC->enemy->currentOrigin ) > 4096 && (NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )//64 squared
			{
				NPCInfo->goalEntity = NPC->enemy;
				GM_Move();
			}
			else
			{//got there
				GM_StartGloat();
			}
		}
		NPC_FaceEnemy( qtrue );
		NPC_UpdateAngles( qtrue, qtrue );
		return;
	}
	//If we don't have an enemy, just idle
	if ( NPC_CheckEnemyExt() == qfalse || !NPC->enemy )
	{
		NPC->enemy = NULL;
		NPC_BSGM_Patrol();
		return;
	}

	enemyLOS = enemyCS = qfalse;
	bMove = qtrue;
	faceEnemy = qfalse;
	shoot = qfalse;
	hitAlly = qfalse;
	VectorClear( impactPos );
	enemyDist = DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );

	if ( NPC->client->ps.torsoAnim == BOTH_ATTACK4 ||
		NPC->client->ps.torsoAnim == BOTH_ATTACK5 )
	{
		shoot = qfalse;
		if ( TIMER_Done( NPC, "smackTime" ) && !NPCInfo->blockedDebounceTime )
		{//time to smack
			//recheck enemyDist and InFront
			if ( enemyDist < MELEE_DIST_SQUARED && InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f ) )
			{
				vec3_t	smackDir;
				VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, smackDir );
				smackDir[2] += 30;
				VectorNormalize( smackDir );
				//hurt them
				G_Sound( NPC->enemy, G_SoundIndex( "sound/weapons/galak/skewerhit.wav" ) );
				G_Damage( NPC->enemy, NPC, NPC, smackDir, NPC->currentOrigin, (g_spskill->integer+1)*Q_irand( 5, 10), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_CRUSH ); 
				if ( NPC->client->ps.torsoAnim == BOTH_ATTACK4 )
				{//smackdown
					int knockAnim = BOTH_KNOCKDOWN1;
					if ( PM_CrouchAnim( NPC->enemy->client->ps.legsAnim ) )
					{//knockdown from crouch
						knockAnim = BOTH_KNOCKDOWN4;
					}
					//throw them
					smackDir[2] = 1;
					VectorNormalize( smackDir );
					G_Throw( NPC->enemy, smackDir, 50 );
					NPC_SetAnim( NPC->enemy, SETANIM_BOTH, knockAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
				}
				else
				{//uppercut
					//throw them
					G_Throw( NPC->enemy, smackDir, 100 );
					//make them backflip
					NPC_SetAnim( NPC->enemy, SETANIM_BOTH, BOTH_KNOCKDOWN5, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
				}
				//done with the damage
				NPCInfo->blockedDebounceTime = 1;
			}
		}
	}
	else if ( NPC->lockCount ) //already shooting laser
	{//sometimes use the laser beam attack, but only after he's taken down our generator
		shoot = qfalse;
		if ( NPC->lockCount == 1 )
		{//charging up
			if ( TIMER_Done( NPC, "beamDelay" ) )
			{//time to start the beam
				int laserAnim;
				if ( Q_irand( 0, 1 ) )
				{
					laserAnim = BOTH_ATTACK2;
				}
				else
				{
					laserAnim = BOTH_ATTACK7;
				}
				NPC_SetAnim( NPC, SETANIM_BOTH, laserAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
				TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer + Q_irand( 1000, 3000 ) );
				//turn on beam effect
				NPC->lockCount = 2;
				G_PlayEffect( "galak/trace_beam", NPC->s.number );
				NPC->s.loopSound = G_SoundIndex( "sound/weapons/galak/lasercutting.wav" );
				if ( !NPCInfo->coverTarg )
				{//for moving looping sound at end of trace
					NPCInfo->coverTarg = G_Spawn();
					if ( NPCInfo->coverTarg )
					{
						G_SetOrigin( NPCInfo->coverTarg, NPC->client->renderInfo.muzzlePoint );
						NPCInfo->coverTarg->svFlags |= SVF_BROADCAST;
						NPCInfo->coverTarg->s.loopSound = G_SoundIndex( "sound/weapons/galak/lasercutting.wav" );
					}
				}
			}
		}
		else
		{//in the actual attack now
			if ( !NPC->client->ps.torsoAnimTimer )
			{//attack done!
				NPC->lockCount = 0;
				G_FreeEntity( NPCInfo->coverTarg );
				NPC->s.loopSound = 0;
				NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_DROPWEAP2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
				TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer );
			}
			else
			{//attack still going
				//do the trace and damage
				trace_t	trace;
				vec3_t	end, mins={-3,-3,-3}, maxs={3,3,3};
				VectorMA( NPC->client->renderInfo.muzzlePoint, 1024, NPC->client->renderInfo.muzzleDir, end );
				gi.trace( &trace, NPC->client->renderInfo.muzzlePoint, mins, maxs, end, NPC->s.number, MASK_SHOT );
				if ( trace.allsolid || trace.startsolid )
				{//oops, in a wall
					if ( NPCInfo->coverTarg )
					{
						G_SetOrigin( NPCInfo->coverTarg, NPC->client->renderInfo.muzzlePoint );
					}
				}
				else
				{//clear
					if ( trace.fraction < 1.0f )
					{//hit something
						gentity_t *traceEnt = &g_entities[trace.entityNum];
						if ( traceEnt && traceEnt->takedamage )
						{//damage it
							G_SoundAtSpot( trace.endpos, G_SoundIndex( "sound/weapons/galak/laserdamage.wav" ) );
							G_Damage( traceEnt, NPC, NPC, NPC->client->renderInfo.muzzleDir, trace.endpos, 10, 0, MOD_ENERGY );
						}
					}
					if ( NPCInfo->coverTarg )
					{
						G_SetOrigin( NPCInfo->coverTarg, trace.endpos );
					}
					if ( !Q_irand( 0, 5 ) )
					{
						G_SoundAtSpot( trace.endpos, G_SoundIndex( "sound/weapons/galak/laserdamage.wav" ) );
					}
				}
			}
		}
	}
	else 
	{//Okay, we're not in a special attack, see if we should switch weapons or start a special attack
		/*
		if ( NPC->s.weapon == WP_REPEATER 
			&& !(NPCInfo->scriptFlags & SCF_ALT_FIRE)//using rapid-fire
			&& NPC->enemy->s.weapon == WP_SABER //enemy using saber
			&& NPC->client && (NPC->client->ps.saberEventFlags&SEF_DEFLECTED)
			&& !Q_irand( 0, 50 ) )
		{//he's deflecting my shots, switch to the laser or the lob fire for a while
			TIMER_Set( NPC, "noRapid", Q_irand( 2000, 6000 ) );
			NPCInfo->scriptFlags |= SCF_ALT_FIRE;
			NPC->alt_fire = qtrue;
			if ( NPC->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH && (Q_irand( 0, 1 )||enemyDist < MAX_LOB_DIST_SQUARED) )
			{//shield down, use laser
				NPC_GM_StartLaser();
			}
		}
		else*/
		if ( !NPC->client->ps.powerups[PW_GALAK_SHIELD] 
			&& enemyDist < MELEE_DIST_SQUARED 
			&& InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f ) 
			&& G_StandardHumanoid( NPC->enemy->NPC_type ) )//within 80 and in front
		{//our shield is down, and enemy within 80, if very close, use melee attack to slap away
			if ( TIMER_Done( NPC, "attackDelay" ) )
			{
				//animate me
				int swingAnim;
				if ( NPC->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH )
				{//generator down, use random melee
					swingAnim = Q_irand( BOTH_ATTACK4, BOTH_ATTACK5 );//smackdown or uppercut
				}
				else
				{//always knock-away
					swingAnim = BOTH_ATTACK5;//uppercut
				}
				//FIXME: swing sound
				NPC_SetAnim( NPC, SETANIM_BOTH, swingAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
				TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer + Q_irand( 1000, 3000 ) );
				//delay the hurt until the proper point in the anim
				TIMER_Set( NPC, "smackTime", 600 );
				NPCInfo->blockedDebounceTime = 0;
				//FIXME: say something?
			}
		}
		else if ( !NPC->lockCount && NPC->locationDamage[HL_GENERIC1] > GENERATOR_HEALTH
			&& TIMER_Done( NPC, "attackDelay" )
			&& InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f )
			&& ((!Q_irand( 0, 10*(2-g_spskill->integer))&& enemyDist > MIN_LOB_DIST_SQUARED&& enemyDist < MAX_LOB_DIST_SQUARED)
				||(!TIMER_Done( NPC, "noLob" )&&!TIMER_Done( NPC, "noRapid" ))) 
			&& NPC->enemy->s.weapon != WP_TURRET )
		{//sometimes use the laser beam attack, but only after he's taken down our generator
			shoot = qfalse;
			NPC_GM_StartLaser();
		}
		else if ( enemyDist < MIN_LOB_DIST_SQUARED 
			&& (NPC->enemy->s.weapon != WP_TURRET || Q_stricmp( "PAS", NPC->enemy->classname ))
			&& TIMER_Done( NPC, "noRapid" ) )//256
		{//enemy within 256
			if ( (NPC->client->ps.weapon == WP_REPEATER) && (NPCInfo->scriptFlags & SCF_ALT_FIRE) )
			{//shooting an explosive, but enemy too close, switch to primary fire
				NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
				NPC->alt_fire = qfalse;
				//FIXME: use weap raise & lower anims
				NPC_ChangeWeapon( WP_REPEATER );
			}
		}
		else if ( (enemyDist > MAX_LOB_DIST_SQUARED || (NPC->enemy->s.weapon == WP_TURRET && !Q_stricmp( "PAS", NPC->enemy->classname )))
			&& TIMER_Done( NPC, "noLob" ) )//448
		{//enemy more than 448 away and we are ready to try lob fire again
			if ( (NPC->client->ps.weapon == WP_REPEATER) && !(NPCInfo->scriptFlags & SCF_ALT_FIRE) )
			{//enemy far enough away to use lobby explosives
				NPCInfo->scriptFlags |= SCF_ALT_FIRE;
				NPC->alt_fire = qtrue;
				//FIXME: use weap raise & lower anims
				NPC_ChangeWeapon( WP_REPEATER );
			}
		}
	}

	//can we see our target?
	if ( NPC_ClearLOS( NPC->enemy ) )
	{
		NPCInfo->enemyLastSeenTime = level.time;//used here for aim debouncing, not always a clear LOS
		enemyLOS = qtrue;

		if ( NPC->client->ps.weapon == WP_NONE )
		{
			enemyCS = qfalse;//not true, but should stop us from firing
			NPC_AimAdjust( -1 );//adjust aim worse longer we have no weapon
		}
		else
		{//can we shoot our target?
			if ( ((NPC->client->ps.weapon == WP_REPEATER && (NPCInfo->scriptFlags&SCF_ALT_FIRE))) && enemyDist < MIN_LOB_DIST_SQUARED )//256
			{
				enemyCS = qfalse;//not true, but should stop us from firing
				hitAlly = qtrue;//us!
				//FIXME: if too close, run away!
			}
			else
			{
				int hit = NPC_ShotEntity( NPC->enemy, impactPos );
				gentity_t *hitEnt = &g_entities[hit];
				if ( hit == NPC->enemy->s.number 
					|| ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam )
					|| ( hitEnt && hitEnt->takedamage ) )
				{//can hit enemy or will hit glass or other breakable, so shoot anyway
					enemyCS = qtrue;
					NPC_AimAdjust( 2 );//adjust aim better longer we have clear shot at enemy
					VectorCopy( NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation );
				}
				else
				{//Hmm, have to get around this bastard
					NPC_AimAdjust( 1 );//adjust aim better longer we can see enemy
					if ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->playerTeam )
					{//would hit an ally, don't fire!!!
						hitAlly = qtrue;
					}
					else
					{//Check and see where our shot *would* hit... if it's not close to the enemy (within 256?), then don't fire
					}
				}
			}
		}
	}
	else if ( gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin ) )
	{
		if ( TIMER_Done( NPC, "talkDebounce" ) && !Q_irand( 0, 10 ) )
		{
			if ( NPCInfo->enemyCheckDebounceTime < 8 )
			{
				int speech = -1;
				switch( NPCInfo->enemyCheckDebounceTime )
				{
				case 0:
				case 1:
				case 2:
					speech = EV_CHASE1 + NPCInfo->enemyCheckDebounceTime;
					break;
				case 3:
				case 4:
				case 5:
					speech = EV_COVER1 + NPCInfo->enemyCheckDebounceTime-3;
					break;
				case 6:
				case 7:
					speech = EV_ESCAPING1 + NPCInfo->enemyCheckDebounceTime-6;
					break;
				}
				NPCInfo->enemyCheckDebounceTime++;
				if ( speech != -1 )
				{
					G_AddVoiceEvent( NPC, speech, Q_irand( 3000, 5000 ) );
					TIMER_Set( NPC, "talkDebounce", Q_irand( 5000, 7000 ) );
				}
			}
		}

		NPCInfo->enemyLastSeenTime = level.time;

		int hit = NPC_ShotEntity( NPC->enemy, impactPos );
		gentity_t *hitEnt = &g_entities[hit];
		if ( hit == NPC->enemy->s.number 
			|| ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam )
			|| ( hitEnt && hitEnt->takedamage ) )
		{//can hit enemy or will hit glass or other breakable, so shoot anyway
			enemyCS = qtrue;
		}
		else
		{
			faceEnemy = qtrue;
			NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy
		}
	}

	if ( enemyLOS )
	{
		faceEnemy = qtrue;
	}
	else
	{
		if ( !NPCInfo->goalEntity )
		{
			NPCInfo->goalEntity = NPC->enemy;
		}
		if ( NPCInfo->goalEntity == NPC->enemy )
		{//for now, always chase the enemy
			bMove = qtrue;
		}
	}
	if ( enemyCS )
	{
		shoot = qtrue;
		//NPCInfo->enemyCheckDebounceTime = level.time;//actually used here as a last actual LOS
	}
	else
	{
		if ( !NPCInfo->goalEntity )
		{
			NPCInfo->goalEntity = NPC->enemy;
		}
		if ( NPCInfo->goalEntity == NPC->enemy )
		{//for now, always chase the enemy
			bMove = qtrue;
		}
	}

	//Check for movement to take care of
	GM_CheckMoveState();

	//See if we should override shooting decision with any special considerations
	GM_CheckFireState();

	if ( NPC->client->ps.weapon == WP_REPEATER && (NPCInfo->scriptFlags&SCF_ALT_FIRE) && shoot && TIMER_Done( NPC, "attackDelay" ) )
	{
		vec3_t	muzzle;
		vec3_t	angles;
		vec3_t	target;
		vec3_t velocity = {0,0,0};
		vec3_t mins = {-REPEATER_ALT_SIZE,-REPEATER_ALT_SIZE,-REPEATER_ALT_SIZE}, maxs = {REPEATER_ALT_SIZE,REPEATER_ALT_SIZE,REPEATER_ALT_SIZE};

		CalcEntitySpot( NPC, SPOT_WEAPON, muzzle );
		
		VectorCopy( NPC->enemy->currentOrigin, target );

		target[0] += Q_flrand( -5, 5 )+(crandom()*(6-NPCInfo->currentAim)*2);
		target[1] += Q_flrand( -5, 5 )+(crandom()*(6-NPCInfo->currentAim)*2);
		target[2] += Q_flrand( -5, 5 )+(crandom()*(6-NPCInfo->currentAim)*2);

		//Find the desired angles
		qboolean clearshot = WP_LobFire( NPC, muzzle, target, mins, maxs, MASK_SHOT|CONTENTS_LIGHTSABER, 
			velocity, qtrue, NPC->s.number, NPC->enemy->s.number,
			300, 1100, 1500, qtrue );
		if ( VectorCompare( vec3_origin, velocity ) || (!clearshot&&enemyLOS&&enemyCS)  )
		{//no clear lob shot and no lob shot that will hit something breakable
			if ( enemyLOS && enemyCS && TIMER_Done( NPC, "noRapid" ) )
			{//have a clear straight shot, so switch to primary
				NPCInfo->scriptFlags &= ~SCF_ALT_FIRE;
				NPC->alt_fire = qfalse;
				NPC_ChangeWeapon( WP_REPEATER );
				//keep this weap for a bit
				TIMER_Set( NPC, "noLob", Q_irand( 500, 1000 ) );
			}
			else
			{
				shoot = qfalse;
			}
		}
		else
		{
			vectoangles( velocity, angles );

			NPCInfo->desiredYaw		= AngleNormalize360( angles[YAW] );
			NPCInfo->desiredPitch	= AngleNormalize360( angles[PITCH] );

			VectorCopy( velocity, NPC->client->hiddenDir );
			NPC->client->hiddenDist = VectorNormalize ( NPC->client->hiddenDir );
		}
	}
	else if ( faceEnemy )
	{//face the enemy
		NPC_FaceEnemy( qtrue );
	}

	if ( !TIMER_Done( NPC, "standTime" ) )
	{
		bMove = qfalse;
	}
	if ( !(NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )
	{//not supposed to chase my enemies
		if ( NPCInfo->goalEntity == NPC->enemy )
		{//goal is my entity, so don't bMove
			bMove = qfalse;
		}
	}

	if ( bMove && !NPC->lockCount )
	{//bMove toward goal
		if ( NPCInfo->goalEntity 
			&& NPC->client->ps.legsAnim != BOTH_ALERT1
			&& NPC->client->ps.legsAnim != BOTH_ATTACK2 
			&& NPC->client->ps.legsAnim != BOTH_ATTACK4
			&& NPC->client->ps.legsAnim != BOTH_ATTACK5 
			&& NPC->client->ps.legsAnim != BOTH_ATTACK7 )
		{
			bMove = GM_Move();
		}
		else
		{
			bMove = qfalse;
		}
	}

	if ( !TIMER_Done( NPC, "flee" ) )
	{//running away
		faceEnemy = qfalse;
	}

	//FIXME: check scf_face_move_dir here?

	if ( !faceEnemy )
	{//we want to face in the dir we're running
		if ( !bMove )
		{//if we haven't moved, we should look in the direction we last looked?
			VectorCopy( NPC->client->ps.viewangles, NPCInfo->lastPathAngles );
		}
		if ( bMove )
		{//don't run away and shoot
			NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW];
			NPCInfo->desiredPitch = 0;
			shoot = qfalse;
		}
	}
	NPC_UpdateAngles( qtrue, qtrue );

	if ( NPCInfo->scriptFlags & SCF_DONT_FIRE )
	{
		shoot = qfalse;
	}

	if ( NPC->enemy && NPC->enemy->enemy )
	{
		if ( NPC->enemy->s.weapon == WP_SABER && NPC->enemy->enemy->s.weapon == WP_SABER )
		{//don't shoot at an enemy jedi who is fighting another jedi, for fear of injuring one or causing rogue blaster deflections (a la Obi Wan/Vader duel at end of ANH)
			shoot = qfalse;
		}
	}
	//FIXME: don't shoot right away!
	if ( shoot )
	{//try to shoot if it's time
		if ( TIMER_Done( NPC, "attackDelay" ) )
		{
			if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here
			{
				WeaponThink( qtrue );
			}
		}
	}

	//also:
	if ( NPC->enemy->s.weapon == WP_TURRET && !Q_stricmp( "PAS", NPC->enemy->classname ) )
	{//crush turrets
		if ( G_BoundsOverlap( NPC->absmin, NPC->absmax, NPC->enemy->absmin, NPC->enemy->absmax ) )
		{//have to do this test because placed turrets are not solid to NPCs (so they don't obstruct navigation)
			if ( NPC->client->ps.powerups[PW_GALAK_SHIELD] > 0 )
			{
				NPC->client->ps.powerups[PW_BATTLESUIT] = level.time + ARMOR_EFFECT_TIME;
				G_Damage( NPC->enemy, NPC, NPC, NULL, NPC->currentOrigin, 100, DAMAGE_NO_KNOCKBACK, MOD_ELECTROCUTE ); 
			}
			else
			{
				G_Damage( NPC->enemy, NPC, NPC, NULL, NPC->currentOrigin, 100, DAMAGE_NO_KNOCKBACK, MOD_CRUSH ); 
			}
		}
	}
	else if ( NPCInfo->touchedByPlayer != NULL && NPCInfo->touchedByPlayer == NPC->enemy )
	{//touched enemy
		if ( NPC->client->ps.powerups[PW_GALAK_SHIELD] > 0 )
		{//zap him!
			//animate me
			NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK6, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
			TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer );
			TIMER_Set( NPC, "standTime", NPC->client->ps.legsAnimTimer );
			//FIXME: debounce this?
			NPCInfo->touchedByPlayer = NULL;
			//FIXME: some shield effect?
			NPC->client->ps.powerups[PW_BATTLESUIT] = level.time + ARMOR_EFFECT_TIME;
			vec3_t	smackDir;
			VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, smackDir );
			smackDir[2] += 30;
			VectorNormalize( smackDir );
			G_Damage( NPC->enemy, NPC, NPC, smackDir, NPC->currentOrigin, (g_spskill->integer+1)*Q_irand( 5, 10), DAMAGE_NO_KNOCKBACK, MOD_ELECTROCUTE ); 
			//throw them
			G_Throw( NPC->enemy, smackDir, 100 );
			NPC->enemy->s.powerups |= ( 1 << PW_SHOCKED );
			if ( NPC->enemy->client )
			{
				NPC->enemy->client->ps.powerups[PW_SHOCKED] = level.time + 1000;
			}
			//stop any attacks
			ucmd.buttons = 0;
		}
	}

	if ( NPCInfo->movementSpeech < 3 && NPCInfo->blockedSpeechDebounceTime <= level.time )
	{
		if ( NPC->enemy && NPC->enemy->health > 0 && NPC->enemy->painDebounceTime > level.time )
		{
			if ( NPC->enemy->health < 50 && NPCInfo->movementSpeech == 2 )
			{
				G_AddVoiceEvent( NPC, EV_ANGER2, Q_irand( 2000, 4000 ) );
				NPCInfo->movementSpeech = 3;
			}
			else if ( NPC->enemy->health < 75 && NPCInfo->movementSpeech == 1 )
			{
				G_AddVoiceEvent( NPC, EV_ANGER1, Q_irand( 2000, 4000 ) );
				NPCInfo->movementSpeech = 2;
			}
			else if ( NPC->enemy->health < 100 && NPCInfo->movementSpeech == 0 )
			{
				G_AddVoiceEvent( NPC, EV_ANGER3, Q_irand( 2000, 4000 ) );
				NPCInfo->movementSpeech = 1;
			}
		}
	}
}
Beispiel #4
0
void fx_rain_think( gentity_t *ent )
{
	if (player)
	{
 		if (ent->count!=0)
		{
			ent->count--;
			if (ent->count==0 || (ent->count%2)==0)
			{
				gi.WE_SetTempGlobalFogColor(ent->pos2);		// Turn Off
				if (ent->count==0)
				{
					ent->nextthink = level.time + Q_irand(1000, 12000);
				}
				else if (ent->count==2)
				{
					ent->nextthink = level.time + Q_irand(150, 450);
				}
				else
				{
					ent->nextthink = level.time + Q_irand(50, 150);
				}
			}
			else
			{
				gi.WE_SetTempGlobalFogColor(ent->pos3);		// Turn On
				ent->nextthink = level.time + 50;
			}
		}
		else if (gi.WE_IsOutside(player->currentOrigin))
		{
			vec3_t	effectPos;
			vec3_t	effectDir;
			VectorClear(effectDir);
		 	effectDir[0] += Q_flrand(-1.0f, 1.0f);
			effectDir[1] += Q_flrand(-1.0f, 1.0f);

			bool	PlayEffect	= Q_irand(1,ent->aimDebounceTime)==1;
			bool	PlayFlicker = Q_irand(1,ent->attackDebounceTime)==1;
			bool	PlaySound	= (PlayEffect || PlayFlicker || Q_irand(1,ent->pushDebounceTime)==1);

			// Play The Sound
			//----------------
			if (PlaySound && !PlayEffect)
			{
				VectorMA(player->currentOrigin, 250.0f, effectDir, effectPos);
				G_SoundAtSpot(effectPos, G_SoundIndex(va("sound/ambience/thunder%d", Q_irand(1,4))), qtrue);
			}

			// Play The Effect
			//-----------------
 			if (PlayEffect)
			{ 
  			 	VectorMA(player->currentOrigin, 400.0f, effectDir, effectPos);
				if (PlaySound) 
				{
					G_Sound(player, G_SoundIndex(va("sound/ambience/thunder_close%d", Q_irand(1,2))));
				}

				// Raise It Up Into The Sky
				//--------------------------
				effectPos[2] += Q_flrand(600.0f, 1000.0f);

				VectorClear(effectDir);
				effectDir[2]  = -1.0f;

				G_PlayEffect("env/huge_lightning", effectPos, effectDir);
				ent->nextthink = level.time + Q_irand(100, 200);
			}

			// Change The Fog Color
			//----------------------
			if (PlayFlicker)
			{
				ent->count = (Q_irand(1,4) * 2);
				ent->nextthink = level.time + 50;
				gi.WE_SetTempGlobalFogColor(ent->pos3);
			}
			else
			{
				ent->nextthink = level.time + Q_irand(1000, ent->delay);
			}
		}
		else
		{
			ent->nextthink = level.time + Q_irand(1000, ent->delay);
		}
	}
	else
	{
		ent->nextthink = level.time + Q_irand(1000, ent->delay);
	}
}
Beispiel #5
0
void	Rail_Update()
{
	if (mRailSystemActive)// && false)
	{
		for (int track=0; track<mRailTracks.size(); track++)
		{
			if (level.time>mRailTracks[track].mNextUpdateTime && !mRailTracks[track].mMovers.empty())
			{
				mRailTracks[track].Update();
			}
		}

		// Is The Player Outside?
		//------------------------
 		if (player && gi.WE_IsOutside(player->currentOrigin))
		{
			int		wooshSound;
			vec3_t	wooshSoundPos;
			vec3_t	moverOrigin;
			vec3_t	playerToMover;
			float	playerToMoverDistance;
			float	playerToMoverDistanceFraction;

			// Iterate Over All The Movers
			//-----------------------------
 			for (int moverIndex=0; moverIndex<mRailMovers.size(); moverIndex++)
			{
 				CRailMover&	mover = mRailMovers[moverIndex];

				// Is It Active, And Has The Sound Already Played On It?
				//--------------------------------------------------------
   			 	if (mover.Active() && !mover.mSoundPlayed)
				{ 
 					VectorAdd(mover.mEnt->currentOrigin, mover.mOriginOffset.v, moverOrigin);
 					VectorSubtract(moverOrigin, player->currentOrigin, playerToMover);
					playerToMover[2]		= 0.0f;
 					playerToMoverDistance	= VectorNormalize(playerToMover);


					// Is It Close Enough?
					//---------------------
					if ((( mover.mLane || !mover.mCenter) &&								// Not Center Track
						 (playerToMoverDistance<WOOSH_ALL_RANGE) && 						//  And Close Enough
						 (DotProduct(playerToMover, mover.mTrack->mDirection.v)>-0.45f))	//  And On The Side
						||																	//OR
						((!mover.mLane &&  mover.mCenter) &&								// Is Center Track
						  (playerToMoverDistance<WOOSH_SUPPORT_RANGE ||						//  And Close Enough for Support
						  (playerToMoverDistance<WOOSH_TUNNEL_RANGE && mover.mRows>10))		//   Or Close Enough For Tunnel
						 ))
					{
						mover.mSoundPlayed = true;
						wooshSound = 0;

						// The Centered Entities Play Right On The Player's Head For Full Volume
						//-----------------------------------------------------------------------
						if (mover.mCenter && !mover.mLane)
						{
 							VectorCopy(player->currentOrigin, wooshSoundPos);
 							wooshSoundPos[2] += 50;

							// If It Is Very Long, Play The Tunnel Sound
							//-------------------------------------------
							if (mover.mRows>10)
							{
								wooshSound = mWooshTun[Q_irand(0, mWooshTun.size()-1)];
							}

							// Otherwise It Is A Support
							//---------------------------
							else 
							{ 
								wooshSound = mWooshSup[Q_irand(0, mWooshSup.size()-1)];
							}
						}

						// All Other Entities Play At A Fraction Of Their Normal Range
						//-------------------------------------------------------------
 						else 
						{
							// Scale The Play Pos By The Square Of The Distance
							//--------------------------------------------------
							playerToMoverDistanceFraction = playerToMoverDistance/WOOSH_ALL_RANGE;
 							playerToMoverDistanceFraction *= playerToMoverDistanceFraction;
							playerToMoverDistanceFraction *= 0.6f;
							playerToMoverDistance *= playerToMoverDistanceFraction;
 							VectorMA(player->currentOrigin, playerToMoverDistance, playerToMover, wooshSoundPos);

							// Large Building
							//----------------
							if (mover.mRows>4)
							{
								wooshSound = mWooshLar[Q_irand(0, mWooshLar.size()-1)];
							}

							// Medium Building
							//-----------------
							else if (mover.mRows>2)
							{
								wooshSound = mWooshMed[Q_irand(0, mWooshMed.size()-1)];
							}

							// Small Building
							//----------------
							else 
							{ 
								wooshSound = mWooshSml[Q_irand(0, mWooshSml.size()-1)];
							}
						}

						// If A Woosh Sound Was Selected, Play It Now
						//--------------------------------------------
						if (wooshSound)
						{
							G_SoundAtSpot(wooshSoundPos, wooshSound, qfalse);
							if (WOOSH_DEBUG)
							{
								CG_DrawEdge(player->currentOrigin, wooshSoundPos, EDGE_WHITE_TWOSECOND);
							}
						}
					}
				}
			}
		}
	}
}