首页 > 代码库 > [Developing]HeadshotRecover Mut - 爆头回血插件 - Killing Floor 2
[Developing]HeadshotRecover Mut - 爆头回血插件 - Killing Floor 2
目前正在翻看官方SRC
收获如下
[class‘Weapon‘]
simulated function CalcWeaponFire(vector StartTrace, vector EndTrace, optional out array<ImpactInfo> ImpactList, optional vector Extent) : ImpactInfo
/** * CalcWeaponFire: Simulate an instant hit shot. * This doesn‘t deal any damage nor trigger any effect. It just simulates a shot and returns * the hit information, to be post-processed later. * * ImpactList returns a list of ImpactInfo containing all listed impacts during the simulation. * CalcWeaponFire however returns one impact (return variable) being the first geometry impact * straight, with no direction change. If you were to do refraction, reflection, bullet penetration * or something like that, this would return exactly when the crosshair sees: * The first ‘real geometry‘ impact, skipping invisible triggers and volumes. * * @param StartTrace world location to start trace from * @param EndTrace world location to end trace at * @param Extent extent of trace performed * @output ImpactList list of all impacts that occured during simulation * @return first ‘real geometry‘ impact that occured. * * @note if an impact didn‘t occur, and impact is still returned, with its HitLocation being the EndTrace value. */ simulated function ImpactInfo CalcWeaponFire(vector StartTrace, vector EndTrace, optional out array<ImpactInfo> ImpactList, optional vector Extent) { local vector HitLocation, HitNormal, Dir; local Actor HitActor; local TraceHitInfo HitInfo; local ImpactInfo CurrentImpact; local PortalTeleporter Portal; local float HitDist; local bool bOldBlockActors, bOldCollideActors; // Perform trace to retrieve hit info HitActor = GetTraceOwner().Trace(HitLocation, HitNormal, EndTrace, StartTrace, TRUE, Extent, HitInfo, TRACEFLAG_Bullet); // If we didn‘t hit anything, then set the HitLocation as being the EndTrace location if( HitActor == None ) { HitLocation = EndTrace; } // Convert Trace Information to ImpactInfo type. CurrentImpact.HitActor = HitActor; CurrentImpact.HitLocation = HitLocation; CurrentImpact.HitNormal = HitNormal; CurrentImpact.RayDir = Normal(EndTrace-StartTrace); CurrentImpact.StartTrace = StartTrace; CurrentImpact.HitInfo = HitInfo; // Add this hit to the ImpactList ImpactList[ImpactList.Length] = CurrentImpact; // check to see if we‘ve hit a trigger. // In this case, we want to add this actor to the list so we can give it damage, and then continue tracing through. if( HitActor != None ) { if (PassThroughDamage(HitActor)) { // disable collision temporarily for the actor we can pass-through HitActor.bProjTarget = false; bOldCollideActors = HitActor.bCollideActors; bOldBlockActors = HitActor.bBlockActors; if (HitActor.IsA(‘Pawn‘)) { // For pawns, we need to disable bCollideActors as well HitActor.SetCollision(false, false); // recurse another trace CalcWeaponFire(HitLocation, EndTrace, ImpactList, Extent); } else { if( bOldBlockActors ) { HitActor.SetCollision(bOldCollideActors, false); } // recurse another trace and override CurrentImpact CurrentImpact = CalcWeaponFire(HitLocation, EndTrace, ImpactList, Extent); } // and reenable collision for the trigger HitActor.bProjTarget = true; HitActor.SetCollision(bOldCollideActors, bOldBlockActors); } else { // if we hit a PortalTeleporter, recurse through Portal = PortalTeleporter(HitActor); if( Portal != None && Portal.SisterPortal != None ) { Dir = EndTrace - StartTrace; HitDist = VSize(HitLocation - StartTrace); // calculate new start and end points on the other side of the portal StartTrace = Portal.TransformHitLocation(HitLocation); EndTrace = StartTrace + Portal.TransformVectorDir(Normal(Dir) * (VSize(Dir) - HitDist)); //@note: intentionally ignoring return value so our hit of the portal is used for effects //@todo: need to figure out how to replicate that there should be effects on the other side as well CalcWeaponFire(StartTrace, EndTrace, ImpactList, Extent); } } } return CurrentImpact; }
simulated function InstantFire() 其中调用了 ProcessInstantHit()
原理:
对 玩家武器位置 以 GetAdjustedAim() 为方向 发射Trace(类似U3d Raycast)进行模拟武器伤害输出计算 得到 RealImpact
对RealImpact调用ProcessInstantHit,参数 <当前武器,RealImpact>
/** * Performs an ‘Instant Hit‘ shot. * Also, sets up replication for remote clients, * and processes all the impacts to deal proper damage and play effects. * * Network: Local Player and Server */ simulated function InstantFire() { local vector StartTrace, EndTrace; local Array<ImpactInfo> ImpactList; local int Idx; local ImpactInfo RealImpact; // define range to use for CalcWeaponFire() StartTrace = Instigator.GetWeaponStartTraceLocation(); EndTrace = StartTrace + vector(GetAdjustedAim(StartTrace)) * GetTraceRange(); // Perform shot RealImpact = CalcWeaponFire(StartTrace, EndTrace, ImpactList); if (Role == ROLE_Authority) { /* FlushPersistentDebugLines(); DrawDebugSphere( StartTrace, 10, 10, 0, 255, 0 ); DrawDebugSphere( EndTrace, 10, 10, 255, 0, 0 ); DrawDebugSphere( RealImpact.HitLocation, 10, 10, 0, 0, 255 ); `log( self@GetFuncName()@Instigator@RealImpact.HitLocation@RealImpact.HitActor );*/ // Set flash location to trigger client side effects. // if HitActor == None, then HitLocation represents the end of the trace (maxrange) // Remote clients perform another trace to retrieve the remaining Hit Information (HitActor, HitNormal, HitInfo...) // Here, The final impact is replicated. More complex bullet physics (bounce, penetration...) // would probably have to run a full simulation on remote clients. SetFlashLocation(RealImpact.HitLocation); } // Process all Instant Hits on local player and server (gives damage, spawns any effects). for (Idx = 0; Idx < ImpactList.Length; Idx++) { ProcessInstantHit(CurrentFireMode, ImpactList[Idx]); } }
simulated function ProcessInstantHit(byte FiringMode, ImpactInfo Impact, optional int NumHits)
作为子级被InstantFire()调用
作为父级被class‘KFWeapon‘::simulated function ProcessInstantHitEx(byte FiringMode, ImpactInfo Impact, optional int NumHits, optional out float out_PenetrationVal, optional int ImpactNum)调用,其中所有延续KFWeapon的类如KFWeap_MedicBase和KFWeap_Assaultrifle_Medic可以重写以实现自定义
原理:
对ImpactInfo::HitActor执行即刻的TakeDamage
/** * Processes a successful ‘Instant Hit‘ trace and eventually spawns any effects. * Network: LocalPlayer and Server * @param FiringMode: index of firing mode being used * @param Impact: hit information * @param NumHits (opt): number of hits to apply using this impact * this is useful for handling multiple nearby impacts of multihit weapons (e.g. shotguns) * without having to execute the entire damage code path for each one * an omitted or <= 0 value indicates a single hit */ simulated function ProcessInstantHit(byte FiringMode, ImpactInfo Impact, optional int NumHits) { local int TotalDamage; local KActorFromStatic NewKActor; local StaticMeshComponent HitStaticMesh; if (Impact.HitActor != None) { // default damage model is just hits * base damage NumHits = Max(NumHits, 1); TotalDamage = InstantHitDamage[CurrentFireMode] * NumHits; if ( Impact.HitActor.bWorldGeometry ) { HitStaticMesh = StaticMeshComponent(Impact.HitInfo.HitComponent); if ( (HitStaticMesh != None) && HitStaticMesh.CanBecomeDynamic() ) { NewKActor = class‘KActorFromStatic‘.Static.MakeDynamic(HitStaticMesh); if ( NewKActor != None ) { Impact.HitActor = NewKActor; } } } Impact.HitActor.TakeDamage( TotalDamage, Instigator.Controller, Impact.HitLocation, InstantHitMomentum[FiringMode] * Impact.RayDir, InstantHitDamageTypes[FiringMode], Impact.HitInfo, self ); } }
--
大体思路:
进行Trace确定ImpactInfo,原理是运用CalcWeaponFire(),方法类似于InstantFire(),然后判断HitZoneIndex == HZI_Head是否成立以检测是否爆头
目前在BGWeap_Assaultrifle_Medic.uc中 爆头提示 的实现
class BGWeap_Assaultrifle_Medic extends KFWeap_MedicBase; simulated function ProcessInstantHitEx( byte FiringMode, ImpactInfo Impact, optional int NumHits, optional out float out_PenetrationVal, optional int ImpactNum ) { local int HitZoneIndex; local KFPawn ImpactTarget; local KFPawn_Human HealTarget; local KFPawn_Monster KFPM_Victim; local KFPlayerController doer; local KFPlayerController KFPC; ImpactTarget=KFPawn(Impact.HitActor); HealTarget=KFPawn_Human(ImpactTarget); KFPM_Victim=KFPawn_Monster(ImpactTarget); doer=KFPlayerController(Instigator.Controller); if(KFPM_Victim!=None && !KFPM_Victim.bIsHeadless) { HitZoneIndex=KFPM_Victim.HitZones.Find(‘ZoneName‘, Impact.HitInfo.BoneName); if(HitZoneIndex == HZI_Head && KFPM != none && KFPM.IsAliveAndWell()) { if(doer.GetPerk()==class‘KFPerk_FieldMedic‘) { doer.ServerTeamSay("[HMT401_BUFF]Healing AOE Triggered"); ForEach WorldInfo.AllControllers(class‘KFPlayerController‘, KFPC) { if(KFPC.Pawn!=None) { KFPC.Pawn.Health=Min(KFPC.Pawn.Health+1, KFPC.Pawn.HealthMax); KFPC.TeamMessage(KFPC.PlayerReplicationInfo,"[HMT401_BUFF]Getting healed +2 by headshots from "$doer.PlayerReplicationInfo.PlayerName, ‘Event‘); } } } } } super.ProcessInstantHitEx(FiringMode, Impact, NumHits, out_PenetrationVal, ImpactNum); } defaultproperties { // Healing charge HealAmount=20 //Changed from 15 to 20 HealFullRechargeSeconds=10 // Inventory InventorySize=7 GroupPriority=100 WeaponSelectTexture=Texture2D‘ui_weaponselect_tex.UI_WeaponSelect_MedicAssault‘ SecondaryAmmoTexture=Texture2D‘UI_SecondaryAmmo_TEX.MedicDarts‘ // Shooting Animations FireSightedAnims[0]=Shoot_Iron FireSightedAnims[1]=Shoot_Iron2 FireSightedAnims[2]=Shoot_Iron3 // FOV MeshFOV=75 MeshIronSightFOV=52 PlayerIronSightFOV=70 // Depth of field DOF_FG_FocalRadius=85 DOF_FG_MaxNearBlurSize=2.5 Begin Object Name=FirstPersonMesh SkeletalMesh=SkeletalMesh‘WEP_1P_Medic_Assault_MESH.Wep_1stP_Medic_Assault_Rig‘ AnimSets(0)=AnimSet‘WEP_1P_Medic_Assault_ANIM.Wep_1stP_Medic_Assault_Anim‘ End Object Begin Object Name=StaticPickupComponent StaticMesh=StaticMesh‘WEP_3P_Pickups_MESH.Wep_Medic_Assault_Pickup‘ End Object AttachmentArchetype=KFWeaponAttachment‘WEP_Medic_Assault_ARCH.Wep_Medic_Assault_3P‘ // Zooming/Position PlayerViewOffset=(X=15.0,Y=6.5,Z=-3) IronSightPosition=(X=12,Y=0,Z=0) // Ammo MagazineCapacity[0]=30 SpareAmmoCapacity[0]=360 InitialSpareMags[0]=3 bCanBeReloaded=true bReloadFromMagazine=true // Recoil maxRecoilPitch=200 minRecoilPitch=150 maxRecoilYaw=175 minRecoilYaw=-125 RecoilRate=0.085 RecoilMaxYawLimit=500 RecoilMinYawLimit=65035 RecoilMaxPitchLimit=900 RecoilMinPitchLimit=65035 RecoilISMaxYawLimit=75 RecoilISMinYawLimit=65460 RecoilISMaxPitchLimit=375 RecoilISMinPitchLimit=65460 IronSightMeshFOVCompensationScale=1.5 // DEFAULT_FIREMODE FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D‘ui_firemodes_tex.UI_FireModeSelect_BulletAuto‘ FiringStatesArray(DEFAULT_FIREMODE)=WeaponFiring WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit WeaponProjectiles(DEFAULT_FIREMODE)=class‘KFProj_Bullet_AssaultRifle‘ InstantHitDamageTypes(DEFAULT_FIREMODE)=class‘KFDT_Ballistic_Assault_Medic‘ FireInterval(DEFAULT_FIREMODE)=+0.1 // 650 to 600 Spread(DEFAULT_FIREMODE)=0.0085 InstantHitDamage(DEFAULT_FIREMODE)=40 FireOffset=(X=30,Y=4.5,Z=-5) // ALTFIRE_FIREMODE AmmoCost(ALTFIRE_FIREMODE)=25 //decrease 16.7% // BASH_FIREMODE InstantHitDamage(BASH_FIREMODE)=27 InstantHitDamageTypes(BASH_FIREMODE)=class‘KFDT_Bludgeon_Assault_Medic‘ // Fire Effects MuzzleFlashTemplate=KFMuzzleFlash‘WEP_Medic_Assault_ARCH.Wep_Medic_Assault_MuzzleFlash‘ WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent‘WW_WEP_SA_MedicAssault.Play_SA_MedicAssault_Fire_3P_Loop‘, FirstPersonCue=AkEvent‘WW_WEP_SA_MedicAssault.Play_SA_MedicAssault_Fire_1P_Loop‘) WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent‘WW_WEP_SA_MedicAssault.Play_SA_MedicAssault_Fire_3P_Single‘, FirstPersonCue=AkEvent‘WW_WEP_SA_MedicAssault.Play_SA_MedicAssault_Fire_1P_Single‘) WeaponFireLoopEndSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent‘WW_WEP_SA_MedicAssault.Play_SA_MedicAssault_Fire_3P_EndLoop‘, FirstPersonCue=AkEvent‘WW_WEP_SA_MedicAssault.Play_SA_MedicAssault_Fire_1P_EndLoop‘) WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent‘WW_WEP_SA_MedicAssault.Play_SA_MedicAssault_Handling_DryFire‘ WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent‘WW_WEP_SA_MedicDart.Play_WEP_SA_Medic_Dart_DryFire‘ // Advanced (High RPM) Fire Effects bLoopingFireAnim(DEFAULT_FIREMODE)=true bLoopingFireSnd(DEFAULT_FIREMODE)=true SingleFireSoundIndex=ALTFIRE_FIREMODE // Attachments bHasIronSights=true bHasFlashlight=true AssociatedPerkClasses(0)=class‘KFPerk_FieldMedic‘ AssociatedPerkClasses(1)=class‘KFPerk_Commando‘ }
参考Instant Healing Mut
http://www.cnblogs.com/ArHShRn/p/7140193.html
[Developing]HeadshotRecover Mut - 爆头回血插件 - Killing Floor 2