//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL1_Player::FindMissTargets( void ) { if ( m_flTargetFindTime > gpGlobals->curtime ) return; m_flTargetFindTime = gpGlobals->curtime + 1.0f; m_nNumMissPositions = 0; CBaseEntity *pEnts[256]; Vector radius( 80, 80, 80); int numEnts = UTIL_EntitiesInBox( pEnts, 256, GetAbsOrigin()-radius, GetAbsOrigin()+radius, 0 ); for ( int i = 0; i < numEnts; i++ ) { if ( pEnts[i] == NULL ) continue; if ( m_nNumMissPositions >= 16 ) return; //See if it's a good target candidate if ( FClassnameIs( pEnts[i], "prop_dynamic" ) || FClassnameIs( pEnts[i], "dynamic_prop" ) || FClassnameIs( pEnts[i], "prop_physics" ) || FClassnameIs( pEnts[i], "physics_prop" ) ) { //NDebugOverlay::Cross3D( pEnts[i]->WorldSpaceCenter(), -Vector(4,4,4), Vector(4,4,4), 0, 255, 0, true, 1.0f ); m_vecMissPositions[m_nNumMissPositions++] = pEnts[i]->WorldSpaceCenter(); continue; } } }
CBaseEntity *CBarnacle :: TongueTouchEnt ( float *pflLength ) { TraceResult tr; float length; // trace once to hit architecture and see if the tongue needs to change position. UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0 , 0 , 2048 ), ignore_monsters, ENT(pev), &tr ); length = fabs( pev->origin.z - tr.vecEndPos.z ); if ( pflLength ) { *pflLength = length; } Vector delta = Vector( BARNACLE_CHECK_SPACING, BARNACLE_CHECK_SPACING, 0 ); Vector mins = pev->origin - delta; Vector maxs = pev->origin + delta; maxs.z = pev->origin.z; mins.z -= length; CBaseEntity *pList[10]; int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, (FL_CLIENT|FL_MONSTER) ); if ( count ) { for ( int i = 0; i < count; i++ ) { // only clients and monsters if ( pList[i] != this && IRelationship( pList[i] ) > R_NO && pList[ i ]->pev->deadflag == DEAD_NO ) // this ent is one of our enemies. Barnacle tries to eat it. { return pList[i]; } } } return NULL; }
bool AvHHive::SetSolid(bool inForce) { // Check to make sure there aren't any players in the destination area CBaseEntity* pList[128]; // Crank up the area just to be safe Vector theMinArea = this->pev->origin + kHiveMinSize; Vector theMaxArea = this->pev->origin + kHiveMaxSize; // TODO: If players are blocking this area for too long, spawn hive and kill them int theNumBlockingEntities = UTIL_EntitiesInBox(pList, 128, theMinArea, theMaxArea, FL_CLIENT); if((theNumBlockingEntities == 0) || inForce) { this->pev->solid = SOLID_BBOX; this->pev->movetype = MOVETYPE_NONE; UTIL_SetSize(this->pev, kHiveMinSize, kHiveMaxSize); // pev->frame = 0; // pev->body = 3; // pev->sequence = 0; // // ResetSequenceInfo( ); // pev->framerate = 0; // // UTIL_SetOrigin(pev, pev->origin); // UTIL_SetSize(pev, Vector(-20, -20, 0), Vector(20, 20, 28) ); SetTouch(&AvHHive::HiveTouch); this->mSolid = true; } return this->mSolid; }
// This function takes a lot of CPU, so make sure it's not called often! Don't call this function directly, use UpdateEnemy instead whenever possible. CBaseEntity* AvHTurret::FindBestEnemy() { PROFILE_START() CBaseEntity* theEntityList[100]; int theMaxRange = this->GetXYRange(); Vector delta = Vector(theMaxRange, theMaxRange, theMaxRange); CBaseEntity* theCurrentEntity = NULL; CBaseEntity* theBestPlayer = NULL; CBaseEntity* theBestStructure = NULL; float theCurrentEntityRange = 100000; // Find only monsters/clients in box, NOT limited to PVS int theCount = UTIL_EntitiesInBox(theEntityList, 100, this->pev->origin - delta, this->pev->origin + delta, FL_CLIENT | FL_MONSTER); for(int i = 0; i < theCount; i++ ) { theCurrentEntity = theEntityList[i]; if((theCurrentEntity != this) && theCurrentEntity->IsAlive()) { // the looker will want to consider this entity // don't check anything else about an entity that can't be seen, or an entity that you don't care about. if(this->IRelationship(theCurrentEntity ) != R_NO && FInViewCone(theCurrentEntity) && !FBitSet(theCurrentEntity->pev->flags, FL_NOTARGET)) { AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(theCurrentEntity); if(!thePlayer || thePlayer->GetCanBeAffectedByEnemies()) { if(this->GetIsValidTarget(theCurrentEntity)) { // Find nearest enemy float theRangeToTarget = VectorDistance2D(this->pev->origin, theCurrentEntity->pev->origin); if(theRangeToTarget < theCurrentEntityRange) { // FVisible is expensive, so defer until necessary if(!this->GetRequiresLOS() || FVisible(theCurrentEntity)) { theCurrentEntityRange = theRangeToTarget; if ( thePlayer ) { theBestPlayer = theCurrentEntity; } else { theBestStructure = theCurrentEntity; } } } } } } } } PROFILE_END(kAvHTurretFindBestEnemy); return (theBestPlayer != NULL ) ? theBestPlayer : theBestStructure; }
//========================================================= // TryMakeMonster- check that it's ok to drop a monster. //========================================================= void CMonsterMaker::TryMakeMonster( void ) { if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren ) {// not allowed to make a new one yet. Too many live ones out right now. return; } if ( !m_flGround ) { // set altitude. Now that I'm activated, any breakables, etc should be out from under me. TraceResult tr; UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr ); m_flGround = tr.vecEndPos.z; } Vector mins = pev->origin - Vector( 34, 34, 0 ); Vector maxs = pev->origin + Vector( 34, 34, 0 ); maxs.z = pev->origin.z; mins.z = m_flGround; CBaseEntity *pList[2]; int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER ); if ( count ) { // don't build a stack of monsters! return; } if (m_fSpawnDelay) { // If I have a target, fire. (no locus) if ( !FStringNull ( pev->target ) ) { // delay already overloaded for this entity, so can't call SUB_UseTargets() FireTargets( STRING(pev->target), this, this, USE_TOGGLE, 0 ); } // ALERT(at_console,"Making Monster in %f seconds\n",m_fSpawnDelay); SetThink(&CMonsterMaker:: MakeMonsterThink ); SetNextThink( m_fSpawnDelay ); } else { // ALERT(at_console,"No delay. Making monster.\n",m_fSpawnDelay); CBaseMonster* pMonst = MakeMonster(); // If I have a target, fire! (the new monster is the locus) if ( !FStringNull ( pev->target ) ) { FireTargets( STRING(pev->target), pMonst, this, USE_TOGGLE, 0 ); } } }
boost::python::object UTIL_PyEntitiesInBox( int listMax, const Vector &mins, const Vector &maxs, int flagMask ) { int i, n; CBaseEntity **pList; boost::python::list pylist = boost::python::list(); pList = (CBaseEntity **)malloc(listMax*sizeof(CBaseEntity *)); n = UTIL_EntitiesInBox(pList, listMax, mins, maxs, flagMask); for( i=0; i < n; i++) pylist.append(*pList[i]); free(pList); return pylist; }
void CBaseMonster::Look(int iDistance) { int iSighted = 0; ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT); m_pLink = NULL; CBaseEntity *pSightEnt = NULL; CBaseEntity *pList[100]; Vector delta = Vector(iDistance, iDistance, iDistance); int count = UTIL_EntitiesInBox(pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT | FL_MONSTER); for (int i = 0; i < count; i++) { pSightEnt = pList[i]; if (pSightEnt != this && pSightEnt->pev->health > 0) { if (IRelationship(pSightEnt) != R_NO && FInViewCone(pSightEnt) && !FBitSet(pSightEnt->pev->flags, FL_NOTARGET) && FVisible(pSightEnt)) { if (pSightEnt->IsPlayer()) iSighted |= bits_COND_SEE_CLIENT; pSightEnt->m_pLink = m_pLink; m_pLink = pSightEnt; if (pSightEnt == m_hEnemy) iSighted |= bits_COND_SEE_ENEMY; switch (IRelationship(pSightEnt)) { case R_NM: iSighted |= bits_COND_SEE_NEMESIS; break; case R_HT: iSighted |= bits_COND_SEE_HATE; break; case R_DL: iSighted |= bits_COND_SEE_DISLIKE; break; case R_FR: iSighted |= bits_COND_SEE_FEAR; break; case R_AL: break; } } } } SetConditions(iSighted); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CGrenadeHopwire::KillStriders( void ) { CBaseEntity *pEnts[128]; Vector mins, maxs; ClearBounds( mins, maxs ); AddPointToBounds( -Vector( MAX_STRIDER_STUN_DISTANCE_HORZ, MAX_STRIDER_STUN_DISTANCE_HORZ, MAX_STRIDER_STUN_DISTANCE_HORZ ), mins, maxs ); AddPointToBounds( Vector( MAX_STRIDER_STUN_DISTANCE_HORZ, MAX_STRIDER_STUN_DISTANCE_HORZ, MAX_STRIDER_STUN_DISTANCE_HORZ ), mins, maxs ); AddPointToBounds( -Vector( MAX_STRIDER_STUN_DISTANCE_VERT, MAX_STRIDER_STUN_DISTANCE_VERT, MAX_STRIDER_STUN_DISTANCE_VERT ), mins, maxs ); AddPointToBounds( Vector( MAX_STRIDER_STUN_DISTANCE_VERT, MAX_STRIDER_STUN_DISTANCE_VERT, MAX_STRIDER_STUN_DISTANCE_VERT ), mins, maxs ); // FIXME: It's probably much faster to simply iterate over the striders in the map, rather than any entity in the radius - jdw // Find any striders in range of us int numTargets = UTIL_EntitiesInBox( pEnts, ARRAYSIZE( pEnts ), GetAbsOrigin()+mins, GetAbsOrigin()+maxs, FL_NPC ); float targetDistHorz, targetDistVert; for ( int i = 0; i < numTargets; i++ ) { // Only affect striders if ( FClassnameIs( pEnts[i], "npc_strider" ) == false ) continue; // We categorize our spatial relation to the strider in horizontal and vertical terms, so that we can specify both parameters separately targetDistHorz = UTIL_DistApprox2D( pEnts[i]->GetAbsOrigin(), GetAbsOrigin() ); targetDistVert = fabs( pEnts[i]->GetAbsOrigin()[2] - GetAbsOrigin()[2] ); if ( targetDistHorz < MAX_STRIDER_KILL_DISTANCE_HORZ && targetDistHorz < MAX_STRIDER_KILL_DISTANCE_VERT ) { // Kill the strider float fracDamage = ( pEnts[i]->GetMaxHealth() / hopwire_strider_hits.GetFloat() ) + 1.0f; CTakeDamageInfo killInfo( this, this, fracDamage, DMG_GENERIC ); Vector killDir = pEnts[i]->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize( killDir ); killInfo.SetDamageForce( killDir * -1000.0f ); killInfo.SetDamagePosition( GetAbsOrigin() ); pEnts[i]->TakeDamage( killInfo ); } else if ( targetDistHorz < MAX_STRIDER_STUN_DISTANCE_HORZ && targetDistHorz < MAX_STRIDER_STUN_DISTANCE_VERT ) { // Stun the strider CTakeDamageInfo killInfo( this, this, 200.0f, DMG_GENERIC ); pEnts[i]->TakeDamage( killInfo ); } } }
//LRC void CBreakable::RespawnThink( void ) { // ALERT(at_debug,"RespawnThink: "); CBaseEntity *pList[2]; int count = UTIL_EntitiesInBox( pList, 2, pev->mins, pev->maxs, FL_MONSTER | FL_CLIENT ); if ( count ) { // Can't respawn right now, a monster or player is in the way. Wait a bit. // ALERT(at_debug,"Respawn failed, count is %d\n",count); SetThink(&CBreakable:: RespawnThink ); SetNextThink( 2 ); // CONSIDER: change this number? } else { // fade in, don't just appear(?) if (pev->spawnflags & SF_BREAK_FADE_RESPAWN) { SetThink(&CBreakable:: RespawnFadeThink ); SetNextThink( 0.1 ); pev->renderamt = 0; if (m_iInitialRenderMode == kRenderNormal) { pev->rendermode = kRenderTransTexture; m_iInitialRenderAmt = 255; } } // ALERT(at_debug,"Respawn OK\n"); /* if (FStrEq("func_pushable",STRING(pev->classname))){ //AJH Fix for respawnable breakable pushables pev->solid = SOLID_BBOX; //For some reason this code must be executed outside of pev->origin.z+=1; //the RespawnThink function. Uses DoRespawn() UTIL_SetOrigin(this,pev->origin); }else{ pev->solid = SOLID_BSP; } */ DoRespawn(); //AJH Fix for respawnable breakable pushables (BY HAWK777) SetUse(&CBreakable:: BreakUse ); pev->effects &= ~EF_NODRAW; pev->health = m_iInitialHealth; if ( !FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) pev->takedamage = DAMAGE_YES; // trigger the "fire on respawn" target FireTargets( STRING(pev->netname), this, this, USE_TOGGLE, 0); } }
//----------------------------------------------------------------------------- // Purpose: Returns whether or not it is OK to make an NPC at this instant. //----------------------------------------------------------------------------- bool CHL1NPCMaker::CanMakeNPC( void ) { if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren ) {// not allowed to make a new one yet. Too many live ones out right now. return false; } if ( !m_flGround ) { // set altitude. Now that I'm activated, any breakables, etc should be out from under me. trace_t tr; UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() - Vector ( 0, 0, 2048 ), MASK_NPCSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); m_flGround = tr.endpos.z; } Vector mins = GetAbsOrigin() - Vector( 34, 34, 0 ); Vector maxs = GetAbsOrigin() + Vector( 34, 34, 0 ); maxs.z = GetAbsOrigin().z; //Only adjust for the ground if we want it if ( ( m_spawnflags & SF_NPCMakerHL1_NO_DROP ) == false ) { mins.z = m_flGround; } CBaseEntity *pList[128]; int count = UTIL_EntitiesInBox( pList, 128, mins, maxs, FL_CLIENT|FL_NPC ); if ( count ) { //Iterate through the list and check the results for ( int i = 0; i < count; i++ ) { //Don't build on top of another entity if ( pList[i] == NULL ) continue; //If one of the entities is solid, then we can't spawn now if ( ( pList[i]->GetSolidFlags() & FSOLID_NOT_SOLID ) == false ) return false; } } return true; }
//------------------------------------------------------------------------------ // Purpose : Reset the OnGround flags for any entities that may have been // resting on me // Input : // Output : //------------------------------------------------------------------------------ void CBreakable::ResetOnGroundFlags(void) { // !!! HACK This should work! // Build a box above the entity that looks like an 9 inch high sheet Vector mins, maxs; CollisionProp()->WorldSpaceAABB( &mins, &maxs ); mins.z -= 1; maxs.z += 8; // BUGBUG -- can only find 256 entities on a breakable -- should be enough CBaseEntity *pList[256]; int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND ); if ( count ) { for ( int i = 0; i < count; i++ ) { pList[i]->SetGroundEntity( (CBaseEntity *)NULL ); } } #ifdef PORTAL // !!! HACK This should work! // Tell touching portals to fizzle int iPortalCount = CProp_Portal_Shared::AllPortals.Count(); if( iPortalCount != 0 ) { Vector vMin, vMax; CollisionProp()->WorldSpaceAABB( &vMin, &vMax ); Vector vBoxCenter = ( vMin + vMax ) * 0.5f; Vector vBoxExtents = ( vMax - vMin ) * 0.5f; CProp_Portal **pPortals = CProp_Portal_Shared::AllPortals.Base(); for( int i = 0; i != iPortalCount; ++i ) { CProp_Portal *pTempPortal = pPortals[i]; if( UTIL_IsBoxIntersectingPortal( vBoxCenter, vBoxExtents, pTempPortal ) ) { pTempPortal->DoFizzleEffect( PORTAL_FIZZLE_KILLED, false ); pTempPortal->Fizzle(); } } } #endif }
//------------------------------------------------------------------------------ // Purpose : Reset the OnGround flags for any entities that may have been // resting on me // Input : // Output : //------------------------------------------------------------------------------ void CBreakable::ResetOnGroundFlags(void) { // !!! HACK This should work! // Build a box above the entity that looks like an 9 inch high sheet Vector mins, maxs; CollisionProp()->WorldSpaceAABB( &mins, &maxs ); mins.z -= 1; maxs.z += 8; // BUGBUG -- can only find 256 entities on a breakable -- should be enough CBaseEntity *pList[256]; int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND ); if ( count ) { for ( int i = 0; i < count; i++ ) { pList[i]->SetGroundEntity( (CBaseEntity *)NULL ); } } }
BOOL CanLayCrab( void ) { if ( m_crabTime < gpGlobals->curtime && m_crabCount < BIG_MAXCHILDREN ) { // Don't spawn crabs inside each other Vector mins = GetAbsOrigin() - Vector( 32, 32, 0 ); Vector maxs = GetAbsOrigin() + Vector( 32, 32, 0 ); CBaseEntity *pList[2]; int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_NPC ); for ( int i = 0; i < count; i++ ) { if ( pList[i] != this ) // Don't hurt yourself! return COND_NONE; } return COND_CAN_MELEE_ATTACK2; } return COND_NONE; }
BOOL CanLayCrab( void ) { if ( m_crabTime < gpGlobals->time && m_crabCount < BIG_MAXCHILDREN ) { // Don't spawn crabs inside each other Vector mins = pev->origin - Vector( 32, 32, 0 ); Vector maxs = pev->origin + Vector( 32, 32, 0 ); CBaseEntity *pList[2]; int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_MONSTER ); for ( int i = 0; i < count; i++ ) { if ( pList[i] != this ) // Don't hurt yourself! return FALSE; } return TRUE; } return FALSE; }
bool C_DynamicProp::TestBoneFollowers( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ) { // UNDONE: There is no list of the bone followers that is networked to the client // so instead we do a search for solid stuff here. This is not really great - a list would be // preferable. CBaseEntity *pList[128]; Vector mins, maxs; CollisionProp()->WorldSpaceAABB( &mins, &maxs ); int count = UTIL_EntitiesInBox( pList, ARRAYSIZE(pList), mins, maxs, 0, PARTITION_CLIENT_SOLID_EDICTS ); for ( int i = 0; i < count; i++ ) { if ( pList[i]->GetOwnerEntity() == this ) { if ( pList[i]->TestCollision(ray, fContentsMask, tr) ) { return true; } } } return false; }
//LRC void CBreakable::RespawnThink( void ) { // ALERT(at_debug,"RespawnThink: "); CBaseEntity *pList[2]; int count = UTIL_EntitiesInBox( pList, 2, pev->mins, pev->maxs, FL_MONSTER | FL_CLIENT ); if ( count ) { // Can't respawn right now, a monster or player is in the way. Wait a bit. // ALERT(at_debug,"Respawn failed, count is %d\n",count); SetThink(&CBreakable:: RespawnThink ); SetNextThink( 2 ); // CONSIDER: change this number? } else { // fade in, don't just appear(?) if (pev->spawnflags & SF_BREAK_FADE_RESPAWN) { SetThink(&CBreakable:: RespawnFadeThink ); SetNextThink( 0.1 ); pev->renderamt = 0; if (m_iInitialRenderMode == kRenderNormal) { pev->rendermode = kRenderTransTexture; m_iInitialRenderAmt = 255; } } // ALERT(at_debug,"Respawn OK\n"); pev->solid = SOLID_BSP; pev->effects &= ~EF_NODRAW; pev->health = m_iInitialHealth; SetUse(&CBreakable:: BreakUse ); if ( !FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) pev->takedamage = DAMAGE_YES; // trigger the "fire on respawn" target FireTargets( STRING(pev->netname), this, this, USE_TOGGLE, 0); } }
void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case TREE_AE_ATTACK: { CBaseEntity *pList[8]; BOOL sound = FALSE; int count = UTIL_EntitiesInBox( pList, 8, m_pTrigger->pev->absmin, m_pTrigger->pev->absmax, FL_MONSTER|FL_CLIENT ); Vector forward; UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); for ( int i = 0; i < count; i++ ) { if ( pList[i] != this ) { if ( pList[i]->pev->owner != edict() ) { sound = TRUE; pList[i]->TakeDamage( pev, pev, 25, DMG_CRUSH | DMG_SLASH ); pList[i]->pev->punchangle.x = 15; pList[i]->pev->velocity = pList[i]->pev->velocity + forward * 100; } } } if ( sound ) { EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackHitSounds ); } } return; } CActAnimating::HandleAnimEvent( pEvent ); }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CBigMomma :: HandleAnimEvent( MonsterEvent_t *pEvent ) { switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: case BIG_AE_MELEE_ATTACKBL: case BIG_AE_MELEE_ATTACK1: { Vector forward, right; UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); Vector center = pev->origin + forward * 128; Vector mins = center - Vector( 64, 64, 0 ); Vector maxs = center + Vector( 64, 64, 64 ); CBaseEntity *pList[8]; int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_MONSTER|FL_CLIENT ); CBaseEntity *pHurt = NULL; for ( int i = 0; i < count && !pHurt; i++ ) { if ( pList[i] != this ) { if ( pList[i]->pev->owner != edict() ) pHurt = pList[i]; } } if ( pHurt ) { pHurt->TakeDamage( pev, pev, gSkillData.bigmommaDmgSlash, DMG_CRUSH | DMG_SLASH ); pHurt->pev->punchangle.x = 15; switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) - (right * 200); break; case BIG_AE_MELEE_ATTACKBL: pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) + (right * 200); break; case BIG_AE_MELEE_ATTACK1: pHurt->pev->velocity = pHurt->pev->velocity + (forward * 220) + Vector(0,0,200); break; } pHurt->pev->flags &= ~FL_ONGROUND; EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); } } break; case BIG_AE_SCREAM: EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); break; case BIG_AE_PAIN_SOUND: EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); break; case BIG_AE_ATTACK_SOUND: EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackSounds ); break; case BIG_AE_BIRTH_SOUND: EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pBirthSounds ); break; case BIG_AE_SACK: if ( RANDOM_LONG(0,100) < 30 ) EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pSackSounds ); break; case BIG_AE_DEATHSOUND: EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); break; case BIG_AE_STEP1: // Footstep left case BIG_AE_STEP3: // Footstep back left EMIT_SOUND_ARRAY_DYN( CHAN_ITEM, pFootSounds ); break; case BIG_AE_STEP4: // Footstep back right case BIG_AE_STEP2: // Footstep right EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pFootSounds ); break; case BIG_AE_MORTAR_ATTACK1: LaunchMortar(); break; case BIG_AE_LAY_CRAB: LayHeadcrab(); break; case BIG_AE_JUMP_FORWARD: ClearBits( pev->flags, FL_ONGROUND ); UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground UTIL_MakeVectors ( pev->angles ); pev->velocity = (gpGlobals->v_forward * 200) + gpGlobals->v_up * 500; break; case BIG_AE_EARLY_TARGET: { CBaseEntity *pTarget = m_hTargetEnt; if ( pTarget && pTarget->pev->message ) FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); Remember( bits_MEMORY_FIRED_NODE ); } break; default: CBaseMonster::HandleAnimEvent( pEvent ); break; } }
//----------------------------------------------------------------------------- // Purpose: Pulls physical objects towards the vortex center, killing them if they come too near //----------------------------------------------------------------------------- void CGravityVortexController::PullThink( void ) { // Pull any players close enough to us PullPlayersInRange(); Vector mins, maxs; mins = GetAbsOrigin() - Vector( m_flRadius, m_flRadius, m_flRadius ); maxs = GetAbsOrigin() + Vector( m_flRadius, m_flRadius, m_flRadius ); // Draw debug information if ( g_debug_hopwire.GetBool() ) { NDebugOverlay::Box( GetAbsOrigin(), mins - GetAbsOrigin(), maxs - GetAbsOrigin(), 0, 255, 0, 16, 4.0f ); } CBaseEntity *pEnts[128]; int numEnts = UTIL_EntitiesInBox( pEnts, 128, mins, maxs, 0 ); for ( int i = 0; i < numEnts; i++ ) { IPhysicsObject *pPhysObject = NULL; // Attempt to kill and ragdoll any victims in range if ( KillNPCInRange( pEnts[i], &pPhysObject ) == false ) { // If we didn't have a valid victim, see if we can just get the vphysics object pPhysObject = pEnts[i]->VPhysicsGetObject(); if ( pPhysObject == NULL ) continue; } float mass; CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( pEnts[i] ); if ( pRagdoll != NULL ) { ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll(); mass = 0.0f; // Find the aggregate mass of the whole ragdoll for ( int j = 0; j < pRagdollPhys->listCount; ++j ) { mass += pRagdollPhys->list[j].pObject->GetMass(); } } else { mass = pPhysObject->GetMass(); } Vector vecForce = GetAbsOrigin() - pEnts[i]->WorldSpaceCenter(); Vector vecForce2D = vecForce; vecForce2D[2] = 0.0f; float dist2D = VectorNormalize( vecForce2D ); float dist = VectorNormalize( vecForce ); // FIXME: Need a more deterministic method here if ( dist < 48.0f ) { ConsumeEntity( pEnts[i] ); continue; } // Must be within the radius if ( dist > m_flRadius ) continue; // Find the pull force vecForce *= ( 1.0f - ( dist2D / m_flRadius ) ) * m_flStrength * mass; if ( pEnts[i]->VPhysicsGetObject() ) { // Pull the object in pEnts[i]->VPhysicsTakeDamage( CTakeDamageInfo( this, this, vecForce, GetAbsOrigin(), m_flStrength, DMG_BLAST ) ); } } // Keep going if need-be if ( m_flEndTime > gpGlobals->curtime ) { SetThink( &CGravityVortexController::PullThink ); SetNextThink( gpGlobals->curtime + 0.1f ); } else { //Msg( "Consumed %.2f kilograms\n", m_flMass ); //CreateDenseBall(); } }
//----------------------------------------------------------------------------- // Purpose: Update the fire and its children //----------------------------------------------------------------------------- void CFire::Update( float simTime ) { VPROF_FIRE( "CFire::Update" ); if ( m_flFuel != 0 ) { m_flFuel -= simTime; if ( m_flFuel <= 0 ) { GoOutInSeconds( 1 ); return; } } float strength = m_flHeatLevel / FIRE_MAX_HEAT_LEVEL; if ( m_flHeatLevel != m_flLastHeatLevel ) { m_flLastHeatLevel = m_flHeatLevel; // Make the effect the appropriate size given the heat level m_hEffect->Scale( strength, 0.5f ); } // add heat to myself (grow) float addedHeat = (m_flAttackTime > 0) ? m_flMaxHeat / m_flAttackTime : m_flMaxHeat; addedHeat *= simTime * fire_growthrate.GetFloat(); AddHeat( addedHeat, true ); // add heat to nearby fires float outputHeat = strength * m_flHeatLevel; Vector fireMins; Vector fireMaxs; Vector fireEntityDamageMins; Vector fireEntityDamageMaxs; GetFireDimensions( &fireMins, &fireMaxs ); if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 ) // if set to 1.0, optimizer will remove this code { fireEntityDamageMins = fireMins / FIRE_SPREAD_DAMAGE_MULTIPLIER; fireEntityDamageMaxs = fireMaxs / FIRE_SPREAD_DAMAGE_MULTIPLIER; } //NDebugOverlay::Box( GetAbsOrigin(), fireMins, fireMaxs, 255, 255, 255, 0, fire_dmginterval.GetFloat() ); fireMins += GetAbsOrigin(); fireMaxs += GetAbsOrigin(); if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 ) { fireEntityDamageMins += GetAbsOrigin(); fireEntityDamageMaxs += GetAbsOrigin(); } CBaseEntity *pNearby[256]; CFire *pFires[16]; int nearbyCount = UTIL_EntitiesInBox( pNearby, ARRAYSIZE(pNearby), fireMins, fireMaxs, 0 ); int fireCount = 0; int i; // is it time to do damage? bool damage = false; int outputDamage = 0; if ( m_flDamageTime <= gpGlobals->curtime ) { m_flDamageTime = gpGlobals->curtime + fire_dmginterval.GetFloat(); outputDamage = (fire_dmgbase.GetFloat() + outputHeat * fire_dmgscale.GetFloat() * m_flDamageScale) * fire_dmginterval.GetFloat(); if ( outputDamage ) { damage = true; } } int damageFlags = (m_nFireType == FIRE_NATURAL) ? DMG_BURN : DMG_PLASMA; for ( i = 0; i < nearbyCount; i++ ) { CBaseEntity *pOther = pNearby[i]; if ( pOther == this ) { continue; } else if ( FClassnameIs( pOther, "env_fire" ) ) { if ( fireCount < ARRAYSIZE(pFires) ) { pFires[fireCount] = (CFire *)pOther; fireCount++; } continue; } else if ( pOther->m_takedamage == DAMAGE_NO ) { pNearby[i] = NULL; } else if ( damage ) { bool bDoDamage; if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 && !pOther->IsPlayer() ) // if set to 1.0, optimizer will remove this code { Vector otherMins, otherMaxs; pOther->CollisionProp()->WorldSpaceAABB( &otherMins, &otherMaxs ); bDoDamage = IsBoxIntersectingBox( otherMins, otherMaxs, fireEntityDamageMins, fireEntityDamageMaxs ); } else bDoDamage = true; if ( bDoDamage ) { // Make sure can actually see entity (don't damage through walls) trace_t tr; UTIL_TraceLine( this->WorldSpaceCenter(), pOther->WorldSpaceCenter(), MASK_FIRE_SOLID, pOther, COLLISION_GROUP_NONE, &tr ); if (tr.fraction == 1.0 && !tr.startsolid) { pOther->TakeDamage( CTakeDamageInfo( this, this, outputDamage, damageFlags ) ); } } } } outputHeat *= fire_heatscale.GetFloat() * simTime; if ( fireCount > 0 ) { outputHeat /= fireCount; for ( i = 0; i < fireCount; i++ ) { pFires[i]->AddHeat( outputHeat, false ); } } }
void CBreakable::Die( void ) { Vector vecSpot;// shard origin Vector vecVelocity;// shard velocity CBaseEntity *pEntity = NULL; char cFlag = 0; int pitch; float fvol; pitch = 95 + RANDOM_LONG(0,29); if (pitch > 97 && pitch < 103) pitch = 100; // The more negative pev->health, the louder // the sound should be. fvol = RANDOM_FLOAT(0.85, 1.0) + (abs(pev->health) / 100.0); if (fvol > 1.0) fvol = 1.0; switch (m_Material) { case matGlass: switch ( RANDOM_LONG(0,1) ) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_GLASS; break; case matWood: switch ( RANDOM_LONG(0,1) ) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_WOOD; break; case matComputer: case matMetal: switch ( RANDOM_LONG(0,1) ) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_METAL; break; case matFlesh: switch ( RANDOM_LONG(0,1) ) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_FLESH; break; case matRocks: case matCinderBlock: switch ( RANDOM_LONG(0,1) ) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_CONCRETE; break; case matCeilingTile: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); break; } if (m_Explosion == expDirected) vecVelocity = g_vecAttackDir * 200; else { vecVelocity.x = 0; vecVelocity.y = 0; vecVelocity.z = 0; } vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); WRITE_BYTE( TE_BREAKMODEL); // position WRITE_COORD( vecSpot.x ); WRITE_COORD( vecSpot.y ); WRITE_COORD( vecSpot.z ); // size WRITE_COORD( pev->size.x); WRITE_COORD( pev->size.y); WRITE_COORD( pev->size.z); // velocity WRITE_COORD( vecVelocity.x ); WRITE_COORD( vecVelocity.y ); WRITE_COORD( vecVelocity.z ); // randomization WRITE_BYTE( 10 ); // Model WRITE_SHORT( m_idShard ); //model id# // # of shards WRITE_BYTE( 0 ); // let client decide // duration WRITE_BYTE( 25 );// 2.5 seconds // flags WRITE_BYTE( cFlag ); MESSAGE_END(); float size = pev->size.x; if ( size < pev->size.y ) size = pev->size.y; if ( size < pev->size.z ) size = pev->size.z; // !!! HACK This should work! // Build a box above the entity that looks like an 8 pixel high sheet Vector mins = pev->absmin; Vector maxs = pev->absmax; mins.z = pev->absmax.z; maxs.z += 8; // BUGBUG -- can only find 256 entities on a breakable -- should be enough CBaseEntity *pList[256]; int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND ); if ( count ) { for ( int i = 0; i < count; i++ ) { ClearBits( pList[i]->pev->flags, FL_ONGROUND ); pList[i]->pev->groundentity = NULL; } } // Don't fire something that could fire myself pev->targetname = 0; pev->solid = SOLID_NOT; // Fire targets on break SUB_UseTargets( NULL, USE_TOGGLE, 0 ); SetThink( &CBreakable::SUB_Remove ); pev->nextthink = pev->ltime + 0.1; if ( m_iszSpawnObject ) CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() ); if ( Explodable() ) { ExplosionCreate( Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE ); } }
//----------------------------------------------------------------------------- // Purpose: Give the buster a slight attraction to striders. // Ported back from the magnade. //----------------------------------------------------------------------------- void CWeaponStriderBuster::BusterFlyThink() { if (IsAttachedToStrider()) return; // early out. Think no more. // If we're nosediving, forget about magnetism. if ( m_bNoseDiving ) { if ( VPhysicsGetObject() ) VPhysicsGetObject()->ApplyForceCenter( Vector( 0, 0, striderbuster_dive_force.GetFloat() ) ); SetNextThink(gpGlobals->curtime + 0.01f); return; } // seek? const float magradius = 38.0 * sk_striderbuster_magnet_multiplier.GetFloat(); // radius of strider hull times multiplier if (magradius > 0 && GetMoveType() == MOVETYPE_VPHYSICS && VPhysicsGetObject() ) { // find the nearest enemy. CBaseEntity *pList[16]; Vector origin = GetAbsOrigin(); // do a find in box ( a little faster than sphere ) int count; { Vector mins,maxs; mins = origin; mins -= magradius; maxs = origin; maxs += magradius; count = UTIL_EntitiesInBox(pList, 16, mins, maxs, FL_NPC); } float magradiusSq = Square( magradius ); float nearestDistSq = magradiusSq + 1; int bestFit = -1; Vector toTarget; // will be garbage unless something good is found CNPC_Strider *pBestStrider = NULL; for ( int ii = 0 ; ii < count ; ++ii ) { CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(pList[ii]); if ( pStrider && !pStrider->CarriedByDropship() ) // ShouldStickToEntity() doesn't work because the strider NPC isn't what we glue to { // get distance squared VectorSubtract( pStrider->GetAdjustedOrigin(), GetAbsOrigin(), toTarget ); //NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + toTarget, 128, 0, 128, false, 0.1 ); float dSq = toTarget.LengthSqr(); if (dSq < nearestDistSq) { bestFit = ii; nearestDistSq = dSq; pBestStrider = pStrider; } } } if (bestFit >= 0) // we found something and should attract towards it. (hysterisis later?) { if ( striderbuster_debugseek.GetBool() ) { NDebugOverlay::Circle( GetAbsOrigin() + toTarget, magradius, 255, 255, 255, 255, true, .1 ); NDebugOverlay::Cross3D( GetAbsOrigin() + toTarget, magradius, 255, 255, 255, true, .1 ); } // force magnitude. float magnitude = GetMass() * striderbuster_magnetic_force_strider.GetFloat(); int falloff = striderbuster_falloff_power.GetInt(); switch (falloff) { case 1: VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / nearestDistSq) ); // dividing through by distance squared normalizes toTarget and gives a linear falloff break; case 2: VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / (nearestDistSq * sqrtf(nearestDistSq))) ); // dividing through by distance cubed normalizes toTarget and gives a quadratic falloff break; case 3: VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / (nearestDistSq * nearestDistSq)) ); // dividing through by distance fourth normalizes toTarget and gives a cubic falloff break; case 4: { Vector toTarget; pBestStrider->GetAttachment( "buster_target", toTarget ); if ( striderbuster_debugseek.GetBool() ) { NDebugOverlay::Cross3D( toTarget, magradius, 255, 0, 255, true, .1 ); NDebugOverlay::Cross3D( toTarget, magradius, 255, 0, 255, true, .1 ); } toTarget -= GetAbsOrigin(); toTarget.NormalizeInPlace(); VPhysicsGetObject()->ApplyForceCenter( toTarget * magnitude ); } break; default: // arbitrary powers VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude * powf(nearestDistSq,(falloff+1.0f)/2)) ); // square root for distance instead of squared, add one to normalize toTarget break; } } SetNextThink(gpGlobals->curtime + 0.01f); } }
//========================================================= // MakeMonster- this is the code that drops the monster //========================================================= void CMonsterMaker::MakeMonster( void ) { edict_t *pent; entvars_t *pevCreate; if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren ) {// not allowed to make a new one yet. Too many live ones out right now. return; } if ( !m_flGround ) { // set altitude. Now that I'm activated, any breakables, etc should be out from under me. TraceResult tr; UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr ); m_flGround = tr.vecEndPos.z; } Vector mins = pev->origin - Vector( 34, 34, 0 ); Vector maxs = pev->origin + Vector( 34, 34, 0 ); maxs.z = pev->origin.z; mins.z = m_flGround; CBaseEntity *pList[2]; int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER ); if ( count ) { // don't build a stack of monsters! return; } pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname ); if ( FNullEnt( pent ) ) { ALERT ( at_console, "NULL Ent in MonsterMaker!\n" ); return; } // If I have a target, fire! if ( !FStringNull ( pev->target ) ) { // delay already overloaded for this entity, so can't call SUB_UseTargets() FireTargets( STRING(pev->target), this, this, USE_TOGGLE, 0 ); } pevCreate = VARS( pent ); pevCreate->origin = pev->origin; pevCreate->angles = pev->angles; SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND ); // Children hit monsterclip brushes if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP ) SetBits( pevCreate->spawnflags, SF_MONSTER_HITMONSTERCLIP ); DispatchSpawn( ENT( pevCreate ) ); pevCreate->owner = edict(); if ( !FStringNull( pev->netname ) ) { // if I have a netname (overloaded), give the child monster that name as a targetname pevCreate->targetname = pev->netname; } m_cLiveChildren++;// count this monster m_cNumMonsters--; if ( m_cNumMonsters == 0 ) { // Disable this forever. Don't kill it because it still gets death notices SetThink( NULL ); SetUse( NULL ); } }
void CBreakable::Die() { Vector vecSpot; // shard origin Vector vecVelocity; // shard velocity CBaseEntity *pEntity = NULL; char cFlag = 0; int pitch; float fvol; pev->takedamage = DAMAGE_NO; pev->deadflag = DEAD_DEAD; pev->effects = EF_NODRAW; pitch = 95 + RANDOM_LONG(0, 29); if (pitch > 97 && pitch < 103) pitch = 100; // The more negative pev->health, the louder // the sound should be. fvol = RANDOM_FLOAT(0.85, 1.0) + (abs((int)pev->health) / 100.0f); if (fvol > 1.0f) fvol = 1.0f; switch (m_Material) { case matGlass: switch (RANDOM_LONG(0, 1)) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_GLASS; if (TheBots != NULL) { TheBots->OnEvent(EVENT_BREAK_GLASS, this); } break; case matWood: switch (RANDOM_LONG(0, 1)) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_WOOD; if (TheBots != NULL) { TheBots->OnEvent(EVENT_BREAK_WOOD, this); } break; case matMetal: case matComputer: switch (RANDOM_LONG(0, 1)) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_METAL; if (TheBots != NULL) { TheBots->OnEvent(EVENT_BREAK_METAL, this); } break; case matFlesh: switch (RANDOM_LONG(0, 1)) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_FLESH; if (TheBots != NULL) { TheBots->OnEvent(EVENT_BREAK_FLESH, this); } break; case matCinderBlock: case matRocks: switch (RANDOM_LONG(0, 1)) { case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch); break; case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete2.wav", fvol, ATTN_NORM, 0, pitch); break; } cFlag = BREAK_CONCRETE; if (TheBots != NULL) { TheBots->OnEvent(EVENT_BREAK_CONCRETE, this); } break; case matCeilingTile: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); break; default: break; } if (m_Explosion == expDirected) { vecVelocity = g_vecAttackDir * 200.0f; } else { vecVelocity.x = 0; vecVelocity.y = 0; vecVelocity.z = 0; } vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSpot); WRITE_BYTE(TE_BREAKMODEL); WRITE_COORD(vecSpot.x); // position WRITE_COORD(vecSpot.y); WRITE_COORD(vecSpot.z); WRITE_COORD(pev->size.x); // size WRITE_COORD(pev->size.y); WRITE_COORD(pev->size.z); WRITE_COORD(vecVelocity.x); // velocity WRITE_COORD(vecVelocity.y); WRITE_COORD(vecVelocity.z); WRITE_BYTE(10); // randomization WRITE_SHORT(m_idShard); // model id# WRITE_BYTE(0); // # of shards, let client decide WRITE_BYTE(25); // duration, 2.5 seconds WRITE_BYTE(cFlag); // flags MESSAGE_END(); float size = pev->size.x; if (size < pev->size.y) size = pev->size.y; if (size < pev->size.z) size = pev->size.z; Vector mins = pev->absmin; Vector maxs = pev->absmax; mins.z = pev->absmax.z; maxs.z += 8; CBaseEntity *pList[256]; int count = UTIL_EntitiesInBox(pList, ARRAYSIZE(pList), mins, maxs, FL_ONGROUND); if (count) { for (int i = 0; i < count; ++i) { pList[i]->pev->flags &= ~FL_ONGROUND; pList[i]->pev->groundentity = NULL; } } pev->solid = SOLID_NOT; SUB_UseTargets(NULL, USE_TOGGLE, 0); SetThink(NULL); pev->nextthink = pev->ltime + 0.1f; if (m_iszSpawnObject) { CBaseEntity::Create((char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict()); } if (Explodable()) { ExplosionCreate(Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE); } }
//----------------------------------------------------------------------------- // Purpose: Returns whether or not it is OK to make an NPC at this instant. //----------------------------------------------------------------------------- bool CBaseNPCMaker::CanMakeNPC( bool bIgnoreSolidEntities ) { if( ai_inhibit_spawners.GetBool() ) return false; if ( m_nMaxLiveChildren > 0 && m_nLiveChildren >= m_nMaxLiveChildren ) {// not allowed to make a new one yet. Too many live ones out right now. return false; } if ( m_iszIngoreEnt != NULL_STRING ) { m_hIgnoreEntity = gEntList.FindEntityByName( NULL, m_iszIngoreEnt ); } Vector mins = GetAbsOrigin() - Vector( 34, 34, 0 ); Vector maxs = GetAbsOrigin() + Vector( 34, 34, 0 ); maxs.z = GetAbsOrigin().z; // If we care about not hitting solid entities, look for 'em if ( !bIgnoreSolidEntities ) { CBaseEntity *pList[128]; int count = UTIL_EntitiesInBox( pList, 128, mins, maxs, FL_CLIENT|FL_NPC ); if ( count ) { //Iterate through the list and check the results for ( int i = 0; i < count; i++ ) { //Don't build on top of another entity if ( pList[i] == NULL ) continue; //If one of the entities is solid, then we may not be able to spawn now if ( ( pList[i]->GetSolidFlags() & FSOLID_NOT_SOLID ) == false ) { // Since the outer method doesn't work well around striders on account of their huge bounding box. // Find the ground under me and see if a human hull would fit there. trace_t tr; UTIL_TraceHull( GetAbsOrigin() + Vector( 0, 0, 2 ), GetAbsOrigin() - Vector( 0, 0, 8192 ), NAI_Hull::Mins(HULL_HUMAN), NAI_Hull::Maxs(HULL_HUMAN), MASK_NPCSOLID, m_hIgnoreEntity, COLLISION_GROUP_NONE, &tr ); if( !HumanHullFits( tr.endpos + Vector( 0, 0, 1 ) ) ) { return false; } } } } } // Do we need to check to see if the player's looking? if ( HasSpawnFlags( SF_NPCMAKER_HIDEFROMPLAYER ) ) { for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); if ( pPlayer ) { // Only spawn if the player's looking away from me if( pPlayer->FInViewCone( GetAbsOrigin() ) && pPlayer->FVisible( GetAbsOrigin() ) ) { if ( !(pPlayer->GetFlags() & FL_NOTARGET) ) return false; DevMsg( 2, "Spawner %s spawning even though seen due to notarget\n", STRING( GetEntityName() ) ); } } } } return true; }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CNPC_BigMomma::HandleAnimEvent( animevent_t *pEvent ) { CPASAttenuationFilter filter( this ); Vector vecFwd, vecRight, vecUp; QAngle angles; angles = GetAbsAngles(); AngleVectors( angles, &vecFwd, &vecRight, &vecUp ); switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: case BIG_AE_MELEE_ATTACKBL: case BIG_AE_MELEE_ATTACK1: { Vector center = GetAbsOrigin() + vecFwd * 128; Vector mins = center - Vector( 64, 64, 0 ); Vector maxs = center + Vector( 64, 64, 64 ); CBaseEntity *pList[8]; int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_NPC | FL_CLIENT ); CBaseEntity *pHurt = NULL; for ( int i = 0; i < count && !pHurt; i++ ) { if ( pList[i] != this ) { if ( pList[i]->GetOwnerEntity() != this ) { pHurt = pList[i]; } } } if ( pHurt ) { CTakeDamageInfo info( this, this, 15, DMG_CLUB | DMG_SLASH ); CalculateMeleeDamageForce( &info, (pHurt->GetAbsOrigin() - GetAbsOrigin()), pHurt->GetAbsOrigin() ); pHurt->TakeDamage( info ); QAngle newAngles = angles; newAngles.x = 15; if ( pHurt->IsPlayer() ) { ((CBasePlayer *)pHurt)->SetPunchAngle( newAngles ); } switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: // pHurt->pev->velocity = pHurt->pev->velocity + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200) ); break; case BIG_AE_MELEE_ATTACKBL: pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) + (vecRight * 200) ); break; case BIG_AE_MELEE_ATTACK1: pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 220) + Vector(0,0,200) ); break; } pHurt->SetGroundEntity( NULL ); EmitSound( filter, entindex(), "BigMomma.AttackHit" ); } } break; case BIG_AE_SCREAM: EmitSound( filter, entindex(), "BigMomma.Alert" ); break; case BIG_AE_PAIN_SOUND: EmitSound( filter, entindex(), "BigMomma.Pain" ); break; case BIG_AE_ATTACK_SOUND: EmitSound( filter, entindex(), "BigMomma.Attack" ); break; case BIG_AE_BIRTH_SOUND: EmitSound( filter, entindex(), "BigMomma.Birth" ); break; case BIG_AE_SACK: if ( RandomInt(0,100) < 30 ) { EmitSound( filter, entindex(), "BigMomma.Sack" ); } break; case BIG_AE_DEATHSOUND: EmitSound( filter, entindex(), "BigMomma.Die" ); break; case BIG_AE_STEP1: // Footstep left case BIG_AE_STEP3: // Footstep back left EmitSound( filter, entindex(), "BigMomma.FootstepLeft" ); break; case BIG_AE_STEP4: // Footstep back right case BIG_AE_STEP2: // Footstep right EmitSound( filter, entindex(), "BigMomma.FootstepRight" ); break; case BIG_AE_MORTAR_ATTACK1: LaunchMortar(); break; case BIG_AE_LAY_CRAB: LayHeadcrab(); break; case BIG_AE_JUMP_FORWARD: SetGroundEntity( NULL ); SetAbsOrigin(GetAbsOrigin() + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground SetAbsVelocity(vecFwd * 200 + vecUp * 500 ); break; case BIG_AE_EARLY_TARGET: { CInfoBM *pTarget = (CInfoBM*) GetTarget(); if ( pTarget ) { pTarget->m_OnAnimationEvent.FireOutput( this, this ); } Remember( bits_MEMORY_FIRED_NODE ); } break; default: BaseClass::HandleAnimEvent( pEvent ); break; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponHarpoon::SecondaryAttack( void ) { CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() ); if ( !pPlayer ) return; // Slap things in front of me Vector vecForward; Vector vecBox = Vector( FIST_RANGE,FIST_RANGE,FIST_RANGE * 1.5 ) * 0.5; pPlayer->EyeVectors( &vecForward ); Vector vecSrc = pPlayer->Weapon_ShootPosition( ); Vector vecCenter = vecSrc + (FIST_RANGE * 0.5 * vecForward); #if !defined( CLIENT_DLL ) //NDebugOverlay::Box( vecCenter, -Vector(2,2,2), Vector(2,2,2), 255,0,0,20,2.0); //NDebugOverlay::Box( vecCenter, -vecBox, vecBox, 255,255,255,20,2.0); bool bHitMetal = false; bool bHitPlayer = false; CBaseEntity *pList[100]; int count = UTIL_EntitiesInBox( pList, 100, vecSrc - vecBox, vecSrc + vecBox, FL_CLIENT|FL_NPC|FL_OBJECT ); for ( int i = 0; i < count; i++ ) { CBaseEntity *pEntity = pList[i]; if ( !pEntity->m_takedamage ) continue; if ( pEntity->InSameTeam( this ) ) continue; //NDebugOverlay::EntityBounds( pEntity, 0,255,0,20,2.0); if ( pEntity->IsPlayer() ) { bHitPlayer = true; CTakeDamageInfo info( this, pPlayer, weapon_fist_damage.GetFloat(), DMG_CLUB ); CalculateMeleeDamageForce( &info, (pEntity->GetAbsOrigin() - vecCenter), pEntity->GetAbsOrigin() ); pEntity->TakeDamage( info ); } else if ( pEntity->Classify() == CLASS_MILITARY ) { bHitMetal = true; CTakeDamageInfo info( this, pPlayer, weapon_fist_damage_objects.GetFloat(), DMG_CLUB ); CalculateMeleeDamageForce( &info, (pEntity->GetAbsOrigin() - vecCenter), pEntity->GetAbsOrigin() ); pEntity->TakeDamage( info ); } else { bHitMetal = true; CTakeDamageInfo info( this, pPlayer, weapon_fist_damage.GetFloat(), DMG_CLUB ); CalculateMeleeDamageForce( &info, (pEntity->GetAbsOrigin() - vecCenter), pEntity->GetAbsOrigin() ); pEntity->TakeDamage( info ); } } // Play the right sound if ( bHitPlayer ) { EmitSound( "Harpoon.HitFlesh" ); } else if ( bHitMetal ) { EmitSound( "Harpoon.HitMetal" ); } #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CASWEnvShake::ApplyShake( ShakeCommand_t command ) { if ( !HasSpawnFlags( SF_ASW_SHAKE_NO_VIEW ) ) { bool air = (GetSpawnFlags() & SF_ASW_SHAKE_INAIR) ? true : false; UTIL_ASW_ScreenShake( GetAbsOrigin(), Amplitude(), Frequency(), Duration(), Radius(), command, air ); } if ( GetSpawnFlags() & SF_ASW_SHAKE_ROPES ) { CRopeKeyframe::ShakeRopes( GetAbsOrigin(), Radius(), Frequency() ); } if ( GetSpawnFlags() & SF_ASW_SHAKE_PHYSICS ) { if ( !m_pShakeController ) { m_pShakeController = physenv->CreateMotionController( &m_shakeCallback ); } // do physics shake switch( command ) { case SHAKE_START: { m_stopTime = gpGlobals->curtime + Duration(); m_nextShake = 0; m_pShakeController->ClearObjects(); SetNextThink( gpGlobals->curtime ); m_currentAmp = Amplitude(); CBaseEntity *list[1024]; float radius = Radius(); // probably checked "Shake Everywhere" do a big radius if ( !radius ) { radius = MAX_COORD_INTEGER; } Vector extents = Vector(radius, radius, radius); Vector mins = GetAbsOrigin() - extents; Vector maxs = GetAbsOrigin() + extents; int count = UTIL_EntitiesInBox( list, 1024, mins, maxs, 0 ); for ( int i = 0; i < count; i++ ) { // // Only shake physics entities that players can see. This is one frame out of date // so it's possible that we could miss objects if a player changed PVS this frame. // if ( ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) ) { IPhysicsObject *pPhys = list[i]->VPhysicsGetObject(); if ( pPhys && pPhys->IsMoveable() ) { m_pShakeController->AttachObject( pPhys, false ); pPhys->Wake(); } } } } break; case SHAKE_STOP: m_pShakeController->ClearObjects(); break; case SHAKE_AMPLITUDE: m_currentAmp = Amplitude(); case SHAKE_FREQUENCY: m_pShakeController->WakeObjects(); break; } } }
//========================================================= // Look - Base class monster function to find enemies or // food by sight. iDistance is distance ( in units ) that the // monster can see. // // Sets the sight bits of the m_afConditions mask to indicate // which types of entities were sighted. // Function also sets the Looker's m_pLink // to the head of a link list that contains all visible ents. // (linked via each ent's m_pLink field) // //========================================================= void CBaseMonster :: Look ( int iDistance ) { int iSighted = 0; // DON'T let visibility information from last frame sit around! ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT); m_pLink = NULL; CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with CBaseEntity *pList[100]; Vector delta = Vector( iDistance, iDistance, iDistance ); // Find only monsters/clients in box, NOT limited to PVS int count = UTIL_EntitiesInBox( pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT|FL_MONSTER ); for ( int i = 0; i < count; i++ ) { pSightEnt = pList[i]; if ( pSightEnt != this && pSightEnt->pev->health > 0 ) { // the looker will want to consider this entity // don't check anything else about an entity that can't be seen, or an entity that you don't care about. if ( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) ) { if ( pSightEnt->IsPlayer() ) { // if we see a client, remember that (mostly for scripted AI) iSighted |= bits_COND_SEE_CLIENT; } pSightEnt->m_pLink = m_pLink; m_pLink = pSightEnt; if ( pSightEnt == m_hEnemy ) { // we know this ent is visible, so if it also happens to be our enemy, store that now. iSighted |= bits_COND_SEE_ENEMY; } // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when // we see monsters other than the Enemy. switch ( IRelationship ( pSightEnt ) ) { case R_NM: iSighted |= bits_COND_SEE_NEMESIS; break; case R_HT: iSighted |= bits_COND_SEE_HATE; break; case R_DL: iSighted |= bits_COND_SEE_DISLIKE; break; case R_FR: iSighted |= bits_COND_SEE_FEAR; break; case R_AL: break; default: ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); break; } } } } SetConditions( iSighted ); }
//----------------------------------------------------------------------------- // Purpose: Activate any nearby bugbait targets // Returns true if the bugbait target wants to suppress the call. //----------------------------------------------------------------------------- bool CGrenadeBugBait::ActivateBugbaitTargets( CBaseEntity *pOwner, Vector vecOrigin, bool bSqueezed ) { //Attempt to activate any spawners in a radius around the bugbait CBaseEntity* pList[100]; Vector delta( bugbait_grenade_radius.GetFloat(), bugbait_grenade_radius.GetFloat(), bugbait_grenade_radius.GetFloat() ); bool suppressCall = false; int count = UTIL_EntitiesInBox( pList, 100, vecOrigin - delta, vecOrigin + delta, 0 ); // If the bugbait's been thrown, look for nearby targets to affect if ( !bSqueezed ) { for ( int i = 0; i < count; i++ ) { // If close enough, make combine soldiers freak out when hit if ( UTIL_DistApprox( pList[i]->WorldSpaceCenter(), vecOrigin ) < bugbait_grenade_radius.GetFloat() ) { // Must be a soldier if ( FClassnameIs( pList[i], "npc_combine_s") ) { CAI_BaseNPC *pCombine = pList[i]->MyNPCPointer(); if ( pCombine != NULL ) { trace_t tr; UTIL_TraceLine( vecOrigin, pCombine->EyePosition(), MASK_ALL, pOwner, COLLISION_GROUP_NONE, &tr); if ( tr.fraction == 1.0 || tr.m_pEnt == pCombine ) { // Randomize the start time a little so multiple combine hit by // the same bugbait don't all dance in synch. g_EventQueue.AddEvent( pCombine, "HitByBugbait", RandomFloat(0, 0.5), pOwner, pOwner ); } } } } } } // Iterate over all sensors to see if they detected this impact for ( CBugBaitSensor *pSensor = GetBugBaitSensorList(); pSensor != NULL; pSensor = pSensor->m_pNext ) { if ( pSensor == NULL ) continue; if ( pSensor->IsDisabled() ) continue; if ( bSqueezed && pSensor->DetectsSqueeze() == false ) continue; if ( !bSqueezed && pSensor->DetectsThrown() == false ) continue; //Make sure we're within range of the sensor if ( pSensor->GetRadius() > ( pSensor->GetAbsOrigin() - vecOrigin ).Length() ) { //Tell the sensor it's been hit if ( pSensor->Baited( pOwner ) ) { //If we're suppressing the call to antlions, then don't make a bugbait sound if ( pSensor->SuppressCall() ) { suppressCall = true; } } } } return suppressCall; }