//============================================================================= // KFDT_Slashing_EvisceratorProj //============================================================================= // Damage type for projectiles fired from the Eviscerator //============================================================================= // Killing Floor 2 // Copyright (C) 2015 Tripwire Interactive LLC // John "Ramm-Jaeger" Gibson //============================================================================= class KFDT_Slashing_EvisceratorProj extends KFDT_Slashing abstract hidedropdown; `define COSINE_0_DEGREES 1 `define COSINE_20_DEGREES 0.94 `define COSINE_70_DEGREES 0.34 `define COSINE_90_DEGREES 0 /** Allows the damage type to customize exactly which hit zones it can dismember */ static simulated function bool CanDismemberHitZone( name InHitZoneName ) { return true; } /** @return The slast type from the HitFxInfo. This returns a 8-way slash info. */ static simulated function EPawnOctant GetLastSlashDirection(KFPawn_Monster InPawn, vector HitDirection) { local vector SlashPlaneNormal; local rotator InstigatorRotation; local vector InstigatorFaceDir, InstigatorRightDir; local float UpDotSlash, RightDotSlash, UpThresholdValue; if( InPawn != none ) { HitDirection = Normal(HitDirection); InstigatorRotation = InPawn.GetBaseAimRotation(); InstigatorFaceDir = GetRotatorAxis(InstigatorRotation, 0); InstigatorRightDir = GetRotatorAxis(InstigatorRotation, 1); // Cross the face direction of the instigator with the hit direction to find // the normal to the "slashing" plane SlashPlaneNormal = Normal(InstigatorFaceDir Cross HitDirection); // Dot the slash plane normal with the world up direction to figure out // the quadrant for the normal of the slash plane UpDotSlash = vect(0,0,1) Dot SlashPlaneNormal; UpThresholdValue = Abs(UpDotSlash); // Dot the slash plane normal with the instigator right to figure out // the direction of the slash RightDotSlash = InstigatorRightDir Dot SlashPlaneNormal; // Threshhold against the preset values to find out the type of slash. The sign (+ or -) of the // dot products are used to further classify the direction of the slash if( UpThresholdValue <= `COSINE_0_DEGREES && UpThresholdValue >= `COSINE_20_DEGREES ) { if( UpDotSlash > 0 ) return DIR_Right; else return DIR_Left; } else if( UpThresholdValue <= `COSINE_20_DEGREES && UpThresholdValue >= `COSINE_70_DEGREES ) { if( UpDotSlash < 0 && RightDotSlash > 0 ) return DIR_ForwardLeft; else if( UpDotSlash > 0 && RightDotSlash > 0 ) return DIR_ForwardRight; else if( UpDotSlash > 0 && RightDotSlash < 0 ) return DIR_BackwardRight; else if( UpDotSlash < 0 && RightDotSlash < 0 ) return DIR_BackwardLeft; } else if( UpThresholdValue <= `COSINE_70_DEGREES && UpThresholdValue >= `COSINE_90_DEGREES ) { if( RightDotSlash > 0 ) return DIR_Forward; else return DIR_Backward; } } return DIR_None; } /** Allows the damage type to map a hit zone to a different bone for dismemberment purposes */ static simulated function GetBoneToDismember(KFPawn_Monster InPawn, vector HitDirection, name InHitZoneName, out name OutBoneName) { local EPawnOctant SlashDir; local KFCharacterInfo_Monster MonsterInfo; MonsterInfo = InPawn.GetCharacterMonsterInfo(); if ( MonsterInfo == none ) { return; } SlashDir = GetLastSlashDirection(InPawn, HitDirection); if( SlashDir == DIR_Forward || SlashDir == DIR_Backward ) { if( InHitZoneName == 'chest' || InHitZoneName == 'head' ) { if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit ) { // Randomly pick the left or right shoulder bone and split the guy in half vertically OutBoneName = Rand(2) == 0 ? MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName : MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName; } } } else if( SlashDir == DIR_Left || SlashDir == DIR_Right ) { if( InHitZoneName == 'chest' || InHitZoneName == 'abdomen' || InHitZoneName == 'stomach') { if( MonsterInfo.SpecialMeleeDismemberment.bAllowHorizontalSplit ) { // Split the guy in half horizontally OutBoneName = MonsterInfo.SpecialMeleeDismemberment.SpineBoneName; } } } else if( SlashDir == DIR_ForwardLeft || SlashDir == DIR_BackwardRight ) { if( InHitZoneName == 'chest' ) { if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit ) { OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName; } } else if( InHitZoneName == 'head' ) { if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit ) { // Use a random chance to decide whether to dismember the head or the shoulder constraints if( Rand(2) == 0 ) { // ... and choose one of the shoulder constraints at random OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName; } } } } else if( SlashDir == DIR_ForwardRight || SlashDir == DIR_BackwardLeft ) { if( InHitZoneName == 'chest' ) { if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit ) { OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName; } } else if( InHitZoneName == 'head' ) { if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit ) { // Use a random chance to decide whether to dismember the head or the shoulder constraints if( Rand(2) == 0 ) { OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName; } } } } } defaultproperties { EffectGroup=FXG_Sawblade KDamageImpulse=1000 KDeathUpKick=800 KDeathVel=135 // Instigator damage can happen on owning client when projectile hits before Instigator is replicated and // (Other != Instigator) == FALSE. This problem is specific to the eviscerator projectile since it's a // replicated CSHD weapon, but it might make sense to have bNoInstigatorDamage=true on more weapons. bNoInstigatorDamage=true StunPower=0 StumblePower=100 GunHitPower=0 MeleeHitPower=100 WeaponDef=class'KFWeapDef_Eviscerator' ModifierPerkList(0)=class'KFPerk_Berserker' }