void CHgun::SecondaryAttack( void ) { Reload(); if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) { return; } //Wouldn't be a bad idea to completely predict these, since they fly so fast... #ifndef CLIENT_DLL CBaseEntity *pHornet; Vector vecSrc; UTIL_MakeVectors( m_pPlayer->pev->v_angle ); vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12; m_iFirePhase++; switch ( m_iFirePhase ) { case 1: vecSrc = vecSrc + gpGlobals->v_up * 8; break; case 2: vecSrc = vecSrc + gpGlobals->v_up * 8; vecSrc = vecSrc + gpGlobals->v_right * 8; break; case 3: vecSrc = vecSrc + gpGlobals->v_right * 8; break; case 4: vecSrc = vecSrc + gpGlobals->v_up * -8; vecSrc = vecSrc + gpGlobals->v_right * 8; break; case 5: vecSrc = vecSrc + gpGlobals->v_up * -8; break; case 6: vecSrc = vecSrc + gpGlobals->v_up * -8; vecSrc = vecSrc + gpGlobals->v_right * -8; break; case 7: vecSrc = vecSrc + gpGlobals->v_right * -8; break; case 8: vecSrc = vecSrc + gpGlobals->v_up * 8; vecSrc = vecSrc + gpGlobals->v_right * -8; m_iFirePhase = 0; break; } pHornet = CBaseEntity::Create( "hornet", vecSrc, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); pHornet->pev->velocity = gpGlobals->v_forward * 1200; pHornet->pev->angles = UTIL_VecToAngles( pHornet->pev->velocity ); pHornet->SetThink( &CHornet::StartDart ); m_flRechargeTime = gpGlobals->time + 0.5; #endif int flags; #if defined( CLIENT_WEAPONS ) flags = FEV_NOTHOST; #else flags = 0; #endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_FAST, 0, 0, 0 ); m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); }
void CBasePlayer::SimulatePlayerSimulatedEntities( void ) { int c = m_SimulatedByThisPlayer.Count(); int i; for ( i = c - 1; i >= 0; i-- ) { CHandle< CBaseEntity > h; h = m_SimulatedByThisPlayer[ i ]; CBaseEntity *e = h; if ( !e || !e->IsPlayerSimulated() ) { m_SimulatedByThisPlayer.Remove( i ); continue; } #if defined( CLIENT_DLL ) if ( e->IsClientCreated() && prediction->InPrediction() && !prediction->IsFirstTimePredicted() ) { continue; } #endif Assert( e->IsPlayerSimulated() ); Assert( e->GetSimulatingPlayer() == this ); e->PhysicsSimulate(); } // Loop through all entities again, checking their untouch if flagged to do so c = m_SimulatedByThisPlayer.Count(); for ( i = c - 1; i >= 0; i-- ) { CHandle< CBaseEntity > h; h = m_SimulatedByThisPlayer[ i ]; CBaseEntity *e = h; if ( !e || !e->IsPlayerSimulated() ) { m_SimulatedByThisPlayer.Remove( i ); continue; } #if defined( CLIENT_DLL ) if ( e->IsClientCreated() && prediction->InPrediction() && !prediction->IsFirstTimePredicted() ) { continue; } #endif Assert( e->IsPlayerSimulated() ); Assert( e->GetSimulatingPlayer() == this ); if ( !e->GetCheckUntouch() ) continue; e->PhysicsCheckForEntityUntouch(); } }
/* <1bc358> ../cstrike/dlls/vehicle.cpp:466 */ void CFuncVehicle::CollisionDetection() { TraceResult tr; bool bHitSomething = false; if (pev->speed < 0) { UTIL_TraceLine(m_vBackLeft, m_vBackLeft + (gpGlobals->v_forward * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr); if (tr.flFraction == 1.0f) { UTIL_TraceLine(m_vBackRight, m_vBackRight + (gpGlobals->v_forward * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr); if (tr.flFraction == 1.0f) { UTIL_TraceLine(m_vBack, m_vBack + (gpGlobals->v_forward * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr); if (tr.flFraction == 1.0f) { return; } } if (DotProduct(gpGlobals->v_forward, tr.vecPlaneNormal * -1.0) < 0.7 && tr.vecPlaneNormal.z < 0.1) { m_vSurfaceNormal = tr.vecPlaneNormal; m_vSurfaceNormal.z = 0; pev->speed *= 0.99; } else if (tr.vecPlaneNormal.z < 0.65 || tr.fStartSolid) { pev->speed *= -1.0; } else { m_vSurfaceNormal = tr.vecPlaneNormal; } } else { if (DotProduct(gpGlobals->v_forward, tr.vecPlaneNormal * -1.0) < 0.7 && tr.vecPlaneNormal.z < 0.1) { m_vSurfaceNormal = tr.vecPlaneNormal; m_vSurfaceNormal.z = 0; pev->speed *= 0.99; } else if (tr.vecPlaneNormal[2] < 0.65 || tr.fStartSolid) { pev->speed *= -1.0; } else { m_vSurfaceNormal = tr.vecPlaneNormal; } CBaseEntity *pHit = CBaseEntity::Instance(tr.pHit); if (pHit && pHit->Classify() == CLASS_VEHICLE) { bHitSomething = true; ALERT(at_console, "I hit another vehicle\n"); } } } else if (pev->speed > 0) { UTIL_TraceLine(m_vFrontLeft, m_vFrontLeft - (gpGlobals->v_forward * 16.0), dont_ignore_monsters, dont_ignore_glass, ENT(pev), &tr); if (tr.flFraction == 1.0f) { UTIL_TraceLine(m_vFrontRight, m_vFrontRight - (gpGlobals->v_forward * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr); if (tr.flFraction == 1.0f) { UTIL_TraceLine(m_vFront, m_vFront - (gpGlobals->v_forward * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr); if (tr.flFraction == 1.0f) { return; } } } if (DotProduct(gpGlobals->v_forward, tr.vecPlaneNormal * -1.0) > -0.7 && tr.vecPlaneNormal.z < 0.1) { m_vSurfaceNormal = tr.vecPlaneNormal; m_vSurfaceNormal.z = 0; pev->speed *= 0.99; } else if (tr.vecPlaneNormal.z < 0.65 || tr.fStartSolid) { pev->speed *= -1.0; } else { m_vSurfaceNormal = tr.vecPlaneNormal; } } }
//----------------------------------------------------------------------------- // Purpose: // Input : flDot - // flDist - // Output : int //----------------------------------------------------------------------------- int CWeaponSMG1::WeaponRangeAttack2Condition( float flDot, float flDist ) { CAI_BaseNPC *npcOwner = GetOwner()->MyNPCPointer(); return COND_NONE; /* // -------------------------------------------------------- // Assume things haven't changed too much since last time // -------------------------------------------------------- if (gpGlobals->curtime < m_flNextGrenadeCheck ) return m_lastGrenadeCondition; */ // ----------------------- // If moving, don't check. // ----------------------- if ( npcOwner->IsMoving()) return COND_NONE; CBaseEntity *pEnemy = npcOwner->GetEnemy(); if (!pEnemy) return COND_NONE; Vector vecEnemyLKP = npcOwner->GetEnemyLKP(); if ( !( pEnemy->GetFlags() & FL_ONGROUND ) && pEnemy->GetWaterLevel() == 0 && vecEnemyLKP.z > (GetAbsOrigin().z + WorldAlignMaxs().z) ) { //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to // be grenaded. // don't throw grenades at anything that isn't on the ground! return COND_NONE; } // -------------------------------------- // Get target vector // -------------------------------------- Vector vecTarget; if (random->RandomInt(0,1)) { // magically know where they are vecTarget = pEnemy->WorldSpaceCenter(); } else { // toss it to where you last saw them vecTarget = vecEnemyLKP; } // vecTarget = m_vecEnemyLKP + (pEnemy->BodyTarget( GetLocalOrigin() ) - pEnemy->GetLocalOrigin()); // estimate position // vecTarget = vecTarget + pEnemy->m_vecVelocity * 2; if ( ( vecTarget - npcOwner->GetLocalOrigin() ).Length2D() <= COMBINE_MIN_GRENADE_CLEAR_DIST ) { // crap, I don't want to blow myself up m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second. return (COND_NONE); } // --------------------------------------------------------------------- // Are any friendlies near the intended grenade impact area? // --------------------------------------------------------------------- CBaseEntity *pTarget = NULL; while ( ( pTarget = gEntList.FindEntityInSphere( pTarget, vecTarget, COMBINE_MIN_GRENADE_CLEAR_DIST ) ) != NULL ) { //Check to see if the default relationship is hatred, and if so intensify that if ( npcOwner->IRelationType( pTarget ) == D_LI ) { // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while. m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second. return (COND_WEAPON_BLOCKED_BY_FRIEND); } } // --------------------------------------------------------------------- // Check that throw is legal and clear // --------------------------------------------------------------------- // FIXME: speed is based on difficulty... Vector vecToss = VecCheckThrow( this, npcOwner->GetLocalOrigin() + Vector(0,0,60), vecTarget, 600.0, 0.5 ); if ( vecToss != vec3_origin ) { m_vecTossVelocity = vecToss; // don't check again for a while. // JAY: HL1 keeps checking - test? //m_flNextGrenadeCheck = gpGlobals->curtime; m_flNextGrenadeCheck = gpGlobals->curtime + 0.3; // 1/3 second. return COND_CAN_RANGE_ATTACK2; } else { // don't check again for a while. m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second. return COND_WEAPON_SIGHT_OCCLUDED; } }
int CAI_LeadBehavior::SelectSchedule() { if (HasGoal()) { if (HasCondition(COND_LEAD_SUCCESS)) { return SCHED_LEAD_SUCCEED; } // Player's here, but does he have the weapon we want him to have? if (m_weaponname != NULL_STRING) { CBasePlayer *pFollower = AI_GetSinglePlayer(); if (pFollower && !pFollower->Weapon_OwnsThisType(STRING(m_weaponname))) { // If the safety timeout has run out, just give the player the weapon if (!m_flWeaponSafetyTimeOut || (m_flWeaponSafetyTimeOut > gpGlobals->curtime)) return SCHED_LEAD_PLAYERNEEDSWEAPON; string_t iszItem = AllocPooledString("weapon_bugbait"); pFollower->GiveNamedItem(STRING(iszItem)); } } // If we have a waitpoint, we want to wait at it for the player. if (HasWaitPoint() && !PlayerIsAheadOfMe(true)) { bool bKeepWaiting = true; // If we have no wait distance, trigger as soon as the player comes in view if (!m_waitdistance) { if (HasCondition(COND_SEE_PLAYER)) { // We've spotted the player, so stop waiting bKeepWaiting = false; } } else { // We have to collect data about the person we're leading around. CBaseEntity *pFollower = AI_GetSinglePlayer(); if (pFollower) { float flFollowerDist = (WorldSpaceCenter() - pFollower->WorldSpaceCenter()).Length(); if (flFollowerDist < m_waitdistance) { bKeepWaiting = false; } } } // Player still not here? if (bKeepWaiting) return SCHED_LEAD_WAITFORPLAYER; // We're finished waiting m_waitpoint = vec3_origin; Speak(TLK_LEAD_WAITOVER); // Don't speak the start line, because we've said m_hasspokenstart = true; return SCHED_WAIT_FOR_SPEAK_FINISH; } // If we haven't spoken our start speech, do that first if (!m_hasspokenstart) { if (HasCondition(COND_LEAD_HAVE_FOLLOWER_LOS) && HasCondition(COND_LEAD_FOLLOWER_VERY_CLOSE)) return SCHED_LEAD_SPEAK_START; // We haven't spoken to him, and we still need to. Go get him. return SCHED_LEAD_RETRIEVE; } if (HasCondition(COND_LEAD_FOLLOWER_LOST)) { if (m_args.iRetrievePlayer) { // If not, we want to go get the player. DevMsg(GetOuter(), "Follower lost. Spoke COMING_BACK.\n"); Speak(TLK_LEAD_COMINGBACK); m_MoveMonitor.ClearMark(); // If we spoke something, wait for it to finish if (m_args.iComingBackWaitForSpeak && IsSpeaking()) return SCHED_LEAD_SPEAK_THEN_RETRIEVE_PLAYER; return SCHED_LEAD_RETRIEVE; } else { // Just stay right here and wait. return SCHED_LEAD_WAITFORPLAYERIDLE; } } if (HasCondition(COND_LEAD_FOLLOWER_LAGGING)) { DevMsg(GetOuter(), "Follower lagging. Spoke CATCHUP.\n"); Speak(TLK_LEAD_CATCHUP); return SCHED_LEAD_PAUSE; } else { // If we're at the goal, wait for the player to get here if ((WorldSpaceCenter() - m_goal).LengthSqr() < (64 * 64)) return SCHED_LEAD_AWAIT_SUCCESS; // If we were retrieving the player, speak the resume if (IsCurSchedule(SCHED_LEAD_RETRIEVE, false) || IsCurSchedule(SCHED_LEAD_WAITFORPLAYERIDLE, false)) { Speak(TLK_LEAD_RETRIEVE); // If we spoke something, wait for it to finish, if the mapmakers wants us to if (m_args.iRetrieveWaitForSpeak && IsSpeaking()) return SCHED_LEAD_SPEAK_THEN_LEAD_PLAYER; } DevMsg(GetOuter(), "Leading Follower.\n"); return SCHED_LEAD_PLAYER; } } return BaseClass::SelectSchedule(); }
IterationRetval_t CPortalCollideableEnumerator::EnumElement( IHandleEntity *pHandleEntity ) { EHANDLE hEnt = pHandleEntity->GetRefEHandle(); CBaseEntity *pEnt = hEnt.Get(); if( pEnt == NULL ) //I really never thought this would be necessary return ITERATION_CONTINUE; if( hEnt == m_hTestPortal ) return ITERATION_CONTINUE; //ignore this portal /*if( staticpropmgr->IsStaticProp( pHandleEntity ) ) { //we're dealing with a static prop, which unfortunately doesn't have everything I want to use for checking ICollideable *pCollideable = pEnt->GetCollideable(); Vector vMins, vMaxs; pCollideable->WorldSpaceSurroundingBounds( &vMins, &vMaxs ); Vector ptTest( (m_vPlaneNormal.x > 0.0f)?(vMaxs.x):(vMins.x), (m_vPlaneNormal.y > 0.0f)?(vMaxs.y):(vMins.y), (m_vPlaneNormal.z > 0.0f)?(vMaxs.z):(vMins.z) ); float fPtPlaneDist = m_vPlaneNormal.Dot( ptTest ) - m_fPlaneDist; if( fPtPlaneDist <= 0.0f ) return ITERATION_CONTINUE; } else*/ { //not a static prop, w00t CCollisionProperty *pEntityCollision = pEnt->CollisionProp(); if( !pEntityCollision->IsSolid() ) return ITERATION_CONTINUE; //not solid Vector ptEntCenter = pEntityCollision->WorldSpaceCenter(); float fBoundRadius = pEntityCollision->BoundingRadius(); float fPtPlaneDist = m_vPlaneNormal.Dot( ptEntCenter ) - m_fPlaneDist; if( fPtPlaneDist < -fBoundRadius ) return ITERATION_CONTINUE; //object wholly behind the portal if( !(fPtPlaneDist > fBoundRadius) && (fPtPlaneDist > -fBoundRadius) ) //object is not wholly in front of the portal, but could be partially in front, do more checks { Vector ptNearest; pEntityCollision->CalcNearestPoint( m_ptForward1000, &ptNearest ); fPtPlaneDist = m_vPlaneNormal.Dot( ptNearest ) - m_fPlaneDist; if( fPtPlaneDist < 0.0f ) return ITERATION_CONTINUE; //closest point was behind the portal plane, we don't want it } } //if we're down here, this entity needs to be added to our enumeration Assert( m_iHandleCount < 1024 ); if( m_iHandleCount < 1024 ) m_pHandles[m_iHandleCount] = pHandleEntity; ++m_iHandleCount; return ITERATION_CONTINUE; }
//----------------------------------------------------------------------------- // Purpose: Only called on BSP load. Parses and spawns all the entities in the BSP. // Input : pMapData - Pointer to the entity data block to parse. //----------------------------------------------------------------------------- void MapEntity_ParseAllEntities(const char *pMapData, IMapEntityFilter *pFilter, bool bActivateEntities) { VPROF("MapEntity_ParseAllEntities"); HierarchicalSpawnMapData_t pSpawnMapData[NUM_ENT_ENTRIES]; HierarchicalSpawn_t pSpawnList[NUM_ENT_ENTRIES]; CUtlVector< CPointTemplate* > pPointTemplates; int nEntities = 0; char szTokenBuffer[MAPKEY_MAXLENGTH]; #if !defined( _RETAIL ) #if defined( _XBOX ) char sz[ 128 ]; Q_snprintf( sz, sizeof( sz ), "MapEntity_ParseAllEntities():Start" ); XBX_rTimeStampLog( Plat_FloatTime(), sz ); #endif #endif // Allow the tools to spawn different things if ( serverenginetools ) { pMapData = serverenginetools->GetEntityData( pMapData ); } // Loop through all entities in the map data, creating each. for ( ; true; pMapData = MapEntity_SkipToNextEntity(pMapData, szTokenBuffer) ) { // // Parse the opening brace. // char token[MAPKEY_MAXLENGTH]; pMapData = MapEntity_ParseToken( pMapData, token ); // // Check to see if we've finished or not. // if (!pMapData) break; if (token[0] != '{') { Error( "MapEntity_ParseAllEntities: found %s when expecting {", token); continue; } // // Parse the entity and add it to the spawn list. // CBaseEntity *pEntity; const char *pCurMapData = pMapData; pMapData = MapEntity_ParseEntity(pEntity, pMapData, pFilter); if (pEntity == NULL) continue; if (pEntity->IsTemplate()) { // It's a template entity. Squirrel away its keyvalue text so that we can // recreate the entity later via a spawner. pMapData points at the '}' // so we must add one to include it in the string. Templates_Add(pEntity, pCurMapData, (pMapData - pCurMapData) + 2); // Remove the template entity so that it does not show up in FindEntityXXX searches. UTIL_Remove(pEntity); gEntList.CleanupDeleteList(); continue; } // To if ( dynamic_cast<CWorld*>( pEntity ) ) { VPROF( "MapEntity_ParseAllEntities_SpawnWorld"); pEntity->m_iParent = NULL_STRING; // don't allow a parent on the first entity (worldspawn) DispatchSpawn(pEntity); continue; } CNodeEnt *pNode = dynamic_cast<CNodeEnt*>(pEntity); if ( pNode ) { VPROF( "MapEntity_ParseAllEntities_SpawnTransients"); // We overflow the max edicts on large maps that have lots of entities. // Nodes & Lights remove themselves immediately on Spawn(), so dispatch their // spawn now, to free up the slot inside this loop. // NOTE: This solution prevents nodes & lights from being used inside point_templates. // // NOTE: Nodes spawn other entities (ai_hint) if they need to have a persistent presence. // To ensure keys are copied over into the new entity, we pass the mapdata into the // node spawn function. if ( pNode->Spawn( pCurMapData ) < 0 ) { gEntList.CleanupDeleteList(); } continue; } if ( dynamic_cast<CLight*>(pEntity) ) { VPROF( "MapEntity_ParseAllEntities_SpawnTransients"); // We overflow the max edicts on large maps that have lots of entities. // Nodes & Lights remove themselves immediately on Spawn(), so dispatch their // spawn now, to free up the slot inside this loop. // NOTE: This solution prevents nodes & lights from being used inside point_templates. if (DispatchSpawn(pEntity) < 0) { gEntList.CleanupDeleteList(); } continue; } // Build a list of all point_template's so we can spawn them before everything else CPointTemplate *pTemplate = dynamic_cast< CPointTemplate* >(pEntity); if ( pTemplate ) { pPointTemplates.AddToTail( pTemplate ); } else { // Queue up this entity for spawning pSpawnList[nEntities].m_pEntity = pEntity; pSpawnList[nEntities].m_nDepth = 0; pSpawnMapData[nEntities].m_pMapData = pCurMapData; pSpawnMapData[nEntities].m_iMapDataLength = (pMapData - pCurMapData) + 2; nEntities++; } } #if !defined( _RETAIL ) #if defined( _XBOX ) Q_snprintf( sz, sizeof( sz ), "Template Spawn:Start" ); XBX_rTimeStampLog( Plat_FloatTime(), sz ); #endif #endif // Now loop through all our point_template entities and tell them to make templates of everything they're pointing to int iTemplates = pPointTemplates.Count(); for ( int i = 0; i < iTemplates; i++ ) { VPROF( "MapEntity_ParseAllEntities_SpawnTemplates"); CPointTemplate *pPointTemplate = pPointTemplates[i]; // First, tell the Point template to Spawn if ( DispatchSpawn(pPointTemplate) < 0 ) { UTIL_Remove(pPointTemplate); gEntList.CleanupDeleteList(); continue; } pPointTemplate->StartBuildingTemplates(); // Now go through all it's templates and turn the entities into templates int iNumTemplates = pPointTemplate->GetNumTemplateEntities(); for ( int iTemplateNum = 0; iTemplateNum < iNumTemplates; iTemplateNum++ ) { // Find it in the spawn list CBaseEntity *pEntity = pPointTemplate->GetTemplateEntity( iTemplateNum ); for ( int iEntNum = 0; iEntNum < nEntities; iEntNum++ ) { if ( pSpawnList[iEntNum].m_pEntity == pEntity ) { // Give the point_template the mapdata pPointTemplate->AddTemplate( pEntity, pSpawnMapData[iEntNum].m_pMapData, pSpawnMapData[iEntNum].m_iMapDataLength ); if ( pPointTemplate->ShouldRemoveTemplateEntities() ) { // Remove the template entity so that it does not show up in FindEntityXXX searches. UTIL_Remove(pEntity); gEntList.CleanupDeleteList(); // Remove the entity from the spawn list pSpawnList[iEntNum].m_pEntity = NULL; } break; } } } pPointTemplate->FinishBuildingTemplates(); } #if !defined( _RETAIL ) #if defined( _XBOX ) Q_snprintf( sz, sizeof( sz ), "Template Spawn:Finish" ); XBX_rTimeStampLog( Plat_FloatTime(), sz ); #endif #endif SpawnHierarchicalList( nEntities, pSpawnList, bActivateEntities ); #if !defined( _RETAIL ) #if defined( _XBOX ) Q_snprintf( sz, sizeof( sz ), "SpawnHierarchicalList" ); XBX_rTimeStampLog( Plat_FloatTime(), sz ); #endif #endif }
void CASW_Simple_Alien::MeleeAttack( float distance, float damage, QAngle &viewPunch, Vector &shove ) { Vector vecForceDir; // Always hurt bullseyes for now if ( ( GetEnemy() != NULL ) && ( GetEnemy()->Classify() == CLASS_BULLSEYE ) ) { vecForceDir = (GetEnemy()->GetAbsOrigin() - GetAbsOrigin()); CTakeDamageInfo info( this, this, damage, DMG_SLASH ); CalculateMeleeDamageForce( &info, vecForceDir, GetEnemy()->GetAbsOrigin() ); GetEnemy()->TakeDamage( info ); return; } CBaseEntity *pHurt = CheckTraceHullAttack( distance, -Vector(16,16,32), Vector(16,16,32), damage, DMG_SLASH, 5.0f ); if ( pHurt ) { vecForceDir = ( pHurt->WorldSpaceCenter() - WorldSpaceCenter() ); CBasePlayer *pPlayer = ToBasePlayer( pHurt ); if ( pPlayer != NULL ) { //Kick the player angles pPlayer->ViewPunch( viewPunch ); Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize(dir); QAngle angles; VectorAngles( dir, angles ); Vector forward, right; AngleVectors( angles, &forward, &right, NULL ); //Push the target back pHurt->ApplyAbsVelocityImpulse( - right * shove[1] - forward * shove[0] ); } // Play a random attack hit sound AttackSound(); // bleed em if ( UTIL_ShouldShowBlood(pHurt->BloodColor()) ) { // Hit an NPC. Bleed them! Vector vecBloodPos; Vector forward, right, up; AngleVectors( GetAbsAngles(), &forward, &right, &up ); //if( GetAttachment( "leftclaw", vecBloodPos ) ) { //Vector diff = vecBloodPos - GetAbsOrigin(); //if (diff.z < 0) //vecBloodPos.z = GetAbsOrigin().z - (diff.z * 2); vecBloodPos = GetAbsOrigin() + forward * 60 - right * 14 + up * 50; SpawnBlood( vecBloodPos, g_vecAttackDir, pHurt->BloodColor(), MIN( damage, 30 ) ); } //if( GetAttachment( "rightclaw", vecBloodPos ) ) { vecBloodPos = GetAbsOrigin() + forward * 60 + right * 14 + up * 50; SpawnBlood( vecBloodPos, g_vecAttackDir, pHurt->BloodColor(), MIN( damage, 30 ) ); } } } }
void AvHBaseBuildable::WorldUpdate() { this->UpdateTechSlots(); // Organic buildings heal themselves if(this->GetIsOrganic()) { this->UpdateAutoHeal(); } else { //this->UpdateDamageEffects(); } // If we're electrified, set render mode if(GetHasUpgrade(this->pev->iuser4, MASK_UPGRADE_11)) { // Base marine building const int kElectrifyRenderMode = kRenderFxGlowShell; const int kElectrifyRenderAmount = 40; this->pev->renderfx = kElectrifyRenderMode; this->pev->renderamt = kElectrifyRenderAmount; this->pev->rendercolor.x = kTeamColors[this->pev->team][0]; this->pev->rendercolor.y = kTeamColors[this->pev->team][1]; this->pev->rendercolor.z = kTeamColors[this->pev->team][2]; // Check for enemy players/structures nearby CBaseEntity* theBaseEntity = NULL; int theNumEntsDamaged = 0; while(((theBaseEntity = UTIL_FindEntityInSphere(theBaseEntity, this->pev->origin, BALANCE_VAR(kElectricalRange))) != NULL) && (theNumEntsDamaged < BALANCE_VAR(kElectricalMaxTargets))) { // When "electric" cheat is enabled, shock all non-self entities, else shock enemies if((GetGameRules()->GetIsCheatEnabled(kcElectric) && (theBaseEntity != this)) || ((theBaseEntity->pev->team != this->pev->team) && theBaseEntity->IsAlive())) { // Make sure it's not blocked TraceResult theTraceResult; UTIL_TraceLine(this->pev->origin, theBaseEntity->pev->origin, ignore_monsters, dont_ignore_glass, this->edict(), &theTraceResult); if(theTraceResult.flFraction == 1.0f) { CBaseEntity* theAttacker = this->GetAttacker(); ASSERT(theAttacker); if(theBaseEntity->TakeDamage(this->pev, theAttacker->pev, BALANCE_VAR(kElectricalDamage), DMG_GENERIC) > 0) { MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE(TE_BEAMENTPOINT); WRITE_SHORT(theBaseEntity->entindex()); WRITE_COORD( this->pev->origin.x); WRITE_COORD( this->pev->origin.y); WRITE_COORD( this->pev->origin.z); WRITE_SHORT( this->mElectricalSprite ); WRITE_BYTE( 0 ); // framestart WRITE_BYTE( (int)15); // framerate WRITE_BYTE( (int)(2) ); // life WRITE_BYTE( 60 ); // width WRITE_BYTE( 15 ); // noise WRITE_BYTE( (int)this->pev->rendercolor.x ); // r, g, b WRITE_BYTE( (int)this->pev->rendercolor.y ); // r, g, b WRITE_BYTE( (int)this->pev->rendercolor.z ); // r, g, b WRITE_BYTE( 200 ); // brightness WRITE_BYTE( 10 ); // speed MESSAGE_END(); gSoundListManager.PlaySoundInList(kElectricSparkSoundList, this, CHAN_AUTO, .7f); UTIL_Sparks(theBaseEntity->pev->origin); theNumEntsDamaged++; } } } } } }
//----------------------------------------------------------------------------- // Computes the bounding box of a beam local to the origin of the beam //----------------------------------------------------------------------------- void CBeam::ComputeBounds( Vector& mins, Vector& maxs ) { Vector vecAbsStart = GetAbsStartPos(); Vector vecAbsEnd = GetAbsEndPos(); // May need extra points for creating the min/max bounds bool bUseExtraPoints = false; Vector vecAbsExtra1, vecAbsExtra2; #ifdef PORTAL CBaseEntity *pStartEntity = GetStartEntityPtr(); CTraceFilterSkipClassname traceFilter( pStartEntity, "prop_energy_ball", COLLISION_GROUP_NONE ); ITraceFilter *pEntityBeamTraceFilter = NULL; if ( pStartEntity ) pEntityBeamTraceFilter = pStartEntity->GetBeamTraceFilter(); CTraceFilterChain traceFilterChain( &traceFilter, pEntityBeamTraceFilter ); bUseExtraPoints = UTIL_Portal_Trace_Beam( this, vecAbsStart, vecAbsEnd, vecAbsExtra1, vecAbsExtra2, &traceFilterChain ); #endif switch( GetType() ) { case BEAM_LASER: case BEAM_ENTS: case BEAM_SPLINE: case BEAM_ENTPOINT: { // Compute the bounds here... Vector attachmentPoint( 0, 0, 0 ); mins.Init( 99999, 99999, 99999 ); maxs.Init( -99999, -99999, -99999 ); for (int i = 0; i < m_nNumBeamEnts; ++i ) { C_BaseEntity *pTestEnt = m_hAttachEntity[i].Get(); if ( pTestEnt ) { if ( pTestEnt == this ) { mins = maxs = GetAbsOrigin(); } else { // We do this so we don't have to calculate attachments (and do expensive bone-setup calculations) on our attachments. Vector attMins, attMaxs; m_hAttachEntity[i]->GetRenderBoundsWorldspace( attMins, attMaxs ); mins = mins.Min( attMins ); mins = mins.Min( attMaxs ); maxs = maxs.Max( attMins ); maxs = maxs.Max( attMaxs ); } //ASSERT_COORD( mins ); //ASSERT_COORD( maxs ); } else { if (i == 0) { VectorCopy( vecAbsStart, attachmentPoint ); } else if (i == 1) { VectorCopy( vecAbsEnd, attachmentPoint ); } else { Assert(0); } mins = mins.Min( attachmentPoint ); maxs = maxs.Max( attachmentPoint ); } } } break; case BEAM_POINTS: default: { for (int i = 0; i < 3; ++i) { if (vecAbsStart[i] < vecAbsEnd[i]) { mins[i] = vecAbsStart[i]; maxs[i] = vecAbsEnd[i]; } else { mins[i] = vecAbsEnd[i]; maxs[i] = vecAbsStart[i]; } } } break; } if ( bUseExtraPoints ) { mins = mins.Min( vecAbsExtra1 ); mins = mins.Min( vecAbsExtra2 ); maxs = maxs.Max( vecAbsExtra1 ); maxs = maxs.Max( vecAbsExtra2 ); } // Make sure the bounds are measured in *relative coords* Vector vecAbsOrigin = GetAbsOrigin(); mins -= vecAbsOrigin; maxs -= vecAbsOrigin; }
Vector CASW_Simple_Alien::CalcDeathForceVector( const CTakeDamageInfo &info ) { // Already have a damage force in the data, use that. if ( info.GetDamageForce() != vec3_origin || (g_pGameRules->Damage_NoPhysicsForce(info.GetDamageType()))) { if( info.GetDamageType() & DMG_BLAST ) { float scale = random->RandomFloat( 0.85, 1.15 ); Vector force = info.GetDamageForce(); force.x *= scale; force.y *= scale; // Try to always exaggerate the upward force because we've got pretty harsh gravity force.z *= (force.z > 0) ? 1.15 : scale; return force; } return info.GetDamageForce(); } CBaseEntity *pForce = info.GetInflictor(); if ( !pForce ) { pForce = info.GetAttacker(); } if ( pForce ) { // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage float forceScale = info.GetDamage() * 75 * 4; Vector forceVector; // If the damage is a blast, point the force vector higher than usual, this gives // the ragdolls a bodacious "really got blowed up" look. if( info.GetDamageType() & DMG_BLAST ) { // exaggerate the force from explosions a little (37.5%) forceVector = (GetLocalOrigin() + Vector(0, 0, WorldAlignSize().z) ) - pForce->GetLocalOrigin(); VectorNormalize(forceVector); forceVector *= 1.375f; } else { // taking damage from self? Take a little random force, but still try to collapse on the spot. if ( this == pForce ) { forceVector.x = random->RandomFloat( -1.0f, 1.0f ); forceVector.y = random->RandomFloat( -1.0f, 1.0f ); forceVector.z = 0.0; forceScale = random->RandomFloat( 1000.0f, 2000.0f ); } else { // UNDONE: Collision forces are baked in to CTakeDamageInfo now // UNDONE: Is this MOVETYPE_VPHYSICS code still necessary? if ( pForce->GetMoveType() == MOVETYPE_VPHYSICS ) { // killed by a physics object IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( !pPhysics ) { pPhysics = pForce->VPhysicsGetObject(); } pPhysics->GetVelocity( &forceVector, NULL ); forceScale = pPhysics->GetMass(); } else { forceVector = GetLocalOrigin() - pForce->GetLocalOrigin(); VectorNormalize(forceVector); } } } return forceVector * forceScale; } return vec3_origin; }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CNPC_Monk::GatherConditions() { BaseClass::GatherConditions(); // Build my zombie danger index! m_iNumZombies = 0; m_iDangerousZombies = 0; AISightIter_t iter; CBaseEntity *pSightEnt; pSightEnt = GetSenses()->GetFirstSeenEntity( &iter ); while( pSightEnt ) { if( pSightEnt->Classify() == CLASS_ZOMBIE && pSightEnt->IsAlive() ) { // Is this zombie coming for me? CAI_BaseNPC *pZombie = dynamic_cast<CAI_BaseNPC*>(pSightEnt); if( pZombie && pZombie->GetEnemy() == this ) { m_iNumZombies++; // if this zombie is close enough to attack, add him to the zombie danger! float flDist; flDist = (pZombie->GetAbsOrigin() - GetAbsOrigin()).Length2DSqr(); if( flDist <= 128.0f * 128.0f ) { m_iDangerousZombies++; } } } pSightEnt = GetSenses()->GetNextSeenEntity( &iter ); } if( m_iDangerousZombies >= 3 || (GetEnemy() && GetHealth() < 25) ) { // I see many zombies, or I'm quite injured. SpeakIfAllowed( TLK_HELP_ME ); } // NOTE!!!!!! This code assumes grigori is using annabelle! ClearCondition(COND_LOW_PRIMARY_AMMO); if ( GetActiveWeapon() ) { if ( GetActiveWeapon()->UsesPrimaryAmmo() ) { if (!GetActiveWeapon()->HasPrimaryAmmo() ) { SetCondition(COND_NO_PRIMARY_AMMO); } else if ( m_NPCState != NPC_STATE_COMBAT && GetActiveWeapon()->UsesClipsForAmmo1() && GetActiveWeapon()->Clip1() < 2 ) { // Don't send a low ammo message unless we're not in combat. SetCondition(COND_LOW_PRIMARY_AMMO); } } } }
//========================================================= //========================================================= void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) { char *pName; char teamlist[TEAMPLAY_TEAMLISTLENGTH]; // loop through all teams, recounting everything num_teams = 0; // Copy all of the teams from the teamlist // make a copy because strtok is destructive strcpy( teamlist, m_szTeamList ); pName = teamlist; pName = strtok( pName, ";" ); while ( pName != NULL && *pName ) { if ( GetTeamIndex( pName ) < 0 ) { strcpy( team_names[num_teams], pName ); num_teams++; } pName = strtok( NULL, ";" ); } if ( num_teams < 2 ) { num_teams = 0; m_teamLimit = FALSE; } // Sanity check memset( team_scores, 0, sizeof(team_scores) ); // loop through all clients for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *plr = UTIL_PlayerByIndex( i ); if ( plr ) { const char *pTeamName = plr->TeamID(); // try add to existing team int tm = GetTeamIndex( pTeamName ); if ( tm < 0 ) // no team match found { if ( !m_teamLimit ) { // add to new team tm = num_teams; num_teams++; team_scores[tm] = 0; strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH ); } } if ( tm >= 0 ) { team_scores[tm] += plr->pev->frags; } if ( bResendInfo ) //Someone's info changed, let's send the team info again. { if ( plr && IsValidTeam( plr->TeamID() ) ) { MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo, NULL ); WRITE_BYTE( plr->entindex() ); WRITE_STRING( plr->TeamID() ); MESSAGE_END(); } } } } }
//----------------------------------------------------------------------------- // Purpose: Catches the monster-specific messages that occur when tagged // animation frames are played. // Input : *pEvent - //----------------------------------------------------------------------------- void CNPC_Headcrab::HandleAnimEvent( animevent_t *pEvent ) { switch ( pEvent->event ) { case HC_AE_JUMPATTACK: { RemoveFlag( FL_ONGROUND ); // // Take him off ground so engine doesn't instantly reset FL_ONGROUND. // UTIL_SetOrigin( this, GetAbsOrigin() + Vector( 0 , 0 , 1 )); Vector vecJumpDir; CBaseEntity *pEnemy = GetEnemy(); if ( pEnemy ) { Vector vecEnemyEyePos = pEnemy->EyePosition(); float gravity = sv_gravity.GetFloat(); if ( gravity <= 1 ) { gravity = 1; } // // How fast does the headcrab need to travel to reach my enemy's eyes given gravity? // float height = ( vecEnemyEyePos.z - GetAbsOrigin().z ); if ( height < 16 ) { height = 16; } else if ( height > 120 ) { height = 120; } float speed = sqrt( 2 * gravity * height ); float time = speed / gravity; // // Scale the sideways velocity to get there at the right time // vecJumpDir = vecEnemyEyePos - GetAbsOrigin(); vecJumpDir = vecJumpDir / time; // // Speed to offset gravity at the desired height. // vecJumpDir.z = speed; // // Don't jump too far/fast. // float distance = vecJumpDir.Length(); if ( distance > 650 ) { vecJumpDir = vecJumpDir * ( 650.0 / distance ); } } else { // // Jump hop, don't care where. // Vector forward, up; AngleVectors( GetAbsAngles(), &forward, NULL, &up ); vecJumpDir = Vector( forward.x, forward.y, up.z ) * 350; } int iSound = random->RandomInt( 0 , 1 ); if ( iSound != 0 ) { AttackSound(); } SetAbsVelocity( vecJumpDir ); m_flNextAttack = gpGlobals->curtime + 2; break; } default: { CAI_BaseNPC::HandleAnimEvent( pEvent ); break; } } }
void CFuncTank::TrackTarget(void) { TraceResult tr; edict_t * pPlayer = FIND_CLIENT_IN_PVS(edict()); BOOL updateTime = FALSE, lineOfSight; Vector angles, direction, targetPosition, barrelEnd; edict_t * pTarget; // Get a position to aim for if(m_pController) { // Tanks attempt to mirror the player's angles angles = m_pController->pev->v_angle; angles[0] = 0 - angles[0]; pev->nextthink = pev->ltime + 0.05; } else { if(IsActive()) pev->nextthink = pev->ltime + 0.1; else return; if(FNullEnt(pPlayer)) { if(IsActive()) pev->nextthink = pev->ltime + 2; // Wait 2 secs return; } pTarget = FindTarget(pPlayer); if(!pTarget) return; // Calculate angle needed to aim at target barrelEnd = BarrelPosition(); targetPosition = pTarget->v.origin + pTarget->v.view_ofs; float range = (targetPosition - barrelEnd).Length(); if(!InRange(range)) return; UTIL_TraceLine(barrelEnd, targetPosition, dont_ignore_monsters, edict(), &tr); lineOfSight = FALSE; // No line of sight, don't track if(tr.flFraction == 1.0 || tr.pHit == pTarget) { lineOfSight = TRUE; CBaseEntity *pInstance = CBaseEntity::Instance(pTarget); if(InRange(range) && pInstance && pInstance->IsAlive()) { updateTime = TRUE; m_sightOrigin = UpdateTargetPosition(pInstance); } } // Track sight origin // !!! I'm not sure what i changed direction = m_sightOrigin - pev->origin; // direction = m_sightOrigin - barrelEnd; angles = UTIL_VecToAngles(direction); // Calculate the additional rotation to point the end of the barrel at the target (not the gun's center) AdjustAnglesForBarrel(angles, direction.Length()); } angles.x = -angles.x; // Force the angles to be relative to the center position angles.y = m_yawCenter + UTIL_AngleDistance(angles.y, m_yawCenter); angles.x = m_pitchCenter + UTIL_AngleDistance(angles.x, m_pitchCenter); // Limit against range in y if(angles.y > m_yawCenter + m_yawRange) { angles.y = m_yawCenter + m_yawRange; updateTime = FALSE; // Don't update if you saw the player, but out of range } else if(angles.y < (m_yawCenter - m_yawRange)) { angles.y = (m_yawCenter - m_yawRange); updateTime = FALSE; // Don't update if you saw the player, but out of range } if(updateTime) m_lastSightTime = gpGlobals->time; // Move toward target at rate or less float distY = UTIL_AngleDistance(angles.y, pev->angles.y); pev->avelocity.y = distY * 10; if(pev->avelocity.y > m_yawRate) pev->avelocity.y = m_yawRate; else if(pev->avelocity.y < -m_yawRate) pev->avelocity.y = -m_yawRate; // Limit against range in x if(angles.x > m_pitchCenter + m_pitchRange) angles.x = m_pitchCenter + m_pitchRange; else if(angles.x < m_pitchCenter - m_pitchRange) angles.x = m_pitchCenter - m_pitchRange; // Move toward target at rate or less float distX = UTIL_AngleDistance(angles.x, pev->angles.x); pev->avelocity.x = distX * 10; if(pev->avelocity.x > m_pitchRate) pev->avelocity.x = m_pitchRate; else if(pev->avelocity.x < -m_pitchRate) pev->avelocity.x = -m_pitchRate; if(m_pController) return; if(CanFire() && ((fabs(distX) < m_pitchTolerance && fabs(distY) < m_yawTolerance) || (pev->spawnflags & SF_TANK_LINEOFSIGHT))) { BOOL fire = FALSE; Vector forward; UTIL_MakeVectorsPrivate(pev->angles, forward, NULL, NULL); if(pev->spawnflags & SF_TANK_LINEOFSIGHT) { float length = direction.Length(); UTIL_TraceLine(barrelEnd, barrelEnd + forward * length, dont_ignore_monsters, edict(), &tr); if(tr.pHit == pTarget) fire = TRUE; } else fire = TRUE; if(fire) { Fire(BarrelPosition(), forward, pev); } else m_fireLast = 0; } else m_fireLast = 0; }
void CLightning::StrikeThink(void) { if (m_life != 0) { if (pev->spawnflags & SF_BEAM_RANDOM) pev->nextthink = gpGlobals->time + m_life + RANDOM_FLOAT(0, m_restrike); else pev->nextthink = gpGlobals->time + m_life + m_restrike; } m_active = 1; if (FStringNull(m_iszEndEntity)) { if (FStringNull(m_iszStartEntity)) { RandomArea(); } else { CBaseEntity *pStart = RandomTargetname(STRING(m_iszStartEntity)); if (pStart != NULL) RandomPoint(pStart->pev->origin); else ALERT(at_console, "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity)); } return; } CBaseEntity *pStart = RandomTargetname(STRING(m_iszStartEntity)); CBaseEntity *pEnd = RandomTargetname(STRING(m_iszEndEntity)); if (pStart != NULL && pEnd != NULL) { if (IsPointEntity(pStart) || IsPointEntity(pEnd)) { if (pev->spawnflags & SF_BEAM_RING) { // don't work return; } } MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY); if (IsPointEntity(pStart) || IsPointEntity(pEnd)) { if (!IsPointEntity(pEnd)) // One point entity must be in pEnd { CBaseEntity *pTemp; pTemp = pStart; pStart = pEnd; pEnd = pTemp; } if (!IsPointEntity(pStart)) // One sided { WRITE_BYTE(TE_BEAMENTPOINT); WRITE_SHORT(pStart->entindex()); WRITE_COORD(pEnd->pev->origin.x); WRITE_COORD(pEnd->pev->origin.y); WRITE_COORD(pEnd->pev->origin.z); } else { WRITE_BYTE(TE_BEAMPOINTS); WRITE_COORD(pStart->pev->origin.x); WRITE_COORD(pStart->pev->origin.y); WRITE_COORD(pStart->pev->origin.z); WRITE_COORD(pEnd->pev->origin.x); WRITE_COORD(pEnd->pev->origin.y); WRITE_COORD(pEnd->pev->origin.z); } } else { if (pev->spawnflags & SF_BEAM_RING) WRITE_BYTE(TE_BEAMRING); else WRITE_BYTE(TE_BEAMENTS); WRITE_SHORT(pStart->entindex()); WRITE_SHORT(pEnd->entindex()); } WRITE_SHORT(m_spriteTexture); WRITE_BYTE(m_frameStart); // framestart WRITE_BYTE((int)pev->framerate); // framerate WRITE_BYTE((int)(m_life*10.0)); // life WRITE_BYTE(m_boltWidth); // width WRITE_BYTE(m_noiseAmplitude); // noise WRITE_BYTE((int)pev->rendercolor.x); // r, g, b WRITE_BYTE((int)pev->rendercolor.y); // r, g, b WRITE_BYTE((int)pev->rendercolor.z); // r, g, b WRITE_BYTE(pev->renderamt); // brightness WRITE_BYTE(m_speed); // speed MESSAGE_END(); DoSparks(pStart->pev->origin, pEnd->pev->origin); if (pev->dmg > 0) { TraceResult tr; UTIL_TraceLine(pStart->pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr); BeamDamageInstant(&tr, pev->dmg); } } }
void CHUDAutoAim::OnThink() { int wide, tall; GetSize( wide, tall ); BaseClass::OnThink(); // Get the HL2 player C_BaseHLPlayer *pLocalPlayer = (C_BaseHLPlayer *)C_BasePlayer::GetLocalPlayer(); if ( pLocalPlayer == NULL ) { // Just turn the autoaim crosshair off. ResetPosition(); ResetAlpha(); ResetScale(); m_alphaFixed = 0.0f; return; } // Get the autoaim target. CBaseEntity *pTarget = pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get(); // Fixed element stuff float flFixedAlphaGoal; if( pTarget ) { flFixedAlphaGoal = hud_reticle_maxalpha.GetFloat(); } else { flFixedAlphaGoal = hud_reticle_minalpha.GetFloat(); } if( pLocalPlayer->m_HL2Local.m_bZooming || pLocalPlayer->m_HL2Local.m_bWeaponLowered ) { flFixedAlphaGoal = 0.0f; } m_alphaFixed = Approach( flFixedAlphaGoal, m_alphaFixed, (hud_alpha_speed.GetFloat() * gpGlobals->frametime) ); switch( hud_autoaim_method.GetInt() ) { case AUTOAIM_METHOD_RETICLE: { if( pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get() && pLocalPlayer->m_HL2Local.m_bStickyAutoAim ) { if( !pLocalPlayer->IsInAVehicle() ) { Vector vecLook; pLocalPlayer->EyeVectors( &vecLook, NULL, NULL ); Vector vecMove = pLocalPlayer->GetAbsVelocity(); float flSpeed = VectorNormalize( vecMove ); float flDot = DotProduct( vecLook, vecMove ); if( flSpeed >= 100 && fabs(flDot) <= 0.707f ) { QAngle viewangles; QAngle targetangles; QAngle delta; engine->GetViewAngles( viewangles ); Vector vecDir = pLocalPlayer->m_HL2Local.m_vecAutoAimPoint - pLocalPlayer->EyePosition(); VectorNormalize(vecDir); VectorAngles( vecDir, targetangles ); float magnetism = hud_magnetism.GetFloat(); delta[0] = ApproachAngle( targetangles[0], viewangles[0], magnetism ); delta[1] = ApproachAngle( targetangles[1], viewangles[1], magnetism ); delta[2] = targetangles[2]; //viewangles[PITCH] = clamp( viewangles[ PITCH ], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() ); engine->SetViewAngles( delta ); } } } #if 0 bool doScaling = hud_autoaim_scale_icon.GetBool(); // These are the X & Y coords of where the crosshair should be. Default to // returning to the center of the screen if there is no target. int goalx = ScreenWidth() / 2; int goaly = ScreenHeight() / 2; int goalalpha = 0; float goalscale = AUTOAIM_MIN_SCALE; float speed = AUTOAIM_OFFTARGET_CROSSHAIR_SPEED; if( pTarget ) { // Get the autoaim crosshair onto the target. Vector screen; // Center the crosshair on the entity. if( doScaling ) { // Put the crosshair over the center of the target. ScreenTransform( pTarget->WorldSpaceCenter(), screen ); } else { // Put the crosshair exactly where the player is aiming. ScreenTransform( pLocalPlayer->m_HL2Local.m_vecAutoAimPoint, screen ); } // Set Goal Position and speed. goalx += 0.5f * screen[0] * ScreenWidth() + 0.5f; goaly -= 0.5f * screen[1] * ScreenHeight() + 0.5f; speed = AUTOAIM_ONTARGET_CROSSHAIR_SPEED; goalalpha = AUTOAIM_MAX_ALPHA; if( doScaling ) { // Scale the crosshair to envelope the entity's bounds on screen. Vector vecMins, vecMaxs; Vector vecScreenMins, vecScreenMaxs; // Get mins and maxs in world space vecMins = pTarget->GetAbsOrigin() + pTarget->WorldAlignMins(); vecMaxs = pTarget->GetAbsOrigin() + pTarget->WorldAlignMaxs(); // Project them to screen ScreenTransform( vecMins, vecScreenMins ); ScreenTransform( vecMaxs, vecScreenMaxs ); vecScreenMins.y = (ScreenWidth()/2) - 0.5f * vecScreenMins.y * ScreenWidth() + 0.5f; vecScreenMaxs.y = (ScreenWidth()/2) - 0.5f * vecScreenMaxs.y * ScreenWidth() + 0.5f; float screenSize = vecScreenMins.y - vecScreenMaxs.y; // Set goal scale goalscale = screenSize / 64.0f; // 64 is the width of the crosshair art. } else { goalscale = 1.0f; } } // Now approach the goal, alpha, and scale Vector vecGoal( goalx, goaly, 0 ); Vector vecDir = vecGoal - m_vecPos; float flDistRemaining = VectorNormalize( vecDir ); m_vecPos += vecDir * min(flDistRemaining, (speed * gpGlobals->frametime) ); // Lerp and Clamp scale float scaleDelta = fabs( goalscale - m_scale ); float scaleMove = min( AUTOAIM_SCALE_SPEED * gpGlobals->frametime, scaleDelta ); if( m_scale < goalscale ) { m_scale += scaleMove; } else if( m_scale > goalscale ) { m_scale -= scaleMove; } if( m_scale > AUTOAIM_MAX_SCALE ) { m_scale = AUTOAIM_MAX_SCALE; } else if( m_scale < AUTOAIM_MIN_SCALE ) { m_scale = AUTOAIM_MIN_SCALE; } if( goalalpha > m_alpha ) { m_alpha += AUTOAIM_ALPHA_UP_SPEED * gpGlobals->frametime; } else if( goalalpha < m_alpha ) { m_alpha -= AUTOAIM_ALPHA_DOWN_SPEED * gpGlobals->frametime; } // Clamp alpha if( m_alpha < 0 ) { m_alpha = 0; } else if( m_alpha > AUTOAIM_MAX_ALPHA ) { m_alpha = AUTOAIM_MAX_ALPHA; } #endif } break; case AUTOAIM_METHOD_DRIFT: { if( pLocalPlayer->m_HL2Local.m_hAutoAimTarget.Get() ) { QAngle viewangles; engine->GetViewAngles( viewangles ); Vector vecDir = pLocalPlayer->m_HL2Local.m_vecAutoAimPoint - pLocalPlayer->EyePosition(); VectorNormalize(vecDir); VectorAngles( vecDir, viewangles ); //viewangles[PITCH] = clamp( viewangles[ PITCH ], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() ); engine->SetViewAngles( viewangles ); } } break; } }
// bayonet attack void CBaseBayonet::SecondaryAttack( void ) { if(m_pPlayer->pev->flags & FL_DUCKING || m_pPlayer->pev->button & IN_DUCK) return; //BP to prevent players from stabbing right after getting up if(m_fNextStabTime > UTIL_WeaponTimeBase()) return; SetWeaponDamage(pData->flSecondaryDmgModifier); TraceResult tr; UTIL_MakeVectors(m_pPlayer->pev->v_angle); Vector vecSrc = m_pPlayer->GetGunPosition(); Vector vecEnd = vecSrc + gpGlobals->v_forward * this->pData->flBladeLength; UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); #ifndef CLIENT_DLL CBaseEntity *pHit = NULL; /* if ( tr.flFraction >= 1.0 ) { UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr ); if ( tr.flFraction < 1.0 ) { // Calculate the point of intersection of the line (or hull) and the object we hit // This is and approximation of the "best" intersection pHit = CBaseEntity::Instance( tr.pHit ); if ( !pHit || pHit->IsBSPModel() ) { FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() ); } vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space) } }*/ if(tr.flFraction < 1.0) { pHit = CBaseEntity::Instance( tr.pHit ); if (pHit && pHit->pev->takedamage) { float flDamage = m_pPlayer->GetDamage(m_pPlayer->pev, gpGlobals->v_forward, &tr); if(pHit->IsPlayer()) { Vector vecOrg = tr.vecEndPos - gpGlobals->v_forward * 4; if ( g_pGameRules->FPlayerCanTakeDamage( m_pPlayer, pHit ) && flDamage != 0.0) { pev->classname = MAKE_STRING("weapon_Bayonet"); ClearMultiDamage( ); pHit->TraceAttack(m_pPlayer->pev, flDamage, gpGlobals->v_forward, &tr, DMG_CLUB | DMG_NEVERGIB ); pev->iuser3 = tr.iHitgroup; // hack to get the hitgroup used ApplyMultiDamage( pev, m_pPlayer->pev ); EMIT_SOUND(ENT(pev), CHAN_WEAPON, pData->snd_hit, 1, ATTN_NORM); SpawnBlood( vecOrg, BLOOD_COLOR_RED, flDamage * 4 ); // Make a lot of Blood! } } else { ClearMultiDamage( ); pHit->TraceAttack(m_pPlayer->pev, flDamage, gpGlobals->v_forward, &tr, DMG_CLUB | DMG_NEVERGIB ); ApplyMultiDamage( pev, m_pPlayer->pev ); } } else { if(pData->snd_hitwall) EMIT_SOUND(ENT(pev), CHAN_AUTO, pData->snd_hitwall, 1, ATTN_NORM); DecalGunshot( &tr, BULLET_BLADE ); } } #endif m_pPlayer->SetAnimation( PLAYER_BAYONET ); int flags; #if defined( CLIENT_WEAPONS ) flags = FEV_NOTHOST; #else flags = 0; #endif int iIsEmpty = (m_iClip > 0 ? 0 : 1); // use event secondary so that the bayonet weapons can use there events // melee weapons can use the same event for primary and secondary PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), pData->m_usSecondaryAttack, 0.0, m_pPlayer->pev->origin, m_pPlayer->pev->angles, 0.0, 0, m_pPlayer->pev->team, m_iId, iIsEmpty, 0 ); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + pData->flAttackDelay; m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + pData->flAttackDelay; m_pPlayer->BurnStamina(MAX_STAMINA / 5, (float)0.1); }
void SpawnAllEntities( int nEntities, HierarchicalSpawn_t *pSpawnList, bool bActivateEntities ) { #if !defined( _RETAIL ) #if defined( _XBOX ) char sz[ 128 ]; Q_snprintf( sz, sizeof( sz ), "SpawnAllEntities(%d)", nEntities ); XBX_rTimeStampLog( Plat_FloatTime(), sz ); #endif #endif int nEntity; for (nEntity = 0; nEntity < nEntities; nEntity++) { VPROF( "MapEntity_ParseAllEntities_Spawn"); CBaseEntity *pEntity = pSpawnList[nEntity].m_pEntity; if ( pEntity ) { if (DispatchSpawn(pEntity) < 0) { for ( int i = nEntity+1; i < nEntities; i++ ) { // this is a child object that will be deleted now if ( pSpawnList[i].m_pEntity && pSpawnList[i].m_pEntity->IsMarkedForDeletion() ) { pSpawnList[i].m_pEntity = NULL; } } // Spawn failed. gEntList.CleanupDeleteList(); // Remove the entity from the spawn list pSpawnList[nEntity].m_pEntity = NULL; } } } #if !defined( _RETAIL ) #if defined( _XBOX ) Q_snprintf( sz, sizeof( sz ), "SpawnAllEntities(%d) -activate", nEntities ); XBX_rTimeStampLog( Plat_FloatTime(), sz ); #endif #endif if ( bActivateEntities ) { VPROF( "MapEntity_ParseAllEntities_Activate"); bool bAsyncAnims = mdlcache->SetAsyncLoad( MDLCACHE_ANIMBLOCK, false ); for (nEntity = 0; nEntity < nEntities; nEntity++) { CBaseEntity *pEntity = pSpawnList[nEntity].m_pEntity; if ( pEntity ) { MDLCACHE_CRITICAL_SECTION(); pEntity->Activate(); } } mdlcache->SetAsyncLoad( MDLCACHE_ANIMBLOCK, bAsyncAnims ); } #if !defined( _RETAIL ) #if defined( _XBOX ) Q_snprintf( sz, sizeof( sz ), "SpawnAllEntities(%d) -done activating", nEntities ); XBX_rTimeStampLog( Plat_FloatTime(), sz ); #endif #endif }
//========================================================= //========================================================= void CBarnacle :: BarnacleThink ( void ) { CBaseEntity *pTouchEnt; CBaseMonster *pVictim; float flLength; pev->nextthink = gpGlobals->time + 0.1; if ( m_hEnemy != NULL ) { // barnacle has prey. if ( !m_hEnemy->IsAlive() ) { // someone (maybe even the barnacle) killed the prey. Reset barnacle. m_fLiftingPrey = FALSE;// indicate that we're not lifting prey. m_hEnemy = NULL; return; } if ( m_fLiftingPrey ) { if ( m_hEnemy != NULL && m_hEnemy->pev->deadflag != DEAD_NO ) { // crap, someone killed the prey on the way up. m_hEnemy = NULL; m_fLiftingPrey = FALSE; return; } // still pulling prey. Vector vecNewEnemyOrigin = m_hEnemy->pev->origin; vecNewEnemyOrigin.x = pev->origin.x; vecNewEnemyOrigin.y = pev->origin.y; // guess as to where their neck is vecNewEnemyOrigin.x -= 6 * cos(m_hEnemy->pev->angles.y * M_PI/180.0); vecNewEnemyOrigin.y -= 6 * sin(m_hEnemy->pev->angles.y * M_PI/180.0); m_flAltitude -= BARNACLE_PULL_SPEED; vecNewEnemyOrigin.z += BARNACLE_PULL_SPEED; if ( fabs( pev->origin.z - ( vecNewEnemyOrigin.z + m_hEnemy->pev->view_ofs.z - 8 ) ) < BARNACLE_BODY_HEIGHT ) { // prey has just been lifted into position ( if the victim origin + eye height + 8 is higher than the bottom of the barnacle, it is assumed that the head is within barnacle's body ) m_fLiftingPrey = FALSE; EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_bite3.wav", 1, ATTN_NORM ); pVictim = m_hEnemy->MyMonsterPointer(); m_flKillVictimTime = gpGlobals->time + 10;// now that the victim is in place, the killing bite will be administered in 10 seconds. if ( pVictim ) { pVictim->BarnacleVictimBitten( pev ); SetActivity ( ACT_EAT ); } } UTIL_SetOrigin ( m_hEnemy->pev, vecNewEnemyOrigin ); } else { // prey is lifted fully into feeding position and is dangling there. pVictim = m_hEnemy->MyMonsterPointer(); if ( m_flKillVictimTime != -1 && gpGlobals->time > m_flKillVictimTime ) { // kill! if ( pVictim ) { pVictim->TakeDamage ( pev, pev, pVictim->pev->health, DMG_SLASH | DMG_ALWAYSGIB ); m_cGibs = 3; } return; } // bite prey every once in a while if ( pVictim && ( RANDOM_LONG(0,49) == 0 ) ) { switch ( RANDOM_LONG(0,2) ) { case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); break; case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); break; case 2: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); break; } pVictim->BarnacleVictimBitten( pev ); } } } else { // barnacle has no prey right now, so just idle and check to see if anything is touching the tongue. // If idle and no nearby client, don't think so often if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); // Stagger a bit to keep barnacles from thinking on the same frame if ( m_fSequenceFinished ) {// this is done so barnacle will fidget. SetActivity ( ACT_IDLE ); m_flTongueAdj = -100; } if ( m_cGibs && RANDOM_LONG(0,99) == 1 ) { // cough up a gib. CGib::SpawnRandomGibs( pev, 1, 1 ); m_cGibs--; switch ( RANDOM_LONG(0,2) ) { case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); break; case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); break; case 2: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); break; } } pTouchEnt = TongueTouchEnt( &flLength ); if ( pTouchEnt != NULL && m_fTongueExtended ) { // tongue is fully extended, and is touching someone. if ( pTouchEnt->FBecomeProne() ) { EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_alert2.wav", 1, ATTN_NORM ); SetSequenceByName ( "attack1" ); m_flTongueAdj = -20; m_hEnemy = pTouchEnt; pTouchEnt->pev->movetype = MOVETYPE_FLY; pTouchEnt->pev->velocity = g_vecZero; pTouchEnt->pev->basevelocity = g_vecZero; pTouchEnt->pev->origin.x = pev->origin.x; pTouchEnt->pev->origin.y = pev->origin.y; m_fLiftingPrey = TRUE;// indicate that we should be lifting prey. m_flKillVictimTime = -1;// set this to a bogus time while the victim is lifted. m_flAltitude = (pev->origin.z - pTouchEnt->EyePosition().z); } } else { // calculate a new length for the tongue to be clear of anything else that moves under it. if ( m_flAltitude < flLength ) { // if tongue is higher than is should be, lower it kind of slowly. m_flAltitude += BARNACLE_PULL_SPEED; m_fTongueExtended = FALSE; } else { m_flAltitude = flLength; m_fTongueExtended = TRUE; } } } // ALERT( at_console, "tounge %f\n", m_flAltitude + m_flTongueAdj ); SetBoneController( 0, -(m_flAltitude + m_flTongueAdj) ); StudioFrameAdvance( 0.1 ); }
//========================================================= //========================================================= void CHalfLifeTeamplay::RecountTeams( void ) { char *pName; char teamlist[TEAMPLAY_TEAMLISTLENGTH]; // loop through all teams, recounting everything num_teams = 0; // Copy all of the teams from the teamlist // make a copy because strtok is destructive strcpy( teamlist, m_szTeamList ); pName = teamlist; pName = strtok( pName, ";" ); while ( pName != NULL && *pName ) { if ( GetTeamIndex( pName ) < 0 ) { strcpy( team_names[num_teams], pName ); num_teams++; } pName = strtok( NULL, ";" ); } if ( num_teams < 2 ) { num_teams = 0; m_teamLimit = FALSE; } // Sanity check memset( team_scores, 0, sizeof(team_scores) ); // loop through all clients for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseEntity *plr = UTIL_PlayerByIndex( i ); if ( plr ) { const char *pTeamName = plr->TeamID(); // try add to existing team int tm = GetTeamIndex( pTeamName ); if ( tm < 0 ) // no team match found { if ( !m_teamLimit ) { // add to new team tm = num_teams; num_teams++; team_scores[tm] = 0; strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH ); } } if ( tm >= 0 ) { team_scores[tm] += static_cast<int>(plr->pev->frags); } } } }
//========================================================= // 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 (this, pev->origin + Vector ( 0 , 0 , 1) );// take her 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: //----------------------------------------------------------------------------- void CAI_LeadBehavior::GatherConditions(void) { BaseClass::GatherConditions(); if (HasGoal()) { // Fix for bad transition case (to investigate) if ((WorldSpaceCenter() - m_goal).LengthSqr() > (64 * 64) && IsCurSchedule(SCHED_LEAD_AWAIT_SUCCESS, false)) { GetOuter()->ClearSchedule("Lead behavior - bad transition?"); } // We have to collect data about the person we're leading around. CBaseEntity *pFollower = AI_GetSinglePlayer(); if (pFollower) { ClearCondition(COND_LEAD_FOLLOWER_VERY_CLOSE); ClearCondition(COND_LEAD_FOLLOWER_MOVING_TOWARDS_ME); // Check distance to the follower float flFollowerDist = (WorldSpaceCenter() - pFollower->WorldSpaceCenter()).Length(); bool bLagging = flFollowerDist > (m_leaddistance * 4); if (bLagging) { if (PlayerIsAheadOfMe()) { bLagging = false; } } // Player heading towards me? // Only factor this in if you're not too far from them if (flFollowerDist < (m_leaddistance * 4)) { Vector vecVelocity = pFollower->GetSmoothedVelocity(); if (VectorNormalize(vecVelocity) > 50) { Vector vecToPlayer = (GetAbsOrigin() - pFollower->GetAbsOrigin()); VectorNormalize(vecToPlayer); if (DotProduct(vecVelocity, vecToPlayer) > 0.5) { SetCondition(COND_LEAD_FOLLOWER_MOVING_TOWARDS_ME); bLagging = false; } } } // If he's outside our lag range, consider him lagging if (bLagging) { SetCondition(COND_LEAD_FOLLOWER_LAGGING); ClearCondition(COND_LEAD_FOLLOWER_NOT_LAGGING); } else { ClearCondition(COND_LEAD_FOLLOWER_LAGGING); SetCondition(COND_LEAD_FOLLOWER_NOT_LAGGING); // If he's really close, note that if (flFollowerDist < m_leaddistance) { SetCondition(COND_LEAD_FOLLOWER_VERY_CLOSE); } } // To be considered not lagging, the follower must be visible, and within the lead distance if (GetOuter()->FVisible(pFollower) && GetOuter()->GetSenses()->ShouldSeeEntity(pFollower)) { SetCondition(COND_LEAD_HAVE_FOLLOWER_LOS); m_LostLOSTimer.Stop(); } else { ClearCondition(COND_LEAD_HAVE_FOLLOWER_LOS); // We don't have a LOS. But if we did have LOS, don't clear it until the timer is up. if (m_LostLOSTimer.IsRunning()) { if (m_LostLOSTimer.Expired()) { SetCondition(COND_LEAD_FOLLOWER_LAGGING); ClearCondition(COND_LEAD_FOLLOWER_NOT_LAGGING); } } else { m_LostLOSTimer.Start(); } } // Now we want to see if the follower is lost. Being lost means being (far away || out of LOS ) // && some time has passed. Also, lagging players are considered lost if the NPC's never delivered // the start speech, because it means the NPC should run to the player to start the lead. if (HasCondition(COND_LEAD_FOLLOWER_LAGGING)) { if (!m_hasspokenstart) { SetCondition(COND_LEAD_FOLLOWER_LOST); } else { if (m_args.bStopScenesWhenPlayerLost) { // Try and stop me speaking my monolog, if I am if (!m_hasPausedScenes && IsRunningScriptedScene(GetOuter())) { //Msg("Stopping scenes.\n"); PauseActorsScriptedScenes(GetOuter(), false); m_hasPausedScenes = true; } } if (m_LostTimer.IsRunning()) { if (m_LostTimer.Expired()) { SetCondition(COND_LEAD_FOLLOWER_LOST); } } else { m_LostTimer.Start(); } } } else { // If I was speaking a monolog, resume it if (m_args.bStopScenesWhenPlayerLost && m_hasPausedScenes) { if (IsRunningScriptedScene(GetOuter())) { //Msg("Resuming scenes.\n"); ResumeActorsScriptedScenes(GetOuter(), false); } m_hasPausedScenes = false; } m_LostTimer.Stop(); ClearCondition(COND_LEAD_FOLLOWER_LOST); } // Evaluate for success // Success right now means being stationary, close to the goal, and having the player close by if (!(m_args.flags & AILF_NO_DEF_SUCCESS)) { ClearCondition(COND_LEAD_SUCCESS); // Check Z first, and only check 2d if we're within that bool bWithinZ = fabs(GetLocalOrigin().z - m_goal.z) < 64; if (bWithinZ && (GetLocalOrigin() - m_goal).Length2D() <= 64) { if (HasCondition(COND_LEAD_FOLLOWER_VERY_CLOSE)) { SetCondition(COND_LEAD_SUCCESS); } else if (m_successdistance) { float flDistSqr = (pFollower->GetAbsOrigin() - GetLocalOrigin()).Length2DSqr(); if (flDistSqr < (m_successdistance*m_successdistance)) { SetCondition(COND_LEAD_SUCCESS); } } } } if (m_MoveMonitor.IsMarkSet() && m_MoveMonitor.TargetMoved(pFollower)) SetCondition(COND_LEAD_FOLLOWER_MOVED_FROM_MARK); else ClearCondition(COND_LEAD_FOLLOWER_MOVED_FROM_MARK); } } if (m_args.bLeadDuringCombat) { ClearCondition(COND_LIGHT_DAMAGE); ClearCondition(COND_HEAVY_DAMAGE); } }
// Regular explosions void CPlantedC4::Explode( trace_t *pTrace, int bitsDamageType ) { // Check to see if the round is over after the bomb went off... CSGameRules()->m_bTargetBombed = true; m_bBombTicking = false; CSGameRules()->CheckWinConditions(); // Do the Damage float flBombRadius = 500; if ( g_pMapInfo ) flBombRadius = g_pMapInfo->m_flBombRadius; // Output to the bomb target ent CBaseEntity *pTarget = NULL; variant_t emptyVariant; while ((pTarget = gEntList.FindEntityByClassname( pTarget, "func_bomb_target" )) != NULL) { //Adrian - But only to the one we want! if ( pTarget->entindex() != m_iBombSiteIndex ) continue; pTarget->AcceptInput( "BombExplode", this, this, emptyVariant, 0 ); break; } // Pull out of the wall a bit if ( pTrace->fraction != 1.0 ) { SetAbsOrigin( pTrace->endpos + (pTrace->plane.normal * 0.6) ); } { Vector pos = GetAbsOrigin() + Vector( 0,0,8 ); // add an explosion TE so it affects clientside physics CPASFilter filter( pos ); te->Explosion( filter, 0.0, &pos, g_sModelIndexFireball, 50.0, 25, TE_EXPLFLAG_NONE, flBombRadius * 3.5, 200 ); } // Fireball sprite and sound!! { Vector fireballPos = GetAbsOrigin(); CPVSFilter filter( fireballPos ); te->Sprite( filter, 0, &fireballPos, g_sModelIndexFireball, 100, 150 ); } { Vector fireballPos = GetAbsOrigin() + Vector( random->RandomFloat( -512, 512 ), random->RandomFloat( -512, 512 ), random->RandomFloat( -10, 10 ) ); CPVSFilter filter( fireballPos ); te->Sprite( filter, 0, &fireballPos, g_sModelIndexFireball, 100, 150 ); } { Vector fireballPos = GetAbsOrigin() + Vector( random->RandomFloat( -512, 512 ), random->RandomFloat( -512, 512 ), random->RandomFloat( -10, 10 ) ); CPVSFilter filter( fireballPos ); te->Sprite( filter, 0, &fireballPos, g_sModelIndexFireball, 100, 150 ); } // Sound! for everyone CBroadcastRecipientFilter filter; EmitSound( filter, entindex(), "c4.explode" ); // Decal! UTIL_DecalTrace( pTrace, "Scorch" ); // Shake! UTIL_ScreenShake( pTrace->endpos, 25.0, 150.0, 1.0, 3000, SHAKE_START ); SetOwnerEntity( NULL ); // can't traceline attack owner if this is set CSGameRules()->RadiusDamage( CTakeDamageInfo( this, GetOwnerEntity(), flBombRadius, bitsDamageType ), GetAbsOrigin(), flBombRadius * 3.5, //Matt - don't ask me, this is how CS does it. CLASS_NONE, true ); // IGNORE THE WORLD!! // send director message, that something important happed here /* MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); WRITE_BYTE ( 9 ); // command length in bytes WRITE_BYTE ( DRC_CMD_EVENT ); // bomb explode WRITE_SHORT( ENTINDEX(this->edict()) ); // index number of primary entity WRITE_SHORT( 0 ); // index number of secondary entity WRITE_LONG( 15 | DRC_FLAG_FINAL ); // eventflags (priority and flags) MESSAGE_END(); */ UTIL_Remove( this ); }
//----------------------------------------------------------------------------- // Purpose: Handles USE keypress //----------------------------------------------------------------------------- void CBasePlayer::PlayerUse ( void ) { #ifdef GAME_DLL // Was use pressed or released? if ( ! ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) ) return; if ( IsObserver() ) { // do special use operation in oberserver mode if ( m_afButtonPressed & IN_USE ) ObserverUse( true ); else if ( m_afButtonReleased & IN_USE ) ObserverUse( false ); return; } #if !defined(_XBOX) // push objects in turbo physics mode if ( (m_nButtons & IN_USE) && sv_turbophysics.GetBool() ) { Vector forward, up; EyeVectors( &forward, NULL, &up ); trace_t tr; // Search for objects in a sphere (tests for entities that are not solid, yet still useable) Vector searchCenter = EyePosition(); CUsePushFilter filter; UTIL_TraceLine( searchCenter, searchCenter + forward * 96.0f, MASK_SOLID, &filter, &tr ); // try the hit entity if there is one, or the ground entity if there isn't. CBaseEntity *entity = tr.m_pEnt; if ( entity ) { IPhysicsObject *pObj = entity->VPhysicsGetObject(); if ( pObj ) { Vector vPushAway = (entity->WorldSpaceCenter() - WorldSpaceCenter()); vPushAway.z = 0; float flDist = VectorNormalize( vPushAway ); flDist = MAX( flDist, 1 ); float flForce = sv_pushaway_force.GetFloat() / flDist; flForce = MIN( flForce, sv_pushaway_max_force.GetFloat() ); pObj->ApplyForceOffset( vPushAway * flForce, WorldSpaceCenter() ); } } } #endif if ( m_afButtonPressed & IN_USE ) { // Controlling some latched entity? if ( ClearUseEntity() ) { return; } else { if ( m_afPhysicsFlags & PFLAG_DIROVERRIDE ) { m_afPhysicsFlags &= ~PFLAG_DIROVERRIDE; m_iTrain = TRAIN_NEW|TRAIN_OFF; return; } else { // Start controlling the train! CBaseEntity *pTrain = GetGroundEntity(); if ( pTrain && !(m_nButtons & IN_JUMP) && (GetFlags() & FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(this) ) { m_afPhysicsFlags |= PFLAG_DIROVERRIDE; m_iTrain = TrainSpeed(pTrain->m_flSpeed, ((CFuncTrackTrain*)pTrain)->GetMaxSpeed()); m_iTrain |= TRAIN_NEW; EmitSound( "Player.UseTrain" ); return; } } } } CBaseEntity *pUseEntity = FindUseEntity(); // Found an object if ( pUseEntity ) { //!!!UNDONE: traceline here to prevent +USEing buttons through walls int caps = pUseEntity->ObjectCaps(); variant_t emptyVariant; if ( ( (m_nButtons & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) ) { if ( caps & FCAP_CONTINUOUS_USE ) { m_afPhysicsFlags |= PFLAG_USING; } if ( pUseEntity->ObjectCaps() & FCAP_ONOFF_USE ) { pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_ON ); } else { pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE ); } } // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away else if ( (m_afButtonReleased & IN_USE) && (pUseEntity->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use { pUseEntity->AcceptInput( "Use", this, this, emptyVariant, USE_OFF ); } } else if ( m_afButtonPressed & IN_USE ) { PlayUseDenySound(); } #endif }
void CC4::PrimaryAttack() { bool PlaceBomb = false; CCSPlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; int onGround = FBitSet( pPlayer->GetFlags(), FL_ONGROUND ); CBaseEntity *groundEntity = (onGround) ? pPlayer->GetGroundEntity() : NULL; if ( groundEntity ) { // Don't let us stand on players, breakables, or pushaway physics objects to plant if ( groundEntity->IsPlayer() || IsPushableEntity( groundEntity ) || #ifndef CLIENT_DLL IsBreakableEntity( groundEntity ) || #endif // !CLIENT_DLL IsPushAwayEntity( groundEntity ) ) { onGround = false; } } if( m_bStartedArming == false && m_bBombPlanted == false ) { if( pPlayer->m_bInBombZone && onGround ) { m_bStartedArming = true; m_fArmedTime = gpGlobals->curtime + WEAPON_C4_ARM_TIME; m_bBombPlacedAnimation = false; #if !defined( CLIENT_DLL ) // init the beep flags int i; for( i=0;i<NUM_BEEPS;i++ ) m_bPlayedArmingBeeps[i] = false; // freeze the player in place while planting pPlayer->SetMaxSpeed( 1 ); // player "arming bomb" animation pPlayer->SetAnimation( PLAYER_ATTACK1 ); pPlayer->SetNextAttack( gpGlobals->curtime ); IGameEvent * event = gameeventmanager->CreateEvent( "bomb_beginplant" ); if( event ) { event->SetInt("userid", pPlayer->GetUserID() ); event->SetInt("site", pPlayer->m_iBombSiteIndex ); event->SetInt( "priority", 8 ); gameeventmanager->FireEvent( event ); } #endif SendWeaponAnim( ACT_VM_PRIMARYATTACK ); FX_PlantBomb( pPlayer->entindex(), pPlayer->Weapon_ShootPosition() ); } else { if ( !pPlayer->m_bInBombZone ) { ClientPrint( pPlayer, HUD_PRINTCENTER, "#C4_Plant_At_Bomb_Spot"); } else { ClientPrint( pPlayer, HUD_PRINTCENTER, "#C4_Plant_Must_Be_On_Ground"); } m_flNextPrimaryAttack = gpGlobals->curtime + 1.0; return; } } else { if ( !onGround || !pPlayer->m_bInBombZone ) { if( !pPlayer->m_bInBombZone ) { ClientPrint( pPlayer, HUD_PRINTCENTER, "#C4_Arming_Cancelled" ); } else { ClientPrint( pPlayer, HUD_PRINTCENTER, "#C4_Plant_Must_Be_On_Ground" ); } m_flNextPrimaryAttack = gpGlobals->curtime + 1.5; m_bStartedArming = false; #if !defined( CLIENT_DLL ) // release the player from being frozen, we've somehow left the bomb zone pPlayer->ResetMaxSpeed(); pPlayer->SetProgressBarTime( 0 ); //pPlayer->SetAnimation( PLAYER_HOLDBOMB ); IGameEvent * event = gameeventmanager->CreateEvent( "bomb_abortplant" ); if( event ) { event->SetInt("userid", pPlayer->GetUserID() ); event->SetInt("site", pPlayer->m_iBombSiteIndex ); event->SetInt( "priority", 8 ); gameeventmanager->FireEvent( event ); } #endif if(m_bBombPlacedAnimation == true) //this means the placement animation is canceled { SendWeaponAnim( ACT_VM_DRAW ); } else { SendWeaponAnim( ACT_VM_IDLE ); } return; } else { #ifndef CLIENT_DLL PlayArmingBeeps(); #endif if( gpGlobals->curtime >= m_fArmedTime ) //the c4 is ready to be armed { //check to make sure the player is still in the bomb target area PlaceBomb = true; } else if( ( gpGlobals->curtime >= (m_fArmedTime - 0.75) ) && ( !m_bBombPlacedAnimation ) ) { //call the c4 Placement animation m_bBombPlacedAnimation = true; SendWeaponAnim( ACT_VM_SECONDARYATTACK ); #if !defined( CLIENT_DLL ) // player "place" animation //pPlayer->SetAnimation( PLAYER_HOLDBOMB ); #endif } } } if ( PlaceBomb && m_bStartedArming ) { m_bStartedArming = false; m_fArmedTime = 0; if( pPlayer->m_bInBombZone ) { #if !defined( CLIENT_DLL ) CPlantedC4 *pC4 = CPlantedC4::ShootSatchelCharge( pPlayer, pPlayer->GetAbsOrigin(), pPlayer->GetAbsAngles() ); if ( pC4 ) { pC4->SetBombSiteIndex( pPlayer->m_iBombSiteIndex ); trace_t tr; UTIL_TraceEntity( pC4, GetAbsOrigin(), GetAbsOrigin() + Vector(0,0,-200), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); pC4->SetAbsOrigin( tr.endpos ); CBombTarget *pBombTarget = (CBombTarget*)UTIL_EntityByIndex( pPlayer->m_iBombSiteIndex ); if ( pBombTarget ) { CBaseEntity *pAttachPoint = gEntList.FindEntityByName( NULL, pBombTarget->GetBombMountTarget() ); if ( pAttachPoint ) { pC4->SetAbsOrigin( pAttachPoint->GetAbsOrigin() ); pC4->SetAbsAngles( pAttachPoint->GetAbsAngles() ); pC4->SetParent( pAttachPoint ); } variant_t emptyVariant; pBombTarget->AcceptInput( "BombPlanted", pC4, pC4, emptyVariant, 0 ); } } IGameEvent * event = gameeventmanager->CreateEvent( "bomb_planted" ); if( event ) { event->SetInt("userid", pPlayer->GetUserID() ); event->SetInt("site", pPlayer->m_iBombSiteIndex ); event->SetInt("posx", pPlayer->GetAbsOrigin().x ); event->SetInt("posy", pPlayer->GetAbsOrigin().y ); event->SetInt( "priority", 8 ); gameeventmanager->FireEvent( event ); } // Fire a beep event also so the bots have a chance to hear the bomb event = gameeventmanager->CreateEvent( "bomb_beep" ); if ( event ) { event->SetInt( "entindex", entindex() ); gameeventmanager->FireEvent( event ); } pPlayer->SetProgressBarTime( 0 ); CSGameRules()->m_bBombDropped = false; CSGameRules()->m_bBombPlanted = true; // Play the plant sound. Vector plantPosition = pPlayer->GetAbsOrigin() + Vector( 0, 0, 5 ); CPASAttenuationFilter filter( plantPosition ); EmitSound( filter, entindex(), "c4.plant" ); // release the player from being frozen pPlayer->ResetMaxSpeed(); // No more c4! pPlayer->Weapon_Drop( this, NULL, NULL ); UTIL_Remove( this ); #endif //don't allow the planting to start over again next frame. m_bBombPlanted = true; return; } else { ClientPrint( pPlayer, HUD_PRINTCENTER, "#C4_Activated_At_Bomb_Spot" ); #if !defined( CLIENT_DLL ) //pPlayer->SetAnimation( PLAYER_HOLDBOMB ); // release the player from being frozen pPlayer->ResetMaxSpeed(); IGameEvent * event = gameeventmanager->CreateEvent( "bomb_abortplant" ); if( event ) { event->SetInt("userid", pPlayer->GetUserID() ); event->SetInt("site", pPlayer->m_iBombSiteIndex ); event->SetInt( "priority", 8 ); gameeventmanager->FireEvent( event ); } #endif m_flNextPrimaryAttack = gpGlobals->curtime + 1.0; return; } } m_flNextPrimaryAttack = gpGlobals->curtime + 0.3; SetWeaponIdleTime( gpGlobals->curtime + SharedRandomFloat("C4IdleTime", 10, 15 ) ); }
CBaseEntity *CBasePlayer::FindUseEntity() { Vector forward, up; EyeVectors( &forward, NULL, &up ); trace_t tr; // Search for objects in a sphere (tests for entities that are not solid, yet still useable) Vector searchCenter = EyePosition(); // NOTE: Some debris objects are useable too, so hit those as well // A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too. int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP; #ifdef CSTRIKE_DLL useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS; #endif #ifdef HL1_DLL useableContents = MASK_SOLID; #endif #ifndef CLIENT_DLL CBaseEntity *pFoundByTrace = NULL; #endif // UNDONE: Might be faster to just fold this range into the sphere query CBaseEntity *pObject = NULL; float nearestDist = FLT_MAX; // try the hit entity if there is one, or the ground entity if there isn't. CBaseEntity *pNearest = NULL; const int NUM_TANGENTS = 8; // trace a box at successive angles down // forward, 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15 const float tangents[NUM_TANGENTS] = { 0, 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f }; for ( int i = 0; i < NUM_TANGENTS; i++ ) { if ( i == 0 ) { UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr ); } else { Vector down = forward - tangents[i]*up; VectorNormalize(down); UTIL_TraceHull( searchCenter, searchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr ); } pObject = tr.m_pEnt; #ifndef CLIENT_DLL pFoundByTrace = pObject; #endif bool bUsable = IsUseableEntity(pObject, 0); while ( pObject && !bUsable && pObject->GetMoveParent() ) { pObject = pObject->GetMoveParent(); bUsable = IsUseableEntity(pObject, 0); } if ( bUsable ) { Vector delta = tr.endpos - tr.startpos; float centerZ = CollisionProp()->WorldSpaceCenter().z; delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z ); float dist = delta.Length(); if ( dist < PLAYER_USE_RADIUS ) { #ifndef CLIENT_DLL if ( sv_debug_player_use.GetBool() ) { NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 ); NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 ); } if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) ) { // If about to select an NPC, do a more thorough check to ensure // that we're selecting the right one from a group. pObject = DoubleCheckUseNPC( pObject, searchCenter, forward ); } #endif if ( sv_debug_player_use.GetBool() ) { Msg( "Trace using: %s\n", pObject ? pObject->GetDebugName() : "no usable entity found" ); } pNearest = pObject; // if this is directly under the cursor just return it now if ( i == 0 ) return pObject; } } } // check ground entity first // if you've got a useable ground entity, then shrink the cone of this search to 45 degrees // otherwise, search out in a 90 degree cone (hemisphere) if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) ) { pNearest = GetGroundEntity(); } if ( pNearest ) { // estimate nearest object by distance from the view vector Vector point; pNearest->CollisionProp()->CalcNearestPoint( searchCenter, &point ); nearestDist = CalcDistanceToLine( point, searchCenter, forward ); if ( sv_debug_player_use.GetBool() ) { Msg("Trace found %s, dist %.2f\n", pNearest->GetClassname(), nearestDist ); } } for ( CEntitySphereQuery sphere( searchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if ( !pObject ) continue; if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) ) continue; // see if it's more roughly in front of the player than previous guess Vector point; pObject->CollisionProp()->CalcNearestPoint( searchCenter, &point ); Vector dir = point - searchCenter; VectorNormalize(dir); float dot = DotProduct( dir, forward ); // Need to be looking at the object more or less if ( dot < 0.8 ) continue; float dist = CalcDistanceToLine( point, searchCenter, forward ); if ( sv_debug_player_use.GetBool() ) { Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist ); } if ( dist < nearestDist ) { // Since this has purely been a radius search to this point, we now // make sure the object isn't behind glass or a grate. trace_t trCheckOccluded; UTIL_TraceLine( searchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded ); if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject ) { pNearest = pObject; nearestDist = dist; } } } #ifndef CLIENT_DLL if ( !pNearest ) { // Haven't found anything near the player to use, nor any NPC's at distance. // Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume. trace_t trAllies; UTIL_TraceLine( searchCenter, searchCenter + forward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies ); if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) ) { // This is an NPC, take it! pNearest = trAllies.m_pEnt; } } if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) ) { pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward ); } if ( sv_debug_player_use.GetBool() ) { if ( !pNearest ) { NDebugOverlay::Line( searchCenter, tr.endpos, 255, 0, 0, true, 30 ); NDebugOverlay::Cross3D( tr.endpos, 16, 255, 0, 0, true, 30 ); } else if ( pNearest == pFoundByTrace ) { NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 ); NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 ); } else { NDebugOverlay::Box( pNearest->WorldSpaceCenter(), Vector(-8, -8, -8), Vector(8, 8, 8), 0, 255, 0, true, 30 ); } } #endif if ( sv_debug_player_use.GetBool() ) { Msg( "Radial using: %s\n", pNearest ? pNearest->GetDebugName() : "no usable entity found" ); } return pNearest; }
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 CNihilanthHVR :: ZapThink( void ) { pev->nextthink = gpGlobals->time + 0.05; // check world boundaries if (m_hEnemy == NULL || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) { SetTouch( NULL ); UTIL_Remove( this ); return; } if (pev->velocity.Length() < 2000) { pev->velocity = pev->velocity * 1.2; } // MovetoTarget( m_hEnemy->Center( ) ); if ((m_hEnemy->Center() - pev->origin).Length() < 256) { TraceResult tr; UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, edict(), &tr ); CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); if (pEntity != NULL && pEntity->pev->takedamage) { ClearMultiDamage( ); pEntity->TraceAttack( pev, gSkillData.nihilanthZap, pev->velocity, &tr, DMG_SHOCK ); ApplyMultiDamage( pev, pev ); } MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_BEAMENTPOINT ); WRITE_SHORT( entindex() ); WRITE_COORD( tr.vecEndPos.x ); WRITE_COORD( tr.vecEndPos.y ); WRITE_COORD( tr.vecEndPos.z ); WRITE_SHORT( g_sModelIndexLaser ); WRITE_BYTE( 0 ); // frame start WRITE_BYTE( 10 ); // framerate WRITE_BYTE( 3 ); // life WRITE_BYTE( 20 ); // width WRITE_BYTE( 20 ); // noise WRITE_BYTE( 64 ); // r, g, b WRITE_BYTE( 196 ); // r, g, b WRITE_BYTE( 255); // r, g, b WRITE_BYTE( 255 ); // brightness WRITE_BYTE( 10 ); // speed MESSAGE_END(); UTIL_EmitAmbientSound( edict(), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); SetTouch( NULL ); UTIL_Remove( this ); pev->nextthink = gpGlobals->time + 0.2; return; } pev->frame = (int)(pev->frame + 1) % 11; MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_ELIGHT ); WRITE_SHORT( entindex( ) ); // entity, attachment WRITE_COORD( pev->origin.x ); // origin WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); WRITE_COORD( 128 ); // radius WRITE_BYTE( 128 ); // R WRITE_BYTE( 128 ); // G WRITE_BYTE( 255 ); // B WRITE_BYTE( 10 ); // life * 10 WRITE_COORD( 128 ); // decay MESSAGE_END(); // Crawl( ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CFastZombie::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_FASTZOMBIE_VERIFY_ATTACK: // Simply ensure that the zombie still has a valid melee attack if( HasCondition( COND_CAN_MELEE_ATTACK1 ) ) { TaskComplete(); } else { TaskFail(""); } break; case TASK_FASTZOMBIE_JUMP_BACK: { SetActivity( ACT_IDLE ); RemoveFlag( FL_ONGROUND ); BeginAttackJump(); Vector forward; AngleVectors( GetLocalAngles(), &forward ); // // Take him off ground so engine doesn't instantly reset FL_ONGROUND. // UTIL_SetOrigin( this, GetLocalOrigin() + Vector( 0 , 0 , 1 )); ApplyAbsVelocityImpulse( forward * -200 + Vector( 0, 0, 200 ) ); } break; case TASK_FASTZOMBIE_UNSTICK_JUMP: { RemoveFlag( FL_ONGROUND ); // Call begin attack jump. A little bit later if we fail to pathfind, we check // this value to see if we just jumped. If so, we assume we've jumped // to someplace that's not pathing friendly, and so must jump again to get out. BeginAttackJump(); // // Take him off ground so engine doesn't instantly reset FL_ONGROUND. // UTIL_SetOrigin( this, GetLocalOrigin() + Vector( 0 , 0 , 1 )); CBaseEntity *pEnemy = GetEnemy(); Vector vecJumpDir; if ( GetActivity() == ACT_CLIMB_UP || GetActivity() == ACT_CLIMB_DOWN ) { // Jump off the pipe backwards! Vector forward; GetVectors( &forward, NULL, NULL ); ApplyAbsVelocityImpulse( forward * -200 ); } else if( pEnemy ) { vecJumpDir = pEnemy->GetLocalOrigin() - GetLocalOrigin(); VectorNormalize( vecJumpDir ); vecJumpDir.z = 0; ApplyAbsVelocityImpulse( vecJumpDir * 300 + Vector( 0, 0, 200 ) ); } else { Msg("UNHANDLED CASE! Stuck Fast Zombie with no enemy!\n"); } } break; case TASK_WAIT_FOR_MOVEMENT: // If we're waiting for movement, that means that pathfinding succeeded, and // we're about to be moving. So we aren't stuck. So clear this flag. m_fJustJumped = false; BaseClass::StartTask( pTask ); break; case TASK_FACE_ENEMY: { // We don't use the base class implementation of this, because GetTurnActivity // stomps our landing scrabble animations (sjb) Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTarget( flEnemyLKP ); } break; case TASK_FASTZOMBIE_LAND_RECOVER: { // Set the ideal yaw Vector flEnemyLKP = GetEnemyLKP(); GetMotor()->SetIdealYawToTarget( flEnemyLKP ); // figure out which way to turn. float flDeltaYaw = GetMotor()->DeltaIdealYaw(); if( flDeltaYaw < 0 ) { SetIdealActivity( (Activity)ACT_FASTZOMBIE_LAND_RIGHT ); } else { SetIdealActivity( (Activity)ACT_FASTZOMBIE_LAND_LEFT ); } TaskComplete(); } break; case TASK_RANGE_ATTACK1: // Make melee attacks impossible until we land! m_flNextMeleeAttack = gpGlobals->curtime + 60; SetTouch( LeapAttackTouch ); break; case TASK_FASTZOMBIE_DO_ATTACK: SetActivity( (Activity)ACT_FASTZOMBIE_LEAP_SOAR ); break; default: BaseClass::StartTask( pTask ); break; } }