abstract class AIDeathReactionsTask extends AIbehaviortaskScript { editable inlined var m_fastForwardAnimation : AIArgumentMapping; protected var m_hitData : AnimFeature_HitReactionsData; private var m_hitReactionAction : ActionHitReactionScriptProxy; private var m_previousRagdollTimeStamp : Float; private var m_deathHasBeenPlayed : Bool; private var m_updateFrame : Int32; protected export override function Activate( context : ScriptExecutionContext ) { var puppet : NPCPuppet; var victimYaw : Float; var instigatorYaw : Float; var npcType : gamedataNPCType; puppet = ( ( NPCPuppet )( GetPuppet( context ) ) ); npcType = puppet.GetNPCType(); m_updateFrame = 0; puppet.GetHitReactionComponent().UpdateDeathHasBeenPlayed(); NPCPuppet.ChangeHighLevelState( ScriptExecutionContext.GetOwner( context ), gamedataNPCHighLevelState.Dead ); m_hitData = new AnimFeature_HitReactionsData; m_hitData = GetHitData( context ); m_hitData.hitType = GetDeathReactionType( context ); if( CanSkipDeathAnimation() && ( m_hitData.hitType == ( ( Int32 )( animHitReactionType.Ragdoll ) ) ) ) { if( !( StatusEffectSystem.ObjectHasStatusEffect( puppet, T"BaseStatusEffect.ForceKillFromRagdoll" ) ) ) { TurnOnRagdoll( context, 'AIDeathReactionTask - forced ragdoll' ); } } else { if( m_hitData.hitSource != 0 ) { instigatorYaw = Vector4.Heading( puppet.GetHitReactionComponent().GetHitInstigator().GetWorldForward() ); victimYaw = Vector4.Heading( puppet.GetWorldForward() ); m_hitData.hitDirectionWs = Vector4.RotByAngleXY( puppet.GetWorldForward(), victimYaw - instigatorYaw ); if( ( m_hitData.hitIntensity == 2 ) && ( ( m_hitData.hitBodyPart == 5 ) || ( m_hitData.hitBodyPart == 6 ) ) ) { ScriptExecutionContext.GetOwner( context ).SetIndividualTimeDilation( 'MeleeLegKnockdown', 1.60000002, 0.5, '', '' ); } } else { m_hitData.hitDirectionWs = puppet.GetLastHitAttackDirection(); } m_hitData.angleToAttack = AngleToAttackSource( context, m_hitData ); m_hitData.initialRotationDuration = 0.1; if( ( puppet.GetStanceStateFromBlackboard() == gamedataNPCStanceState.Cover && ( m_hitData.hitIntensity != 3 ) ) && ( m_hitData.hitIntensity != 2 ) ) { m_hitData.hitIntensity = 4; } if( !( ScriptExecutionContext.GetArgumentBool( context, 'WasDeadOnInit' ) ) ) { PlayHitReactionAction( context ); if( ( npcType == gamedataNPCType.Human || npcType == gamedataNPCType.Android ) && IsFloorSteepEnoughToRagdoll( context ) ) { GameInstance.GetDelaySystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).DelayEvent( ScriptExecutionContext.GetOwner( context ), CreateForceRagdollEvent( 'NPC died on sloped terrain' ), TDB.GetFloat( T"AIGeneralSettings.ragdollFloorAngleActivationDelay" ), true ); } } AnimationControllerComponent.ApplyFeatureToReplicate( puppet, 'hit', m_hitData ); AnimationControllerComponent.PushEventToReplicate( puppet, 'hit' ); } if( npcType == gamedataNPCType.Human && puppet.ShouldSpawnBloodPuddle() ) { SpawnBloodPuddle( puppet ); } StopMotionExtraction( context ); } protected function IsFloorSteepEnoughToRagdoll( context : ScriptExecutionContext ) : Bool { var floorAngle : Float; if( SpatialQueriesHelper.GetFloorAngle( ScriptExecutionContext.GetOwner( context ), floorAngle ) && ( floorAngle >= TDB.GetFloat( T"AIGeneralSettings.maxAllowedIncapacitatedFloorAngle" ) ) ) { return true; } return false; } protected function TurnOnRagdoll( context : ScriptExecutionContext, activationReason : CName ) { var hitPosition : Vector4; var hitImpulse : Vector4; var ragdollImpulse : Float; var hitInfluenceRadius : Float; var owner : ScriptedPuppet; var hrc : HitReactionComponent; if( m_previousRagdollTimeStamp == EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ) ) { return; } m_previousRagdollTimeStamp = EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ); owner = GetPuppet( context ); if( !( ( ( NPCPuppet )( owner ) ).IsRagdolling() ) && !( StatusEffectSystem.ObjectHasStatusEffect( owner, T"BaseStatusEffect.ForceKillFromRagdoll" ) ) ) { hrc = owner.GetHitReactionComponent(); if( hrc ) { hitPosition = hrc.GetHitPosition(); hitImpulse = hrc.GetOverridenHitDirection(); ragdollImpulse = hrc.GetRagdollImpulse(); } if( ragdollImpulse <= 0.0 ) { ragdollImpulse = 1.0; } hitInfluenceRadius = 10000.0; owner.QueueEvent( CreateForceRagdollEvent( activationReason ) ); GameInstance.GetDelaySystem( owner.GetGame() ).DelayEvent( owner, CreateRagdollApplyImpulseEvent( hitPosition, hitImpulse * ragdollImpulse, hitInfluenceRadius ), 0.1, false ); } owner.GetHitReactionComponent().UpdateDeathHasBeenPlayed(); ChangeHighLevelState( context ); } protected virtual function CanSkipDeathAnimation() : Bool { return true; } protected virtual function PlayHitReactionAction( context : ScriptExecutionContext ) : Bool { m_hitReactionAction = GetPuppet( context ).GetHitReactionComponent().GetHitReactionProxyAction(); m_hitReactionAction.Stop(); if( !( m_hitReactionAction.Setup( m_hitData, ShouldFastForward( context ) ) ) ) { m_hitReactionAction.Launch(); return false; } m_hitReactionAction.Launch(); return true; } protected virtual function StopMotionExtraction( context : ScriptExecutionContext ) { var stopMotionExtractionDelay : Float; var evt : HitReactionStopMotionExtraction; stopMotionExtractionDelay = GetPuppet( context ).GetFloatFromCharacterTweak( "deathReaction_motionDuration", -1.0 ); if( stopMotionExtractionDelay > 0.0 ) { evt = new HitReactionStopMotionExtraction; GameInstance.GetDelaySystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).DelayEvent( ScriptExecutionContext.GetOwner( context ), evt, stopMotionExtractionDelay ); } } protected export override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome { m_updateFrame += 1; if( m_updateFrame >= 2 ) { if( ( ( !( ScriptExecutionContext.GetArgumentBool( context, 'WasDeadOnInit' ) ) && !( m_deathHasBeenPlayed ) ) && !( GetPuppet( context ).GetHitReactionComponent().GetDefeatedHasBeenPlayed() ) ) && !( PlayHitReactionAction( context ) ) ) { TurnOnRagdoll( context, 'Death animation likely isnt streamed in!' ); } SetUpdateInterval( context, 999999.0 ); } return AIbehaviorUpdateOutcome.IN_PROGRESS; } protected export override function Deactivate( context : ScriptExecutionContext ) { super.Deactivate( context ); m_deathHasBeenPlayed = true; if( m_hitReactionAction ) { m_hitReactionAction.Stop(); } m_hitReactionAction = NULL; } public static function ShouldUseRagdoll( owner : ScriptedPuppet ) : Bool { if( !( owner ) ) { return false; } if( owner.GetMovePolicesComponent().IsOnOffMeshLink() && owner.GetNPCType() != gamedataNPCType.Drone ) { return true; } if( owner.ShouldSkipDeathAnimation() ) { return true; } if( GameInstance.GetWorkspotSystem( owner.GetGame() ).IsActorInWorkspot( owner ) && owner.GetNPCType() != gamedataNPCType.Drone ) { return !( owner.GetAIControllerComponent().IsCommandExecuting( 'AIPatrolCommand', true ) ); } return false; } protected virtual function GetDeathReactionType( context : ScriptExecutionContext ) : Int32 { var owner : ScriptedPuppet; owner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ); if( AIDeathReactionsTask.ShouldUseRagdoll( owner ) ) { return ( ( Int32 )( animHitReactionType.Ragdoll ) ); } if( ( owner && owner.GetNPCType() == gamedataNPCType.Human ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'BrainMeltDeathAnimation' ) ) { return 10; } if( owner && ( ( NPCPuppet )( owner ) ).ShouldSkipDeathAnimation() == true ) { return ( ( Int32 )( animHitReactionType.None ) ); } return ( ( Int32 )( animHitReactionType.Death ) ); } protected function ChangeHighLevelState( context : ScriptExecutionContext ) { NPCPuppet.ChangeHighLevelState( ScriptExecutionContext.GetOwner( context ), gamedataNPCHighLevelState.Dead ); } protected function SpawnBloodPuddle( puppet : weak< ScriptedPuppet > ) { var evt : BloodPuddleEvent; evt = new BloodPuddleEvent; if( !( puppet ) || VehicleComponent.IsMountedToVehicle( puppet.GetGame(), puppet ) ) { return; } evt = new BloodPuddleEvent; evt.m_slotName = 'Chest'; evt.cyberBlood = NPCManager.HasVisualTag( puppet, 'CyberTorso' ); GameInstance.GetDelaySystem( puppet.GetGame() ).DelayEvent( puppet, evt, 3.0 ); } protected virtual function AngleToAttackSource( context : ScriptExecutionContext, hitData : AnimFeature_HitReactionsData ) : Float { var newLocalHitDirection : Vector4; var finalAngleToAttackSource : Float; var newForwardLocalToWorldAngle : Float; var finalHitDirection : Int32; if( hitData.hitSource == 0 ) { switch( ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetHitReactionComponent().GetHitReactionData().hitDirection ) { case 4: finalAngleToAttackSource = 180.0; break; case 1: finalAngleToAttackSource = 270.0; break; case 2: finalAngleToAttackSource = 0.0; break; case 3: finalAngleToAttackSource = 90.0; break; default: break; } } else { newForwardLocalToWorldAngle = Vector4.Heading( GetPuppet( context ).GetWorldForward() ); newLocalHitDirection = Vector4.RotByAngleXY( GetPuppet( context ).GetHitReactionComponent().GetHitSource().GetWorldForward(), newForwardLocalToWorldAngle ); finalHitDirection = RoundMath( ( Vector4.Heading( newLocalHitDirection ) + 180.0 ) / 90.0 ); if( finalHitDirection == 0 ) { finalHitDirection = 4; } switch( finalHitDirection ) { case 4: finalAngleToAttackSource = 180.0; break; case 1: finalAngleToAttackSource = 270.0; break; case 2: finalAngleToAttackSource = 0.0; break; case 3: finalAngleToAttackSource = 90.0; break; default: break; } } return finalAngleToAttackSource; } protected virtual function GetHitData( context : ScriptExecutionContext ) : AnimFeature_HitReactionsData { var animFeature : AnimFeature_HitReactionsData; var owner : ScriptedPuppet; owner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ); animFeature = owner.GetHitReactionComponent().GetHitReactionData(); if( ( owner && owner.GetNPCType() == gamedataNPCType.Drone ) && !( GameInstance.GetNavigationSystem( owner.GetGame() ).IsOnGround( owner ) ) ) { animFeature.animVariation = 10; } if( ( owner && owner.GetNPCType() == gamedataNPCType.Human ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'BrainMeltDeathAnimation' ) ) { return BrainMeltDeathData( context ); } return animFeature; } protected virtual function ShouldFastForward( context : ref< ScriptExecutionContext > ) : Bool { var rawValue : Variant; if( !( m_fastForwardAnimation ) ) { return false; } rawValue = ScriptExecutionContext.GetMappingValue( context, m_fastForwardAnimation ); return ( ( Bool )rawValue ); } protected function BrainMeltDeathData( context : ScriptExecutionContext ) : AnimFeature_HitReactionsData { var animFeature : AnimFeature_HitReactionsData; var owner : ScriptedPuppet; var numberOfBaseAnims : Int32; var numberOfBlackwallAnims : Int32; var blackwallDeathAnim : Int32; var bbSystem : BlackboardSystem; var blackboard : IBlackboard; var min : Int32; var max : Int32; numberOfBaseAnims = AITweakParams.GetIntFromTweak( T"AIGeneralSettings", "numberOfBrainMeltAnimations" ); numberOfBlackwallAnims = AITweakParams.GetIntFromTweak( T"AIGeneralSettings", "numberOfBlackwallBrainMeltDeathAnimation" ); owner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ); max = numberOfBaseAnims; animFeature = new AnimFeature_HitReactionsData; animFeature.hitIntensity = 1; animFeature.hitSource = 1; animFeature.hitType = 10; animFeature.npcMovementSpeed = 1; animFeature.hitDirection = 0; animFeature.npcMovementDirection = 0; animFeature.stance = 0; if( StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'BlackwallBrainMeltDeathAnimation' ) ) { bbSystem = GameInstance.GetBlackboardSystem( owner.GetGame() ); blackboard = bbSystem.Get( GetAllBlackboardDefs().BlackwallDeathAnim ); blackwallDeathAnim = blackboard.GetInt( GetAllBlackboardDefs().BlackwallDeathAnim.deathAnimNumber ); max += numberOfBlackwallAnims; min = numberOfBaseAnims; if( ( blackwallDeathAnim < min ) || ( blackwallDeathAnim >= max ) ) { blackwallDeathAnim = numberOfBaseAnims; } animFeature.animVariation = blackwallDeathAnim; blackboard.SetInt( GetAllBlackboardDefs().BlackwallDeathAnim.deathAnimNumber, blackwallDeathAnim + 1 ); } else { min = 0; max = numberOfBaseAnims; animFeature.animVariation = RandRange( min, max ); } return animFeature; } } class DeadOnInitTask extends AIbehaviortaskScript { editable var m_preventSkippingDeathAnimation : Bool; default m_preventSkippingDeathAnimation = true; protected override function Activate( context : ScriptExecutionContext ) { var puppet : NPCPuppet; NPCPuppet.ChangeHighLevelState( ScriptExecutionContext.GetOwner( context ), gamedataNPCHighLevelState.Dead ); puppet = GetNPCPuppet( context ); if( puppet ) { if( m_preventSkippingDeathAnimation ) { puppet.SetSkipDeathAnimation( false ); } } puppet.DisableCollision(); } } class NormalDeathTask extends AIDeathReactionsTask { } class DeathIsRagdollCondition extends AIbehaviorconditionScript { protected export override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes { var owner : ScriptedPuppet; owner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ); return AIDeathReactionsTask.ShouldUseRagdoll( owner ); } } class WithoutHitDataDeathTask extends AIDeathReactionsTask { protected override function GetHitData( context : ScriptExecutionContext ) : AnimFeature_HitReactionsData { var owner : ScriptedPuppet; owner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ); if( StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'Crippled' ) ) { return BleedingDeathData( context ); } if( ( owner && owner.GetNPCType() == gamedataNPCType.Human ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'BrainMeltDeathAnimation' ) ) { return BrainMeltDeathData( context ); } return DebugDeathData( context ); } protected override function GetDeathReactionType( context : ScriptExecutionContext ) : Int32 { var owner : ScriptedPuppet; owner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ); if( ( owner && owner.GetNPCType() == gamedataNPCType.Drone ) || StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'Crippled' ) ) { return ( ( Int32 )( animHitReactionType.Death ) ); } if( ( owner && owner.GetNPCType() == gamedataNPCType.Human ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( owner, 'BrainMeltDeathAnimation' ) ) { return 10; } if( ( owner && owner.GetNPCType() == gamedataNPCType.Human ) && ScriptExecutionContext.GetArgumentBool( context, 'WasDeadOnInit' ) ) { return 0; } return ( ( Int32 )( animHitReactionType.Ragdoll ) ); } private virtual function BleedingDeathData( context : ScriptExecutionContext ) : AnimFeature_HitReactionsData { var animFeature : AnimFeature_HitReactionsData; animFeature = new AnimFeature_HitReactionsData; animFeature.hitIntensity = 1; animFeature.hitSource = 0; animFeature.hitType = 7; animFeature.npcMovementSpeed = 0; animFeature.hitDirection = 1; animFeature.npcMovementDirection = 0; animFeature.stance = 1; if( StatusEffectSystem.ObjectHasStatusEffectOfType( ScriptExecutionContext.GetOwner( context ), gamedataStatusEffectType.Wounded ) ) { if( StatusEffectSystem.ObjectHasStatusEffectWithTag( ScriptExecutionContext.GetOwner( context ), 'LeftArm' ) ) { animFeature.hitBodyPart = 2; } if( StatusEffectSystem.ObjectHasStatusEffectWithTag( ScriptExecutionContext.GetOwner( context ), 'RightArm' ) ) { animFeature.hitBodyPart = 3; } if( StatusEffectSystem.ObjectHasStatusEffectWithTag( ScriptExecutionContext.GetOwner( context ), 'LeftLeg' ) ) { animFeature.hitBodyPart = 5; } if( StatusEffectSystem.ObjectHasStatusEffectWithTag( ScriptExecutionContext.GetOwner( context ), 'RightLeg' ) ) { animFeature.hitBodyPart = 6; } } return animFeature; } private virtual function DebugDeathData( context : ScriptExecutionContext ) : AnimFeature_HitReactionsData { var animFeature : AnimFeature_HitReactionsData; var puppet : ScriptedPuppet; puppet = GetPuppet( context ); animFeature = new AnimFeature_HitReactionsData; animFeature.hitIntensity = 1; animFeature.hitSource = 0; animFeature.hitType = ( ( Int32 )( animHitReactionType.Ragdoll ) ); animFeature.hitBodyPart = 4; animFeature.npcMovementSpeed = 0; animFeature.hitDirection = 4; animFeature.npcMovementDirection = 0; animFeature.stance = 2; if( puppet.GetNPCType() == gamedataNPCType.Drone ) { animFeature.hitType = ( ( Int32 )( animHitReactionType.Death ) ); animFeature.animVariation = 10; GameInstance.GetDelaySystem( puppet.GetGame() ).DelayEvent( puppet, CreateForceRagdollEvent( 'Drone aerial death fallback event' ), TweakDBInterface.GetFloat( puppet.GetRecordID() + T".airDeathRagdollDelay", 1.0 ), true ); } if( ( puppet && puppet.GetNPCType() == gamedataNPCType.Human ) && ScriptExecutionContext.GetArgumentBool( context, 'WasDeadOnInit' ) ) { animFeature = new AnimFeature_HitReactionsData; } return animFeature; } } class SyncAnimDeathTask extends WithoutHitDataDeathTask { protected export override function Activate( context : ScriptExecutionContext ) { GetPuppet( context ).GetHitReactionComponent().UpdateDeathHasBeenPlayed(); NPCPuppet.ChangeHighLevelState( ScriptExecutionContext.GetOwner( context ), gamedataNPCHighLevelState.Dead ); } protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome { SetUpdateInterval( context, 999999.0 ); return AIbehaviorUpdateOutcome.IN_PROGRESS; } } class ForcedRagdollDeathTask extends AIDeathReactionsTask { protected override function Activate( context : ScriptExecutionContext ) { TurnOnRagdoll( context, 'The ragdoll was forced on the NPC by the behavior tree' ); } } class VehicleDeathTask extends AIDeathReactionsTask { var m_vehNPCDeathData : AnimFeature_VehicleNPCDeathData; var m_previousState : gamedataNPCHighLevelState; var m_timeToRagdoll : Float; default m_timeToRagdoll = 0.44f; var m_hasRagdolled : Bool; var m_activationTimeStamp : Float; private var m_readyToUnmount : Bool; protected override function Activate( context : ScriptExecutionContext ) { m_readyToUnmount = false; m_vehNPCDeathData = new AnimFeature_VehicleNPCDeathData; m_previousState = ( ( gamedataNPCHighLevelState )( GetPuppet( context ).GetPuppetStateBlackboard().GetInt( GetAllBlackboardDefs().PuppetState.HighLevel ) ) ); if( VehicleComponent.IsMountedToVehicle( GetPuppet( context ).GetGame(), GetPuppet( context ) ) ) { GameInstance.GetWorkspotSystem( GetPuppet( context ).GetGame() ).HardResetPlaybackToStart( GetPuppet( context ) ); } super.Activate( context ); m_vehNPCDeathData.deathType = GetVehicleDeathType( context ); m_vehNPCDeathData.side = m_hitData.hitDirection; SendVehNPCDeathData( context ); m_activationTimeStamp = EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ); if( m_vehNPCDeathData.deathType != ( ( Int32 )( animNPCVehicleDeathType.Ragdoll ) ) ) { GetNPCPuppet( context ).SetDisableRagdoll( true ); } } protected override function CanSkipDeathAnimation() : Bool { return false; } protected override function PlayHitReactionAction( context : ScriptExecutionContext ) : Bool { return true; } protected override function Deactivate( context : ScriptExecutionContext ) { GetNPCPuppet( context ).SetDisableRagdoll( false ); ScriptExecutionContext.GetOwner( context ).QueueEvent( CreateForceRagdollEvent( 'VehicleDeathTask_Deactivate' ) ); super.Deactivate( context ); } protected function GetVehicleDeathType( context : ScriptExecutionContext ) : Int32 { var mountInfo : MountingInfo; var slotName : CName; var vehType : String; var slotNames : array< CName >; VehicleComponent.GetVehicleType( ScriptExecutionContext.GetOwner( context ).GetGame(), ScriptExecutionContext.GetOwner( context ), vehType ); mountInfo = GameInstance.GetMountingFacility( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetMountingInfoSingleWithObjects( ScriptExecutionContext.GetOwner( context ) ); slotName = mountInfo.slotId.id; if( vehType == "Bike" ) { return ( ( Int32 )( animNPCVehicleDeathType.Ragdoll ) ); } VehicleComponent.GetPassengersSlotNames( slotNames ); if( !( slotNames.Contains( slotName ) ) ) { return ( ( Int32 )( animNPCVehicleDeathType.Ragdoll ) ); } if( m_previousState == gamedataNPCHighLevelState.Combat ) { if( slotName == VehicleComponent.GetDriverSlotName() ) { return ( ( Int32 )( animNPCVehicleDeathType.Combat ) ); } return ( ( Int32 )( animNPCVehicleDeathType.Ragdoll ) ); } return ( ( Int32 )( animNPCVehicleDeathType.Relaxed ) ); } protected override function GetDeathReactionType( context : ScriptExecutionContext ) : Int32 { return ( ( Int32 )( animHitReactionType.Death ) ); } protected function SendVehNPCDeathData( context : ScriptExecutionContext ) { var mountInfo : MountingInfo; var vehicle : weak< VehicleObject >; mountInfo = GameInstance.GetMountingFacility( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetMountingInfoSingleWithObjects( ScriptExecutionContext.GetOwner( context ) ); vehicle = ( ( VehicleObject )( GameInstance.FindEntityByID( ScriptExecutionContext.GetOwner( context ).GetGame(), mountInfo.parentId ) ) ); AnimationControllerComponent.ApplyFeatureToReplicate( ScriptExecutionContext.GetOwner( context ), 'VehicleNPCDeathData', m_vehNPCDeathData ); AnimationControllerComponent.PushEventToReplicate( ScriptExecutionContext.GetOwner( context ), 'VehicleNPCDeathData' ); if( !( vehicle.IsVehicleAccelerateQuickhackActive() ) && VehicleComponent.IsDriver( ScriptExecutionContext.GetOwner( context ).GetGame(), ScriptExecutionContext.GetOwner( context ) ) ) { SendAIEventToMountedVehicle( context, 'DriverDead' ); } } protected function SendAIEventToMountedVehicle( context : ScriptExecutionContext, eventName : CName ) : Bool { var vehicle : weak< GameObject >; var evt : AIEvent; if( !( IsNameValid( eventName ) ) || !( GetAIComponent( context ).GetAssignedVehicle( ScriptExecutionContext.GetOwner( context ).GetGame(), vehicle ) ) ) { return false; } evt = new AIEvent; evt.name = eventName; vehicle.QueueEvent( evt ); return true; } protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome { var workspotSystem : WorkspotGameSystem; var knockOverBike : KnockOverBikeEvent; var mountInfo : MountingInfo; if( m_readyToUnmount ) { workspotSystem = GameInstance.GetWorkspotSystem( GetPuppet( context ).GetGame() ); workspotSystem.UnmountFromVehicle( NULL, ScriptExecutionContext.GetOwner( context ), true ); AIbehaviorUpdateOutcome.IN_PROGRESS; } if( m_vehNPCDeathData.deathType == ( ( Int32 )( animNPCVehicleDeathType.Ragdoll ) ) ) { if( !( m_hasRagdolled ) && ( ( EngineTime.ToFloat( ScriptExecutionContext.GetAITime( context ) ) - m_activationTimeStamp ) >= m_timeToRagdoll ) ) { mountInfo = GameInstance.GetMountingFacility( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetMountingInfoSingleWithObjects( ScriptExecutionContext.GetOwner( context ), ); ScriptExecutionContext.GetOwner( context ).QueueEvent( CreateForceRagdollWithCustomFilterDataEvent( 'RagdollVehicle', 'VehicleDeathTask_Update' ) ); m_readyToUnmount = true; m_hasRagdolled = true; knockOverBike = new KnockOverBikeEvent; knockOverBike.forceKnockdown = true; knockOverBike.applyDirectionalForce = true; GameInstance.FindEntityByID( ScriptExecutionContext.GetOwner( context ).GetGame(), mountInfo.parentId ).QueueEvent( knockOverBike ); } } return AIbehaviorUpdateOutcome.IN_PROGRESS; } } class SetSkipDeathAnimationTask extends AIbehaviortaskScript { editable var m_value : Bool; protected export override function Activate( context : ScriptExecutionContext ) { var puppet : NPCPuppet; puppet = ( ( NPCPuppet )( GetPuppet( context ) ) ); if( puppet ) { puppet.SetSkipDeathAnimation( m_value ); } } }