示例#1
0
void CASW_Harvester::Event_Killed( const CTakeDamageInfo &info )
{
	BaseClass::Event_Killed(info);

	// spawn a bunch of harvesites
	int iNumParasites = 4 + RandomInt(0,2);
	QAngle angParasiteFacing[6];
	float fJumpDistance[6];
	// for some reason if we calculate these inside the loop, the random numbers all come out the same.  Worrying.
	angParasiteFacing[0] = GetAbsAngles(); angParasiteFacing[0].y = RandomFloat( -180.0f, 180.0f );
	angParasiteFacing[1] = GetAbsAngles(); angParasiteFacing[1].y = RandomFloat( -180.0f, 180.0f );
	angParasiteFacing[2] = GetAbsAngles(); angParasiteFacing[2].y = RandomFloat( -180.0f, 180.0f );
	angParasiteFacing[3] = GetAbsAngles(); angParasiteFacing[3].y = RandomFloat( -180.0f, 180.0f );
	angParasiteFacing[4] = GetAbsAngles(); angParasiteFacing[4].y = RandomFloat( -180.0f, 180.0f );
	angParasiteFacing[5] = GetAbsAngles(); angParasiteFacing[5].y = RandomFloat( -180.0f, 180.0f );
	fJumpDistance[0] = RandomFloat( 30.0f, 70.0f );
	fJumpDistance[1] = RandomFloat( 30.0f, 70.0f );
	fJumpDistance[2] = RandomFloat( 30.0f, 70.0f );
	fJumpDistance[3] = RandomFloat( 30.0f, 70.0f );
	fJumpDistance[4] = RandomFloat( 30.0f, 70.0f );
	fJumpDistance[5] = RandomFloat( 30.0f, 70.0f );

	for ( int i = 0; i < iNumParasites; i++ )
	{
		bool bBlocked = true;			
		int k = 0;

		Vector vecSpawnPos = GetAbsOrigin();
		float fCircleDegree = ( static_cast< float >( i ) / iNumParasites ) * 2.0f * M_PI;
		vecSpawnPos.x += sinf( fCircleDegree ) * RandomFloat( 3.0f, 20.0f );
		vecSpawnPos.y += cosf( fCircleDegree ) * RandomFloat( 3.0f, 20.0f );
		vecSpawnPos.z += RandomFloat( 20.0f, 40.0f );

		while ( bBlocked && k < 6 )
		{
			if ( k > 0 )
			{
				// Scooch it up
				vecSpawnPos.z += NAI_Hull::Maxs( HULL_TINY ).z - NAI_Hull::Mins( HULL_TINY ).z;
			}

			// check if there's room at this position
			trace_t tr;
			UTIL_TraceHull( vecSpawnPos, vecSpawnPos + Vector( 0.0f, 0.0f, 1.0f ), 
				NAI_Hull::Mins(HULL_TINY) + Vector( -4.0f, -4.0f, -4.0f ),NAI_Hull::Maxs(HULL_TINY) + Vector( 4.0f, 4.0f, 4.0f ),
				MASK_NPCSOLID, this, ASW_COLLISION_GROUP_PARASITE, &tr );	
			
			//NDebugOverlay::Box(vecSpawnPos[i], NAI_Hull::Mins(HULL_TINY),NAI_Hull::Maxs(HULL_TINY), 255,255,0,255,15.0f);
			if ( tr.fraction == 1.0 )
			{
				bBlocked = false;
			}

			k++;				
		}

		if ( bBlocked )
			continue;	// couldn't find room for parasites

		CASW_Parasite *pParasite = dynamic_cast< CASW_Parasite* >( CreateNoSpawn("asw_parasite_defanged",
			vecSpawnPos, angParasiteFacing[i], this));

		if ( pParasite )
		{
			DispatchSpawn( pParasite );
			pParasite->SetSleepState(AISS_WAITING_FOR_INPUT);
			pParasite->SetJumpFromEgg(true, fJumpDistance[i]);
			pParasite->Wake();

			if ( IsOnFire() )
			{
				pParasite->ASW_Ignite( 30.0f, 0, info.GetAttacker(), info.GetWeapon() );
			}
		}
	}

	m_fGibTime = gpGlobals->curtime + random->RandomFloat(20.0f, 30.0f);
}
//-----------------------------------------------------------------------------
// Purpose: Catches the monster-specific events that occur when tagged animation
//			frames are played.
// Input  : pEvent - 
//-----------------------------------------------------------------------------
void CNPC_PoisonZombie::HandleAnimEvent( animevent_t *pEvent )
{
	
	if ( pEvent->event == AE_ZOMBIE_POISON_PICKUP_CRAB )
	{
		EnableCrab( m_nThrowCrab, false );
		SetBodygroup( ZOMBIE_BODYGROUP_THROW, 1 );
		return;
	}

	if ( pEvent->event == AE_ZOMBIE_POISON_THROW_WARN_SOUND )
	{
		BreatheOffShort();
		EmitSound( "NPC_PoisonZombie.ThrowWarn" );
		return;
	}

	if ( pEvent->event == AE_ZOMBIE_POISON_THROW_SOUND )
	{
		BreatheOffShort();
		EmitSound( "NPC_PoisonZombie.Throw" );
		return;
	}

	if ( pEvent->event == AE_ZOMBIE_POISON_THROW_CRAB )
	{
		SetBodygroup( ZOMBIE_BODYGROUP_THROW, 0 );

		CBlackHeadcrab *pCrab = (CBlackHeadcrab *)CreateNoSpawn( GetHeadcrabClassname(), EyePosition(), vec3_angle, this );
		pCrab->AddSpawnFlags( SF_NPC_FALL_TO_GROUND );
		
		// Fade if our parent is supposed to
		if ( HasSpawnFlags( SF_NPC_FADE_CORPSE ) )
		{
			pCrab->AddSpawnFlags( SF_NPC_FADE_CORPSE );
		}

		// make me the crab's owner to avoid collision issues
		pCrab->SetOwnerEntity( this );

		pCrab->Spawn();

		pCrab->SetLocalAngles( GetLocalAngles() );
		pCrab->SetActivity( ACT_RANGE_ATTACK1 );
		pCrab->SetNextThink( gpGlobals->curtime );
		pCrab->PhysicsSimulate();

		pCrab->GetMotor()->SetIdealYaw( GetAbsAngles().y );

		if ( IsOnFire() )
		{
			pCrab->Ignite( 100.0 );
		}

		CBaseEntity *pEnemy = GetEnemy();
		if ( pEnemy )
		{
			Vector vecEnemyEyePos = pEnemy->EyePosition();
			pCrab->ThrowAt( vecEnemyEyePos );
		}

		if (m_nCrabCount == 0)
		{
			CapabilitiesRemove( bits_CAP_INNATE_RANGE_ATTACK1 | bits_CAP_INNATE_RANGE_ATTACK2 );
		}

		m_flNextCrabThrowTime = gpGlobals->curtime + random->RandomInt( ZOMBIE_THROW_MIN_DELAY, ZOMBIE_THROW_MAX_DELAY );
		return;
	}

	if ( pEvent->event == AE_ZOMBIE_POISON_SPIT )
	{
		Vector forward;
		QAngle qaPunch( 45, random->RandomInt(-5, 5), random->RandomInt(-5, 5) );
		AngleVectors( GetLocalAngles(), &forward );
		forward = forward * 200;
		ClawAttack( GetClawAttackRange(), sk_zombie_poison_dmg_spit.GetFloat(), qaPunch, forward, ZOMBIE_BLOOD_BITE );
		return;
	}

	BaseClass::HandleAnimEvent( pEvent );
}
//-----------------------------------------------------------------------------
// Purpose: The nest is dead! Evacuate the nest!
// Input  : bExplosion - We were evicted by an explosion so we should go a-flying.
//			flDamage - The damage that was done to cause the evacuation.
//-----------------------------------------------------------------------------
void CNPC_PoisonZombie::EvacuateNest( bool bExplosion, float flDamage, CBaseEntity *pAttacker )
{
	// HACK: if we were in mid-throw, drop the throwing crab also.
	if ( GetBodygroup( ZOMBIE_BODYGROUP_THROW ) )
	{
		SetBodygroup( ZOMBIE_BODYGROUP_THROW, 0 );
		m_nCrabCount++;
	}

	for( int i = 0; i < MAX_CRABS ; i++ )
	{
		if( m_bCrabs[i] )
		{
			Vector vecPosition;
			QAngle vecAngles;

			char szAttachment[64];

			switch( i )
			{
			case 0:
				strcpy( szAttachment, "headcrab2" );
				break;
			case 1:
				strcpy( szAttachment, "headcrab3" );
				break;
			case 2:
				strcpy( szAttachment, "headcrab4" );
				break;
			}

			GetAttachment( szAttachment, vecPosition, vecAngles );

			// Now slam the angles because the attachment point will have pitch and roll, which we can't use.
			vecAngles = QAngle( 0, random->RandomFloat( 0, 360 ), 0 );

			CBlackHeadcrab *pCrab = (CBlackHeadcrab *)CreateNoSpawn( GetHeadcrabClassname(), vecPosition, vecAngles, this );
			pCrab->Spawn();

			if( !HeadcrabFits(pCrab) )
			{
				UTIL_Remove(pCrab);
				continue;
			}

			float flVelocityScale = 2.0f;
			if ( bExplosion && ( flDamage > 10 ) )
			{
				flVelocityScale = 0.1 * flDamage;
			}

			if (IsOnFire())
			{
				pCrab->Ignite( 100.0 );
			}

			pCrab->Eject( vecAngles, flVelocityScale, pAttacker );
			EnableCrab( i, false );
		}
	}
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=========================================================
void CNPC_Bullsquid::HandleAnimEvent( animevent_t *pEvent )
{
	switch( pEvent->event )
	{
		case BSQUID_AE_SPIT:
		{
			if ( GetEnemy() )
			{
				Vector vSpitPos;
				QAngle vSpitAngle;

				GetAttachment( "Mouth", vSpitPos, vSpitAngle);
				
				Vector			vTarget = GetEnemy()->GetAbsOrigin();
				Vector			vToss;
				CBaseEntity*	pBlocker;
				float flGravity  = sv_gravity.GetFloat() * SPIT_GRAVITY;
				ThrowLimit(vSpitPos, vTarget, flGravity, 3, Vector(0,0,0), Vector(0,0,0), GetEnemy(), &vToss, &pBlocker);

				CGrenadeSpit *pGrenade = (CGrenadeSpit*)CreateNoSpawn( "grenade_spit", vSpitPos, vec3_angle, this );
				//pGrenade->KeyValue( "velocity", vToss );
				pGrenade->Spawn( );
				pGrenade->SetOwner( this );
				pGrenade->SetOwnerEntity( this );
				pGrenade->SetSpitSize( 2 );
				pGrenade->SetAbsVelocity( vToss );

				// Tumble through the air
				pGrenade->SetLocalAngularVelocity(
					QAngle(
						random->RandomFloat ( -100, -500 ),
						random->RandomFloat ( -100, -500 ),
						random->RandomFloat ( -100, -500 )
					)
				);
						
				AttackSound();
			
				CPVSFilter filter( vSpitPos );
				te->SpriteSpray( filter, 0.0,
					&vSpitPos, &vToss, m_nSquidSpitSprite, 5, 10, 15 );
			}
		}
		break;

		case BSQUID_AE_BITE:
		{
		// SOUND HERE!
			CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), sk_bullsquid_dmg_bite.GetFloat(), DMG_SLASH );
			if ( pHurt )
			{
				Vector forward, up;
				AngleVectors( GetAbsAngles(), &forward, NULL, &up );
				pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() - (forward * 100) );
				pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (up * 100) );
				pHurt->RemoveFlag( FL_ONGROUND );
			}
		}
		break;

		case BSQUID_AE_WHIP_SND:
		{
			EmitSound( "NPC_Bullsquid.TailWhip" );
			break;
		}

