//========================================================= // CheckRangeAttack1 //========================================================= BOOL COtis :: CheckRangeAttack1 ( float flDot, float flDist ) { if ( flDist <= 1024 && flDot >= 0.5 ) { if ( gpGlobals->time > m_checkAttackTime ) { TraceResult tr; Vector shootOrigin = pev->origin + Vector( 0, 0, 55 ); CBaseEntity *pEnemy = m_hEnemy; Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP ); UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT(pev), &tr ); m_checkAttackTime = gpGlobals->time + 1; if ( tr.flFraction == 1.0 || (tr.pHit != NULL && CBaseEntity::Instance(tr.pHit) == pEnemy) ) m_lastAttackCheck = TRUE; else m_lastAttackCheck = FALSE; m_checkAttackTime = gpGlobals->time + 1.5; } return m_lastAttackCheck; } return FALSE; }
void CBlackHole::RadiusDamage( ) { CBaseEntity *pEntity = NULL; TraceResult tr; float flAdjustedDamage; Vector vecSpot; entvars_t *pevOwner = VARS( pev->owner ); Vector vecSrc = pev->origin + Vector(0,0,1); if ( !pevOwner ) pevOwner = pev; CBaseEntity *pPlayer = CBaseEntity::Instance (pevOwner); // iterate on all entities in the vicinity. while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, (dmg_chrono_radius.value * (mp_wpn_power.value/100)) )) != NULL) { if ( pEntity->pev->movetype != MOVETYPE_PUSH && pEntity->pev->movetype != MOVETYPE_NONE && pEntity->pev->movetype != MOVETYPE_FOLLOW && pEntity->pev->movetype != MOVETYPE_NOCLIP ) { if (pEntity == this) continue; if (CVAR_GET_FLOAT("mp_noselfdamage")==1 && pEntity->pev == pevOwner ) continue; if (CVAR_GET_FLOAT("mp_noteamdamage")==1 && g_pGameRules->PlayerRelationship(pPlayer, pEntity) == GR_TEAMMATE && pEntity->pev != pevOwner) continue; vecSpot = pEntity->BodyTarget( vecSrc ); UTIL_TraceLine ( vecSrc, vecSpot, ignore_monsters, ENT(pev), &tr ); if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) { flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length(); if ( flAdjustedDamage < 1 ) flAdjustedDamage = 1; Vector m_vel = ( vecSrc - tr.vecEndPos ).Normalize() * ((500 * (dmg_chrono_radius.value * (mp_wpn_power.value/100)) / flAdjustedDamage) + 150); if (m_vel.Length() > 1000) m_vel = m_vel.Normalize() * 1000; pEntity->pev->velocity = m_vel; if (flAdjustedDamage < 200) { if (!(pEntity->Classify() == CLASS_MACHINE || pEntity->IsBot() || pEntity->IsPlayer() || FClassnameIs(pEntity->pev, "laser_dot") || FClassnameIs(pEntity->pev, "laser_spot"))) { pEntity->Killed ( pevOwner, 0 ); return; } } } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPhysExplosion::Explode( CBaseEntity *pActivator ) { CBaseEntity *pEntity = NULL; float adjustedDamage, falloff, flDist; Vector vecSpot; falloff = 1.0 / 2.5; // iterate on all entities in the vicinity. // I've removed the traceline heuristic from phys explosions. SO right now they will // affect entities through walls. (sjb) // UNDONE: Try tracing world-only? while ((pEntity = FindEntity(pEntity, pActivator)) != NULL) { // UNDONE: Ask the object if it should get force if it's not MOVETYPE_VPHYSICS? if ( pEntity->m_takedamage != DAMAGE_NO && (pEntity->GetMoveType() == MOVETYPE_VPHYSICS || (pEntity->VPhysicsGetObject() && !pEntity->IsPlayer())) ) { vecSpot = pEntity->BodyTarget( GetAbsOrigin() ); // decrease damage for an ent that's farther from the bomb. flDist = ( GetAbsOrigin() - vecSpot ).Length(); if( m_radius == 0 || flDist <= m_radius ) { adjustedDamage = flDist * falloff; adjustedDamage = m_damage - adjustedDamage; if ( adjustedDamage < 0 ) { adjustedDamage = 0; } CTakeDamageInfo info( this, this, adjustedDamage, DMG_BLAST ); CalculateExplosiveDamageForce( &info, (vecSpot - GetAbsOrigin()), GetAbsOrigin() ); if ( HasSpawnFlags( SF_PHYSEXPLOSION_NODAMAGE ) ) { pEntity->VPhysicsTakeDamage( info ); } else { pEntity->TakeDamage( info ); } } } } }
// Mortar launch BOOL CBigMomma::CheckRangeAttack1( float flDot, float flDist ) { if ( flDist <= BIG_MORTARDIST && m_mortarTime < gpGlobals->time ) { CBaseEntity *pEnemy = m_hEnemy; if ( pEnemy ) { Vector startPos = pev->origin; startPos.z += 180; pev->movedir = VecCheckSplatToss( pev, startPos, pEnemy->BodyTarget( pev->origin ), RANDOM_FLOAT( 150, 500 ) ); if ( pev->movedir != g_vecZero ) return TRUE; } } return FALSE; }
//----------------------------------------------------------------------------- // Purpose: Push a physics object in our wash. Return false if it's now out of our wash //----------------------------------------------------------------------------- bool CBaseHelicopter::DoWashPush( washentity_t *pWash, Vector vecWashOrigin ) { if ( !pWash || !pWash->hEntity.Get() ) return false; // Make sure the entity is still within our wash's radius CBaseEntity *pEntity = pWash->hEntity; Vector vecSpot = pEntity->BodyTarget( vecWashOrigin ); Vector vecToSpot = ( vecSpot - vecWashOrigin ); vecToSpot.z = 0; float flDist = VectorNormalize( vecToSpot ); if ( flDist > BASECHOPPER_WASH_RADIUS ) return false; IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject(); if ( pPhysObject == NULL ) return false; // Push it away from the center of the wash float flMass = pPhysObject->GetMass(); float flPushTime = (gpGlobals->curtime - pWash->flWashStartTime); float flMinPush = BASECHOPPER_WASH_PUSH_MIN * flMass; float flMaxPush = BASECHOPPER_WASH_PUSH_MAX * flMass; float flWashAmount = min( flMaxPush, RemapVal( flPushTime, 0, BASECHOPPER_WASH_RAMP_TIME, flMinPush, flMaxPush ) ); Vector vecForce = flWashAmount * vecToSpot * phys_pushscale.GetFloat(); pEntity->VPhysicsTakeDamage( CTakeDamageInfo( this, this, vecForce, vecWashOrigin, flWashAmount, DMG_BLAST ) ); // Debug if ( g_debug_basehelicopter.GetInt() == BASECHOPPER_DEBUG_WASH ) { NDebugOverlay::Cross3D( pEntity->GetAbsOrigin(), -Vector(4,4,4), Vector(4,4,4), 255, 0, 0, true, 0.1f ); NDebugOverlay::Line( pEntity->GetAbsOrigin(), pEntity->GetAbsOrigin() + vecForce, 255, 255, 0, true, 0.1f ); IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject(); Msg("Pushed %s (mass %f) with force %f (min %.2f max %.2f) at time %.2f\n", pEntity->GetClassname(), pPhysObject->GetMass(), flWashAmount, flMinPush, flMaxPush, gpGlobals->curtime ); } // If we've pushed this thing for some time, remove it to give us a chance to find lighter things nearby if ( flPushTime > 2.0 ) return false; return true; }
//========================================================= // CheckRangeAttack1 //========================================================= bool CNPC_HL1Barney::CheckRangeAttack1 ( float flDot, float flDist ) { if ( gpGlobals->curtime > m_flCheckAttackTime ) { trace_t tr; Vector shootOrigin = GetAbsOrigin() + Vector( 0, 0, 55 ); CBaseEntity *pEnemy = GetEnemy(); Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->GetAbsOrigin()) + GetEnemyLKP() ); UTIL_TraceLine ( shootOrigin, shootTarget, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr); m_flCheckAttackTime = gpGlobals->curtime + 1; if ( tr.fraction == 1.0 || ( tr.m_pEnt != NULL && tr.m_pEnt == pEnemy) ) m_fLastAttackCheck = TRUE; else m_fLastAttackCheck = FALSE; m_flCheckAttackTime = gpGlobals->curtime + 1.5; } return m_fLastAttackCheck; }
// Mortar launch int CNPC_BigMomma::RangeAttack1Conditions( float flDot, float flDist ) { if ( flDist > BIG_MORTARDIST ) return COND_TOO_FAR_TO_ATTACK; if ( flDist <= BIG_MORTARDIST && m_mortarTime < gpGlobals->curtime ) { CBaseEntity *pEnemy = GetEnemy(); if ( pEnemy ) { Vector startPos = GetAbsOrigin(); startPos.z += 180; m_vTossDir = VecCheckSplatToss( this, startPos, pEnemy->BodyTarget( GetAbsOrigin() ), random->RandomFloat( 150, 500 ) ); if ( m_vTossDir != vec3_origin ) return COND_CAN_RANGE_ATTACK1; } } return COND_NONE; }
void CAPCController::TrackTarget( void ) { trace_t tr; bool updateTime = FALSE, lineOfSight; QAngle angles; Vector barrelEnd; CBaseEntity *pTarget = NULL; barrelEnd.Init(); if ( IsActive() ) { SetNextThink( gpGlobals->curtime + 0.1f ); } else { return; } // ----------------------------------- // Get world target position // ----------------------------------- barrelEnd = WorldBarrelPosition(); Vector worldTargetPosition; CBaseEntity *pEntity = (CBaseEntity *)m_hTarget; if ( !pEntity || ( pEntity->GetFlags() & FL_NOTARGET ) ) { m_hTarget = FindTarget( m_targetEntityName, NULL ); if ( IsActive() ) { SetNextThink( gpGlobals->curtime + 2 ); // Wait 2 sec s } return; } pTarget = pEntity; // Calculate angle needed to aim at target worldTargetPosition = pEntity->EyePosition(); float range = (worldTargetPosition - barrelEnd).Length(); if ( !InRange( range ) ) { m_bFireDelayed = false; return; } UTIL_TraceLine( barrelEnd, worldTargetPosition, MASK_BLOCKLOS, this, COLLISION_GROUP_NONE, &tr ); lineOfSight = FALSE; // No line of sight, don't track if ( tr.fraction == 1.0 || tr.m_pEnt == pTarget ) { lineOfSight = TRUE; CBaseEntity *pInstance = pTarget; if ( InRange( range ) && pInstance && pInstance->IsAlive() ) { updateTime = TRUE; // Sight position is BodyTarget with no noise (so gun doesn't bob up and down) m_sightOrigin = pInstance->BodyTarget( GetLocalOrigin(), false ); } } // Convert targetPosition to parent angles = AimBarrelAt( m_parentMatrix.WorldToLocal( m_sightOrigin ) ); // Force the angles to be relative to the center position float offsetY = UTIL_AngleDistance( angles.y, m_yawCenter ); float offsetX = UTIL_AngleDistance( angles.x, m_pitchCenter ); angles.y = m_yawCenter + offsetY; angles.x = m_pitchCenter + offsetX; // Move toward target at rate or less float distY = UTIL_AngleDistance( angles.y, GetLocalAngles().y ); QAngle vecAngVel = GetLocalAngularVelocity(); vecAngVel.y = distY * 10; vecAngVel.y = clamp( vecAngVel.y, -m_yawRate, m_yawRate ); // Move toward target at rate or less float distX = UTIL_AngleDistance( angles.x, GetLocalAngles().x ); vecAngVel.x = distX * 10; vecAngVel.x = clamp( vecAngVel.x, -m_pitchRate, m_pitchRate ); SetLocalAngularVelocity( vecAngVel ); SetMoveDoneTime( 0.1 ); Vector forward; AngleVectors( GetLocalAngles(), &forward ); forward = m_parentMatrix.ApplyRotation( forward ); AngleVectors(angles, &forward); if ( lineOfSight == TRUE ) { // FIXME: This will ultimately have to deal with NPCs being in the vehicle as well // See if the target is in a vehicle. If so, check its relationship CBasePlayer *pPlayer = ToBasePlayer( pTarget ); if ( pPlayer && pPlayer->IsInAVehicle() ) { IServerVehicle *pVehicle = pPlayer->GetVehicle(); if ( pVehicle->ClassifyPassenger( pPlayer, CLASS_PLAYER ) == CLASS_PLAYER) { if ( !m_bFireDelayed ) { m_bFireDelayed = true; m_flFiringDelay = gpGlobals->curtime + 1.5; // setup delay time before we start firing return; } if ( gpGlobals->curtime > m_flFiringDelay ) { m_OnFireAtTarget.Set(forward, this, this); // tell apc to fire rockets, and what direction } } } } else { m_bFireDelayed = false; // reset flag since we can no longer see target } }
void CGargantua::RunTask( const Task_t& task ) { switch ( task.iTask ) { case TASK_DIE: if ( gpGlobals->time > m_flWaitFinished ) { SetRenderFX( kRenderFxExplode ); SetRenderColor( Vector( 255, 0, 0 ) ); StopAnimation(); SetNextThink( gpGlobals->time + 0.15 ); SetThink( &CGargantua::SUB_Remove ); int i; int parts = MODEL_FRAMES( gGargGibModel ); for ( i = 0; i < 10; i++ ) { auto pGib = CGib::GibCreate( GARG_GIB_MODEL ); int bodyPart = 0; if ( parts > 1 ) bodyPart = RANDOM_LONG( 0, GetBody() -1 ); pGib->SetBody( bodyPart ); pGib->m_bloodColor = BLOOD_COLOR_YELLOW; pGib->m_material = matNone; pGib->SetAbsOrigin( GetAbsOrigin() ); pGib->SetAbsVelocity( UTIL_RandomBloodVector() * RANDOM_FLOAT( 300, 500 ) ); pGib->SetNextThink( gpGlobals->time + 1.25 ); pGib->SetThink( &CGib::SUB_FadeOut ); } MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, GetAbsOrigin() ); WRITE_BYTE( TE_BREAKMODEL); // position WRITE_COORD( GetAbsOrigin().x ); WRITE_COORD( GetAbsOrigin().y ); WRITE_COORD( GetAbsOrigin().z ); // size WRITE_COORD( 200 ); WRITE_COORD( 200 ); WRITE_COORD( 128 ); // velocity WRITE_COORD( 0 ); WRITE_COORD( 0 ); WRITE_COORD( 0 ); // randomization WRITE_BYTE( 200 ); // Model WRITE_SHORT( gGargGibModel ); //model id# // # of shards WRITE_BYTE( 50 ); // duration WRITE_BYTE( 20 );// 3.0 seconds // flags WRITE_BYTE( BREAK_FLESH ); MESSAGE_END(); return; } else CBaseMonster::RunTask( task ); break; case TASK_FLAME_SWEEP: if ( gpGlobals->time > m_flWaitFinished ) { FlameDestroy(); TaskComplete(); FlameControls( 0, 0 ); SetBoneController( 0, 0 ); SetBoneController( 1, 0 ); } else { bool cancel = false; Vector angles = g_vecZero; FlameUpdate(); CBaseEntity *pEnemy = m_hEnemy; if ( pEnemy ) { Vector org = GetAbsOrigin(); org.z += 64; Vector dir = pEnemy->BodyTarget(org) - org; angles = UTIL_VecToAngles( dir ); angles.x = -angles.x; angles.y -= GetAbsAngles().y; if ( dir.Length() > 400 ) cancel = true; } if ( fabs(angles.y) > 60 ) cancel = true; if ( cancel ) { m_flWaitFinished -= 0.5; m_flameTime -= 0.5; } // FlameControls( angles.x + 2 * sin(gpGlobals->time*8), angles.y + 28 * sin(gpGlobals->time*8.5) ); FlameControls( angles.x, angles.y ); } break; default: CBaseMonster::RunTask( task ); break; } }
void CNPC_Portal_FloorTurret::FireBullet( const char *pTargetName ) { CBaseEntity *pEnemy = gEntList.FindEntityByName( NULL, pTargetName ); if ( !pEnemy ) return; //Get our shot positions Vector vecMid = EyePosition(); Vector vecMidEnemy = pEnemy->BodyTarget( vecMid ); // Store off our last seen location so we can suppress it later m_vecEnemyLKP = vecMidEnemy; //Calculate dir and dist to enemy Vector vecDirToEnemy = vecMidEnemy - vecMid; m_flDistToEnemy = VectorNormalize( vecDirToEnemy ); //We want to look at the enemy's eyes so we don't jitter Vector vecDirToEnemyEyes = vecMidEnemy - vecMid; VectorNormalize( vecDirToEnemyEyes ); QAngle vecAnglesToEnemy; VectorAngles( vecDirToEnemyEyes, vecAnglesToEnemy ); Vector vecMuzzle, vecMuzzleDir; GetAttachment( m_iMuzzleAttachment, vecMuzzle, &vecMuzzleDir ); if ( m_flShotTime < gpGlobals->curtime ) { Vector2D vecDirToEnemy2D = vecDirToEnemy.AsVector2D(); Vector2D vecMuzzleDir2D = vecMuzzleDir.AsVector2D(); if ( m_flDistToEnemy < 60.0 ) { vecDirToEnemy2D.NormalizeInPlace(); vecMuzzleDir2D.NormalizeInPlace(); } //Fire the gun if( m_bOutOfAmmo ) { DryFire(); } else { SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE ); SetActivity( (Activity)( ( m_bShootWithBottomBarrels ) ? ( ACT_FLOOR_TURRET_FIRE2 ) : ( ACT_FLOOR_TURRET_FIRE ) ) ); //Fire the weapon #if !DISABLE_SHOT Shoot( vecMuzzle, vecDirToEnemy, true ); #endif } //If we can see our enemy, face it m_vecGoalAngles.y = vecAnglesToEnemy.y; m_vecGoalAngles.x = vecAnglesToEnemy.x; //Turn to face UpdateFacing(); EmitSound( "NPC_FloorTurret.Alert" ); SetThink( &CNPC_FloorTurret::SuppressThink ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseHelicopter::DoRotorPhysicsPush( const Vector &vecRotorOrigin, float flAltitude ) { CBaseEntity *pEntity = NULL; trace_t tr; // First, trace down and find out where the was is hitting the ground UTIL_TraceLine( vecRotorOrigin, vecRotorOrigin+Vector(0,0,-flAltitude), (MASK_SOLID_BRUSHONLY|CONTENTS_WATER), NULL, COLLISION_GROUP_NONE, &tr ); // Always raise the physics origin a bit Vector vecPhysicsOrigin = tr.endpos + Vector(0,0,64); // Debug if ( g_debug_basehelicopter.GetInt() == BASECHOPPER_DEBUG_WASH ) { NDebugOverlay::Cross3D( vecPhysicsOrigin, -Vector(16,16,16), Vector(16,16,16), 0, 255, 255, true, 0.1f ); } // Push entities that we've pushed before, and are still within range // Walk backwards because they may be removed if they're now out of range int iCount = m_hEntitiesPushedByWash.Count(); bool bWasPushingObjects = (iCount > 0); for ( int i = (iCount-1); i >= 0; i-- ) { if ( !DoWashPush( &(m_hEntitiesPushedByWash[i]), vecPhysicsOrigin ) ) { // Out of range now, so remove m_hEntitiesPushedByWash.Remove(i); } } if ( m_flRotorWashEntitySearchTime > gpGlobals->curtime ) return; // Any spare slots? iCount = m_hEntitiesPushedByWash.Count(); if ( iCount >= BASECHOPPER_WASH_MAX_OBJECTS ) return; // Find the lightest physics entity below us and add it to our list to push around CBaseEntity *pLightestEntity = NULL; float flLightestMass = 9999; while ((pEntity = gEntList.FindEntityInSphere(pEntity, vecPhysicsOrigin, BASECHOPPER_WASH_RADIUS )) != NULL) { IRotorWashShooter *pShooter = GetRotorWashShooter( pEntity ); if ( pEntity->IsEFlagSet( EFL_NO_ROTORWASH_PUSH )) continue; if ( pShooter || pEntity->GetMoveType() == MOVETYPE_VPHYSICS || (pEntity->VPhysicsGetObject() && !pEntity->IsPlayer()) ) { // Make sure it's not already in our wash bool bAlreadyPushing = false; for ( int i = 0; i < iCount; i++ ) { if ( m_hEntitiesPushedByWash[i].hEntity == pEntity ) { bAlreadyPushing = true; break; } } if ( bAlreadyPushing ) continue; float flMass = FLT_MAX; if ( pShooter ) { flMass = 1.0f; } else { // Don't try to push anything too big IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject(); if ( pPhysObject ) { flMass = pPhysObject->GetMass(); if ( flMass > BASECHOPPER_WASH_MAX_MASS ) continue; } } // Ignore anything bigger than the one we've already found if ( flMass > flLightestMass ) continue; Vector vecSpot = pEntity->BodyTarget( vecPhysicsOrigin ); // Don't push things too far below our starting point (helps reduce through-roof cases w/o doing a trace) if ( fabs( vecSpot.z - vecPhysicsOrigin.z ) > 96 ) continue; Vector vecToSpot = ( vecSpot - vecPhysicsOrigin ); vecToSpot.z = 0; float flDist = VectorNormalize( vecToSpot ); if ( flDist > BASECHOPPER_WASH_RADIUS ) continue; // Try to cast to the helicopter; if we can't, then we can't be hit. if ( pEntity->GetServerVehicle() ) { UTIL_TraceLine( vecSpot, vecPhysicsOrigin, MASK_SOLID_BRUSHONLY, pEntity, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction != 1.0f ) continue; } flLightestMass = flMass; pLightestEntity = pEntity; washentity_t Wash; Wash.hEntity = pLightestEntity; Wash.flWashStartTime = gpGlobals->curtime; m_hEntitiesPushedByWash.AddToTail( Wash ); // Can we fit more after adding this one? No? Then we are done. iCount = m_hEntitiesPushedByWash.Count(); if ( iCount >= BASECHOPPER_WASH_MAX_OBJECTS ) break; } } // Handle sound. // If we just started pushing objects, ramp the blast sound up. if ( !bWasPushingObjects && m_hEntitiesPushedByWash.Count() ) { if ( m_pRotorBlast ) { CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); controller.SoundChangeVolume( m_pRotorBlast, 1.0, 1.0 ); } } else if ( bWasPushingObjects && m_hEntitiesPushedByWash.Count() == 0 ) { if ( m_pRotorBlast ) { // We just stopped pushing objects, so fade the blast sound out. CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); controller.SoundChangeVolume( m_pRotorBlast, 0, 1.0 ); } } }
// Add the ability to ignore the world trace void CSDKGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, bool bIgnoreWorld ) { CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecToTarget; Vector vecEndPos; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; vecSrc.z += 1;// in case grenade is lying on the ground // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if ( pEntity->m_takedamage != DAMAGE_NO ) { // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // radius damage can only be blocked by the world vecSpot = pEntity->BodyTarget( vecSrc ); bool bHit = false; if( bIgnoreWorld ) { vecEndPos = vecSpot; bHit = true; } else { UTIL_TraceLine( vecSrc, vecSpot, MASK_SOLID_BRUSHONLY, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } vecEndPos = tr.endpos; if( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) { bHit = true; } } if ( bHit ) { // the explosion can 'see' this entity, so hurt them! //vecToTarget = ( vecSrc - vecEndPos ); vecToTarget = ( vecEndPos - vecSrc ); // decrease damage for an ent that's farther from the bomb. flAdjustedDamage = vecToTarget.Length() * falloff; flAdjustedDamage = info.GetDamage() - flAdjustedDamage; if ( flAdjustedDamage > 0 ) { CTakeDamageInfo adjustedInfo = info; adjustedInfo.SetDamage( flAdjustedDamage ); Vector dir = vecToTarget; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc, 1.5 /* explosion scale! */ ); } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } pEntity->TakeDamage( adjustedInfo ); // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, vecEndPos, dir ); } } } } }
void CNPC_Portal_FloorTurret::ActiveThink( void ) { LaserOn(); //Allow descended classes a chance to do something before the think function if ( PreThink( TURRET_ACTIVE ) ) return; HackFindEnemy(); //Update our think time SetNextThink( gpGlobals->curtime + 0.1f ); CBaseEntity *pEnemy = GetEnemy(); //If we've become inactive, go back to searching if ( ( m_bActive == false ) || ( pEnemy == NULL ) ) { SetEnemy( NULL ); m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT; SetThink( &CNPC_FloorTurret::SearchThink ); m_vecGoalAngles = GetAbsAngles(); return; } //Get our shot positions Vector vecMid = EyePosition(); Vector vecMidEnemy = pEnemy->BodyTarget( vecMid ); // Store off our last seen location so we can suppress it later m_vecEnemyLKP = vecMidEnemy; //Look for our current enemy bool bEnemyInFOV = FInViewCone( pEnemy ); bool bEnemyVisible = FVisible( pEnemy ) && pEnemy->IsAlive(); //Calculate dir and dist to enemy Vector vecDirToEnemy = vecMidEnemy - vecMid; m_flDistToEnemy = VectorNormalize( vecDirToEnemy ); // If the enemy isn't in the normal fov, check the fov through portals CProp_Portal *pPortal = NULL; if ( pEnemy->IsAlive() ) { pPortal = FInViewConeThroughPortal( pEnemy ); if ( pPortal && FVisibleThroughPortal( pPortal, pEnemy ) ) { // Translate our target across the portal Vector vecMidEnemyTransformed; UTIL_Portal_PointTransform( pPortal->m_hLinkedPortal->MatrixThisToLinked(), vecMidEnemy, vecMidEnemyTransformed ); //Calculate dir and dist to enemy Vector vecDirToEnemyTransformed = vecMidEnemyTransformed - vecMid; float flDistToEnemyTransformed = VectorNormalize( vecDirToEnemyTransformed ); // If it's not visible through normal means or the enemy is closer through the portal, use the translated info if ( !bEnemyInFOV || !bEnemyVisible || flDistToEnemyTransformed < m_flDistToEnemy ) { bEnemyInFOV = true; bEnemyVisible = true; vecMidEnemy = vecMidEnemyTransformed; vecDirToEnemy = vecDirToEnemyTransformed; m_flDistToEnemy = flDistToEnemyTransformed; } else { pPortal = NULL; } } else { pPortal = NULL; } } //Draw debug info if ( g_debug_turret.GetBool() ) { NDebugOverlay::Cross3D( vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( GetEnemy()->WorldSpaceCenter(), -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); NDebugOverlay::Line( vecMid, GetEnemy()->WorldSpaceCenter(), 0, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMidEnemy, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 ); NDebugOverlay::Line( vecMid, vecMidEnemy, 0, 255, 0, false, 0.05f ); } //See if they're past our FOV of attack if ( bEnemyInFOV == false ) { // Should we look for a new target? ClearEnemyMemory(); SetEnemy( NULL ); if ( m_spawnflags & SF_FLOOR_TURRET_FASTRETIRE ) { // Retire quickly in this case. (The case where we saw the player, but he hid again). m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_SHORT_WAIT; } else { m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT; } SetThink( &CNPC_FloorTurret::SearchThink ); m_vecGoalAngles = GetAbsAngles(); SpinDown(); return; } //Current enemy is not visible if ( ( bEnemyVisible == false ) || ( m_flDistToEnemy > PORTAL_FLOOR_TURRET_RANGE )) { m_flLastSight = gpGlobals->curtime + 2.0f; ClearEnemyMemory(); SetEnemy( NULL ); SetThink( &CNPC_FloorTurret::SuppressThink ); return; } if ( g_debug_turret.GetBool() ) { Vector vecMuzzle, vecMuzzleDir; UpdateMuzzleMatrix(); MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir ); MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle ); // Visualize vertical firing ranges for ( int i = 0; i < 4; i++ ) { QAngle angMaxDownPitch = GetAbsAngles(); switch( i ) { case 0: angMaxDownPitch.x -= 15; break; case 1: angMaxDownPitch.x += 15; break; case 2: angMaxDownPitch.x -= 25; break; case 3: angMaxDownPitch.x += 25; break; default: break; } Vector vecMaxDownPitch; AngleVectors( angMaxDownPitch, &vecMaxDownPitch ); NDebugOverlay::Line( vecMuzzle, vecMuzzle + (vecMaxDownPitch*256), 255, 255, 255, false, 0.1 ); } } if ( m_flShotTime < gpGlobals->curtime ) { Vector vecMuzzle, vecMuzzleDir; UpdateMuzzleMatrix(); MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir ); MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle ); Vector2D vecDirToEnemy2D = vecDirToEnemy.AsVector2D(); Vector2D vecMuzzleDir2D = vecMuzzleDir.AsVector2D(); bool bCanShoot = true; float minCos3d = DOT_10DEGREE; // 10 degrees slop if ( m_flDistToEnemy < 60.0 ) { vecDirToEnemy2D.NormalizeInPlace(); vecMuzzleDir2D.NormalizeInPlace(); bCanShoot = ( vecDirToEnemy2D.Dot(vecMuzzleDir2D) >= DOT_10DEGREE ); minCos3d = 0.7071; // 45 degrees } //Fire the gun if ( bCanShoot ) // 10 degree slop XY { float dot3d = DotProduct( vecDirToEnemy, vecMuzzleDir ); if( m_bOutOfAmmo ) { DryFire(); } else { if ( dot3d >= minCos3d ) { SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE ); SetActivity( (Activity)( ( m_bShootWithBottomBarrels ) ? ( ACT_FLOOR_TURRET_FIRE2 ) : ( ACT_FLOOR_TURRET_FIRE ) ) ); //Fire the weapon #if !DISABLE_SHOT Shoot( vecMuzzle, vecMuzzleDir, (dot3d < DOT_10DEGREE) ); #endif } } } } else { SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE ); } //If we can see our enemy, face it if ( bEnemyVisible ) { //We want to look at the enemy's eyes so we don't jitter Vector vEnemyWorldSpaceCenter = pEnemy->WorldSpaceCenter(); if ( pPortal && pPortal->IsActivedAndLinked() ) { // Translate our target across the portal UTIL_Portal_PointTransform( pPortal->m_hLinkedPortal->MatrixThisToLinked(), vEnemyWorldSpaceCenter, vEnemyWorldSpaceCenter ); } Vector vecDirToEnemyEyes = vEnemyWorldSpaceCenter - vecMid; VectorNormalize( vecDirToEnemyEyes ); QAngle vecAnglesToEnemy; VectorAngles( vecDirToEnemyEyes, vecAnglesToEnemy ); m_vecGoalAngles.y = vecAnglesToEnemy.y; m_vecGoalAngles.x = vecAnglesToEnemy.x; } //Turn to face UpdateFacing(); }
void CNPC_Hydra::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_HYDRA_DEPLOY: { m_flHeadGoalInfluence = 1.0; float dist = (EyePosition() - m_vecHeadGoal).Length(); if (dist < m_idealSegmentLength) { TaskComplete(); } AimHeadInTravelDirection( 0.2 ); } break; case TASK_HYDRA_PREP_STAB: { int i; if (m_body.Count() < 2) { TaskFail( "hydra is too short to begin stab" ); return; } CBaseEntity *pTarget = GetTarget(); if (pTarget == NULL) { TaskFail( FAIL_NO_TARGET ); } if (pTarget->IsPlayer()) { m_vecTarget = pTarget->EyePosition( ); } else { m_vecTarget = pTarget->BodyTarget( EyePosition( ) ); } float distToTarget = (m_vecTarget - m_vecHeadGoal).Length(); float distToBase = (m_vecHeadGoal - GetAbsOrigin()).Length(); m_idealLength = distToTarget + distToBase * 0.5; if (m_idealLength > HYDRA_MAX_LENGTH) m_idealLength = HYDRA_MAX_LENGTH; if (distToTarget < 100.0) { m_vecTargetDir = (m_vecTarget - m_vecHeadGoal); VectorNormalize( m_vecTargetDir ); m_vecHeadGoal = m_vecHeadGoal - m_vecTargetDir * (100 - distToTarget) * 0.5; } else if (distToTarget > 200.0) { m_vecTargetDir = (m_vecTarget - m_vecHeadGoal); VectorNormalize( m_vecTargetDir ); m_vecHeadGoal = m_vecHeadGoal - m_vecTargetDir * (200.0 - distToTarget) * 0.5; } // face enemy m_vecTargetDir = (m_vecTarget - m_body[m_body.Count()-1].vecPos); VectorNormalize( m_vecTargetDir ); m_vecHeadDir = m_vecHeadDir * 0.6 + m_vecTargetDir * 0.4; VectorNormalize( m_vecHeadDir.GetForModify() ); // build tension towards strike time float influence = 1.0 - (m_flTaskEndTime - gpGlobals->curtime) / pTask->flTaskData; if (influence > 1) influence = 1.0; influence = influence * influence * influence; m_flHeadGoalInfluence = influence; // keep head segment straight i = m_body.Count() - 2; m_body[i].vecGoalPos = m_vecHeadGoal - m_vecHeadDir * m_body[i].flActualLength; m_body[i].flGoalInfluence = influence; // curve neck into spiral float distBackFromHead = m_body[i].flActualLength; Vector right, up; VectorVectors( m_vecHeadDir, right, up ); for (i = i - 1; i > 1 && distBackFromHead < distToTarget; i--) { distBackFromHead += m_body[i].flActualLength; float r = (distBackFromHead / 200) * 3.1415 * 2; // spiral Vector p0 = m_vecHeadGoal - m_vecHeadDir * distBackFromHead * 0.5 + cos( r ) * m_body[i].flActualLength * right + sin( r ) * m_body[i].flActualLength * up; // base r = (distBackFromHead / m_idealLength) * 3.1415 * 0.2; r = sin( r ); p0 = p0 * (1 - r) + r * GetAbsOrigin(); m_body[i].vecGoalPos = p0; m_body[i].flGoalInfluence = influence * (1.0 - (distBackFromHead / distToTarget)); /* if ( (pEnemy->EyePosition( ) - m_body[i].vecPos).Length() < distBackFromHead) { if ( gpGlobals->curtime - m_flLastAttackTime > 4.0) { TaskComplete(); } return; } */ } // look to see if any of the goal positions are stuck for (i = i; i < m_body.Count() - 1; i++) { if (m_body[i].bStuck) { Vector delta = DotProduct( m_body[i].vecGoalPos - m_body[i].vecPos, m_vecHeadDir) * m_vecHeadDir; m_vecHeadGoal -= delta * m_body[i].flGoalInfluence; break; } } if ( gpGlobals->curtime >= m_flTaskEndTime ) { if (distToTarget < 500) { TaskComplete( ); return; } else { TaskFail( "target is too far away" ); return; } } } return; case TASK_HYDRA_STAB: { int i; if (m_body.Count() < 2) { TaskFail( "hydra is too short to begin stab" ); return; } if (m_flTaskEndTime <= gpGlobals->curtime) { TaskComplete( ); return; } m_flHeadGoalInfluence = 1.0; // face enemy //m_vecHeadDir = (pEnemy->EyePosition( ) - m_body[m_body.Count()-1].vecPos); //VectorNormalize( m_vecHeadDir.GetForModify() ); // keep head segment straight i = m_body.Count() - 2; m_body[i].vecGoalPos = m_vecHeadGoal + m_vecHeadDir * m_body[i].flActualLength; m_body[i].flGoalInfluence = 1.0; Vector vecToTarget = (m_vecTarget - EyePosition( )); // check to see if we went past target if (DotProduct( vecToTarget, m_vecHeadDir ) < 0.0) { TaskComplete( ); return; } float distToTarget = vecToTarget.Length(); float distToBase = (EyePosition( ) - GetAbsOrigin()).Length(); m_idealLength = distToTarget + distToBase; /* if (distToTarget < 20) { m_vecHeadGoal = m_vecTarget; SetLastAttackTime( gpGlobals->curtime ); TaskComplete(); return; } else */ { // hit enemy m_vecHeadGoal = m_vecTarget + m_vecHeadDir * 300; } if (m_idealLength > HYDRA_MAX_LENGTH) m_idealLength = HYDRA_MAX_LENGTH; // curve neck into spiral float distBackFromHead = m_body[i].flActualLength; Vector right, up; VectorVectors( m_vecHeadDir, right, up ); #if 1 for (i = i - 1; i > 1 && distBackFromHead < distToTarget; i--) { Vector p0 = m_vecHeadGoal - m_vecHeadDir * distBackFromHead * 1.0; m_body[i].vecGoalPos = p0; if ((m_vecTarget - m_body[i].vecPos).Length() > distToTarget + distBackFromHead) { m_body[i].flGoalInfluence = 1.0 - (distBackFromHead / distToTarget); } else { m_body[i].vecGoalPos = EyePosition( ) - m_vecHeadDir * distBackFromHead; m_body[i].flGoalInfluence = 1.0 - (distBackFromHead / distToTarget); } distBackFromHead += m_body[i].flActualLength; } #endif } return; case TASK_HYDRA_PULLBACK: { if (m_body.Count() < 2) { TaskFail( "hydra is too short to begin stab" ); return; } CBaseEntity *pEnemy = (CBaseEntity *)UTIL_GetLocalPlayer(); if (GetEnemy() != NULL) { pEnemy = GetEnemy(); } AimHeadInTravelDirection( 0.2 ); // float dist = (EyePosition() - m_vecHeadGoal).Length(); if (m_flCurrentLength < m_idealLength + m_idealSegmentLength) { TaskComplete(); } } break; default: BaseClass::RunTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: Target doesn't exist or has eluded us, so search for one //----------------------------------------------------------------------------- void CNPC_Portal_FloorTurret::SearchThink( void ) { //Allow descended classes a chance to do something before the think function if ( PreThink( TURRET_SEARCHING ) ) return; SetNextThink( gpGlobals->curtime + 0.05f ); SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE ); //If our enemy has died, pick a new enemy if ( ( GetEnemy() != NULL ) && ( GetEnemy()->IsAlive() == false ) ) { SetEnemy( NULL ); } //Acquire the target if ( GetEnemy() == NULL ) { HackFindEnemy(); } LaserOn(); CBaseEntity *pEnemy = GetEnemy(); //If we've found a target, spin up the barrel and start to attack if ( pEnemy != NULL ) { //Get our shot positions Vector vecMid = EyePosition(); Vector vecMidEnemy = pEnemy->BodyTarget( vecMid ); //Look for our current enemy bool bEnemyInFOV = FInViewCone( pEnemy ); bool bEnemyVisible = FVisible( pEnemy ); //Calculate dir and dist to enemy Vector vecDirToEnemy = vecMidEnemy - vecMid; m_flDistToEnemy = VectorNormalize( vecDirToEnemy ); // If the enemy isn't in the normal fov, check the fov through portals CProp_Portal *pPortal = NULL; pPortal = FInViewConeThroughPortal( pEnemy ); if ( pPortal && FVisibleThroughPortal( pPortal, pEnemy ) ) { // Translate our target across the portal Vector vecMidEnemyTransformed; UTIL_Portal_PointTransform( pPortal->m_hLinkedPortal->MatrixThisToLinked(), vecMidEnemy, vecMidEnemyTransformed ); //Calculate dir and dist to enemy Vector vecDirToEnemyTransformed = vecMidEnemyTransformed - vecMid; float flDistToEnemyTransformed = VectorNormalize( vecDirToEnemyTransformed ); // If it's not visible through normal means or the enemy is closer through the portal, use the translated info if ( !bEnemyInFOV || !bEnemyVisible || flDistToEnemyTransformed < m_flDistToEnemy ) { bEnemyInFOV = true; bEnemyVisible = true; vecMidEnemy = vecMidEnemyTransformed; vecDirToEnemy = vecDirToEnemyTransformed; m_flDistToEnemy = flDistToEnemyTransformed; } } // Give enemies that are farther away a longer grace period float fDistanceRatio = m_flDistToEnemy / PORTAL_FLOOR_TURRET_RANGE; m_flShotTime = gpGlobals->curtime + fDistanceRatio * fDistanceRatio * PORTAL_FLOOR_TURRET_MAX_SHOT_DELAY; m_flLastSight = 0; SetThink( &CNPC_FloorTurret::ActiveThink ); SetEyeState( TURRET_EYE_SEE_TARGET ); SpinUp(); if ( gpGlobals->curtime > m_flNextActivateSoundTime ) { EmitSound( "NPC_FloorTurret.Activate" ); m_flNextActivateSoundTime = gpGlobals->curtime + 3.0; } return; } //Are we out of time and need to retract? if ( gpGlobals->curtime > m_flLastSight ) { //Before we retrace, make sure that we are spun down. m_flLastSight = 0; SetThink( &CNPC_FloorTurret::Retire ); return; } //Display that we're scanning m_vecGoalAngles.x = GetAbsAngles().x + ( sin( ( m_flLastSight + gpGlobals->curtime * m_fSearchSpeed ) * 1.5f ) * 20.0f ); m_vecGoalAngles.y = GetAbsAngles().y + ( sin( ( m_flLastSight + gpGlobals->curtime * m_fSearchSpeed ) * 2.5f ) * 20.0f ); //Turn and ping UpdateFacing(); Ping(); // Update rope positions for ( int iRope = 0; iRope < PORTAL_FLOOR_TURRET_NUM_ROPES; ++iRope ) { if ( m_hRopes[ iRope ] ) { m_hRopes[ iRope ]->EndpointsChanged(); } } }
//========================================================= // RunTask //========================================================= void CGargantua::RunTask( Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_DIE: if ( gpGlobals->time > m_flWaitFinished ) { pev->renderfx = kRenderFxExplode; pev->rendercolor.x = 255; pev->rendercolor.y = 0; pev->rendercolor.z = 0; StopAnimation(); pev->nextthink = gpGlobals->time + 0.15; SetThink( SUB_Remove ); int i; int parts = MODEL_FRAMES( gGargGibModel ); for ( i = 0; i < 10; i++ ) { CGib *pGib = GetClassPtr( (CGib *)NULL ); pGib->Spawn( GARG_GIB_MODEL ); int bodyPart = 0; if ( parts > 1 ) bodyPart = RANDOM_LONG( 0, pev->body-1 ); pGib->pev->body = bodyPart; pGib->m_bloodColor = BLOOD_COLOR_YELLOW; pGib->m_material = matNone; pGib->SetAbsOrigin( GetAbsOrigin() ); pGib->SetAbsVelocity( UTIL_RandomBloodVector() * RANDOM_FLOAT( 300, 500 )); pGib->SetNextThink( 1.25 ); pGib->SetThink( SUB_FadeOut ); } Vector vecOrigin = GetAbsOrigin(); MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); WRITE_BYTE( TE_BREAKMODEL); // position WRITE_COORD( vecOrigin.x ); WRITE_COORD( vecOrigin.y ); WRITE_COORD( vecOrigin.z ); // size WRITE_COORD( 200 ); WRITE_COORD( 200 ); WRITE_COORD( 128 ); // velocity WRITE_COORD( 0 ); WRITE_COORD( 0 ); WRITE_COORD( 0 ); // randomization WRITE_BYTE( 200 ); // Model WRITE_SHORT( gGargGibModel ); //model id# // # of shards WRITE_BYTE( 50 ); // duration WRITE_BYTE( 20 );// 3.0 seconds // flags WRITE_BYTE( BREAK_FLESH ); MESSAGE_END(); return; } else CBaseMonster::RunTask(pTask); break; case TASK_FLAME_SWEEP: if ( gpGlobals->time > m_flWaitFinished ) { FlameDestroy(); TaskComplete(); FlameControls( 0, 0 ); SetBoneController( 0, 0 ); SetBoneController( 1, 0 ); } else { BOOL cancel = FALSE; Vector angles = g_vecZero; FlameUpdate(); CBaseEntity *pEnemy = m_hEnemy; if ( pEnemy ) { Vector org = GetAbsOrigin(); org.z += 64; Vector dir = pEnemy->BodyTarget(org) - org; angles = UTIL_VecToAngles( dir ); angles.y -= GetAbsAngles().y; if ( dir.Length() > 400 ) cancel = TRUE; } if ( fabs(angles.y) > 60 ) cancel = TRUE; if ( cancel ) { m_flWaitFinished -= 0.5; m_flameTime -= 0.5; } // FlameControls( angles.x + 2 * sin(gpGlobals->time*8), angles.y + 28 * sin(gpGlobals->time*8.5) ); FlameControls( angles.x, angles.y ); } break; default: CBaseMonster::RunTask( pTask ); break; } }
//========================================================= // RunTask //========================================================= void CNPC_Gargantua::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_DIE: if ( gpGlobals->curtime > m_flWaitFinished ) { //TEMP TEMP m_nRenderFX = kRenderFxExplode; SetRenderColor( 255, 0, 0 , 255 ); StopAnimation(); SetNextThink( gpGlobals->curtime + 0.15 ); SetThink( &CBaseEntity::SUB_Remove ); int i; int parts = modelinfo->GetModelFrameCount( modelinfo->GetModel( gGargGibModel ) ); for ( i = 0; i < 10; i++ ) { CGib *pGib = CREATE_ENTITY( CGib, "gib" ); pGib->Spawn( GARG_GIB_MODEL); int bodyPart = 0; if ( parts > 1 ) bodyPart = random->RandomInt( 0, parts-1 ); pGib->SetBodygroup( 0, bodyPart ); pGib->SetBloodColor( BLOOD_COLOR_YELLOW ); pGib->m_material = matNone; pGib->SetAbsOrigin( GetAbsOrigin() ); pGib->SetAbsVelocity( UTIL_RandomBloodVector() * random->RandomFloat( 300, 500 ) ); pGib->SetNextThink( gpGlobals->curtime + 1.25 ); pGib->SetThink( &CBaseEntity::SUB_FadeOut ); } Vector vecSize = Vector( 200, 200, 128 ); CPVSFilter filter( GetAbsOrigin() ); te->BreakModel( filter, 0.0, GetAbsOrigin(), vec3_angle, vecSize, vec3_origin, gGargGibModel, 200, 50, 3.0, BREAK_FLESH ); return; } else BaseClass::RunTask( pTask ); break; case TASK_FLAME_SWEEP: if ( gpGlobals->curtime > m_flWaitFinished ) { //TEMP TEMP FlameDestroy(); TaskComplete(); FlameControls( 0, 0 ); SetBoneController( 0, 0 ); SetBoneController( 1, 0 ); } else { bool cancel = false; QAngle angles = QAngle( 0, 0, 0 ); //TEMP TEMP FlameUpdate(); CBaseEntity *pEnemy = GetEnemy(); if ( pEnemy ) { Vector org = GetAbsOrigin(); org.z += 64; Vector dir = pEnemy->BodyTarget(org) - org; VectorAngles( dir, angles ); angles.x = -angles.x; angles.y -= GetAbsAngles().y; if ( dir.Length() > 400 ) cancel = true; } if ( fabs(angles.y) > 60 ) cancel = true; if ( cancel ) { m_flWaitFinished -= 0.5; m_flameTime -= 0.5; } //TEMP TEMP //FlameControls( angles.x + 2 * sin(gpGlobals->curtime*8), angles.y + 28 * sin(gpGlobals->curtime*8.5) ); FlameControls( angles.x, angles.y ); } break; default: BaseClass::RunTask( pTask ); break; } }
void CNPC_Gargantua::FlameDamage( Vector vecStart, Vector vecEnd, CBaseEntity *pevInflictor, CBaseEntity *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage; Vector vecSpot; Vector vecMid = (vecStart + vecEnd) * 0.5; // float searchRadius = (vecStart - vecMid).Length(); float searchRadius = GARG_FLAME_LENGTH; float maxDamageRadius = searchRadius / 2.0; Vector vecAim = (vecEnd - vecStart); VectorNormalize( vecAim ); // iterate on all entities in the vicinity. while ((pEntity = gEntList.FindEntityInSphere( pEntity, GetAbsOrigin(), searchRadius )) != NULL) { if ( pEntity->m_takedamage != DAMAGE_NO ) { // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } vecSpot = pEntity->BodyTarget( vecMid ); float dist = DotProduct( vecAim, vecSpot - vecMid ); if (dist > searchRadius) dist = searchRadius; else if (dist < -searchRadius) dist = searchRadius; Vector vecSrc = vecMid + dist * vecAim; UTIL_TraceLine ( vecStart, vecSpot, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr); // NDebugOverlay::Line( vecStart, vecSpot, 0, 255, 0, false, 10.0f ); if ( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) {// the explosion can 'see' this entity, so hurt them! // decrease damage for an ent that's farther from the flame. dist = ( vecSrc - tr.endpos ).Length(); if (dist > maxDamageRadius) { flAdjustedDamage = flDamage - (dist - maxDamageRadius) * 0.4; if (flAdjustedDamage <= 0) continue; } else { flAdjustedDamage = flDamage; } // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); if (tr.fraction != 1.0) { ClearMultiDamage( ); Vector vDir = (tr.endpos - vecSrc); VectorNormalize( vDir ); CTakeDamageInfo info( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); CalculateMeleeDamageForce( &info, vDir, tr.endpos ); pEntity->DispatchTraceAttack( info, vDir, &tr ); ApplyMultiDamage(); } else { pEntity->TakeDamage( CTakeDamageInfo( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ) ); } } } } }
void CGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { CBaseEntity *pEntity = NULL; TraceResult tr; float flAdjustedDamage; Vector vecSpot; Vector vecMid = (vecStart + vecEnd) * 0.5; float searchRadius = (vecStart - vecMid).Length(); Vector vecAim = (vecEnd - vecStart).Normalize( ); // iterate on all entities in the vicinity. while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecMid, searchRadius )) != NULL) { if ( pEntity->pev->takedamage != DAMAGE_NO ) { // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } vecSpot = pEntity->BodyTarget( vecMid ); float dist = DotProduct( vecAim, vecSpot - vecMid ); if (dist > searchRadius) dist = searchRadius; else if (dist < -searchRadius) dist = searchRadius; Vector vecSrc = vecMid + dist * vecAim; UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pev), &tr ); if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) {// the explosion can 'see' this entity, so hurt them! // decrease damage for an ent that's farther from the flame. dist = ( vecSrc - tr.vecEndPos ).Length(); if (dist > 64) { flAdjustedDamage = flDamage - (dist - 64) * 0.4; if (flAdjustedDamage <= 0) continue; } else { flAdjustedDamage = flDamage; } // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); if (tr.flFraction != 1.0) { ClearMultiDamage( ); pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType ); ApplyMultiDamage( pevInflictor, pevAttacker ); } else { pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); } } } } }
void CWeaponDrainGrenade::RadiusDamage( const CTakeDamageInfo &inputInfo, const Vector &vecSrcIn, float flRadius ) { CTakeDamageInfo info = inputInfo; CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecToTarget; Vector vecEndPos; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; vecSrc.z += 1;// in case grenade is lying on the ground // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if (!pEntity || !ToCFPlayer(pEntity)) continue; // Don't drain teammates. if (CFGameRules()->PlayerRelationship(GetThrower(), pEntity) == GR_TEAMMATE && ToCFPlayer(pEntity) != ToCFPlayer(GetThrower())) continue; if ( !pEntity->IsAlive() ) continue; if ( pEntity->m_takedamage != DAMAGE_NO ) { // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // radius damage can only be blocked by the world vecSpot = pEntity->BodyTarget( vecSrc ); bool bHit = false; UTIL_TraceLine( vecSrc, vecSpot, MASK_SOLID_BRUSHONLY, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } vecEndPos = tr.endpos; if( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) { bHit = true; } if ( bHit ) { // the explosion can 'see' this entity, so hurt them! vecToTarget = ( vecEndPos - vecSrc ); // decrease damage for an ent that's farther from the blast's center. flAdjustedDamage = vecToTarget.Length() * falloff; flAdjustedDamage = info.GetDrainFocus() - flAdjustedDamage; if ( flAdjustedDamage > 0 ) { CTakeDamageInfo adjustedInfo = info; adjustedInfo.SetDrainFocus( flAdjustedDamage ); Vector dir = vecToTarget; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc, 1.5 /* explosion scale! */ ); } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } float flFocusDrained = adjustedInfo.GetDrainFocus(); float& flFocus = ToCFPlayer(pEntity)->m_pStats->m_flFocus.GetForModify(); if (flFocus > cf_minfocusdrain.GetFloat()) flFocus -= flFocusDrained; if (flFocus < cf_minfocusdrain.GetFloat()) flFocus = cf_minfocusdrain.GetFloat(); CEffectData data; data.m_nHitBox = GetParticleSystemIndex( "grenade_drained" ); data.m_vOrigin = ToCFPlayer(pEntity)->GetCentroid(); data.m_vStart = vecSrc; data.m_vAngles = QAngle(0,0,0); data.m_nEntIndex = pEntity->entindex(); data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY; data.m_nDamageType = PATTACH_CUSTOMORIGIN; DispatchEffect( "ParticleEffect", data ); // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, vecEndPos, dir ); } } } } }
void CFuncTank::TrackTarget( void ) { trace_t tr; bool updateTime = FALSE, lineOfSight; QAngle angles; Vector barrelEnd; CBaseEntity *pTarget = NULL; barrelEnd.Init(); // Get a position to aim for if (m_pController) { // Tanks attempt to mirror the player's angles angles = m_pController->EyeAngles(); SetNextThink( gpGlobals->curtime + 0.05 ); } else { if ( IsActive() ) { SetNextThink( gpGlobals->curtime + 0.1f ); } else { return; } // ----------------------------------- // Get world target position // ----------------------------------- barrelEnd = WorldBarrelPosition(); Vector worldTargetPosition; if (m_spawnflags & SF_TANK_AIM_AT_POS) { worldTargetPosition = m_vTargetPosition; } else { CBaseEntity *pEntity = (CBaseEntity *)m_hTarget; if ( !pEntity || ( pEntity->GetFlags() & FL_NOTARGET ) ) { if ( m_targetEntityName != NULL_STRING ) // New HL2 behavior { m_hTarget = FindTarget( m_targetEntityName, NULL ); } else // HL1 style { m_hTarget = ToBasePlayer( GetContainingEntity( UTIL_FindClientInPVS( edict() ) ) ); } if ( m_hTarget != NULL ) { SetNextThink( gpGlobals->curtime ); // Think again immediately } else { if ( IsActive() ) { SetNextThink( gpGlobals->curtime + 2 ); // Wait 2 secs } if ( m_fireLast !=0 ) { m_OnLoseTarget.FireOutput(this, this); m_fireLast = 0; } } return; } pTarget = pEntity; // Calculate angle needed to aim at target worldTargetPosition = pEntity->EyePosition(); } float range = (worldTargetPosition - barrelEnd).Length(); if ( !InRange( range ) ) { m_fireLast = 0; return; } UTIL_TraceLine( barrelEnd, worldTargetPosition, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); if (m_spawnflags & SF_TANK_AIM_AT_POS) { updateTime = TRUE; m_sightOrigin = m_vTargetPosition; } else { lineOfSight = FALSE; // No line of sight, don't track if ( tr.fraction == 1.0 || tr.m_pEnt == pTarget ) { lineOfSight = TRUE; CBaseEntity *pInstance = pTarget; if ( InRange( range ) && pInstance && pInstance->IsAlive() ) { updateTime = TRUE; // Sight position is BodyTarget with no noise (so gun doesn't bob up and down) m_sightOrigin = pInstance->BodyTarget( GetLocalOrigin(), false ); } } } // Convert targetPosition to parent angles = AimBarrelAt( m_parentMatrix.WorldToLocal( m_sightOrigin ) ); } // Force the angles to be relative to the center position float offsetY = UTIL_AngleDistance( angles.y, m_yawCenter ); float offsetX = UTIL_AngleDistance( angles.x, m_pitchCenter ); angles.y = m_yawCenter + offsetY; angles.x = m_pitchCenter + offsetX; // Limit against range in y // MDB - don't check pitch! If two func_tanks are meant to align, // and one can pitch and the other cannot, this can lead to them getting // different values for angles.y. Nothing is lost by not updating yaw // because the target is not in pitch range. bool bOutsideYawRange = ( fabs( offsetY ) > m_yawRange + m_yawTolerance ); bool bOutsidePitchRange = ( fabs( offsetX ) > m_pitchRange + m_pitchTolerance ); Vector vecToTarget = m_sightOrigin - GetLocalOrigin(); // if target is outside yaw range if ( bOutsideYawRange ) { if ( angles.y > m_yawCenter + m_yawRange ) { angles.y = m_yawCenter + m_yawRange; } else if ( angles.y < (m_yawCenter - m_yawRange) ) { angles.y = (m_yawCenter - m_yawRange); } } if ( bOutsidePitchRange || bOutsideYawRange || ( vecToTarget.Length() < ( barrelEnd - GetAbsOrigin() ).Length() ) ) { // Don't update if you saw the player, but out of range updateTime = false; } if ( updateTime ) { m_lastSightTime = gpGlobals->curtime; m_persist2burst = 0; } // Move toward target at rate or less float distY = UTIL_AngleDistance( angles.y, GetLocalAngles().y ); QAngle vecAngVel = GetLocalAngularVelocity(); vecAngVel.y = distY * 10; vecAngVel.y = clamp( vecAngVel.y, -m_yawRate, m_yawRate ); // Limit against range in x angles.x = clamp( angles.x, m_pitchCenter - m_pitchRange, m_pitchCenter + m_pitchRange ); // Move toward target at rate or less float distX = UTIL_AngleDistance( angles.x, GetLocalAngles().x ); vecAngVel.x = distX * 10; vecAngVel.x = clamp( vecAngVel.x, -m_pitchRate, m_pitchRate ); SetLocalAngularVelocity( vecAngVel ); SetMoveDoneTime( 0.1 ); if ( m_pController ) return; if ( CanFire() && ( (fabs(distX) < m_pitchTolerance && fabs(distY) < m_yawTolerance) || (m_spawnflags & SF_TANK_LINEOFSIGHT) ) ) { bool fire = FALSE; Vector forward; AngleVectors( GetLocalAngles(), &forward ); forward = m_parentMatrix.ApplyRotation( forward ); if ( m_spawnflags & SF_TANK_LINEOFSIGHT ) { float length = (m_maxRange > 0) ? m_maxRange : MAX_TRACE_LENGTH; UTIL_TraceLine( barrelEnd, barrelEnd + forward * length, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); if ( tr.m_pEnt == pTarget ) fire = TRUE; } else fire = TRUE; if ( fire ) { if (m_fireLast == 0) { m_OnAquireTarget.FireOutput(this, this); } FiringSequence( barrelEnd, forward, this ); } else { if (m_fireLast !=0) { m_OnLoseTarget.FireOutput(this, this); } m_fireLast = 0; } } else { if (m_fireLast !=0) { m_OnLoseTarget.FireOutput(this, this); } m_fireLast = 0; } }
void RadiusDamage2(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType) { CBaseEntity *pEntity = NULL; TraceResult tr; float flAdjustedDamage, falloff; Vector vecSpot; if (flRadius) falloff = flDamage / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents(vecSrc) == CONTENTS_WATER); // in case grenade is lying on the ground vecSrc.z += 1; if (!pevAttacker) pevAttacker = pevInflictor; // iterate on all entities in the vicinity. while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecSrc, flRadius)) != NULL) { if (pEntity->pev->takedamage != DAMAGE_NO) { // UNDONE: this should check a damage mask, not an ignore if (iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore) continue; // blast's don't tavel into or out of water if (bInWater && pEntity->pev->waterlevel == 0) continue; if (!bInWater && pEntity->pev->waterlevel == 3) continue; vecSpot = pEntity->BodyTarget(vecSrc); UTIL_TraceLine(vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr); if (tr.flFraction == 1.0f || tr.pHit == pEntity->edict()) { if (tr.fStartSolid) { tr.vecEndPos = vecSrc; tr.flFraction = 0; } flAdjustedDamage = flDamage - (vecSrc - pEntity->pev->origin).Length() * falloff; if (flAdjustedDamage < 0) flAdjustedDamage = 0; else if (flAdjustedDamage > 75) flAdjustedDamage = 75; if (tr.flFraction == 1.0f) pEntity->TakeDamage(pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType); else { ClearMultiDamage(); pEntity->TraceAttack(pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize(), &tr, bitsDamageType); ApplyMultiDamage(pevInflictor, pevAttacker); } } } } }
void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ) { CBaseEntity *pEntity = NULL; TraceResult tr; float flAdjustedDamage, falloff; Vector vecSpot; if ( flRadius ) falloff = flDamage / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); vecSrc.z += 1;// in case grenade is lying on the ground if ( !pevAttacker ) pevAttacker = pevInflictor; // iterate on all entities in the vicinity. while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) { if ( pEntity->pev->takedamage != DAMAGE_NO ) { // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } // blast's don't tavel into or out of water if (bInWater && pEntity->pev->waterlevel == 0) continue; if (!bInWater && pEntity->pev->waterlevel == 3) continue; vecSpot = pEntity->BodyTarget( vecSrc ); UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr ); if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) {// the explosion can 'see' this entity, so hurt them! if (tr.fStartSolid) { // if we're stuck inside them, fixup the position and distance tr.vecEndPos = vecSrc; tr.flFraction = 0.0; } // decrease damage for an ent that's farther from the bomb. flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff; flAdjustedDamage = flDamage - flAdjustedDamage; if ( flAdjustedDamage < 0 ) { flAdjustedDamage = 0; } // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); if (tr.flFraction != 1.0) { ClearMultiDamage( ); pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType ); ApplyMultiDamage( pevInflictor, pevAttacker ); } else { pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); } } } } }
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; }
void AvHTurret::ActiveThink(void) { PROFILE_START() // Advance model frame StudioFrameAdvance(); // Find enemy, or reacquire dead enemy this->UpdateEnemy(); // If we have a valid enemy if(!FNullEnt(this->m_hEnemy)) { // If enemy is in FOV Vector theVecMid = this->pev->origin + this->pev->view_ofs; //AvHSUPlayParticleEvent("JetpackEffect", this->edict(), theVecMid); CBaseEntity* theEnemyEntity = this->m_hEnemy; Vector theVecMidEnemy = theEnemyEntity->BodyTarget(theVecMid); //AvHSUPlayParticleEvent("JetpackEffect", theEnemyEntity->edict(), theVecMidEnemy); // calculate dir and dist to enemy Vector theVecDirToEnemy = theVecMidEnemy - theVecMid; Vector theAddition = theVecMid + theVecDirToEnemy; Vector theVecLOS = theVecDirToEnemy.Normalize(); // Update our goal angles to direction to enemy Vector theVecDirToEnemyAngles; VectorAngles(theVecDirToEnemy, theVecDirToEnemyAngles); // Set goal quaternion this->mGoalQuat = Quat(theVecDirToEnemyAngles); // Is the turret looking at the target yet? float theRadians = (this->GetVerticalFOV()/180.0f)*3.1415f; float theCosVerticalFOV = cos(theRadians); Vector theCurrentAngles; this->mCurQuat.GetAngles(theCurrentAngles); UTIL_MakeAimVectors(theCurrentAngles); if(DotProduct(theVecLOS, gpGlobals->v_forward) > theCosVerticalFOV) { // If enemy is visible bool theEnemyVisible = FBoxVisible(this->pev, this->m_hEnemy->pev, theVecMidEnemy) || !this->GetRequiresLOS(); if(theEnemyVisible && this->m_hEnemy->IsAlive()) { // If it's time to attack if((this->mTimeOfNextAttack == -1) || (gpGlobals->time >= this->mTimeOfNextAttack)) { // Shoot and play shoot animation Shoot(theVecMid, theVecDirToEnemy, theEnemyEntity->pev->velocity); this->PlayAnimationAtIndex(this->GetActiveAnimation()); // Set time for next attack this->SetNextAttack(); } // spin the barrel when acquired but not firing else if(this->GetBaseClassAnimatesTurret()) { this->pev->sequence = 2; ResetSequenceInfo(); } } } // Set next active think this->pev->nextthink = gpGlobals->time + kTurretThinkInterval; } // else we have no enemy, go back to search think else { SetThink(&AvHTurret::SearchThink); this->pev->nextthink = gpGlobals->time + kTurretThinkInterval; } this->TurretUpdate(); PROFILE_END(kAvHTurretActiveThink) }
//----------------------------------------------------------------------------- // Purpose: Push a physics object in our wash. Return false if it's now out of our wash //----------------------------------------------------------------------------- bool CBaseHelicopter::DoWashPush( washentity_t *pWash, const Vector &vecWashOrigin ) { if ( !pWash || !pWash->hEntity.Get() ) return false; // Make sure the entity is still within our wash's radius CBaseEntity *pEntity = pWash->hEntity; // This can happen because we can dynamically turn this flag on and off if ( pEntity->IsEFlagSet( EFL_NO_ROTORWASH_PUSH )) return false; Vector vecSpot = pEntity->BodyTarget( vecWashOrigin ); Vector vecToSpot = ( vecSpot - vecWashOrigin ); vecToSpot.z = 0; float flDist = VectorNormalize( vecToSpot ); if ( flDist > BASECHOPPER_WASH_RADIUS ) return false; IRotorWashShooter *pShooter = GetRotorWashShooter( pEntity ); IPhysicsObject *pPhysObject; float flPushTime = (gpGlobals->curtime - pWash->flWashStartTime); flPushTime = clamp( flPushTime, 0, BASECHOPPER_WASH_RAMP_TIME ); float flWashAmount = RemapVal( flPushTime, 0, BASECHOPPER_WASH_RAMP_TIME, BASECHOPPER_WASH_PUSH_MIN, BASECHOPPER_WASH_PUSH_MAX ); if ( pShooter ) { Vector vecForce = (0.015f / 0.1f) * flWashAmount * vecToSpot * phys_pushscale.GetFloat(); pEntity = pShooter->DoWashPush( pWash->flWashStartTime, vecForce ); if ( !pEntity ) return true; washentity_t Wash; Wash.hEntity = pEntity; Wash.flWashStartTime = pWash->flWashStartTime; int i = m_hEntitiesPushedByWash.AddToTail( Wash ); pWash = &m_hEntitiesPushedByWash[i]; pPhysObject = pEntity->VPhysicsGetObject(); if ( !pPhysObject ) return true; } else { // Airboat gets special treatment if ( FClassnameIs( pEntity, "prop_vehicle_airboat" ) ) { DoWashPushOnAirboat( pEntity, vecToSpot, flWashAmount ); return true; } pPhysObject = pEntity->VPhysicsGetObject(); if ( !pPhysObject ) return false; } // Push it away from the center of the wash float flMass = pPhysObject->GetMass(); // This used to be mass independent, which is a bad idea because it blows 200kg engine blocks // as much as it blows cardboard and soda cans. Make this force mass-independent, but clamp at // 30kg. flMass = MIN( flMass, 30.0f ); Vector vecForce = (0.015f / 0.1f) * flWashAmount * flMass * vecToSpot * phys_pushscale.GetFloat(); pEntity->VPhysicsTakeDamage( CTakeDamageInfo( this, this, vecForce, vecWashOrigin, flWashAmount, DMG_BLAST ) ); // Debug if ( g_debug_basehelicopter.GetInt() == BASECHOPPER_DEBUG_WASH ) { NDebugOverlay::Cross3D( pEntity->GetAbsOrigin(), -Vector(4,4,4), Vector(4,4,4), 255, 0, 0, true, 0.1f ); NDebugOverlay::Line( pEntity->GetAbsOrigin(), pEntity->GetAbsOrigin() + vecForce, 255, 255, 0, true, 0.1f ); IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject(); Msg("Pushed %s (index %d) (mass %f) with force %f (min %.2f max %.2f) at time %.2f\n", pEntity->GetClassname(), pEntity->entindex(), pPhysObject->GetMass(), flWashAmount, BASECHOPPER_WASH_PUSH_MIN * flMass, BASECHOPPER_WASH_PUSH_MAX * flMass, gpGlobals->curtime ); } // If we've pushed this thing for some time, remove it to give us a chance to find lighter things nearby if ( flPushTime > 2.0 ) return false; return true; }
void CGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ) { const int MASK_RADIUS_DAMAGE = MASK_SHOT&(~CONTENTS_HITBOX); CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; #ifdef HL2_DLL if( bInWater ) { // Only muffle the explosion if deeper than 2 feet in water. if( !(UTIL_PointContents(vecSrc + Vector(0, 0, 24)) & MASK_WATER) ) { bInWater = false; } } #endif // HL2_DLL vecSrc.z += 1;// in case grenade is lying on the ground float flHalfRadiusSqr = Square( flRadius / 2.0f ); // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) { // This value is used to scale damage when the explosion is blocked by some other object. float flBlockedDamagePercent = 0.0f; if ( pEntity == pEntityIgnore ) continue; if ( pEntity->m_takedamage == DAMAGE_NO ) continue; // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // Check that the explosion can 'see' this entity. vecSpot = pEntity->BodyTarget( vecSrc, false ); UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( old_radius_damage.GetBool() ) { if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity ) continue; } else { if ( tr.fraction != 1.0 ) { if ( IsExplosionTraceBlocked(&tr) ) { if( ShouldUseRobustRadiusDamage( pEntity ) ) { if( vecSpot.DistToSqr( vecSrc ) > flHalfRadiusSqr ) { // Only use robust model on a target within one-half of the explosion's radius. continue; } Vector vecToTarget = vecSpot - tr.endpos; VectorNormalize( vecToTarget ); // We're going to deflect the blast along the surface that // interrupted a trace from explosion to this target. Vector vecUp, vecDeflect; CrossProduct( vecToTarget, tr.plane.normal, vecUp ); CrossProduct( tr.plane.normal, vecUp, vecDeflect ); VectorNormalize( vecDeflect ); // Trace along the surface that intercepted the blast... UTIL_TraceLine( tr.endpos, tr.endpos + vecDeflect * ROBUST_RADIUS_PROBE_DIST, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 10 ); // ...to see if there's a nearby edge that the explosion would 'spill over' if the blast were fully simulated. UTIL_TraceLine( tr.endpos, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 10 ); if( tr.fraction != 1.0 && tr.DidHitWorld() ) { // Still can't reach the target. continue; } // else fall through } else { continue; } } // UNDONE: Probably shouldn't let children block parents either? Or maybe those guys should set their owner if they want this behavior? // HL2 - Dissolve damage is not reduced by interposing non-world objects if( tr.m_pEnt && tr.m_pEnt != pEntity && tr.m_pEnt->GetOwnerEntity() != pEntity ) { // Some entity was hit by the trace, meaning the explosion does not have clear // line of sight to the entity that it's trying to hurt. If the world is also // blocking, we do no damage. CBaseEntity *pBlockingEntity = tr.m_pEnt; //Msg( "%s may be blocked by %s...", pEntity->GetClassname(), pBlockingEntity->GetClassname() ); UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( tr.fraction != 1.0 ) { continue; } // Now, if the interposing object is physics, block some explosion force based on its mass. if( pBlockingEntity->VPhysicsGetObject() ) { const float MASS_ABSORB_ALL_DAMAGE = 350.0f; float flMass = pBlockingEntity->VPhysicsGetObject()->GetMass(); float scale = flMass / MASS_ABSORB_ALL_DAMAGE; // Absorbed all the damage. if( scale >= 1.0f ) { continue; } ASSERT( scale > 0.0f ); flBlockedDamagePercent = scale; //Msg(" Object (%s) weighing %fkg blocked %f percent of explosion damage\n", pBlockingEntity->GetClassname(), flMass, scale * 100.0f); } else { // Some object that's not the world and not physics. Generically block 25% damage flBlockedDamagePercent = 0.25f; } } } } // decrease damage for an ent that's farther from the bomb. flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff; flAdjustedDamage = info.GetDamage() - flAdjustedDamage; if ( flAdjustedDamage <= 0 ) { continue; } // the explosion can 'see' this entity, so hurt them! if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } CTakeDamageInfo adjustedInfo = info; //Msg("%s: Blocked damage: %f percent (in:%f out:%f)\n", pEntity->GetClassname(), flBlockedDamagePercent * 100, flAdjustedDamage, flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); adjustedInfo.SetDamage( flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); // Now make a consideration for skill level! if( info.GetAttacker() && info.GetAttacker()->IsPlayer() && pEntity->IsNPC() ) { // An explosion set off by the player is harming an NPC. Adjust damage accordingly. adjustedInfo.AdjustPlayerDamageInflictedForSkillLevel(); } Vector dir = vecSpot - vecSrc; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { if ( !( adjustedInfo.GetDamageType() & DMG_PREVENT_PHYSICS_FORCE ) ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc ); } } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } if ( tr.fraction != 1.0 && pEntity == tr.m_pEnt ) { ClearMultiDamage( ); pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr ); ApplyMultiDamage(); } else { pEntity->TakeDamage( adjustedInfo ); } // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir ); #if defined( GAME_DLL ) if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && ToBaseCombatCharacter( tr.m_pEnt ) ) { // This is a total hack!!! bool bIsPrimary = true; CBasePlayer *player = ToBasePlayer( info.GetAttacker() ); CBaseCombatWeapon *pWeapon = player->GetActiveWeapon(); if ( pWeapon && FClassnameIs( pWeapon, "weapon_smg1" ) ) { bIsPrimary = false; } //gamestats->Event_WeaponHit( player, bIsPrimary, (pWeapon != NULL) ? player->GetActiveWeapon()->GetClassname() : "NULL", info ); } #endif } }
void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float inDamage, float flRadius, int iClassIgnore, int bitsDamageType ) { CBaseEntity *pEntity = NULL; TraceResult tr; float flAdjustedDamage, falloff; Vector vecSpot; if ( flRadius ) falloff = inDamage / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); vecSrc.z += 1;// in case grenade is lying on the ground if ( !pevAttacker ) pevAttacker = pevInflictor; // iterate on all entities in the vicinity. while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) { // NOTE: Should this be inflictor or attacker? CBaseEntity* theInflictingEntity = CBaseEntity::Instance(pevInflictor); CBaseEntity* theAttackingEntity = CBaseEntity::Instance(pevAttacker); float theScalar = 1.0f; bool aCanDamage=GetGameRules()->CanEntityDoDamageTo(theAttackingEntity, pEntity, &theScalar) || theInflictingEntity->pev->classname == MAKE_STRING(kwsDeployedMine);; bool iCanDamage=GetGameRules()->CanEntityDoDamageTo(theInflictingEntity, pEntity, &theScalar); if(pEntity && ( aCanDamage && iCanDamage )) { // Multiply damage by scalar for tourny mode, etc. float theDamage = inDamage*theScalar; if ( pEntity->pev->takedamage != DAMAGE_NO ) { // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } // blast's don't tavel into or out of water if (bInWater && pEntity->pev->waterlevel == 0) continue; if (!bInWater && pEntity->pev->waterlevel == 3) continue; vecSpot = pEntity->BodyTarget( vecSrc ); // Clear pevInflictor's owner temporarily so it can apply damage to it edict_t* theInflictorOwner = pevInflictor->owner; pevInflictor->owner = NULL; UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr ); // Restore owner pevInflictor->owner = theInflictorOwner; if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) {// the explosion can 'see' this entity, so hurt them! if (tr.fStartSolid) { // if we're stuck inside them, fixup the position and distance tr.vecEndPos = vecSrc; tr.flFraction = 0.0; } // decrease damage for an ent that's farther from the bomb. flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff; flAdjustedDamage = theDamage - flAdjustedDamage; if ( flAdjustedDamage > 0 ) { pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); } } } } } }