//----------------------------------------------------------------------------- // Chooses an item when the player is full //----------------------------------------------------------------------------- void CItem_DynamicResupply::SpawnFullItem( CItem_DynamicResupply *pMaster, CBasePlayer *pPlayer, int iDebug ) { // Can we not actually spawn the item? if ( !HasSpawnFlags(SF_DYNAMICRESUPPLY_ALWAYS_SPAWN) ) return; float flRatio[NUM_AMMO_ITEMS]; int i; float flTotalProb = 0.0f; for ( i = 0; i < NUM_AMMO_ITEMS; ++i ) { int iAmmoType = GetAmmoDef()->Index( g_DynamicResupplyAmmoItems[i].sAmmoDef ); bool bCanSpawn = pPlayer->Weapon_GetWpnForAmmo( iAmmoType ) != NULL; if ( bCanSpawn && ( g_DynamicResupplyAmmoItems[i].flFullProbability != 0 ) && ( pMaster->m_flDesiredAmmo[i] != 0.0f ) ) { flTotalProb += g_DynamicResupplyAmmoItems[i].flFullProbability; flRatio[i] = flTotalProb; } else { flRatio[i] = -1.0f; } } if ( flTotalProb == 0.0f ) { // If we're supposed to fallback to just a health vial, do that and finish. if ( pMaster->HasSpawnFlags(SF_DYNAMICRESUPPLY_FALLBACK_TO_VIAL) ) { CBaseEntity::Create( "item_healthvial", GetAbsOrigin(), GetAbsAngles(), this ); if ( iDebug ) { Msg("Player is full, spawning item_healthvial due to spawnflag.\n", g_DynamicResupplyAmmoItems[i].sEntityName ); } return; } // Otherwise, spawn the first ammo item in the list flRatio[0] = 1.0f; flTotalProb = 1.0f; } float flChoice = random->RandomFloat( 0.0f, flTotalProb ); for ( i = 0; i < NUM_AMMO_ITEMS; ++i ) { if ( flChoice <= flRatio[i] ) { CBaseEntity::Create( g_DynamicResupplyAmmoItems[i].sEntityName, GetAbsOrigin(), GetAbsAngles(), this ); if ( iDebug ) { Msg("Player is full, spawning %s \n", g_DynamicResupplyAmmoItems[i].sEntityName ); } return; } } if ( iDebug ) { Msg("Player is full on all health + ammo, is not spawning.\n" ); } }
void CASW_Shotgun_Pellet_Predicted::PelletTouch( CBaseEntity *pOther ) { if (!pOther) return; if (pOther == m_pLastHit) // don't damage the same alien twice return; if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) ) return; // make sure we don't die on things we shouldn't if (!ASWGameRules() || !ASWGameRules()->ShouldCollide(GetCollisionGroup(), pOther->GetCollisionGroup())) return; if ( pOther->m_takedamage != DAMAGE_NO ) { trace_t tr, tr2; tr = BaseClass::GetTouchTrace(); Vector vecNormalizedVel = GetAbsVelocity(); VectorNormalize( vecNormalizedVel ); #ifdef GAME_DLL ClearMultiDamage(); if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->IsNPC() ) { CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_flDamage, DMG_NEVERGIB ); dmgInfo.AdjustPlayerDamageInflictedForSkillLevel(); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f ); dmgInfo.SetDamagePosition( tr.endpos ); pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); } else { CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_flDamage, DMG_BULLET | DMG_NEVERGIB ); CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f ); dmgInfo.SetDamagePosition( tr.endpos ); pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr ); } ApplyMultiDamage(); #endif //Adrian: keep going through the glass. if ( pOther->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS ) return; // pellets should carry on through spawnable enemies? //IASW_Spawnable_NPC* pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>(pOther); //if (pSpawnable && asw_shotgun_pellets_pass.GetBool()) //{ //m_pLastHit = pOther; //return; //} SetAbsVelocity( Vector( 0, 0, 0 ) ); // play body "thwack" sound EmitSound( "Weapon_Crossbow.BoltHitBody" ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); VectorNormalize ( vForward ); UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vForward * 128, MASK_OPAQUE, pOther, COLLISION_GROUP_NONE, &tr2 ); #ifdef GAME_DLL if ( tr2.fraction != 1.0f ) { // NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 ); // NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 ); if ( tr2.m_pEnt == NULL || ( tr2.m_pEnt && tr2.m_pEnt->GetMoveType() == MOVETYPE_NONE ) ) { CEffectData data; data.m_vOrigin = tr2.endpos; data.m_vNormal = vForward; data.m_nEntIndex = tr2.fraction != 1.0f; //DispatchEffect( "BoltImpact", data ); } } #endif SetTouch( NULL ); SetThink( NULL ); //KillEffects(); //UTIL_Remove( this ); //Release(); SetThink( &CASW_Shotgun_Pellet_Predicted::SUB_Remove ); SetNextThink( gpGlobals->curtime ); } else { trace_t tr; tr = BaseClass::GetTouchTrace(); // See if we struck the world if ( pOther->GetMoveType() == MOVETYPE_NONE && !( tr.surface.flags & SURF_SKY ) ) { //EmitSound( "Weapon_Crossbow.BoltHitWorld" ); // if what we hit is static architecture, can stay around for a while. Vector vecDir = GetAbsVelocity(); VectorNormalize( vecDir ); SetMoveType( MOVETYPE_NONE ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); VectorNormalize ( vForward ); #ifdef GAME_DLL CEffectData data; data.m_vOrigin = tr.endpos; data.m_vNormal = vForward; data.m_nEntIndex = 0; #endif //DispatchEffect( "BoltImpact", data ); UTIL_ImpactTrace( &tr, DMG_BULLET ); AddEffects( EF_NODRAW ); SetTouch( NULL ); //KillEffects(); SetThink( &CASW_Shotgun_Pellet_Predicted::SUB_Remove ); SetNextThink( gpGlobals->curtime + 2.0f ); // Shoot some sparks #ifdef GAME_DLL if ( UTIL_PointContents( GetAbsOrigin(), CONTENTS_WATER ) != CONTENTS_WATER) { g_pEffects->Sparks( GetAbsOrigin() ); } #endif } else { // Put a mark unless we've hit the sky if ( ( tr.surface.flags & SURF_SKY ) == false ) { UTIL_ImpactTrace( &tr, DMG_BULLET ); } //KillEffects(); //UTIL_Remove( this ); //Release(); SetThink( &CASW_Shotgun_Pellet_Predicted::SUB_Remove ); SetNextThink( gpGlobals->curtime ); } } }
//------------------------------------------------------------------------------ // Purpose : //------------------------------------------------------------------------------ void C_DynamicLight::ClientThink(void) { Vector forward; AngleVectors( GetAbsAngles(), &forward ); if ( (m_Flags & DLIGHT_NO_MODEL_ILLUMINATION) == 0 ) { // Deal with the model light if ( !m_pDynamicLight || (m_pDynamicLight->key != index) ) { #if DLIGHT_NO_WORLD_USES_ELIGHT m_pDynamicLight = ShouldBeElight() != 0 ? effects->CL_AllocElight( index ) : effects->CL_AllocDlight( index ); #else m_pDynamicLight = effects->CL_AllocDlight( index ); #endif Assert (m_pDynamicLight); m_pDynamicLight->minlight = 0; } m_pDynamicLight->style = m_LightStyle; m_pDynamicLight->radius = m_Radius; m_pDynamicLight->flags = m_Flags; if ( m_OuterAngle > 0 ) m_pDynamicLight->flags |= DLIGHT_NO_WORLD_ILLUMINATION; m_pDynamicLight->color.r = m_clrRender->r; m_pDynamicLight->color.g = m_clrRender->g; m_pDynamicLight->color.b = m_clrRender->b; m_pDynamicLight->color.exponent = m_Exponent; // this makes it match the world m_pDynamicLight->origin = GetAbsOrigin(); m_pDynamicLight->m_InnerAngle = m_InnerAngle; m_pDynamicLight->m_OuterAngle = m_OuterAngle; m_pDynamicLight->die = gpGlobals->curtime + 1e6; m_pDynamicLight->m_Direction = forward; } else { // In this case, the m_Flags could have changed; which is how we turn the light off if (m_pDynamicLight) { m_pDynamicLight->die = gpGlobals->curtime; m_pDynamicLight = 0; } } #if DLIGHT_NO_WORLD_USES_ELIGHT if (( m_OuterAngle > 0 ) && !ShouldBeElight()) #else if (( m_OuterAngle > 0 ) && ((m_Flags & DLIGHT_NO_WORLD_ILLUMINATION) == 0)) #endif { // Raycast to where the endpoint goes // Deal with the environment light if ( !m_pSpotlightEnd || (m_pSpotlightEnd->key != -index) ) { m_pSpotlightEnd = effects->CL_AllocDlight( -index ); Assert (m_pSpotlightEnd); } // Trace a line outward, don't use hitboxes (too slow) Vector end; VectorMA( GetAbsOrigin(), m_Radius, forward, end ); trace_t pm; C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace UTIL_TraceLine( GetAbsOrigin(), end, MASK_NPCWORLDSTATIC, NULL, COLLISION_GROUP_NONE, &pm ); C_BaseEntity::PopEnableAbsRecomputations(); VectorCopy( pm.endpos, m_pSpotlightEnd->origin ); if (pm.fraction == 1.0f) { m_pSpotlightEnd->die = gpGlobals->curtime; m_pSpotlightEnd = 0; } else { float falloff = 1.0 - pm.fraction; falloff *= falloff; m_pSpotlightEnd->style = m_LightStyle; m_pSpotlightEnd->flags = DLIGHT_NO_MODEL_ILLUMINATION | (m_Flags & DLIGHT_DISPLACEMENT_MASK); m_pSpotlightEnd->radius = m_SpotRadius; // * falloff; m_pSpotlightEnd->die = gpGlobals->curtime + 1e6; m_pSpotlightEnd->color.r = m_clrRender->r * falloff; m_pSpotlightEnd->color.g = m_clrRender->g * falloff; m_pSpotlightEnd->color.b = m_clrRender->b * falloff; m_pSpotlightEnd->color.exponent = m_Exponent; // For bumped lighting m_pSpotlightEnd->m_Direction = forward; // Update list of surfaces we influence render->TouchLight( m_pSpotlightEnd ); } } else { // In this case, the m_Flags could have changed; which is how we turn the light off if (m_pSpotlightEnd) { m_pSpotlightEnd->die = gpGlobals->curtime; m_pSpotlightEnd = 0; } } SetNextClientThink(gpGlobals->curtime + 0.001); }
void CProjectedDecal::ProjectDecal( CRecipientFilter& filter ) { te->ProjectDecal( filter, 0.0, &GetAbsOrigin(), &GetAbsAngles(), m_flDistance, m_nTexture ); }
//----------------------------------------------------------------------------- // Purpose: // Input : percentage - //----------------------------------------------------------------------------- void C_AlyxEmpEffect::UpdateDischarging( void ) { // Emitters must be valid if ( SetupEmitters() == false ) return; // Reset our sort origin m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() ); float flScale = EMP_SCALE * 8.0f; Vector forward, right, up; AngleVectors( GetAbsAngles(), &forward, &right, &up ); SimpleParticle *sParticle; float dTime = gpGlobals->frametime; while ( m_tParticleSpawn.NextEvent( dTime ) ) { // Base of the core effect sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() ); if ( sParticle == NULL ) return; sParticle->m_vecVelocity = vec3_origin; sParticle->m_flDieTime = 0.25f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = 0.0f; float alpha = 64; sParticle->m_uchColor[0] = alpha; sParticle->m_uchColor[1] = alpha; sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchStartSize = flScale * 4.0f; sParticle->m_uchEndSize = 0.0f; // Base of the core effect sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() ); if ( sParticle == NULL ) return; sParticle->m_vecVelocity = vec3_origin; sParticle->m_flDieTime = 0.1f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = 0.0f; alpha = 128; sParticle->m_uchColor[0] = alpha; sParticle->m_uchColor[1] = alpha; sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchStartSize = 0.0f; sParticle->m_uchEndSize = flScale * 2.0f; // Make sure we encompass the complete particle here! m_pSimpleEmitter->SetParticleCullRadius( sParticle->m_uchEndSize ); // Do the core effects sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() ); if ( sParticle == NULL ) return; sParticle->m_vecVelocity = RandomVector( -32.0f, 32.0f ); sParticle->m_flDieTime = 0.2f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = 0.0f; alpha = 255; sParticle->m_uchColor[0] = alpha; sParticle->m_uchColor[1] = alpha; sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchStartSize = flScale; sParticle->m_uchEndSize = 0.0f; } #if 0 // Do the charging particles m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() ); Vector offset; float dist; for ( i = 0; i < 4; i++ ) { dist = random->RandomFloat( 4.0f, 64.0f ); offset = forward * dist; dist = RemapValClamped( dist, 4.0f, 64.0f, 6.0f, 1.0f ); offset += right * random->RandomFloat( -2.0f * dist, 2.0f * dist ); offset += up * random->RandomFloat( -2.0f * dist, 2.0f * dist ); offset += GetAbsOrigin(); sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/combinemuzzle2_dark" ), offset ); if ( sParticle == NULL ) return; sParticle->m_vecVelocity = Vector(0,0,2); sParticle->m_flDieTime = 0.5f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = 0.0f; float alpha = 255; sParticle->m_uchColor[0] = alpha; sParticle->m_uchColor[1] = alpha; sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchStartSize = 1; sParticle->m_uchEndSize = 0; } #endif }
//----------------------------------------------------------------------------- // Purpose: // Input : *pOther - //----------------------------------------------------------------------------- void CGrappleHook::HookTouch(CBaseEntity *pOther) { if (!pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS)) return; if ((pOther != m_hOwner) && (pOther->m_takedamage != DAMAGE_NO)) { m_hOwner->NotifyHookDied(); SetTouch(NULL); SetThink(NULL); UTIL_Remove(this); } else { trace_t tr; tr = BaseClass::GetTouchTrace(); // See if we struck the world if (pOther->GetMoveType() == MOVETYPE_NONE && !(tr.surface.flags & SURF_SKY)) { EmitSound("Weapon_Crossbow.BoltHitWorld"); // if what we hit is static architecture, can stay around for a while. Vector vecDir = GetAbsVelocity(); //FIXME: We actually want to stick (with hierarchy) to what we've hit SetMoveType(MOVETYPE_NONE); Vector vForward; AngleVectors(GetAbsAngles(), &vForward); VectorNormalize(vForward); CEffectData data; data.m_vOrigin = tr.endpos; data.m_vNormal = vForward; data.m_nEntIndex = 0; // DispatchEffect( "Impact", data ); UTIL_ImpactTrace(&tr, DMG_BULLET); // AddEffects( EF_NODRAW ); SetTouch(NULL); // Shoot some sparks if (UTIL_PointContents(GetAbsOrigin()) != CONTENTS_WATER) { g_pEffects->Sparks(GetAbsOrigin()); } VPhysicsDestroyObject(); VPhysicsInitNormal(SOLID_VPHYSICS, FSOLID_NOT_STANDABLE, false); AddSolidFlags(FSOLID_NOT_SOLID); // SetMoveType( MOVETYPE_NONE ); if (!m_hPlayer) { Assert(0); return; } // Set Jay's gai flag m_hPlayer->SetPhysicsFlag(PFLAG_VPHYSICS_MOTIONCONTROLLER, true); IPhysicsObject *pPhysObject = m_hPlayer->VPhysicsGetObject(); IPhysicsObject *pRootPhysObject = VPhysicsGetObject(); Assert(pRootPhysObject); Assert(pPhysObject); pRootPhysObject->EnableMotion(false); // Root has huge mass, tip has little pRootPhysObject->SetMass(VPHYSICS_MAX_MASS); // pPhysObject->SetMass( 100 ); // float damping = 3; // pPhysObject->SetDamping( &damping, &damping ); Vector origin = m_hPlayer->GetAbsOrigin(); Vector rootOrigin = GetAbsOrigin(); m_fSpringLength = (origin - rootOrigin).Length(); springparams_t spring; spring.constant = 8000; spring.damping = 400; spring.naturalLength = m_fSpringLength; spring.relativeDamping = 2; spring.startPosition = origin; spring.endPosition = rootOrigin; spring.useLocalPositions = false; spring.onlyStretch = false; m_pSpring = physenv->CreateSpring(pPhysObject, pRootPhysObject, &spring); m_bPlayerWasStanding = ((m_hPlayer->GetFlags() & FL_DUCKING) == 0); SetThink(&CGrappleHook::HookedThink); SetNextThink(gpGlobals->curtime + 0.1f); } else { // Put a mark unless we've hit the sky if ((tr.surface.flags & SURF_SKY) == false) { UTIL_ImpactTrace(&tr, DMG_BULLET); } SetTouch(NULL); SetThink(NULL); m_hOwner->NotifyHookDied(); UTIL_Remove(this); } } }
void C_EnvProjectedTexture::UpdateLight( void ) { VPROF("C_EnvProjectedTexture::UpdateLight"); bool bVisible = true; Vector vLinearFloatLightColor( m_LightColor.r, m_LightColor.g, m_LightColor.b ); float flLinearFloatLightAlpha = m_LightColor.a; if ( m_bAlwaysUpdate ) { m_bForceUpdate = true; } if ( m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha ) { float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f; m_CurrentLinearFloatLightColor.x = Approach( vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed ); m_CurrentLinearFloatLightColor.y = Approach( vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed ); m_CurrentLinearFloatLightColor.z = Approach( vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed ); m_flCurrentLinearFloatLightAlpha = Approach( flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed ); m_bForceUpdate = true; } if ( !m_bForceUpdate ) { bVisible = IsBBoxVisible(); } if ( m_bState == false || !bVisible ) { // Spotlight's extents aren't in view ShutDownLightHandle(); return; } if ( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE || m_hTargetEntity != NULL || m_bForceUpdate ) { Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); FlashlightState_t state; if ( m_hTargetEntity != NULL ) { if ( m_bCameraSpace ) { const QAngle &angles = GetLocalAngles(); C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if( pPlayer ) { const QAngle playerAngles = pPlayer->GetAbsAngles(); Vector vPlayerForward, vPlayerRight, vPlayerUp; AngleVectors( playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp ); matrix3x4_t mRotMatrix; AngleMatrix( angles, mRotMatrix ); VectorITransform( vPlayerForward, mRotMatrix, vForward ); VectorITransform( vPlayerRight, mRotMatrix, vRight ); VectorITransform( vPlayerUp, mRotMatrix, vUp ); float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; VectorNormalize( vForward ); VectorNormalize( vRight ); VectorNormalize( vUp ); } } else { // VXP: Fixing targeting Vector vecToTarget; QAngle vecAngles; if ( m_hTargetEntity == NULL ) { vecAngles = GetAbsAngles(); } else { vecToTarget = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); VectorAngles( vecToTarget, vecAngles ); } AngleVectors( vecAngles, &vForward, &vRight, &vUp ); } } else { AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp ); } state.m_fHorizontalFOVDegrees = m_flLightFOV; state.m_fVerticalFOVDegrees = m_flLightFOV; state.m_vecLightOrigin = vPos; BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); state.m_NearZ = m_flNearZ; state.m_FarZ = m_flFarZ; // quickly check the proposed light's bbox against the view frustum to determine whether we // should bother to create it, if it doesn't exist, or cull it, if it does. if ( m_bSimpleProjection == false ) { #pragma message("OPTIMIZATION: this should be made SIMD") // get the half-widths of the near and far planes, // based on the FOV which is in degrees. Remember that // on planet Valve, x is forward, y left, and z up. const float tanHalfAngle = tan( m_flLightFOV * ( M_PI/180.0f ) * 0.5f ); const float halfWidthNear = tanHalfAngle * m_flNearZ; const float halfWidthFar = tanHalfAngle * m_flFarZ; // now we can build coordinates in local space: the near rectangle is eg // (0, -halfWidthNear, -halfWidthNear), (0, halfWidthNear, -halfWidthNear), // (0, halfWidthNear, halfWidthNear), (0, -halfWidthNear, halfWidthNear) VectorAligned vNearRect[4] = { VectorAligned( m_flNearZ, -halfWidthNear, -halfWidthNear), VectorAligned( m_flNearZ, halfWidthNear, -halfWidthNear), VectorAligned( m_flNearZ, halfWidthNear, halfWidthNear), VectorAligned( m_flNearZ, -halfWidthNear, halfWidthNear) }; VectorAligned vFarRect[4] = { VectorAligned( m_flFarZ, -halfWidthFar, -halfWidthFar), VectorAligned( m_flFarZ, halfWidthFar, -halfWidthFar), VectorAligned( m_flFarZ, halfWidthFar, halfWidthFar), VectorAligned( m_flFarZ, -halfWidthFar, halfWidthFar) }; matrix3x4_t matOrientation( vForward, -vRight, vUp, vPos ); enum { kNEAR = 0, kFAR = 1, }; VectorAligned vOutRects[2][4]; for ( int i = 0 ; i < 4 ; ++i ) { VectorTransform( vNearRect[i].Base(), matOrientation, vOutRects[0][i].Base() ); } for ( int i = 0 ; i < 4 ; ++i ) { VectorTransform( vFarRect[i].Base(), matOrientation, vOutRects[1][i].Base() ); } // now take the min and max extents for the bbox, and see if it is visible. Vector mins = **vOutRects; Vector maxs = **vOutRects; for ( int i = 1; i < 8 ; ++i ) { VectorMin( mins, *(*vOutRects+i), mins ); VectorMax( maxs, *(*vOutRects+i), maxs ); } #if 0 //for debugging the visibility frustum we just calculated NDebugOverlay::Triangle( vOutRects[0][0], vOutRects[0][1], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f ); //first tri NDebugOverlay::Triangle( vOutRects[0][2], vOutRects[0][1], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f ); //make it double sided NDebugOverlay::Triangle( vOutRects[0][2], vOutRects[0][3], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f ); //second tri NDebugOverlay::Triangle( vOutRects[0][0], vOutRects[0][3], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f ); //make it double sided NDebugOverlay::Triangle( vOutRects[1][0], vOutRects[1][1], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f ); //first tri NDebugOverlay::Triangle( vOutRects[1][2], vOutRects[1][1], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f ); //make it double sided NDebugOverlay::Triangle( vOutRects[1][2], vOutRects[1][3], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f ); //second tri NDebugOverlay::Triangle( vOutRects[1][0], vOutRects[1][3], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f ); //make it double sided NDebugOverlay::Box( vec3_origin, mins, maxs, 0, 255, 0, 100, 0.0f ); #endif bool bVisible = IsBBoxVisible( mins, maxs ); if (!bVisible) { // Spotlight's extents aren't in view if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) { ShutDownLightHandle(); } return; } } float flAlpha = m_flCurrentLinearFloatLightAlpha * ( 1.0f / 255.0f ); state.m_fQuadraticAtten = 0.0; state.m_fLinearAtten = 100; state.m_fConstantAtten = 0.0f; state.m_FarZAtten = m_flFarZ; state.m_fBrightnessScale = m_flBrightnessScale; state.m_Color[0] = m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[1] = m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[2] = m_CurrentLinearFloatLightColor.z * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; state.m_flShadowSlopeScaleDepthBias = g_pMaterialSystemHardwareConfig->GetShadowSlopeScaleDepthBias(); state.m_flShadowDepthBias = g_pMaterialSystemHardwareConfig->GetShadowDepthBias(); state.m_bEnableShadows = m_bEnableShadows; state.m_pSpotlightTexture = m_SpotlightTexture; state.m_pProjectedMaterial = NULL; // only complain if we're using material projection state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; state.m_flProjectionSize = m_flProjectionSize; state.m_flProjectionRotation = m_flRotation; state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality if ( m_bSimpleProjection == true ) { state.m_bSimpleProjection = true; state.m_bOrtho = true; state.m_fOrthoLeft = -m_flProjectionSize; state.m_fOrthoTop = -m_flProjectionSize; state.m_fOrthoRight = m_flProjectionSize; state.m_fOrthoBottom = m_flProjectionSize; } if( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE ) { // Hack: env projected textures don't work like normal flashlights; they're not assigned to a given splitscreen slot, // but the flashlight code requires this HACK_GETLOCALPLAYER_GUARD( "Env projected texture" ); if ( m_bSimpleProjection == true ) { m_LightHandle = g_pClientShadowMgr->CreateProjection( state ); } else { m_LightHandle = g_pClientShadowMgr->CreateFlashlight( state ); } if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) { m_bForceUpdate = false; } } else { if ( m_bSimpleProjection == true ) { g_pClientShadowMgr->UpdateProjectionState( m_LightHandle, state ); } else { g_pClientShadowMgr->UpdateFlashlightState( m_LightHandle, state ); } m_bForceUpdate = false; } g_pClientShadowMgr->GetFrustumExtents( m_LightHandle, m_vecExtentsMin, m_vecExtentsMax ); m_vecExtentsMin = m_vecExtentsMin - GetAbsOrigin(); m_vecExtentsMax = m_vecExtentsMax - GetAbsOrigin(); } if( m_bLightOnlyTarget ) { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, m_hTargetEntity ); } else { g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, NULL ); } g_pClientShadowMgr->SetFlashlightLightWorld( m_LightHandle, m_bLightWorld ); if ( !asw_perf_wtf.GetBool() && !m_bForceUpdate ) { g_pClientShadowMgr->UpdateProjectedTexture( m_LightHandle, true ); } }
//========================================================= // SonicAttack //========================================================= void CNPC_Houndeye::SonicAttack ( void ) { EmitSound( "NPC_Houndeye.SonicAttack" ); if (m_pEnergyWave) { UTIL_Remove(m_pEnergyWave); } Vector vFacingDir = EyeDirection3D( ); m_pEnergyWave = (CEnergyWave*)Create( "energy_wave", EyePosition(), GetLocalAngles() ); m_flEndEnergyWaveTime = gpGlobals->curtime + 1; //<<TEMP>> magic m_pEnergyWave->SetAbsVelocity( 100*vFacingDir ); CBaseEntity *pEntity = NULL; // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( GetAbsOrigin(), HOUNDEYE_MAX_ATTACK_RADIUS ); pEntity = sphere.GetCurrentEntity(); sphere.NextEntity() ) { if (pEntity->Classify() == CLASS_HOUNDEYE) { continue; } if (pEntity->GetFlags() & FL_NOTARGET) { continue; } IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject(); if ( pEntity->m_takedamage != DAMAGE_NO || pPhysicsObject) { // -------------------------- // Adjust damage by distance // -------------------------- float flDist = (pEntity->WorldSpaceCenter() - GetAbsOrigin()).Length(); float flDamageAdjuster = 1-( flDist / HOUNDEYE_MAX_ATTACK_RADIUS ); // -------------------------- // Adjust damage by direction // -------------------------- Vector forward; AngleVectors( GetAbsAngles(), &forward ); Vector vEntDir = (pEntity->GetAbsOrigin() - GetAbsOrigin()); VectorNormalize(vEntDir); float flDotPr = DotProduct(forward,vEntDir); flDamageAdjuster *= flDotPr; if (flDamageAdjuster < 0) { continue; } // -------------------------- // Adjust damage by visibility // -------------------------- if ( !FVisible( pEntity ) ) { if ( pEntity->IsPlayer() ) { // if this entity is a client, and is not in full view, inflict half damage. We do this so that players still // take the residual damage if they don't totally leave the houndeye's effective radius. We restrict it to clients // so that monsters in other parts of the level don't take the damage and get pissed. flDamageAdjuster *= 0.5; } else if ( !FClassnameIs( pEntity, "func_breakable" ) && !FClassnameIs( pEntity, "func_pushable" ) ) { // do not hurt nonclients through walls, but allow damage to be done to breakables continue; } } // ------------------------------ // Apply the damage // ------------------------------ if (pEntity->m_takedamage != DAMAGE_NO) { CTakeDamageInfo info( this, this, flDamageAdjuster * sk_Houndeye_dmg_blast.GetFloat(), DMG_SONIC | DMG_ALWAYSGIB ); CalculateExplosiveDamageForce( &info, (pEntity->GetAbsOrigin() - GetAbsOrigin()), pEntity->GetAbsOrigin() ); pEntity->TakeDamage( info ); // Throw the player if ( pEntity->IsPlayer() ) { Vector forward; AngleVectors( GetLocalAngles(), &forward ); Vector vecVelocity = pEntity->GetAbsVelocity(); vecVelocity += forward * 250 * flDamageAdjuster; vecVelocity.z = 300 * flDamageAdjuster; pEntity->SetAbsVelocity( vecVelocity ); pEntity->ViewPunch( QAngle(random->RandomInt(-20,20), 0, random->RandomInt(-20,20)) ); } } // ------------------------------ // Apply physics foces // ------------------------------ IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject(); if (pPhysicsObject) { float flForce = flDamageAdjuster * 8000; pPhysicsObject->ApplyForceCenter( (vEntDir+Vector(0,0,0.2)) * flForce ); pPhysicsObject->ApplyTorqueCenter( vEntDir * flForce ); } } } }
bool CVehicleMortar::CalcFireInfo( float flFiringPower, float flFiringAccuracy, bool bRangeUpgraded, bool bAccuracyUpgraded, Vector &vStartPt, Vector &vecTargetVel, float &fallTime ) { QAngle dummy; if ( !GetAttachment( "barrel", vStartPt, dummy ) ) vStartPt = WorldSpaceCenter(); // Get target distance float flDistance; if ( bRangeUpgraded ) { flDistance = MORTAR_RANGE_MIN + (flFiringPower * (MORTAR_RANGE_MAX_UPGRADED - MORTAR_RANGE_MIN)); } else { flDistance = MORTAR_RANGE_MIN + (flFiringPower * (MORTAR_RANGE_MAX_INITIAL - MORTAR_RANGE_MIN)); } // Factor in inaccuracy float flInaccuracy; if ( bAccuracyUpgraded ) { flInaccuracy = MORTAR_INACCURACY_MAX_UPGRADED * (flFiringAccuracy * 4); // flFiringAccuracy is a range from -0.25 to 0.25 } else { flInaccuracy = MORTAR_INACCURACY_MAX_INITIAL * (flFiringAccuracy * 4); // flFiringAccuracy is a range from -0.25 to 0.25 } flDistance += (flDistance * MORTAR_DIST_INACCURACY) * random->RandomFloat( -flInaccuracy, flInaccuracy ); float flAngle = GetAbsAngles()[YAW] + m_flMortarYaw; Vector forward( -sin( DEG2RAD( flAngle ) ), cos( DEG2RAD( flAngle ) ), 0 ); Vector right( forward.y, -forward.x, 0 ); Vector vecTargetOrg = vStartPt + (forward * flDistance); // Add in sideways inaccuracy vecTargetOrg += (right * (flDistance * random->RandomFloat( -flInaccuracy, flInaccuracy )) ); // Trace down from the sky and find the point we're actually going to hit trace_t tr; Vector vecSky = vecTargetOrg + Vector(0,0,1024); UTIL_TraceLine( vecSky, vecTargetOrg, MASK_ALL, this, COLLISION_GROUP_NONE, &tr ); vecTargetOrg = tr.endpos; Vector vecMidPoint = vec3_origin; // Start with a low arc, and keep aiming higher until we've got a roughly clear shot for (int i = 512; i <= 4096; i += 512) { trace_t tr1; trace_t tr2; vecMidPoint = Vector(0,0,i) + vStartPt + (vecTargetOrg - vStartPt) * 0.5; UTIL_TraceLine(vStartPt, vecMidPoint, MASK_ALL, this, COLLISION_GROUP_NONE, &tr1); UTIL_TraceLine(vecMidPoint, vecTargetOrg, MASK_ALL, this, COLLISION_GROUP_NONE, &tr2); // Clear shot? // We want a clear shot for the first half, and a fairly clear shot on the fall if ( tr1.fraction == 1 && tr2.fraction > 0.5 ) break; } // How high should we travel to reach the apex float distance1 = (vecMidPoint.z - vStartPt.z); float distance2 = (vecMidPoint.z - vecTargetOrg.z); // How long will it take to travel this distance float flGravity = sv_gravity.GetFloat(); float time1 = sqrt( distance1 / (0.5 * flGravity) ); float time2 = sqrt( distance2 / (0.5 * flGravity) ); if (time1 < 0.1) return false; // how hard to launch to get there in time. vecTargetVel = (vecTargetOrg - vStartPt) / (time1 + time2); vecTargetVel.z = flGravity * time1; fallTime = time1 * 0.5; return true; }
//========================================================= // RunTask //========================================================= void CNPC_Controller::RunTask ( const Task_t *pTask ) { if (m_flShootEnd > gpGlobals->curtime) { Vector vecHand; QAngle vecAngle; GetAttachment( 2, vecHand, vecAngle ); while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->curtime) { Vector vecSrc = vecHand + GetAbsVelocity() * (m_flShootTime - gpGlobals->curtime); Vector vecDir; if (GetEnemy() != NULL) { if (HasCondition( COND_SEE_ENEMY )) { m_vecEstVelocity = m_vecEstVelocity * 0.5 + GetEnemy()->GetAbsVelocity() * 0.5; } else { m_vecEstVelocity = m_vecEstVelocity * 0.8; } vecDir = Intersect( vecSrc, GetEnemy()->BodyTarget( GetAbsOrigin() ), m_vecEstVelocity, sk_controller_speedball.GetFloat() ); float delta = 0.03490; // +-2 degree vecDir = vecDir + Vector( random->RandomFloat( -delta, delta ), random->RandomFloat( -delta, delta ), random->RandomFloat( -delta, delta ) ) * sk_controller_speedball.GetFloat(); vecSrc = vecSrc + vecDir * (gpGlobals->curtime - m_flShootTime); CAI_BaseNPC *pBall = (CAI_BaseNPC*)Create( "controller_energy_ball", vecSrc, GetAbsAngles(), this ); pBall->SetAbsVelocity( vecDir ); // DevMsg( 2, "controller shooting energy ball\n" ); } m_flShootTime += 0.2; } if (m_flShootTime > m_flShootEnd) { m_iBall[0] = 64; m_iBallTime[0] = m_flShootEnd; m_iBall[1] = 64; m_iBallTime[1] = m_flShootEnd; m_fInCombat = FALSE; } } switch ( pTask->iTask ) { case TASK_WAIT_FOR_MOVEMENT: case TASK_WAIT: case TASK_WAIT_FACE_ENEMY: case TASK_WAIT_PVS: { if( GetEnemy() ) { float idealYaw = UTIL_VecToYaw( GetEnemy()->GetAbsOrigin() - GetAbsOrigin() ); GetMotor()->SetIdealYawAndUpdate( idealYaw ); } if ( IsSequenceFinished() || GetActivity() == ACT_IDLE) { m_fInCombat = false; } BaseClass::RunTask ( pTask ); if (!m_fInCombat) { if( HasCondition( COND_CAN_RANGE_ATTACK1 )) { SetActivity( ACT_RANGE_ATTACK1 ); SetCycle( 0 ); ResetSequenceInfo( ); m_fInCombat = true; } else if( HasCondition( COND_CAN_RANGE_ATTACK2 ) ) { SetActivity( ACT_RANGE_ATTACK2 ); SetCycle( 0 ); ResetSequenceInfo( ); m_fInCombat = true; } else { int iFloatActivity = LookupFloat(); if( IsSequenceFinished() || iFloatActivity != GetActivity() ) { SetActivity( (Activity)iFloatActivity ); } } } } break; default: BaseClass::RunTask ( pTask ); break; } }
//========================================================= // SelectSchedule //========================================================= int CNPC_Houndeye::SelectSchedule( void ) { switch ( m_NPCState ) { case NPC_STATE_IDLE: case NPC_STATE_ALERT: { if ( HasCondition(COND_LIGHT_DAMAGE) || HasCondition(COND_HEAVY_DAMAGE) ) { return SCHED_TAKE_COVER_FROM_ORIGIN; } break; } case NPC_STATE_COMBAT: { // dead enemy if ( HasCondition( COND_ENEMY_DEAD ) ) { // call base class, all code to handle dead enemies is centralized there. return BaseClass::SelectSchedule(); } // If a group attack was requested attack even if attack conditions not met if ( HasCondition( COND_HOUND_GROUP_ATTACK )) { // Check that I'm not standing in another hound eye // before attacking trace_t tr; AI_TraceHull( GetAbsOrigin(), GetAbsOrigin() + Vector(0,0,1), GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if (!tr.startsolid) { return SCHED_HOUND_GROUP_ATTACK; } // Otherwise attack as soon as I can else { m_flNextAttack = gpGlobals->curtime; SCHED_HOUND_ATTACK_STRAFE; } } // If a group retread was requested if ( HasCondition( COND_HOUND_GROUP_RETREAT )) { return SCHED_HOUND_GROUP_RETREAT; } if ( HasCondition( COND_LIGHT_DAMAGE ) | HasCondition( COND_HEAVY_DAMAGE ) ) { if ( random->RandomFloat( 0 , 1 ) <= 0.4 ) { trace_t tr; Vector forward; AngleVectors( GetAbsAngles(), &forward ); AI_TraceHull( GetAbsOrigin(), GetAbsOrigin() + forward * -128, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction == 1.0 ) { // it's clear behind, so the hound will jump return SCHED_HOUND_HOP_RETREAT; } } return SCHED_TAKE_COVER_FROM_ENEMY; } // If a group rally was requested if ( HasCondition( COND_HOUND_GROUP_RALLEY )) { return SCHED_HOUND_GROUP_RALLEY; } if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) ) { if (m_pSquad && random->RandomInt(0,4) == 0) { if (!IsAnyoneInSquadAttacking()) { EmitSound( "NPC_Houndeye.GroupAttack" ); m_flSoundWaitTime = gpGlobals->curtime + 1.0; m_pSquad->BroadcastInteraction( g_interactionHoundeyeGroupAttack, NULL, this ); return SCHED_HOUND_GROUP_ATTACK; } } //<<TEMP>>comment SetCollisionGroup( COLLISION_GROUP_NONE ); return SCHED_RANGE_ATTACK1; } else { if (m_pSquad && random->RandomInt(0,5) == 0) { if (!IsAnyoneInSquadAttacking()) { EmitSound( "NPC_Houndeye.GroupFollow" ); m_flSoundWaitTime = gpGlobals->curtime + 1.0; m_pSquad->BroadcastInteraction( g_interactionHoundeyeGroupRalley, NULL, this ); return SCHED_HOUND_ATTACK_STRAFE; } } return SCHED_HOUND_ATTACK_STRAFE; } break; } } return BaseClass::SelectSchedule(); }
void CASW_Rocket::SeekThink( void ) { // If we have a grace period, go solid when it ends if ( m_flGracePeriodEndsAt ) { if ( m_flGracePeriodEndsAt < gpGlobals->curtime ) { RemoveSolidFlags( FSOLID_NOT_SOLID ); m_flGracePeriodEndsAt = 0; } } Vector vNewVelocity = GetAbsVelocity(); if ( m_bFlyingWild ) { // wobble crazily. Poll for a new target every quarter second, and if none is found, go // careering off. if ( gpGlobals->curtime >= m_flNextWobbleTime ) { Assert( !m_hHomingTarget.Get() ); CBaseEntity *pHomingTarget = FindPotentialTarget(); if ( pHomingTarget ) { SetTarget( pHomingTarget ); m_bFlyingWild = false; } else { // pick a new wobble direction /* m_vWobbleAngles = GetAbsAngles(); m_vWobbleAngles.y = m_vWobbleAngles.y + RandomFloat( -asw_rocket_wobble_amp.GetFloat(), asw_rocket_wobble_amp.GetFloat() ) ; if ( m_vWobbleAngles.y < 0 ) { m_vWobbleAngles.y = 360 + m_vWobbleAngles.y; } else if ( m_vWobbleAngles.y > 360 ) { m_vWobbleAngles.y = fmod( m_vWobbleAngles.y, 360 ); } */ m_vWobbleAngles = GetAbsAngles(); m_vWobbleAngles.y = fmodf( m_vWobbleAngles.y + RandomFloat( -asw_rocket_wobble_amp.GetFloat(), asw_rocket_wobble_amp.GetFloat() ), 360 ); m_flNextWobbleTime = gpGlobals->curtime + asw_rocket_wobble_freq.GetFloat(); } } } if ( !m_bFlyingWild ) { Vector targetPos; FindHomingPosition( &targetPos ); // find target direction Vector vTargetDir; VectorSubtract( targetPos, GetAbsOrigin(), vTargetDir ); float flDist = VectorNormalize( vTargetDir ); // find current direction Vector vDir = GetAbsVelocity(); //float flSpeed = VectorNormalize( vDir ); vNewVelocity = IntegrateRocketThrust( vTargetDir, flDist ); // face direction of movement QAngle finalAngles; VectorAngles( vNewVelocity, finalAngles ); SetAbsAngles( finalAngles ); // set to the new calculated velocity SetAbsVelocity( vNewVelocity ); } else // wobble crazily { #pragma message("TODO: straighten out this math") if ( gpGlobals->curtime >= m_flNextWobbleTime ) { // pick a new wobble direction m_vWobbleAngles = GetAbsAngles(); m_vWobbleAngles.y = fmodf( m_vWobbleAngles.y + RandomFloat( -asw_rocket_wobble_amp.GetFloat(), asw_rocket_wobble_amp.GetFloat() ), 360 ); m_flNextWobbleTime = gpGlobals->curtime + asw_rocket_wobble_freq.GetFloat(); } QAngle finalAngles = GetAbsAngles(); finalAngles.y = ApproachAngle( m_vWobbleAngles.y, finalAngles.y, 360.f * (gpGlobals->curtime - GetLastThink()) ); Vector forward; AngleVectors( finalAngles, &forward ); vNewVelocity = forward * FastSqrtEst( vNewVelocity.LengthSqr() ); if ( IsWallDodging() ) { ComputeWallDodge( vNewVelocity ); finalAngles.y = ApproachAngle( m_vWobbleAngles.y, finalAngles.y, 360.f * (gpGlobals->curtime - GetLastThink()) ); } vNewVelocity = IntegrateRocketThrust( forward, 0 ); // face direction of movement SetAbsAngles( finalAngles ); // set to the new calculated velocity SetAbsVelocity( vNewVelocity ); } // blow us up after our lifetime if (GetLifeFraction() >= 1.0f) { Explode(); } else { // Think as soon as possible SetNextThink( gpGlobals->curtime ); } }
CBaseEntity * CASW_Rocket::FindPotentialTarget( void ) const { float bestdist = 0; CBaseEntity *bestent = NULL; Vector v_forward, v_right, v_up; AngleVectors( GetAbsAngles(), &v_forward, &v_right, &v_up ); // find the aimtarget nearest us int count = AimTarget_ListCount(); if ( count ) { CBaseEntity **pList = (CBaseEntity **)stackalloc( sizeof(CBaseEntity *) * count ); AimTarget_ListCopy( pList, count ); CTraceFilterSkipTwoEntities filter(this, GetOwnerEntity(), COLLISION_GROUP_NONE); for ( int i = 0; i < count; i++ ) { CBaseEntity *pEntity = pList[i]; if (!pEntity || !pEntity->IsAlive() || !pEntity->edict() || !pEntity->IsNPC() ) { //Msg("not alive or not an edict, skipping\n"); continue; } if (!pEntity || !pEntity->IsAlive() || !pEntity->edict() || !pEntity->IsNPC() ) { //Msg("not alive or not an edict, skipping\n"); continue; } // don't autoaim onto marines if (pEntity->Classify() == CLASS_ASW_MARINE || pEntity->Classify() == CLASS_ASW_COLONIST) continue; if ( pEntity->Classify() == CLASS_ASW_PARASITE ) { CASW_Parasite *pParasite = static_cast< CASW_Parasite* >( pEntity ); if ( pParasite->m_bInfesting ) { continue; } } Vector center = pEntity->BodyTarget( GetAbsOrigin() ); Vector center_flat = center; center_flat.z = GetAbsOrigin().z; Vector dir = (center - GetAbsOrigin()); VectorNormalize( dir ); Vector dir_flat = (center_flat - GetAbsOrigin()); VectorNormalize( dir_flat ); // make sure it's in front of the rocket float dot = DotProduct (dir, v_forward ); //if (dot < 0) //{ //continue; //} float dist = (pEntity->GetAbsOrigin() - GetAbsOrigin()).LengthSqr(); if (dist > ASW_ROCKET_MAX_HOMING_RANGE) continue; // check another marine isn't between us and the target to reduce FF trace_t tr; UTIL_TraceLine(GetAbsOrigin(), pEntity->WorldSpaceCenter(), MASK_SHOT, &filter, &tr); if (tr.fraction < 1.0f && tr.m_pEnt != pEntity && tr.m_pEnt && tr.m_pEnt->Classify() == CLASS_ASW_MARINE) continue; // does this critter already have enough rockets to kill it? { CASW_DamageAllocationMgr::IndexType_t assignmentIndex = m_RocketAssigner.Find( pEntity ); if ( m_RocketAssigner.IsValid(assignmentIndex) ) { if ( m_RocketAssigner[assignmentIndex].m_flAccumulatedDamage > pEntity->GetHealth() ) { continue; } } } // check another marine isn't between us and the target to reduce FF UTIL_TraceLine(GetAbsOrigin(), pEntity->WorldSpaceCenter(), MASK_SHOT, &filter, &tr); if (tr.fraction < 1.0f && tr.m_pEnt != pEntity && tr.m_pEnt && tr.m_pEnt->Classify() == CLASS_ASW_MARINE) continue; // increase distance if dot isn't towards us dist += (1.0f - dot) * 150; // bias of x units when object is 90 degrees to the side if (bestdist == 0 || dist < bestdist) { bestdist = dist; bestent = pEntity; } } if ( bestent && asw_rocket_debug.GetBool() ) { Vector center = bestent->BodyTarget( GetAbsOrigin() ); Vector center_flat = center; center_flat.z = GetAbsOrigin().z; Vector dir = (center - GetAbsOrigin()); VectorNormalize( dir ); Msg( "Rocket[%d] starting homing in on %s(%d) dir = %f %f %f\n", entindex(), bestent->GetClassname(), bestent->entindex(), VectorExpand( dir ) ); } } return bestent; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CItem_DynamicResupply::SpawnItemFromRatio( int nCount, DynamicResupplyItems_t *pItems, int iDebug, SpawnInfo_t *pSpawnInfo, Vector *pVecSpawnOrigin ) { // Now find the one we're farthest from float flFarthest = 0; int iSelectedIndex = -1; for ( int i = 0; i < nCount; ++i ) { if ( pSpawnInfo[i].m_flDelta > flFarthest ) { flFarthest = pSpawnInfo[i].m_flDelta; iSelectedIndex = i; } } if ( iSelectedIndex < 0 ) return false; if ( iDebug ) { Msg("Chosen item: %s (had farthest delta, %.2f)\n", pItems[iSelectedIndex].sEntityName, pSpawnInfo[iSelectedIndex].m_flDelta ); } CBaseEntity *pEnt = CBaseEntity::Create( pItems[iSelectedIndex].sEntityName, *pVecSpawnOrigin, GetAbsAngles(), this ); pEnt->SetAbsVelocity( GetAbsVelocity() ); pEnt->SetLocalAngularVelocity( GetLocalAngularVelocity() ); // Move the entity up so that it doesn't go below the spawn origin Vector vecWorldMins, vecWorldMaxs; pEnt->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs ); if ( vecWorldMins.z < pVecSpawnOrigin->z ) { float dz = pVecSpawnOrigin->z - vecWorldMins.z; pVecSpawnOrigin->z += dz; vecWorldMaxs.z += dz; pEnt->SetAbsOrigin( *pVecSpawnOrigin ); } // Update the spawn position to spawn them on top of each other pVecSpawnOrigin->z = vecWorldMaxs.z + 6.0f; pVecSpawnOrigin->x += random->RandomFloat( -6, 6 ); pVecSpawnOrigin->y += random->RandomFloat( -6, 6 ); return true; }
void CWeaponStunStick::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ) { switch( pEvent->event ) { case EVENT_WEAPON_MELEE_HIT: { // Trace up or down based on where the enemy is... // But only if we're basically facing that direction Vector vecDirection; AngleVectors( GetAbsAngles(), &vecDirection ); CBaseEntity *pEnemy = pOperator->MyNPCPointer() ? pOperator->MyNPCPointer()->GetEnemy() : NULL; if ( pEnemy ) { Vector vecDelta; VectorSubtract( pEnemy->WorldSpaceCenter(), pOperator->Weapon_ShootPosition(), vecDelta ); VectorNormalize( vecDelta ); Vector2D vecDelta2D = vecDelta.AsVector2D(); Vector2DNormalize( vecDelta2D ); if ( DotProduct2D( vecDelta2D, vecDirection.AsVector2D() ) > 0.8f ) { vecDirection = vecDelta; } } Vector vecEnd; VectorMA( pOperator->Weapon_ShootPosition(), 32, vecDirection, vecEnd ); // Stretch the swing box down to catch low level physics objects CBaseEntity *pHurt = pOperator->CheckTraceHullAttack( pOperator->Weapon_ShootPosition(), vecEnd, Vector(-16,-16,-40), Vector(16,16,16), GetDamageForActivity( GetActivity() ), DMG_CLUB, 0.5f, false ); // did I hit someone? if ( pHurt ) { // play sound WeaponSound( MELEE_HIT ); CBasePlayer *pPlayer = ToBasePlayer( pHurt ); CNPC_MetroPolice *pCop = dynamic_cast<CNPC_MetroPolice *>(pOperator); bool bFlashed = false; if ( pCop != NULL && pPlayer != NULL ) { // See if we need to knock out this target if ( pCop->ShouldKnockOutTarget( pHurt ) ) { float yawKick = random->RandomFloat( -48, -24 ); //Kick the player angles pPlayer->ViewPunch( QAngle( -16, yawKick, 2 ) ); color32 white = {255,255,255,255}; UTIL_ScreenFade( pPlayer, white, 0.2f, 1.0f, FFADE_OUT|FFADE_PURGE|FFADE_STAYOUT ); bFlashed = true; pCop->KnockOutTarget( pHurt ); break; } else { // Notify that we've stunned a target pCop->StunnedTarget( pHurt ); } } // Punch angles if ( pPlayer != NULL && !(pPlayer->GetFlags() & FL_GODMODE) ) { float yawKick = random->RandomFloat( -48, -24 ); //Kick the player angles pPlayer->ViewPunch( QAngle( -16, yawKick, 2 ) ); Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin(); // If the player's on my head, don't knock him up if ( pPlayer->GetGroundEntity() == pOperator ) { dir = vecDirection; dir.z = 0; } VectorNormalize(dir); dir *= 500.0f; //If not on ground, then don't make them fly! if ( !(pPlayer->GetFlags() & FL_ONGROUND ) ) dir.z = 0.0f; //Push the target back pHurt->ApplyAbsVelocityImpulse( dir ); if ( !bFlashed ) { color32 red = {128,0,0,128}; UTIL_ScreenFade( pPlayer, red, 0.5f, 0.1f, FFADE_IN ); } // Force the player to drop anyting they were holding pPlayer->ForceDropOfCarriedPhysObjects(); } // do effect? } else { WeaponSound( MELEE_MISS ); } } break; default: BaseClass::Operator_HandleAnimEvent( pEvent, pOperator ); break; } }
//========================================================= // MoveTurret - handle turret rotation // returns 1 if the turret moved. //========================================================= int CNPC_BaseTurret::MoveTurret(void) { int bMoved = 0; if (m_vecCurAngles.x != m_vecGoalAngles.x) { float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ; m_vecCurAngles.x += 0.1 * m_fTurnRate * flDir; // if we started below the goal, and now we're past, peg to goal if (flDir == 1) { if (m_vecCurAngles.x > m_vecGoalAngles.x) m_vecCurAngles.x = m_vecGoalAngles.x; } else { if (m_vecCurAngles.x < m_vecGoalAngles.x) m_vecCurAngles.x = m_vecGoalAngles.x; } if (m_iOrientation == TURRET_ORIENTATION_FLOOR) SetBoneController(1, m_vecCurAngles.x); else SetBoneController(1, -m_vecCurAngles.x); bMoved = 1; } if (m_vecCurAngles.y != m_vecGoalAngles.y) { float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ; float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y); if (flDist > 180) { flDist = 360 - flDist; flDir = -flDir; } if (flDist > 30) { if (m_fTurnRate < m_iBaseTurnRate * 10) { m_fTurnRate += m_iBaseTurnRate; } } else if (m_fTurnRate > 45) { m_fTurnRate -= m_iBaseTurnRate; } else { m_fTurnRate += m_iBaseTurnRate; } m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir; if (m_vecCurAngles.y < 0) m_vecCurAngles.y += 360; else if (m_vecCurAngles.y >= 360) m_vecCurAngles.y -= 360; if (flDist < (0.05 * m_iBaseTurnRate)) m_vecCurAngles.y = m_vecGoalAngles.y; QAngle angles = GetAbsAngles(); //ALERT(at_console, "%.2f -> %.2f\n", m_vecCurAngles.y, y); if (m_iOrientation == TURRET_ORIENTATION_FLOOR) SetBoneController(0, m_vecCurAngles.y - angles.y ); else SetBoneController(0, angles.y - 180 - m_vecCurAngles.y ); bMoved = 1; } if (!bMoved) m_fTurnRate = m_iBaseTurnRate; //DevMsg(1, "(%.2f, %.2f)->(%.2f, %.2f)\n", m_vecCurAngles.x, // m_vecCurAngles.y, m_vecGoalAngles.x, m_vecGoalAngles.y); return bMoved; }
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); }
void CHL1NPCTalker::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_HL1TALKER_FOLLOW_WALK_PATH_FOR_UNITS: { float distance; distance = (m_vecLastPosition - GetLocalOrigin()).Length2D(); // Walk path until far enough away if ( distance > pTask->flTaskData || GetNavigator()->GetGoalType() == GOALTYPE_NONE ) { TaskComplete(); GetNavigator()->ClearGoal(); // Stop moving } break; } case TASK_TALKER_CLIENT_STARE: case TASK_TALKER_LOOK_AT_CLIENT: { CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); // track head to the client for a while. if ( m_NPCState == NPC_STATE_IDLE && !IsMoving() && !GetExpresser()->IsSpeaking() ) { if ( pPlayer ) { IdleHeadTurn( pPlayer ); } } else { // started moving or talking TaskFail( "moved away" ); return; } if ( pTask->iTask == TASK_TALKER_CLIENT_STARE ) { // fail out if the player looks away or moves away. if ( ( pPlayer->GetAbsOrigin() - GetAbsOrigin() ).Length2D() > TALKER_STARE_DIST ) { // player moved away. TaskFail( NO_TASK_FAILURE ); } Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); if ( UTIL_DotPoints( pPlayer->GetAbsOrigin(), GetAbsOrigin(), vForward ) < m_flFieldOfView ) { // player looked away TaskFail( "looked away" ); } } if ( gpGlobals->curtime > m_flWaitFinished ) { TaskComplete( NO_TASK_FAILURE ); } break; } case TASK_WAIT_FOR_MOVEMENT: { if ( GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { // ALERT(at_console, "walking, talking\n"); IdleHeadTurn( GetSpeechTarget(), GetExpresser()->GetTimeSpeechComplete() - gpGlobals->curtime ); } else if ( GetEnemy() ) { IdleHeadTurn( GetEnemy() ); } BaseClass::RunTask( pTask ); break; } case TASK_FACE_PLAYER: { CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); if ( pPlayer ) { //GetMotor()->SetIdealYaw( pPlayer->GetAbsOrigin() ); IdleHeadTurn( pPlayer ); if ( gpGlobals->curtime > m_flWaitFinished && GetMotor()->DeltaIdealYaw() < 10 ) { TaskComplete(); } } else { TaskFail( FAIL_NO_PLAYER ); } break; } case TASK_TALKER_EYECONTACT: { if (!IsMoving() && GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { // ALERT( at_console, "waiting %f\n", m_flStopTalkTime - gpGlobals->time ); IdleHeadTurn( GetSpeechTarget(), GetExpresser()->GetTimeSpeechComplete() - gpGlobals->curtime ); } BaseClass::RunTask( pTask ); break; } default: { if ( GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { IdleHeadTurn( GetSpeechTarget(), GetExpresser()->GetTimeSpeechComplete() - gpGlobals->curtime ); } else if ( GetEnemy() && m_NPCState == NPC_STATE_COMBAT ) { IdleHeadTurn( GetEnemy() ); } else if ( GetFollowTarget() ) { IdleHeadTurn( GetFollowTarget() ); } BaseClass::RunTask( pTask ); break; } } }
//----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CAI_PolicingBehavior::SelectSchedule( void ) { CBaseEntity *pTarget = m_hPoliceGoal->GetTarget(); // Validate our target if ( pTarget == NULL ) { DevMsg( "ai_goal_police with NULL target entity!\n" ); // Turn us off Disable(); return SCHED_NONE; } // Attack if we're supposed to if ( ( m_flAggressiveTime >= gpGlobals->curtime ) && HasCondition( COND_CAN_MELEE_ATTACK1 ) ) { return SCHED_MELEE_ATTACK1; } // See if we should immediately begin to attack our target if ( HasCondition( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS ) ) { return SelectSuppressSchedule(); } int newSchedule = SCHED_NONE; // See if we're harassing if ( HasCondition( COND_POLICE_TARGET_TOO_CLOSE_HARASS ) ) { newSchedule = SelectHarassSchedule(); } // Return that schedule if it was found if ( newSchedule != SCHED_NONE ) return newSchedule; // If our enemy is set, fogeda'bout it! if ( m_flAggressiveTime < gpGlobals->curtime ) { // Return to your initial spot if ( GetEnemy() ) { GetOuter()->SetEnemy( NULL ); GetOuter()->SetState( NPC_STATE_ALERT ); GetOuter()->GetEnemies()->RefreshMemories(); } HostSetBatonState( false ); m_bTargetIsHostile = false; } // If we just started to police, make sure we're on our mark if ( MaintainGoalPosition() ) return SCHED_POLICE_RETURN_FROM_HARASS; // If I've got my baton on, keep looking at the target if ( HostBatonIsOn() ) return SCHED_POLICE_TRACK_TARGET; // Re-align myself to the goal angles if I've strayed if ( fabs(UTIL_AngleDiff( GetAbsAngles().y, m_hPoliceGoal->GetAbsAngles().y )) > 15 ) return SCHED_POLICE_FACE_ALONG_GOAL; return SCHED_IDLE_STAND; }
//----------------------------------------------------------------------------- // Purpose: Handles all flight movement. // Input : flInterval - Seconds to simulate. //----------------------------------------------------------------------------- void CNPC_Crow::MoveCrowFly( float flInterval ) { // // Bound interval so we don't get ludicrous motion when debugging // or when framerate drops catastrophically. // if (flInterval > 1.0) { flInterval = 1.0; } m_flDangerSoundTime = gpGlobals->curtime + 5.0f; // // Determine the goal of our movement. // Vector vecMoveGoal = GetAbsOrigin(); if ( GetNavigator()->IsGoalActive() ) { vecMoveGoal = GetNavigator()->GetCurWaypointPos(); if ( GetNavigator()->CurWaypointIsGoal() == false ) { AI_ProgressFlyPathParams_t params( MASK_NPCSOLID ); params.bTrySimplify = false; GetNavigator()->ProgressFlyPath( params ); // ignore result, crow handles completion directly // Fly towards the hint. if ( GetNavigator()->GetPath()->GetCurWaypoint() ) { vecMoveGoal = GetNavigator()->GetCurWaypointPos(); } } } else { // No movement goal. vecMoveGoal = GetAbsOrigin(); SetAbsVelocity( vec3_origin ); return; } Vector vecMoveDir = ( vecMoveGoal - GetAbsOrigin() ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); // // Fly towards the movement goal. // float flDistance = ( vecMoveGoal - GetAbsOrigin() ).Length(); if ( vecMoveGoal != m_vDesiredTarget ) { m_vDesiredTarget = vecMoveGoal; } else { m_vCurrentTarget = ( m_vDesiredTarget - GetAbsOrigin() ); VectorNormalize( m_vCurrentTarget ); } float flLerpMod = 0.25f; if ( flDistance <= 256.0f ) { flLerpMod = 1.0f - ( flDistance / 256.0f ); } VectorLerp( vForward, m_vCurrentTarget, flLerpMod, vForward ); if ( flDistance < CROW_AIRSPEED * flInterval ) { if ( GetNavigator()->IsGoalActive() ) { if ( GetNavigator()->CurWaypointIsGoal() ) { m_bReachedMoveGoal = true; } else { GetNavigator()->AdvancePath(); } } else m_bReachedMoveGoal = true; } if ( GetHintNode() ) { AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_FLY, GetAbsOrigin(), GetNavigator()->GetCurWaypointPos(), MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace ); //See if it succeeded if ( IsMoveBlocked( moveTrace.fStatus ) ) { Vector vNodePos = vecMoveGoal; GetHintNode()->GetPosition(this, &vNodePos); GetNavigator()->SetGoal( vNodePos ); } } // // Look to see if we are going to hit anything. // VectorNormalize( vForward ); Vector vecDeflect; if ( Probe( vForward, CROW_AIRSPEED * flInterval, vecDeflect ) ) { vForward = vecDeflect; VectorNormalize( vForward ); } SetAbsVelocity( vForward * CROW_AIRSPEED ); if ( GetAbsVelocity().Length() > 0 && GetNavigator()->CurWaypointIsGoal() && flDistance < CROW_AIRSPEED ) { SetIdealActivity( (Activity)ACT_CROW_LAND ); } //Bank and set angles. Vector vRight; QAngle vRollAngle; VectorAngles( vForward, vRollAngle ); vRollAngle.z = 0; AngleVectors( vRollAngle, NULL, &vRight, NULL ); float flRoll = DotProduct( vRight, vecMoveDir ) * 45; flRoll = clamp( flRoll, -45, 45 ); vRollAngle[ROLL] = flRoll; SetAbsAngles( vRollAngle ); }
void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) { if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() ) return; MDLCACHE_CRITICAL_SECTION(); int nSequences = pStudioHdr->GetNumSeq(); BaseClass::DoAnimationEvents( pStudioHdr ); bool watch = false; // Q_strstr( hdr->name, "rifle" ) ? true : false; CheckForLayerChanges( pStudioHdr, gpGlobals->curtime ); // !!! int j; for (j = 0; j < m_AnimOverlay.Count(); j++) { if ( m_AnimOverlay[j].m_nSequence >= nSequences ) { continue; } mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( m_AnimOverlay[j].m_nSequence ); if ( seqdesc.numevents == 0 ) continue; // stalled? if (m_AnimOverlay[j].m_flCycle == m_flOverlayPrevEventCycle[j]) continue; // check for looping BOOL bLooped = false; if (m_AnimOverlay[j].m_flCycle <= m_flOverlayPrevEventCycle[j]) { if (m_flOverlayPrevEventCycle[j] - m_AnimOverlay[j].m_flCycle > 0.5) { bLooped = true; } else { // things have backed up, which is bad since it'll probably result in a hitch in the animation playback // but, don't play events again for the same time slice return; } } mstudioevent_t *pevent = seqdesc.pEvent( 0 ); // This makes sure events that occur at the end of a sequence occur are // sent before events that occur at the beginning of a sequence. if (bLooped) { for (int i = 0; i < (int)seqdesc.numevents; i++) { // ignore all non-client-side events if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM ) { //TGB: added shared //if ( !( pevent[i].type & AE_TYPE_CLIENT ) ) if ( !( pevent[i].type & AE_TYPE_CLIENT|AE_TYPE_SHARED ) ) continue; } else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system continue; if ( pevent[i].cycle <= m_flOverlayPrevEventCycle[j] ) continue; if ( watch ) { Msg( "%i FE %i Looped cycle %f, prev %f ev %f (time %.3f)\n", gpGlobals->tickcount, pevent[i].event, pevent[i].cycle, m_flOverlayPrevEventCycle[j], m_AnimOverlay[j].m_flCycle, gpGlobals->curtime ); } FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ); } // Necessary to get the next loop working m_flOverlayPrevEventCycle[j] = -0.01; } for (int i = 0; i < (int)seqdesc.numevents; i++) { if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM ) { //TGB: added shared //if ( !( pevent[i].type & AE_TYPE_CLIENT ) ) if ( !( pevent[i].type & AE_TYPE_CLIENT|AE_TYPE_SHARED ) ) continue; } else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system continue; if ( (pevent[i].cycle > m_flOverlayPrevEventCycle[j] && pevent[i].cycle <= m_AnimOverlay[j].m_flCycle) ) { if ( watch ) { Msg( "%i (seq: %d) FE %i Normal cycle %f, prev %f ev %f (time %.3f)\n", gpGlobals->tickcount, m_AnimOverlay[j].m_nSequence, pevent[i].event, pevent[i].cycle, m_flOverlayPrevEventCycle[j], m_AnimOverlay[j].m_flCycle, gpGlobals->curtime ); } FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ); } } m_flOverlayPrevEventCycle[j] = m_AnimOverlay[j].m_flCycle; } }
//----------------------------------------------------------------------------- // Purpose: Stick to an entity (using hierarchy if we can) // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CWeaponStriderBuster::StickToEntity( CBaseEntity *pOther ) { // Make sure the object is travelling fast enough to stick if ( m_flCollisionSpeedSqr > 50 && !m_bNoseDiving ) { // See if this is a valid strider bit if ( ShouldStickToEntity( pOther ) ) { // Attempt to constraint to it if ( CreateConstraintToObject( pOther ) ) { // Only works for striders, at the moment CBaseEntity *pFollowParent = pOther->GetOwnerEntity(); if ( pFollowParent == NULL ) return false; // Allows us to identify our constrained object later SetOwnerEntity( pFollowParent ); // Make a sound EmitSound( "Weapon_StriderBuster.StickToEntity" ); DispatchParticleEffect( "striderbuster_attach", GetAbsOrigin(), GetAbsAngles(), NULL ); if( striderbuster_use_particle_flare.GetBool() ) { // We don't have to save any pointers or handles to this because it's parented to the buster. // So it will die when the buster dies. Yay. CParticleSystem *pFlare = (CParticleSystem *) CreateEntityByName( "info_particle_system" ); if ( pFlare != NULL ) { pFlare->KeyValue( "start_active", "1" ); pFlare->KeyValue( "effect_name", "striderbuster_attached_pulse" ); pFlare->SetParent( this ); pFlare->SetLocalOrigin( vec3_origin ); DispatchSpawn( pFlare ); pFlare->Activate(); } } else { // Create a glow sprite m_hGlowSprite = CSprite::SpriteCreate( "sprites/orangeflare1.vmt", GetLocalOrigin(), false ); Assert( m_hGlowSprite ); if ( m_hGlowSprite != NULL ) { m_hGlowSprite->TurnOn(); m_hGlowSprite->SetTransparency( kRenderWorldGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); m_hGlowSprite->SetAbsOrigin( GetAbsOrigin() ); m_hGlowSprite->SetScale( 5.0f ); m_hGlowSprite->m_nRenderFX = kRenderFxStrobeFaster; m_hGlowSprite->SetGlowProxySize( 16.0f ); m_hGlowSprite->SetParent( this ); } } // Stop touching things SetTouch( NULL ); // Must be a strider CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(pFollowParent); if ( pStrider == NULL ) return false; // Notify the strider we're attaching to him pStrider->StriderBusterAttached( this ); m_OnAttachToStrider.FireOutput( this, this ); // Start the ping sound. SetContextThink( &CWeaponStriderBuster::BusterPingThink, gpGlobals->curtime + BUSTER_PING_SOUND_FREQ, s_pBusterPingThinkContext ); // Don't autodelete this one! WeaponManager_RemoveManaged( this ); return true; } return false; } } return false; }
//----------------------------------------------------------------------------- // Purpose: // Input : percentage - //----------------------------------------------------------------------------- void C_AlyxEmpEffect::UpdateCharging( float percentage ) { // Emitters must be valid if ( SetupEmitters() == false ) return; if ( percentage <= 0.0f ) return; // Reset our sort origin m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() ); float flScale = 4.0f * EMP_SCALE * percentage; SimpleParticle *sParticle; float dTime = gpGlobals->frametime; while ( m_tParticleSpawn.NextEvent( dTime ) ) { // Do the core effects sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() ); if ( sParticle == NULL ) return; sParticle->m_vecVelocity = vec3_origin; sParticle->m_flDieTime = 0.1f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = 0.0f; float alpha = 255 * percentage; sParticle->m_uchColor[0] = alpha; sParticle->m_uchColor[1] = alpha; sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchStartSize = flScale; sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f; } #if 0 // Do the charging particles m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() ); Vector forward, right, up; AngleVectors( GetAbsAngles(), &forward, &right, &up ); Vector offset; float dist; int numParticles = floor( 4.0f * percentage ); for ( i = 0; i < numParticles; i++ ) { dist = random->RandomFloat( 4.0f * percentage, 64.0f * percentage ); offset = forward * dist; dist = RemapValClamped( dist, 4.0f * percentage, 64.0f * percentage, 6.0f, 1.0f ); offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist ); offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist ); offset += GetAbsOrigin(); sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( EMP_PARTICLES ), offset ); if ( sParticle == NULL ) return; sParticle->m_vecVelocity = Vector(0,0,8); sParticle->m_flDieTime = 0.5f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = 0.0f; float alpha = 255 * percentage; sParticle->m_uchColor[0] = alpha; sParticle->m_uchColor[1] = alpha; sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ); sParticle->m_uchEndSize = 0; } #endif }
//----------------------------------------------------------------------------- // Purpose: Intercept damage and decide whether or not we want to trigger // Input : &info - //----------------------------------------------------------------------------- int CWeaponStriderBuster::OnTakeDamage( const CTakeDamageInfo &info ) { // If we're attached, any damage from the player makes us trigger CBaseEntity *pInflictor = info.GetInflictor(); CBaseEntity *pAttacker = info.GetAttacker(); bool bInflictorIsPlayer = ( pInflictor != NULL && pInflictor->IsPlayer() ); bool bAttackerIsPlayer = ( pAttacker != NULL && pAttacker->IsPlayer() ); if ( GetParent() && GetParent()->ClassMatches( g_iszVehicle ) ) { return 0; } // Only take damage from a player, for the moment if ( striderbuster_allow_all_damage.GetBool() || ( IsAttachedToStrider() && ( bAttackerIsPlayer || bInflictorIsPlayer ) ) ) { Detonate(); return 0; } if ( pAttacker && ( pAttacker->Classify() == CLASS_COMBINE || pAttacker->Classify() == CLASS_COMBINE_HUNTER ) ) { if ( VPhysicsGetObject() && !VPhysicsGetObject()->IsMoveable() ) { return 0; } } // Hunters are able to destroy strider busters if ( hunter_hate_held_striderbusters.GetBool() || hunter_hate_thrown_striderbusters.GetBool() || hunter_hate_attached_striderbusters.GetBool() ) { if ( ( GetHealth() > 0 ) && ( pInflictor != NULL ) && FClassnameIs( pInflictor, "hunter_flechette" ) ) { // // Flechette impacts don't hurt the striderbuster unless it's attached to a strider, // but the explosions always do. This is so that held or thrown striderbusters fly // awry because of the flechette, but attached striderbusters break instantly to make // the hunters more effective at defending the strider. // if ( IsAttachedToStrider() || !( info.GetDamageType() & DMG_NEVERGIB ) ) { if( striderbuster_die_detach.GetBool() && IsAttachedToStrider() ) { // Make the buster fall off and break. m_takedamage = DAMAGE_NO; CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(GetOwnerEntity()); Assert( pStrider != NULL ); pStrider->StriderBusterDetached( this ); DestroyConstraint(); // Amplify some lateral force. Vector vecForce = info.GetDamageForce(); vecForce.z = 0.0f; VPhysicsGetObject()->ApplyForceCenter( vecForce * 5.0f ); SetContextThink( NULL, gpGlobals->curtime, s_pBusterPingThinkContext ); SetThink( &CWeaponStriderBuster::BusterDetachThink ); SetNextThink( gpGlobals->curtime ); m_iBusterFlags |= STRIDERBUSTER_FLAG_KNOCKED_OFF_STRIDER; return 0; } else { // Destroy the buster in place // Make sure they know it blew up prematurely. EmitSound( "Weapon_StriderBuster.Dud_Detonate" ); DispatchParticleEffect( "striderbuster_break_flechette", GetAbsOrigin(), GetAbsAngles() ); SetHealth( 0 ); Shatter( info.GetAttacker() ); return 0; } } if ( info.GetDamage() < 5 ) { bool bFirst = ( m_CarryAngles.x == 45 && m_CarryAngles.y == 0 && m_CarryAngles.z == 0); float sinTime = sin( gpGlobals->curtime ); bool bSubtractX = ( bFirst ) ? ( sinTime < 0 ) : ( m_CarryAngles.x < 45 ); m_CarryAngles.x += ( 10.0 + 10.0 * fabsf( sinTime ) + random->RandomFloat( -2.5, 2.5 ) + random->RandomFloat( -2.5, 2.5 ) ) * ( ( bSubtractX ) ? -1.0 : 1.0 ); m_CarryAngles.y = 15 * ( sin( gpGlobals->curtime ) + cos( gpGlobals->curtime * 0.5 ) ) * .5 + random->RandomFloat( -15, 15 ); m_CarryAngles.z = 7.5 * ( sin( gpGlobals->curtime ) + sin( gpGlobals->curtime * 2.0 ) ) * .5 + random->RandomFloat( -7.5, 7.5 ); } return 1; } } // Allow crushing damage if ( info.GetDamageType() & DMG_CRUSH ) return BaseClass::OnTakeDamage( info ); return 0; }
void CTalkMonster :: StartTask( const Task_t& task ) { switch ( task.iTask ) { case TASK_TLK_SPEAK: // ask question or make statement FIdleSpeak(); TaskComplete(); break; case TASK_TLK_RESPOND: // respond to question IdleRespond(); TaskComplete(); break; case TASK_TLK_HELLO: // greet player FIdleHello(); TaskComplete(); break; case TASK_TLK_STARE: // let the player know I know he's staring at me. FIdleStare(); TaskComplete(); break; case TASK_FACE_PLAYER: case TASK_TLK_LOOK_AT_CLIENT: case TASK_TLK_CLIENT_STARE: // track head to the client for a while. m_flWaitFinished = gpGlobals->time + task.flData; break; case TASK_TLK_EYECONTACT: break; case TASK_TLK_IDEALYAW: if (m_hTalkTarget != NULL) { SetYawSpeed( 60 ); float yaw = VecToYaw(m_hTalkTarget->GetAbsOrigin() - GetAbsOrigin()) - GetAbsAngles().y; if (yaw > 180) yaw -= 360; if (yaw < -180) yaw += 360; if (yaw < 0) { SetIdealYaw( min( yaw + 45, 0.0f ) + GetAbsAngles().y ); } else { SetIdealYaw( max( yaw - 45, 0.0f ) + GetAbsAngles().y ); } } TaskComplete(); break; case TASK_TLK_HEADRESET: // reset head position after looking at something m_hTalkTarget = NULL; TaskComplete(); break; case TASK_TLK_STOPSHOOTING: // tell player to stop shooting PlaySentence( m_szGrp[TLK_NOSHOOT], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_NORM ); TaskComplete(); break; case TASK_CANT_FOLLOW: StopFollowing( false ); PlaySentence( m_szGrp[TLK_STOP], RANDOM_FLOAT(2, 2.5), VOL_NORM, ATTN_NORM ); TaskComplete(); break; case TASK_WALK_PATH_FOR_UNITS: m_movementActivity = ACT_WALK; break; case TASK_MOVE_AWAY_PATH: { Vector dir = GetAbsAngles(); dir.y = GetIdealYaw() + 180; Vector move; UTIL_MakeVectorsPrivate( dir, &move, nullptr, nullptr ); dir = GetAbsOrigin() + move * task.flData; if ( MoveToLocation( ACT_WALK, 2, dir ) ) { TaskComplete(); } else if ( FindCover( GetAbsOrigin(), GetViewOffset(), 0, CoverRadius() ) ) { // then try for plain ole cover m_flMoveWaitFinished = gpGlobals->time + 2; TaskComplete(); } else { // nowhere to go? TaskFail(); } } break; case TASK_PLAY_SCRIPT: m_hTalkTarget = NULL; CBaseMonster::StartTask( task ); break; default: CBaseMonster::StartTask( task ); } }
//----------------------------------------------------------------------------- // Purpose: Creates the NPC. //----------------------------------------------------------------------------- void CNPCMaker::MakeNPC( void ) { if (!CanMakeNPC()) return; CAI_BaseNPC *pent = (CAI_BaseNPC*)CreateEntityByName( STRING(m_iszNPCClassname) ); if ( !pent ) { Warning("NULL Ent in NPCMaker!\n" ); return; } // ------------------------------------------------ // Intialize spawned NPC's relationships // ------------------------------------------------ pent->SetRelationshipString( m_RelationshipString ); m_OnSpawnNPC.Set( pent, pent, this ); pent->SetAbsOrigin( GetAbsOrigin() ); // Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC. QAngle angles = GetAbsAngles(); angles.x = 0.0; angles.z = 0.0; pent->SetAbsAngles( angles ); pent->AddSpawnFlags( SF_NPC_FALL_TO_GROUND ); if ( m_spawnflags & SF_NPCMAKER_FADE ) { pent->AddSpawnFlags( SF_NPC_FADE_CORPSE ); } pent->m_spawnEquipment = m_spawnEquipment; pent->SetSquadName( m_SquadName ); pent->SetHintGroup( m_strHintGroup ); ChildPreSpawn( pent ); DispatchSpawn( pent ); pent->SetOwnerEntity( this ); DispatchActivate( pent ); if ( m_ChildTargetName != NULL_STRING ) { // if I have a netname (overloaded), give the child NPC that name as a targetname pent->SetName( m_ChildTargetName ); } ChildPostSpawn( pent ); m_nLiveChildren++;// count this NPC if (!(m_spawnflags & SF_NPCMAKER_INF_CHILD)) { m_nMaxNumNPCs--; if ( IsDepleted() ) { m_OnAllSpawned.FireOutput( this, this ); // Disable this forever. Don't kill it because it still gets death notices SetThink( NULL ); SetUse( NULL ); } } }
void C_BaseHLPlayer::PerformClientSideNPCSpeedModifiers( float flFrameTime, CUserCmd *pCmd ) { if ( m_hClosestNPC == NULL ) { if ( m_flSpeedMod != cl_forwardspeed.GetFloat() ) { float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime); m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_outtime.GetFloat(), 0, m_flExitSpeedMod, cl_forwardspeed.GetFloat() ); } } else { C_AI_BaseNPC *pNPC = dynamic_cast< C_AI_BaseNPC *>( m_hClosestNPC.Get() ); if ( pNPC ) { float flDist = (GetAbsOrigin() - pNPC->GetAbsOrigin()).LengthSqr(); bool bShouldModSpeed = false; // Within range? if ( flDist < pNPC->GetSpeedModifyRadius() ) { // Now, only slowdown if we're facing & running parallel to the target's movement // Facing check first (in 2D) Vector vecTargetOrigin = pNPC->GetAbsOrigin(); Vector los = ( vecTargetOrigin - EyePosition() ); los.z = 0; VectorNormalize( los ); Vector facingDir; AngleVectors( GetAbsAngles(), &facingDir ); float flDot = DotProduct( los, facingDir ); if ( flDot > 0.8 ) { /* // Velocity check (abort if the target isn't moving) Vector vecTargetVelocity; pNPC->EstimateAbsVelocity( vecTargetVelocity ); float flSpeed = VectorNormalize(vecTargetVelocity); Vector vecMyVelocity = GetAbsVelocity(); VectorNormalize(vecMyVelocity); if ( flSpeed > 1.0 ) { // Velocity roughly parallel? if ( DotProduct(vecTargetVelocity,vecMyVelocity) > 0.4 ) { bShouldModSpeed = true; } } else { // NPC's not moving, slow down if we're moving at him //Msg("Dot: %.2f\n", DotProduct( los, vecMyVelocity ) ); if ( DotProduct( los, vecMyVelocity ) > 0.8 ) { bShouldModSpeed = true; } } */ bShouldModSpeed = true; } } if ( !bShouldModSpeed ) { m_hClosestNPC = NULL; m_flSpeedModTime = gpGlobals->curtime + cl_npc_speedmod_outtime.GetFloat(); m_flExitSpeedMod = m_flSpeedMod; return; } else { if ( m_flSpeedMod != pNPC->GetSpeedModifySpeed() ) { float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime); m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_intime.GetFloat(), 0, cl_forwardspeed.GetFloat(), pNPC->GetSpeedModifySpeed() ); } } } } if ( pCmd->forwardmove > 0.0f ) { pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod ); } else { pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod ); } pCmd->sidemove = clamp( pCmd->sidemove, -m_flSpeedMod, m_flSpeedMod ); //Msg( "fwd %f right %f\n", pCmd->forwardmove, pCmd->sidemove ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTemplateNPCMaker::MakeNPC( void ) { // If we should be using the radius spawn method instead, do so if ( m_flRadius && HasSpawnFlags(SF_NPCMAKER_ALWAYSUSERADIUS) ) { MakeNPCInRadius(); return; } if (!CanMakeNPC( ( m_iszDestinationGroup != NULL_STRING ) )) return; CNPCSpawnDestination *pDestination = NULL; if ( m_iszDestinationGroup != NULL_STRING ) { pDestination = FindSpawnDestination(); if ( !pDestination ) { DevMsg( 2, "%s '%s' failed to find a valid spawnpoint in destination group: '%s'\n", GetClassname(), STRING(GetEntityName()), STRING(m_iszDestinationGroup) ); return; } } CAI_BaseNPC *pent = NULL; CBaseEntity *pEntity = NULL; MapEntity_ParseEntity( pEntity, STRING(m_iszTemplateData), NULL ); if ( pEntity != NULL ) { pent = (CAI_BaseNPC *)pEntity; } if ( !pent ) { Warning("NULL Ent in NPCMaker!\n" ); return; } if ( pDestination ) { pent->SetAbsOrigin( pDestination->GetAbsOrigin() ); // Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC. QAngle angles = pDestination->GetAbsAngles(); angles.x = 0.0; angles.z = 0.0; pent->SetAbsAngles( angles ); pDestination->OnSpawnedNPC( pent ); } else { pent->SetAbsOrigin( GetAbsOrigin() ); // Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC. QAngle angles = GetAbsAngles(); angles.x = 0.0; angles.z = 0.0; pent->SetAbsAngles( angles ); } m_OnSpawnNPC.Set( pEntity, pEntity, this ); if ( m_spawnflags & SF_NPCMAKER_FADE ) { pent->AddSpawnFlags( SF_NPC_FADE_CORPSE ); } pent->RemoveSpawnFlags( SF_NPC_TEMPLATE ); if ( ( m_spawnflags & SF_NPCMAKER_NO_DROP ) == false ) { pent->RemoveSpawnFlags( SF_NPC_FALL_TO_GROUND ); // don't fall, slam } ChildPreSpawn( pent ); DispatchSpawn( pent ); pent->SetOwnerEntity( this ); DispatchActivate( pent ); ChildPostSpawn( pent ); m_nLiveChildren++;// count this NPC if (!(m_spawnflags & SF_NPCMAKER_INF_CHILD)) { m_nMaxNumNPCs--; if ( IsDepleted() ) { m_OnAllSpawned.FireOutput( this, this ); // Disable this forever. Don't kill it because it still gets death notices SetThink( NULL ); SetUse( NULL ); } } }
void CASW_Parasite::InfestMarine(CASW_Marine* pMarine) { if ( !pMarine ) return; pMarine->BecomeInfested(this); // attach int attachment = pMarine->LookupAttachment( "chest" ); if ( attachment ) { SetSolid( SOLID_NONE ); SetMoveType( MOVETYPE_NONE ); QAngle current(0,0,0); Vector diff = pMarine->GetAbsOrigin() - GetAbsOrigin(); float angle = UTIL_VecToYaw(diff); angle -= pMarine->GetAbsAngles()[YAW]; // get the diff between our angle from the marine and the marine's facing; current = GetAbsAngles(); Vector vAttachmentPos; pMarine->GetAttachment( attachment, vAttachmentPos ); // Make sure it's near the chest attachement before parenting Teleport( &vAttachmentPos, &vec3_angle, &vec3_origin ); SetParent( pMarine, attachment ); float flRaise = RandomFloat( 15.0f, 18.0f ); float flForward = RandomFloat( -3.0f, 0.0f ); float flSide = RandomFloat( 1.75f, 3.0f ) * ( RandomInt( 0, 1 ) == 0 ? 1.0f : -1.0f ); if ( asw_debug_alien_damage.GetBool() ) { Msg( "INFEST: flRaise = %f flForward = %f flSide = %f yaw = %f\n", flRaise, flForward, flSide, angle + asw_infest_angle.GetFloat() ); } SetLocalOrigin( Vector( flForward, flSide, flRaise ) ); SetLocalAngles( QAngle( asw_infest_pitch.GetFloat(), angle + asw_infest_angle.GetFloat(), 0 ) ); // play our infesting anim if ( asw_parasite_inside.GetBool() ) { SetActivity(ACT_RANGE_ATTACK2); } else { int iInfestAttack = LookupSequence("Infest_attack"); if (GetSequence() != iInfestAttack) { ResetSequence(iInfestAttack); } } AddFlag( FL_NOTARGET ); SetThink( &CASW_Parasite::InfestThink ); SetTouch( NULL ); m_bInfesting = true; } else { FinishedInfesting(); } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pMapData - //----------------------------------------------------------------------------- int CNodeEnt::Spawn( const char *pMapData ) { m_NodeData.strEntityName = GetEntityName(); m_NodeData.vecPosition = GetAbsOrigin(); m_NodeData.nNodeID = NO_NODE; if ( m_NodeData.minState == NPC_STATE_NONE ) m_NodeData.minState = NPC_STATE_IDLE; if ( m_NodeData.maxState == NPC_STATE_NONE ) m_NodeData.maxState = NPC_STATE_COMBAT; // --------------------------------------------------------------------------------- // If just a hint node (not used for navigation) just create a hint and bail // --------------------------------------------------------------------------------- if (FClassnameIs( this, "info_hint" )) { if (m_NodeData.nHintType) { CAI_HintManager::CreateHint( &m_NodeData, pMapData ); } else { Warning("info_hint (HammerID: %d, position (%.2f, %.2f, %.2f)) with no hint type.\n", m_NodeData.nWCNodeID, m_NodeData.vecPosition.x, m_NodeData.vecPosition.y, m_NodeData.vecPosition.z ); } UTIL_RemoveImmediate( this ); return -1; } // --------------------------------------------------------------------------------- // First check if this node has a hint. If so create a hint entity // --------------------------------------------------------------------------------- CAI_Hint *pHint = NULL; if ( ClassMatches( "info_node_hint" ) || ClassMatches( "info_node_air_hint" ) ) { if ( m_NodeData.nHintType || m_NodeData.strGroup != NULL_STRING || m_NodeData.strEntityName != NULL_STRING ) { m_NodeData.nNodeID = m_nNodeCount; pHint = CAI_HintManager::CreateHint( &m_NodeData, pMapData ); pHint->AddSpawnFlags( GetSpawnFlags() ); } } // --------------------------------------------------------------------------------- // If we loaded from disk, we can discard all these node ents as soon as they spawn // unless we are in WC edited mode // --------------------------------------------------------------------------------- if ( g_pAINetworkManager->NetworksLoaded() && !engine->IsInEditMode()) { // If hint exists for this node, set it if (pHint) { CAI_Node *pNode = g_pBigAINet->GetNode(m_nNodeCount); if (pNode) pNode->SetHint( pHint ); else { DevMsg("AI node graph corrupt\n"); } } m_nNodeCount++; UTIL_RemoveImmediate( this ); return -1; } else { m_nNodeCount++; } // --------------------------------------------------------------------------------- // Add a new node to the network // --------------------------------------------------------------------------------- // For now just using one big AI network CAI_Node *new_node = g_pBigAINet->AddNode( GetAbsOrigin(), GetAbsAngles().y ); new_node->SetHint( pHint ); // ------------------------------------------------------------------------- // Update table of how each WC id relates to each engine ID // ------------------------------------------------------------------------- if (g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable) { g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[new_node->GetId()] = m_NodeData.nWCNodeID; } // Keep track of largest index used by WC if (g_pAINetworkManager->GetEditOps()->m_nNextWCIndex <= m_NodeData.nWCNodeID) { g_pAINetworkManager->GetEditOps()->m_nNextWCIndex = m_NodeData.nWCNodeID+1; } // ------------------------------------------------------------------------- // If in WC edit mode: // Remember the original positions of the nodes before // they drop so we can send the undropped positions to wc. // ------------------------------------------------------------------------- if (engine->IsInEditMode()) { if (g_pAINetworkManager->GetEditOps()->m_pWCPosition) { g_pAINetworkManager->GetEditOps()->m_pWCPosition[new_node->GetId()] = new_node->GetOrigin(); } } if (FClassnameIs( this, "info_node_air" ) || FClassnameIs( this, "info_node_air_hint" )) { new_node->SetType( NODE_AIR ); } else if (FClassnameIs( this, "info_node_climb" )) { new_node->SetType( NODE_CLIMB ); } else { new_node->SetType( NODE_GROUND ); } new_node->m_eNodeInfo = ( m_spawnflags << NODE_ENT_FLAGS_SHIFT ); // If changed as part of WC editing process note that network must be rebuilt if (m_debugOverlays & OVERLAY_WC_CHANGE_ENTITY) { g_pAINetworkManager->GetEditOps()->SetRebuildFlags(); new_node->m_eNodeInfo |= bits_NODE_WC_CHANGED; // Initialize the new nodes position. The graph may not be rebuild // right away but the node should at least be positioned correctly g_AINetworkBuilder.InitNodePosition( g_pBigAINet, new_node ); } UTIL_RemoveImmediate( this ); return -1; }