class ProjectileLaunchHelper { public static function SpawnArmsLauncherProjectileWithRotation( ownerObject : GameObject, projectileTemplateName : CName, itemObj : ItemObject, optional rotationRad : Float ) : Bool { var launchEvent : gameprojectileSpawnerLaunchEvent; var targetingSystem : TargetingSystem; var targetComponent : IPlacedComponent; var componentPosition : Vector4; var customTargetSearchQuery : TargetSearchQuery; var angleDist : EulerAngles; var targetingAngle : Float; var orientationEntitySpace : Quaternion; var position, forward : Vector4; targetingSystem = GameInstance.GetTargetingSystem( ownerObject.GetGame() ); launchEvent = new gameprojectileSpawnerLaunchEvent; launchEvent.launchParams.logicalPositionProvider = targetingSystem.GetDefaultCrosshairPositionProvider( ownerObject ); if( ( ( Bool )rotationRad ) ) { targetingSystem.GetDefaultCrosshairData( ownerObject, position, forward ); Quaternion.SetIdentity( orientationEntitySpace ); Quaternion.SetZRot( orientationEntitySpace, rotationRad ); launchEvent.launchParams.logicalOrientationProvider = targetingSystem.GetDefaultCrosshairOrientationProvider( ownerObject, orientationEntitySpace ); } else { launchEvent.launchParams.logicalOrientationProvider = targetingSystem.GetDefaultCrosshairOrientationProvider( ownerObject ); } launchEvent.templateName = projectileTemplateName; launchEvent.appearance = ''; launchEvent.owner = ownerObject; customTargetSearchQuery = TSQ_EnemyNPC(); customTargetSearchQuery.maxDistance = TDB.GetFloat( T"Items.ProjectileLauncher.projectileSmartTargetingDistance", 100.0 ); targetComponent = ProjectileTargetingHelper.GetTargetsTargetingComponent( ownerObject, customTargetSearchQuery, angleDist ); if( targetComponent ) { targetingAngle = TDB.GetFloat( T"Items.ProjectileLauncher.projectileSmartTargetingAngle", 120.0 ); if( ( ( angleDist.Pitch * angleDist.Pitch ) + ( angleDist.Yaw * angleDist.Yaw ) ) < targetingAngle ) { componentPosition = ProjectileTargetingHelper.GetTargetingComponentsWorldPosition( targetComponent ); launchEvent.projectileParams.trackedTargetComponent = targetComponent; launchEvent.projectileParams.targetPosition = componentPosition; } } itemObj.QueueEvent( launchEvent ); return true; } public static function SpawnProjectileFromRightHand( ownerObject : GameObject, projectileTemplateName : CName, appearance : CName, itemObj : ItemObject ) : Bool { var targetingSystem : TargetingSystem; var aimPosition : Vector4; var aimForward : Vector4; targetingSystem = GameInstance.GetTargetingSystem( ownerObject.GetGame() ); targetingSystem.GetCrosshairData( ownerObject, aimPosition, aimForward ); return SpawnProjectile( ownerObject, projectileTemplateName, appearance, itemObj, IPositionProvider.CreateSlotPositionProvider( ownerObject, 'RightHand' ), IOrientationProvider.CreateStaticOrientationProvider( Quaternion.BuildFromDirectionVector( aimForward ) ) ); return false; } public static function SpawnProjectileFromScreenCenter( ownerObject : GameObject, projectileTemplateName : CName, appearance : CName, itemObj : ItemObject ) : Bool { var targetingSystem : TargetingSystem; targetingSystem = GameInstance.GetTargetingSystem( ownerObject.GetGame() ); return SpawnProjectile( ownerObject, projectileTemplateName, appearance, itemObj, targetingSystem.GetDefaultCrosshairPositionProvider( ownerObject ), targetingSystem.GetDefaultCrosshairOrientationProvider( ownerObject ) ); } private static function SpawnProjectile( ownerObject : GameObject, projectileTemplateName : CName, appearance : CName, itemObj : ItemObject, logicalPositionProvider : IPositionProvider, logicalOrientationProvider : IOrientationProvider ) : Bool { var launchEvent : gameprojectileSpawnerLaunchEvent; var componentPosition : Vector4; var angleDist : EulerAngles; var targetingAngle : Float; var customTargetSearchQuery : TargetSearchQuery; var preferableComponent : IPlacedComponent; customTargetSearchQuery = TSQ_EnemyNPC(); launchEvent = new gameprojectileSpawnerLaunchEvent; launchEvent.launchParams.logicalPositionProvider = logicalPositionProvider; launchEvent.launchParams.logicalOrientationProvider = logicalOrientationProvider; launchEvent.templateName = projectileTemplateName; launchEvent.appearance = appearance; launchEvent.owner = ownerObject; launchEvent.projectileParams.ignoreMountedVehicleCollision = true; if( itemObj.GetItemData().GetItemType() == gamedataItemType.Wea_Knife ) { customTargetSearchQuery.maxDistance = TDB.GetFloat( T"Items.Base_Knife.projectileSmartTargetingDistance", 100.0 ); } else if( itemObj.GetItemData().GetItemType() == gamedataItemType.Wea_Axe ) { customTargetSearchQuery.maxDistance = TDB.GetFloat( T"Items.Base_Axe.projectileSmartTargetingDistance", 100.0 ); } else { customTargetSearchQuery.maxDistance = TDB.GetFloat( T"Items.ProjectileLauncher.projectileSmartTargetingDistance", 100.0 ); } preferableComponent = ProjectileTargetingHelper.GetTargetsTargetingComponent( ownerObject, customTargetSearchQuery, angleDist ); if( preferableComponent ) { if( itemObj.GetItemData().GetItemType() == gamedataItemType.Wea_Knife || itemObj.GetItemData().GetItemType() == gamedataItemType.Wea_Axe ) { targetingAngle = TDB.GetFloat( T"Items.Base_Knife.projectileSmartTargetingAngle", 30.0 ); } else { targetingAngle = TDB.GetFloat( T"Items.ProjectileLauncher.projectileSmartTargetingAngle", 120.0 ); } if( ( ( angleDist.Pitch * angleDist.Pitch ) + ( angleDist.Yaw * angleDist.Yaw ) ) < targetingAngle ) { componentPosition = ProjectileTargetingHelper.GetTargetingComponentsWorldPosition( preferableComponent ); launchEvent.projectileParams.trackedTargetComponent = preferableComponent; launchEvent.projectileParams.targetPosition = componentPosition; } } itemObj.QueueEvent( launchEvent ); return true; } public static function SetLinearLaunchTrajectory( projectileComponent : ProjectileComponent, velocity : Float ) : Bool { var linearParams : LinearTrajectoryParams; if( velocity <= 0.0 ) { return false; } linearParams = new LinearTrajectoryParams; linearParams.startVel = velocity; projectileComponent.AddLinear( linearParams ); return true; } public static function SetParabolicLaunchTrajectory( projectileComponent : ProjectileComponent, gravitySimulation : Float, velocity : Float, energyLossFactorAfterCollision : Float ) : Bool { var parabolicParams : ParabolicTrajectoryParams; if( velocity <= 0.0 ) { return false; } parabolicParams = ParabolicTrajectoryParams.GetAccelVelParabolicParams( Vector4( 0.0, 0.0, gravitySimulation, 0.0 ), velocity ); projectileComponent.SetEnergyLossFactor( energyLossFactorAfterCollision, energyLossFactorAfterCollision ); projectileComponent.AddParabolic( parabolicParams ); return true; } public static function SetCurvedLaunchTrajectory( projectileComponent : ProjectileComponent, optional targetObject : weak< GameObject >, targetComponent : IPlacedComponent, startVelocity : Float, linearTimeRatio : Float, interpolationTimeRatio : Float, returnTimeMargin : Float, bendTimeRatio : Float, bendFactor : Float, halfLeanAngle : Float, endLeanAngle : Float, angleInterpolationDuration : Float ) : Bool { var followCurveParams : FollowCurveTrajectoryParams; followCurveParams = new FollowCurveTrajectoryParams; if( ( ( ( !( targetComponent ) && !( targetObject ) ) || ( startVelocity <= 0.0 ) ) || ( linearTimeRatio <= 0.0 ) ) || ( interpolationTimeRatio <= 0.0 ) ) { return false; } followCurveParams.startVelocity = startVelocity; followCurveParams.linearTimeRatio = linearTimeRatio; followCurveParams.interpolationTimeRatio = interpolationTimeRatio; followCurveParams.returnTimeMargin = returnTimeMargin; followCurveParams.bendTimeRatio = bendTimeRatio; followCurveParams.bendFactor = bendFactor; followCurveParams.halfLeanAngle = halfLeanAngle; followCurveParams.endLeanAngle = endLeanAngle; followCurveParams.angleInterpolationDuration = angleInterpolationDuration; followCurveParams.targetComponent = targetComponent; followCurveParams.target = targetObject; projectileComponent.AddFollowCurve( followCurveParams ); return true; } public static function SetCustomTargetPositionToFollow( projectileComponent : ProjectileComponent, const localToWorld : ref< Matrix >, startVelocity : Float, distance : Float, sideOffset : Float, height : Float, linearTimeRatio : Float, interpolationTimeRatio : Float, returnTimeMargin : Float, bendTimeRatio : Float, bendFactor : Float, accuracy : Float, halfLeanAngle : Float, endLeanAngle : Float, angleInterpolationDuration : Float ) : Bool { var followCurveParams : FollowCurveTrajectoryParams; var customTargetPosition : Vector4; followCurveParams = new FollowCurveTrajectoryParams; if( startVelocity <= 0.0 ) { return false; } followCurveParams.startVelocity = startVelocity; followCurveParams.linearTimeRatio = linearTimeRatio; followCurveParams.interpolationTimeRatio = interpolationTimeRatio; followCurveParams.returnTimeMargin = returnTimeMargin; followCurveParams.bendTimeRatio = bendTimeRatio; followCurveParams.bendFactor = bendFactor; followCurveParams.accuracy = accuracy; followCurveParams.halfLeanAngle = halfLeanAngle; followCurveParams.endLeanAngle = endLeanAngle; followCurveParams.angleInterpolationDuration = angleInterpolationDuration; customTargetPosition = ( ( Matrix.GetTranslation( localToWorld ) + ( Matrix.GetAxisY( localToWorld ) * distance ) ) - ( Matrix.GetAxisX( localToWorld ) * sideOffset ) ) + ( Matrix.GetAxisZ( localToWorld ) * height ); followCurveParams.targetPosition = customTargetPosition; projectileComponent.AddFollowCurve( followCurveParams ); return true; } } struct ProjectileHitAoEData { var source : weak< GameObject >; var instigator : weak< GameObject >; var position : Vector4; var radius : Float; var duration : Float; var attackRecord : Attack_Record; var weapon : weak< WeaponObject >; var disableVfx : Bool; var enableImpulseFalloff : Bool; var impulseFalloffFactor : Float; default impulseFalloffFactor = 0.5f; } class ProjectileGameEffectHelper { public static function FillProjectileHitAoEData( const aoeData : ref< ProjectileHitAoEData > ) : Bool { var attack : Attack_GameEffect; var effect : EffectInstance; var attackContext : AttackInitContext; var statMods : array< gameStatModifierData >; var flag : SHitFlag; var hitFlags : array< SHitFlag >; var i : Int32; attackContext.record = aoeData.attackRecord; attackContext.instigator = aoeData.instigator; attackContext.source = aoeData.source; attackContext.weapon = aoeData.weapon; attack = ( ( Attack_GameEffect )( IAttack.Create( attackContext ) ) ); attack.GetStatModList( statMods ); effect = attack.PrepareAttack( aoeData.instigator ); if( !( attack ) ) { return false; } EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.range, aoeData.radius ); EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.radius, aoeData.radius ); EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.duration, aoeData.duration ); EffectData.SetVector( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.position, aoeData.position ); EffectData.SetVariant( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.attack, ( ( IAttack )( attack ) ) ); EffectData.SetVariant( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.attackStatModList, statMods ); EffectData.SetBool( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.disableVfx, aoeData.disableVfx ); EffectData.SetBool( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.enableImpulseFalloff, aoeData.enableImpulseFalloff ); EffectData.SetFloat( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.impulseFalloffFactor, aoeData.impulseFalloffFactor ); for( i = 0; i < aoeData.attackRecord.GetHitFlagsCount(); i += 1 ) { flag.flag = ( ( hitFlag )( ( ( Int32 )( EnumValueFromString( "hitFlag", aoeData.attackRecord.GetHitFlagsItem( i ) ) ) ) ) ); flag.source = 'Attack'; hitFlags.PushBack( flag ); } EffectData.SetVariant( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.flags, hitFlags ); attack.StartAttack(); return true; } public static function FillProjectileHitData( source : weak< GameObject >, user : weak< GameObject >, projectileComponent : ProjectileComponent, eventData : gameprojectileHitEvent ) : Bool { var effect : EffectInstance; var effectData : EffectData; effect = projectileComponent.GetGameEffectInstance(); if( !( effect ) ) { return false; } effectData = effect.GetSharedData(); EffectData.SetVariant( effectData, GetAllBlackboardDefs().EffectSharedData.projectileHitEvent, eventData ); effect.Run(); return true; } public static function RunEffectFromAttack( instigator : weak< GameObject >, source : weak< GameObject >, weapon : weak< WeaponObject >, attackRecord : Attack_Record, eventData : gameprojectileHitEvent ) : Bool { var attack : Attack_GameEffect; var effect : EffectInstance; var attackContext : AttackInitContext; var statMods : array< gameStatModifierData >; attackContext.record = attackRecord; attackContext.instigator = instigator; attackContext.source = source; attackContext.weapon = weapon; attack = ( ( Attack_GameEffect )( IAttack.Create( attackContext ) ) ); if( !( attack ) ) { return false; } attack.GetStatModList( statMods ); effect = attack.PrepareAttack( instigator ); EffectData.SetVariant( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.attack, ( ( IAttack )( attack ) ) ); EffectData.SetVariant( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.attackStatModList, statMods ); EffectData.SetVariant( effect.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.projectileHitEvent, eventData ); effect.Run(); return true; } } class ProjectileTargetingHelper { public static function GetTargetsTargetingComponent( ownerObject : weak< GameObject >, filterBy : TargetSearchQuery, out angleDist : EulerAngles ) : IPlacedComponent { var component : IPlacedComponent; component = GameInstance.GetTargetingSystem( ownerObject.GetGame() ).GetComponentClosestToCrosshair( ownerObject, angleDist, filterBy ); return component; } public static function GetTargetingComponentsWorldPosition( targetComponent : IPlacedComponent ) : Vector4 { var componentPositionMatrix : Matrix; var componentPosition : Vector4; componentPositionMatrix = targetComponent.GetLocalToWorld(); componentPosition = Matrix.GetTranslation( componentPositionMatrix ); return componentPosition; } public static function GetObjectCurrentPosition( obj : weak< GameObject > ) : Vector4 { var objectPosition : Vector4; var positionParameter : Variant; positionParameter = obj.GetWorldPosition(); objectPosition = ( ( Vector4 )positionParameter ); return objectPosition; } } class ProjectileHitHelper { public static function GetHitObject( const hitInstance : ref< gameprojectileHitInstance > ) : weak< GameObject > { var object : GameObject; object = ( ( GameObject )( hitInstance.hitObject ) ); return object; } } class ProjectileHelper { public static function SpawnTrailVFX( projectileComponent : ProjectileComponent ) { projectileComponent.SpawnTrailVFX(); } public static function GetPSMBlackboardIntVariable( user : weak< GameObject >, id : BlackboardID_Int ) : Int32 { var blackboardSystem : BlackboardSystem; var blackboard : IBlackboard; var playerPuppet : GameObject; playerPuppet = GameInstance.GetPlayerSystem( user.GetGame() ).GetLocalPlayerMainGameObject(); blackboardSystem = GameInstance.GetBlackboardSystem( user.GetGame() ); blackboard = blackboardSystem.GetLocalInstanced( playerPuppet.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine ); return blackboard.GetInt( id ); } }