//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_BaseObject::Simulate( void ) { if ( IsPlacing() && !MustBeBuiltOnAttachmentPoint() ) { int iValidPlacement = ( IsPlacementPosValid() && ServerValidPlacement() ) ? 1 : 0; if ( m_iLastPlacementPosValid != iValidPlacement ) { m_iLastPlacementPosValid = iValidPlacement; OnPlacementStateChanged( m_iLastPlacementPosValid > 0 ); } // We figure out our own placement pos, but we still leave it to the server to // do collision with other entities and nobuild triggers, so that sets the // placement animation SetLocalOrigin( m_vecBuildOrigin ); InvalidateBoneCache(); // Clear out our origin and rotation interpolation history // so we don't pop when we teleport in the actual position from the server CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator(); interpolator.ClearHistory(); CInterpolatedVar<QAngle> &rotInterpolator = GetRotationInterpolator(); rotInterpolator.ClearHistory(); } BaseClass::Simulate(); }
//----------------------------------------------------------------------------- // Purpose: Add entity to visibile entities list //----------------------------------------------------------------------------- void C_BaseObject::AddEntity( void ) { // If set to invisible, skip. Do this before resetting the entity pointer so it has // valid data to decide whether it's visible. if ( !ShouldDraw() ) { return; } // Update the entity position //UpdatePosition(); // Yaw preview if (m_YawPreviewState != YAW_PREVIEW_OFF) { // This piece of code makes it so we keep using the preview // until we get a network update which matches the update value if (m_YawPreviewState == YAW_PREVIEW_WAITING_FOR_UPDATE) { if (fmod( fabs(GetLocalAngles().y - m_fYawPreview), 360.0f) < 1.0f) { m_YawPreviewState = YAW_PREVIEW_OFF; } } if (GetLocalOrigin().y != m_fYawPreview) { SetLocalAnglesDim( Y_INDEX, m_fYawPreview ); InvalidateBoneCache(); } } // Create flashlight effects, etc. CreateLightEffects(); }
//----------------------------------------------------------------------------- // Purpose: Causes the turret to face its desired angles //----------------------------------------------------------------------------- bool CNPC_CeilingTurret::UpdateFacing( void ) { bool bMoved = false; matrix3x4_t localToWorld; GetAttachment( LookupAttachment( "eyes" ), localToWorld ); Vector vecGoalDir; AngleVectors( m_vecGoalAngles, &vecGoalDir ); Vector vecGoalLocalDir; VectorIRotate( vecGoalDir, localToWorld, vecGoalLocalDir ); if ( g_debug_turret_ceiling.GetBool() ) { Vector vecMuzzle, vecMuzzleDir; QAngle vecMuzzleAng; GetAttachment( "eyes", vecMuzzle, vecMuzzleAng ); AngleVectors( vecMuzzleAng, &vecMuzzleDir ); NDebugOverlay::Cross3D( vecMuzzle, -Vector(2,2,2), Vector(2,2,2), 255, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMuzzle+(vecMuzzleDir*256), -Vector(2,2,2), Vector(2,2,2), 255, 255, 0, false, 0.05 ); NDebugOverlay::Line( vecMuzzle, vecMuzzle+(vecMuzzleDir*256), 255, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMuzzle, -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMuzzle+(vecGoalDir*256), -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 0.05 ); NDebugOverlay::Line( vecMuzzle, vecMuzzle+(vecGoalDir*256), 255, 0, 0, false, 0.05 ); } QAngle vecGoalLocalAngles; VectorAngles( vecGoalLocalDir, vecGoalLocalAngles ); // Update pitch float flDiff = AngleNormalize( UTIL_ApproachAngle( vecGoalLocalAngles.x, 0.0, 0.1f * MaxYawSpeed() ) ); SetPoseParameter( m_poseAim_Pitch, GetPoseParameter( m_poseAim_Pitch ) + ( flDiff / 1.5f ) ); if ( fabs( flDiff ) > 0.1f ) { bMoved = true; } // Update yaw flDiff = AngleNormalize( UTIL_ApproachAngle( vecGoalLocalAngles.y, 0.0, 0.1f * MaxYawSpeed() ) ); SetPoseParameter( m_poseAim_Yaw, GetPoseParameter( m_poseAim_Yaw ) + ( flDiff / 1.5f ) ); if ( fabs( flDiff ) > 0.1f ) { bMoved = true; } InvalidateBoneCache(); return bMoved; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int C_ObjectSentrygun::DrawModel( int flags ) { float flRealOriginZ = GetLocalOrigin().z; // If we're turtling, slide the model into the ground if ( m_bTurtled ) { // How far down are we? float flTime = min( gpGlobals->curtime - m_flStartedTurtlingAt, SENTRY_TURTLE_TIME ); float flPercent = 1 - (SENTRY_TURTLE_TIME - flTime) / SENTRY_TURTLE_TIME; Vector vNewOrigin = GetLocalOrigin(); vNewOrigin.z -= (EntitySpaceSize().z * flPercent); SetLocalOrigin( vNewOrigin ); InvalidateBoneCache(); } else if ( !m_bTurtled ) { if ( m_flStartedUnTurtlingAt ) { float flTime = min( gpGlobals->curtime - m_flStartedUnTurtlingAt, SENTRY_TURTLE_TIME ); float flPercent = (SENTRY_TURTLE_TIME - flTime) / SENTRY_TURTLE_TIME; Vector vNewOrigin = GetLocalOrigin(); vNewOrigin.z -= (EntitySpaceSize().z * flPercent); SetLocalOrigin( vNewOrigin ); InvalidateBoneCache(); // Fully unturtled? if ( flTime >= SENTRY_TURTLE_TIME ) { m_flStartedUnTurtlingAt = 0; } } } int drawn = BaseClass::DrawModel( flags ); SetLocalOriginDim( Z_INDEX, flRealOriginZ ); return drawn; }
//----------------------------------------------------------------------------- // Purpose: Update the designator position //----------------------------------------------------------------------------- void CObjectBaseMannedGun::UpdateDesignator( void ) { // Make the beam, if we don't have one yet if ( !m_hBeam && GetDriverPlayer() ) { m_hBeam = BEAM_CREATE_PREDICTABLE_PERSIST( "sprites/laserbeam.vmt", 5, GetDriverPlayer() ); if ( m_hBeam.Get() ) { m_hBeam->PointEntInit( vec3_origin, this ); m_hBeam->SetEndAttachment( m_nBarrelAttachment ); m_hBeam->SetColor( 255, 32, 32 ); m_hBeam->SetBrightness( 255 ); m_hBeam->SetNoise( 0 ); m_hBeam->SetWidth( 0.5 ); m_hBeam->SetEndWidth( 0.5 ); } } // We have to flush the bone cache because it's possible that only the bone controllers // have changed since the bonecache was generated, and bone controllers aren't checked. InvalidateBoneCache(); QAngle vecAng; Vector vecSrc, vecAim; GetAttachment( m_nBarrelAttachment, vecSrc, vecAng ); AngleVectors( vecAng, &vecAim, 0, 0 ); // "Fire" the designator beam Vector vecEnd = vecSrc + vecAim * obj_manned_gun_designator_range.GetFloat(); trace_t tr; TFGameRules()->WeaponTraceLine(vecSrc, vecEnd, MASK_SHOT, this, DMG_PROBE, &tr); if ( m_hLaserDesignation.Get() ) { // Only update our designated target point if we hit something if ( tr.fraction != 1.0 ) { m_hLaserDesignation->SetActive( true ); m_hLaserDesignation->SetAbsOrigin( tr.endpos ); } else { m_hLaserDesignation->SetActive( false ); } } // Update beam visual if ( m_hBeam.Get() ) { m_hBeam->SetStartPos( tr.endpos ); m_hBeam->RelinkBeam(); } }
//----------------------------------------------------------------------------- // Purpose: // Output : void SyncPoseToAimAngles //----------------------------------------------------------------------------- void CNPC_RocketTurret::SyncPoseToAimAngles ( void ) { QAngle localAngles = TransformAnglesToLocalSpace( m_vecCurrentAngles.Get(), EntityToWorldTransform() ); // Update pitch SetPoseParameter( m_iPosePitch, localAngles.x ); // Update yaw -- NOTE: This yaw movement is screwy for this model, we must invert the yaw delta and also skew an extra 90 deg to // get the 'forward face' of the turret to match up with the look direction. If the model and it's pose parameters change, this will be wrong. SetPoseParameter( m_iPoseYaw, AngleNormalize( -localAngles.y - 90 ) ); InvalidateBoneCache(); }
//----------------------------------------------------------------------------- // Purpose: Causes the camera to face its desired angles //----------------------------------------------------------------------------- bool CNPC_CombineCamera::UpdateFacing() { bool bMoved = false; matrix3x4_t localToWorld; GetAttachment(LookupAttachment("eyes"), localToWorld); Vector vecGoalDir; AngleVectors(m_vecGoalAngles, &vecGoalDir ); Vector vecGoalLocalDir; VectorIRotate(vecGoalDir, localToWorld, vecGoalLocalDir); QAngle vecGoalLocalAngles; VectorAngles(vecGoalLocalDir, vecGoalLocalAngles); // Update pitch float flDiff = AngleNormalize(UTIL_ApproachAngle( vecGoalLocalAngles.x, 0.0, 0.1f * MaxYawSpeed())); int iPose = LookupPoseParameter(COMBINE_CAMERA_BC_PITCH); SetPoseParameter(iPose, GetPoseParameter(iPose) + (flDiff / 1.5f)); if (fabs(flDiff) > 0.1f) { bMoved = true; } // Update yaw flDiff = AngleNormalize(UTIL_ApproachAngle( vecGoalLocalAngles.y, 0.0, 0.1f * MaxYawSpeed())); iPose = LookupPoseParameter(COMBINE_CAMERA_BC_YAW); SetPoseParameter(iPose, GetPoseParameter(iPose) + (flDiff / 1.5f)); if (fabs(flDiff) > 0.1f) { bMoved = true; } if (bMoved && (m_flMoveSoundTime < gpGlobals->curtime)) { EmitSound("NPC_CombineCamera.Move"); m_flMoveSoundTime = gpGlobals->curtime + CAMERA_MOVE_INTERVAL; } // You're going to make decisions based on this info. So bump the bone cache after you calculate everything InvalidateBoneCache(); return bMoved; }
void CNPC_Dog::PickupOrCatchObject( const char *pAttachmentName ) { if ( m_hPhysicsEnt ) { InvalidateBoneCache(); int iAttachment = LookupAttachment( pAttachmentName ); if ( iAttachment == 0 ) iAttachment = m_iPhysGunAttachment; // Move physobject to shadow IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject(); if ( pPhysicsObject ) { pPhysicsObject->SetShadow( 1e4, 1e4, false, false ); pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 ); } m_iContainerMoveType = m_hPhysicsEnt->GetMoveType(); m_hPhysicsEnt->SetMoveType( MOVETYPE_NONE ); m_hPhysicsEnt->SetParent( this, iAttachment ); m_hPhysicsEnt->SetLocalOrigin( vec3_origin ); m_hPhysicsEnt->SetLocalAngles( vec3_angle ); m_hPhysicsEnt->SetGroundEntity( NULL ); if ( m_hPhysicsEnt->GetOwnerEntity() == NULL ) m_hPhysicsEnt->SetOwnerEntity( this ); if ( pPhysicsObject ) pPhysicsObject->RecheckCollisionFilter(); m_bHasObject = true; //Fire Output! m_OnPickup.FireOutput( this, this ); } }
int C_FirstpersonBody::DrawModel( int flags ) { const int viewId = CurrentViewID(); if ( viewId == VIEW_SHADOW_DEPTH_TEXTURE && !C_GstringPlayer::ShouldFirstpersonModelCastShadow() || viewId == VIEW_MONITOR ) { return 0; } if ( viewId == VIEW_REFLECTION ) { const Vector &vecViewOrigin( CurrentViewOrigin() ); VisibleFogVolumeInfo_t fogVolumeInfo; render->GetVisibleFogVolume( vecViewOrigin, &fogVolumeInfo ); if ( fogVolumeInfo.m_nVisibleFogVolume >= 0 ) { if ( fogVolumeInfo.m_flWaterHeight - vecViewOrigin.z > -25.0f ) { return 0; } } } if ( IsInThirdPersonView() ) { m_bBonescalingEnabled = false; } { CBaseAnimating::AutoAllowBoneAccess boneAccess( true, false ); InvalidateBoneCache(); SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); } int ret = BaseClass::DrawModel( flags ); m_bBonescalingEnabled = true; return ret; }
void C_ClientPartialRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ) { BaseClass::ImpactTrace( pTrace, iDamageType, pCustomImpactName ); // client entities have the network index -1 so lots of effects don't work easily if ( BloodColor() != DONT_BLEED ) { const char *pszDecalName = NULL; switch ( BloodColor() ) { case BLOOD_COLOR_RED: pszDecalName = "Blood"; break; } int index = decalsystem->GetDecalIndexForName( pszDecalName ); Vector vecDir = pTrace->endpos - pTrace->startpos; if ( vecDir.LengthSqr() > FLT_EPSILON ) { vecDir.NormalizeInPlace(); } if ( index >= 0 ) { SetShrinkingEnabled( false ); InvalidateBoneCache(); SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); // add decal to model AddDecal( pTrace->startpos, pTrace->endpos, pTrace->endpos, pTrace->hitbox, index, false, *pTrace ); SetShrinkingEnabled( true ); InvalidateBoneCache(); } // add decal to world trace_t tr; UTIL_TraceLine( pTrace->endpos, pTrace->endpos + vecDir * 35.0f, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); UTIL_BloodDecalTrace( &tr, BloodColor() ); if ( ShouldCreateBloodParticles() ) { UTIL_BloodImpact( pTrace->endpos, -vecDir, BloodColor(), 5 ); } } if ( m_bReleaseRagdoll || m_bFadingOut ) return; const float flGibbingChance = ( ( iDamageType & DMG_BLAST ) != 0 ) ? gstring_gibbing_explosion_chance.GetFloat() : gstring_gibbing_chance.GetFloat(); const bool bSniperImpact = ( iDamageType & DMG_SNIPER ) != 0; if ( !bSniperImpact && RandomFloat() > flGibbingChance / 100.0f ) return; CStudioHdr *pHdr = GetModelPtr(); if ( pHdr == NULL ) return; int iStudioBone = ConvertPhysBoneToStudioBone( this, pTrace->physicsbone ); const bool bExplosionImpact = ( iDamageType & DMG_BLAST ) != 0; // if the hit bone is a valid studio bone and we know that this bone // is drawn as a normal bone (not shrunken) if ( iStudioBone >= 0 && m_normalBones.IsBitSet( iStudioBone ) || bExplosionImpact ) { CUtlVector< ragdollparams_partial_t > gibModels; // we've been analysed already so use the known hit group // and try recusive splitting GibbingParamsRecursive_t params; params.pHdr = pHdr; params.pszHitBone = ( iStudioBone >= 0 && !bExplosionImpact ) ? pHdr->pBone( iStudioBone )->pszName() : NULL; params.pszParentName = STRING( m_strRecursiveParent ); params.pszRootBone = ( m_iBranchRootBone >= 0 && m_iBranchRootBone < pHdr->numbones() ) ? pHdr->pBone( m_iBranchRootBone )->pszName() : NULL; params.pJointBones = &m_jointBones; const char *pszParentSplitBone; // find a suitable joint to cut if ( C_GibConfig::GetInstance()->GetGibsForGroup( params, gibModels, &pszParentSplitBone ) || bExplosionImpact && C_GibConfig::GetInstance()->GetRandomGibsForGroup( params, gibModels, &pszParentSplitBone ) ) { int iSplitboneIndex = Studio_BoneIndexByName( pHdr, pszParentSplitBone ); // don't do cutting if we cut this joint in the past // or if this joint is our current branch root if ( iSplitboneIndex < 0 || m_jointBones.IsBitSet( iSplitboneIndex ) || m_iBranchRootBone == iSplitboneIndex ) return; matrix3x4_t boneDelta0[MAXSTUDIOBONES]; matrix3x4_t boneDelta1[MAXSTUDIOBONES]; matrix3x4_t currentBones[MAXSTUDIOBONES]; const float boneDt = 0.1f; // setup bones without shrinking to position the new gibs SetShrinkingEnabled( false ); GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); SetShrinkingEnabled( true ); InvalidateBoneCache(); // create the new gibmodels FOR_EACH_VEC( gibModels, i ) { ragdollparams_partial_t &partial = gibModels[ i ]; // add old trunk joints for ( int iBit = m_jointBones.FindNextSetBit( 0 ); iBit >= 0; iBit = m_jointBones.FindNextSetBit( iBit + 1 ) ) { if ( m_iBranchRootBone == iBit ) continue; const char *pszName = pHdr->pBone( iBit )->pszName(); partial.trunkBones.AddToTail( pszName ); } // if we create a trunk from an existing branch // we have to propagate the branch root bone if ( partial.rootBone.IsEmpty() && m_iBranchRootBone >= 0 ) { partial.rootBone = pHdr->pBone( m_iBranchRootBone )->pszName(); } C_BaseAnimating *pGib = CreateRagdollCopy( false ); C_ClientPartialRagdoll *pRecursiveRagdoll = dynamic_cast< C_ClientPartialRagdoll* >( pGib ); Assert( pRecursiveRagdoll ); // apply force and propagate cut information if ( pRecursiveRagdoll != NULL ) { pRecursiveRagdoll->SetRecursiveGibData( STRING( m_strRecursiveParent ), STRING( m_strRecursiveGoreName ), STRING( m_strRecursiveGoreMaterialName ) ); pRecursiveRagdoll->SetShrinkingEnabled( true ); Vector vecDelta = pTrace->endpos - pTrace->startpos; if ( vecDelta.LengthSqr() <= FLT_EPSILON ) { vecDelta = RandomVector( -1, 1 ); } vecDelta.NormalizeInPlace(); pRecursiveRagdoll->m_vecForce = vecDelta * RandomFloat( 15000.0f, 35000.0f ); pRecursiveRagdoll->m_nForceBone = pTrace->physicsbone; pRecursiveRagdoll->SetBloodColor( BloodColor() ); pRecursiveRagdoll->m_jointBones.Or( m_jointBones, &pRecursiveRagdoll->m_jointBones ); //FOR_EACH_VEC( m_Gore, i ) //{ // const int iBone = m_Gore[ i ].m_iBone; // if ( iBone >= 0 && iBone == m_iBranchRootBone ) // { // } // pRecursiveRagdoll->m_Gore.AddToTail( m_Gore[ i ] ); // m_Gore.Remove( i ); // i--; //} } pGib->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt, false, &partial ); if ( bExplosionImpact && RandomFloat() <= gstring_gibbing_explosion_recursive_chance.GetFloat() / 100.0f ) { pGib->ImpactTrace( pTrace, iDamageType, pCustomImpactName ); } if ( BloodColor() == BLOOD_COLOR_RED && ( !pRecursiveRagdoll || !pRecursiveRagdoll->m_bReleaseRagdoll ) && ShouldCreateBloodParticles() ) { Assert( pszParentSplitBone != NULL ); DispatchGibParticle( pGib, pszParentSplitBone, bExplosionImpact, BloodColor() ); } }
//----------------------------------------------------------------------------- // Purpose: Aim Gun at a target //----------------------------------------------------------------------------- void CASW_PropJeep::AimGunAt( Vector *endPos, float flInterval ) { Vector aimPos = *endPos; // See if the gun should be allowed to aim if ( IsOverturned() || m_bEngineLocked || m_bHasGun == false ) { SetPoseParameter( JEEP_GUN_YAW, 0 ); SetPoseParameter( JEEP_GUN_PITCH, 0 ); SetPoseParameter( JEEP_GUN_SPIN, 0 ); return; // Make the gun go limp and look "down" Vector v_forward, v_up; AngleVectors( GetLocalAngles(), NULL, &v_forward, &v_up ); aimPos = WorldSpaceCenter() + ( v_forward * -32.0f ) - Vector( 0, 0, 128.0f ); } matrix3x4_t gunMatrix; GetAttachment( LookupAttachment("gun_ref"), gunMatrix ); // transform the enemy into gun space Vector localEnemyPosition; VectorITransform( aimPos, gunMatrix, localEnemyPosition ); // do a look at in gun space (essentially a delta-lookat) QAngle localEnemyAngles; VectorAngles( localEnemyPosition, localEnemyAngles ); // convert to +/- 180 degrees localEnemyAngles.x = UTIL_AngleDiff( localEnemyAngles.x, 0 ); localEnemyAngles.y = UTIL_AngleDiff( localEnemyAngles.y, 0 ); float targetYaw = m_aimYaw + localEnemyAngles.y; float targetPitch = m_aimPitch + localEnemyAngles.x; // Constrain our angles float newTargetYaw = clamp( targetYaw, -CANNON_MAX_LEFT_YAW, CANNON_MAX_RIGHT_YAW ); float newTargetPitch = clamp( targetPitch, -CANNON_MAX_DOWN_PITCH, CANNON_MAX_UP_PITCH ); // If the angles have been clamped, we're looking outside of our valid range if ( fabs(newTargetYaw-targetYaw) > 1e-4 || fabs(newTargetPitch-targetPitch) > 1e-4 ) { m_bUnableToFire = true; } targetYaw = newTargetYaw; targetPitch = newTargetPitch; // Exponentially approach the target float yawSpeed = 8; float pitchSpeed = 8; m_aimYaw = UTIL_Approach( targetYaw, m_aimYaw, yawSpeed ); m_aimPitch = UTIL_Approach( targetPitch, m_aimPitch, pitchSpeed ); SetPoseParameter( JEEP_GUN_YAW, -m_aimYaw); SetPoseParameter( JEEP_GUN_PITCH, -m_aimPitch ); InvalidateBoneCache(); // read back to avoid drift when hitting limits // as long as the velocity is less than the delta between the limit and 180, this is fine. m_aimPitch = -GetPoseParameter( JEEP_GUN_PITCH ); m_aimYaw = -GetPoseParameter( JEEP_GUN_YAW ); // Now draw crosshair for actual aiming point Vector vecMuzzle, vecMuzzleDir; QAngle vecMuzzleAng; GetAttachment( "Muzzle", vecMuzzle, vecMuzzleAng ); AngleVectors( vecMuzzleAng, &vecMuzzleDir ); trace_t tr; UTIL_TraceLine( vecMuzzle, vecMuzzle + (vecMuzzleDir * MAX_TRACE_LENGTH), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); // see if we hit something, if so, adjust endPos to hit location if ( tr.fraction < 1.0 ) { m_vecGunCrosshair = vecMuzzle + ( vecMuzzleDir * MAX_TRACE_LENGTH * tr.fraction ); } }
void CNPC_Dog::ThrowObject( const char *pAttachmentName ) { if ( m_hPhysicsEnt ) { m_bHasObject = false; IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); if ( pPhysObj ) { Vector vGunPos; QAngle angGunAngles; AngularImpulse angVelocity = RandomAngularImpulse( -250 , -250 ) / pPhysObj->GetMass(); InvalidateBoneCache(); int iAttachment = LookupAttachment( pAttachmentName ); if ( iAttachment == 0 ) iAttachment = m_iPhysGunAttachment; GetAttachment( iAttachment, vGunPos, angGunAngles ); pPhysObj->Wake(); if ( pPhysObj->GetShadowController() ) { m_hPhysicsEnt->SetParent( NULL ); m_hPhysicsEnt->SetMoveType( (MoveType_t)m_iContainerMoveType ); m_hPhysicsEnt->SetOwnerEntity( this ); pPhysObj->RemoveShadowController(); pPhysObj->SetPosition( m_hPhysicsEnt->GetLocalOrigin(), m_hPhysicsEnt->GetLocalAngles(), true ); pPhysObj->RecheckCollisionFilter(); pPhysObj->RecheckContactPoints(); } if ( m_hThrowTarget == NULL ) #ifdef SecobMod__Enable_Fixed_Multiplayer_AI m_hThrowTarget = UTIL_GetNearestVisiblePlayer(this); #else m_hThrowTarget = AI_GetSinglePlayer(); #endif //SecobMod__Enable_Fixed_Multiplayer_AI Vector vThrowDirection; if ( m_hThrowTarget ) { Vector vThrowOrigin = m_hThrowTarget->GetAbsOrigin(); if ( m_hThrowTarget->IsPlayer() ) vThrowOrigin = vThrowOrigin + Vector( random->RandomFloat( -128, 128 ), random->RandomFloat( -128, 128 ), 0 ); Vector vecToss = VecCheckToss( this, vGunPos, vThrowOrigin, m_flThrowArcModifier, 1.0f, true ); if( vecToss == vec3_origin ) { // Fix up an impossible throw so dog will at least toss the box in the target's general direction instead of dropping it. // Also toss it up in the air so it will fall down and break. (Just throw the box up at a 45 degree angle) Vector forward, up; GetVectors( &forward, NULL, &up ); vecToss = forward + up; VectorNormalize( vecToss ); vecToss *= pPhysObj->GetMass() * 30.0f; } vThrowDirection = vecToss + ( m_hThrowTarget->GetSmoothedVelocity() / 2 ); Vector vLinearDrag; Vector unitVel = vThrowDirection; VectorNormalize( unitVel ); float flTest = 1000 / vThrowDirection.Length(); float flDrag = pPhysObj->CalculateLinearDrag( vThrowDirection ); vThrowDirection = vThrowDirection + ( unitVel * ( flDrag * flDrag ) ) / flTest; pPhysObj->SetVelocity( &vThrowDirection, &angVelocity ); m_flTimeToCatch = gpGlobals->curtime + dog_max_wait_time.GetFloat(); //Don't start pulling until the object is away from me. //We base the time on the throw velocity. m_flTimeToPull = gpGlobals->curtime + ( 1000 / vThrowDirection.Length() ); } //Fire Output! m_OnThrow.FireOutput( this, this ); ClearBeams(); if ( m_bBeamEffects == true ) { EmitSound( "Weapon_PhysCannon.Launch" ); CBeam *pBeam = CBeam::BeamCreate( "sprites/orangelight1.vmt", 1.8 ); if ( pBeam != NULL ) { pBeam->PointEntInit( m_hPhysicsEnt->WorldSpaceCenter(), this ); pBeam->SetEndAttachment( m_iPhysGunAttachment ); pBeam->SetWidth( 6.4 ); pBeam->SetEndWidth( 12.8 ); pBeam->SetBrightness( 255 ); pBeam->SetColor( 255, 255, 255 ); pBeam->LiveForTime( 0.2f ); pBeam->RelinkBeam(); pBeam->SetNoise( 2 ); } Vector shotDir = ( m_hPhysicsEnt->WorldSpaceCenter() - vGunPos ); VectorNormalize( shotDir ); CPVSFilter filter( m_hPhysicsEnt->WorldSpaceCenter() ); te->GaussExplosion( filter, 0.0f, m_hPhysicsEnt->WorldSpaceCenter() - ( shotDir * 4.0f ), RandomVector(-1.0f, 1.0f), 0 ); } } } }
//----------------------------------------------------------------------------- // Purpose: Plasma sentrygun's fire //----------------------------------------------------------------------------- void CObjectMannedPlasmagun::Fire( ) { if (m_flNextAttack > gpGlobals->curtime) return; // Because the plasma sentrygun always thinks it has ammo (see below) // we might not have ammo here, in which case we should just abort. if ( !m_nAmmoCount ) return; // Make sure we think soon enough in case of firing... float flNextRecharge = gpGlobals->curtime + (HasPowerup(POWERUP_EMP) ? MANNED_PLASMAGUN_RECHARGE_TIME * 1.5 : MANNED_PLASMAGUN_RECHARGE_TIME); SetNextThink( gpGlobals->curtime + flNextRecharge ); // We have to flush the bone cache because it's possible that only the bone controllers // have changed since the bonecache was generated, and bone controllers aren't checked. InvalidateBoneCache(); QAngle vecAng; Vector vecSrc, vecAim; // Alternate barrels when firing if ( m_bFiringLeft ) { // Aliens permanently fire left barrel because they have no right if ( GetTeamNumber() == TEAM_HUMANS ) { m_bFiringLeft = false; } GetAttachment( m_nBarrelAttachment, vecSrc, vecAng ); SetActivity( ACT_VM_PRIMARYATTACK ); } else { m_bFiringLeft = true; GetAttachment( m_nRightBarrelAttachment, vecSrc, vecAng ); SetActivity( ACT_VM_SECONDARYATTACK ); } // Get the distance to the target AngleVectors( vecAng, &vecAim, 0, 0 ); int damageType = GetAmmoDef()->DamageType( m_nAmmoType ); CBasePlasmaProjectile *pPlasma = CBasePlasmaProjectile::CreatePredicted( vecSrc, vecAim, Vector( 0, 0, 0 ), damageType, GetDriverPlayer() ); if ( pPlasma ) { pPlasma->SetDamage( obj_manned_plasmagun_damage.GetFloat() ); pPlasma->m_hOwner = GetDriverPlayer(); //pPlasma->SetOwnerEntity( this ); pPlasma->SetMaxRange( m_flMaxRange ); if ( obj_manned_plasmagun_radius.GetFloat() ) { pPlasma->SetExplosive( obj_manned_plasmagun_radius.GetFloat() ); } } CSoundParameters params; if ( GetParametersForSound( "ObjectMannedPlasmagun.Fire", params, NULL ) ) { CPASAttenuationFilter filter( this, params.soundlevel ); if ( IsPredicted() ) { filter.UsePredictionRules(); } EmitSound( filter, entindex(), "ObjectMannedPlasmagun.Fire" ); } // SetSentryAnim( TFTURRET_ANIM_FIRE ); DoMuzzleFlash(); --m_nAmmoCount; m_flNextIdleTime = gpGlobals->curtime + MANNED_PLASMAGUN_IDLE_TIME; // If I'm EMPed, slow the firing rate down m_flNextAttack = gpGlobals->curtime + ( HasPowerup(POWERUP_EMP) ? 0.3f : 0.1f ); }