/*
		case BSQUID_AE_TAILWHIP:
		{
			CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), sk_bullsquid_dmg_whip.GetFloat(), DMG_SLASH | DMG_ALWAYSGIB );
			if ( pHurt ) 
			{
				Vector right, up;
				AngleVectors( GetAbsAngles(), NULL, &right, &up );

				if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) )
					 pHurt->ViewPunch( QAngle( 20, 0, -20 ) );
			
				pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (right * 200) );
				pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (up * 100) );
			}
		}
		break;
*/

		case BSQUID_AE_BLINK:
		{
			// close eye. 
			m_nSkin = 1;
		}
		break;

		case BSQUID_AE_HOP:
		{
			float flGravity = sv_gravity.GetFloat();

			// throw the squid up into the air on this frame.
			if ( GetFlags() & FL_ONGROUND )
			{
				RemoveFlag( FL_ONGROUND );
			}

			// jump into air for 0.8 (24/30) seconds
			Vector vecVel = GetAbsVelocity();
			vecVel.z += ( 0.625 * flGravity ) * 0.5;
			SetAbsVelocity( vecVel );
		}
		break;

		case BSQUID_AE_THROW:
			{
				// squid throws its prey IF the prey is a client. 
				CBaseEntity *pHurt = CheckTraceHullAttack( 70, Vector(-16,-16,-16), Vector(16,16,16), 0, 0 );


				if ( pHurt )
				{
					pHurt->ViewPunch( QAngle(20,0,-20) );
							
					// screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels.
					UTIL_ScreenShake( pHurt->GetAbsOrigin(), 25.0, 1.5, 0.7, 2, SHAKE_START );

					// If the player, throw him around
					if ( pHurt->IsPlayer())
					{
						Vector forward, up;
						AngleVectors( GetLocalAngles(), &forward, NULL, &up );
						pHurt->ApplyAbsVelocityImpulse( forward * 300 + up * 300 );
					}
					// If not the player see if has bullsquid throw interatcion
					else
					{
						CBaseCombatCharacter *pVictim = ToBaseCombatCharacter( pHurt );
						if (pVictim)
						{
							if ( pVictim->HandleInteraction( g_interactionBullsquidThrow, NULL, this ) )
							{
								Vector forward, up;
								AngleVectors( GetLocalAngles(), &forward, NULL, &up );
								pVictim->ApplyAbsVelocityImpulse( forward * 300 + up * 250 );
							}
						}
					}
				}
			}
		break;

		default:
			BaseClass::HandleAnimEvent( pEvent );
	}
}