//====================================================================================================================== // NicePack / NiceBulletAdapter //====================================================================================================================== // Temporary stand-in for future functionality. //====================================================================================================================== // 'Nice pack' source // Do whatever the fuck you want with it // Author: dkanus // E-mail: dkanus@gmail.com //====================================================================================================================== class NiceBulletAdapter extends Object; var const int BigZedMinHealth; // If zed's base Health >= this value, zed counts as Big var const int MediumZedMinHealth; // If zed's base Health >= this value, zed counts as Medium-size static function Explode( NiceBullet bullet, NiceReplicationInfo niceRI, Vector hitLocation, optional Actor explosionTarget ) { if (!bullet.bGhost) { niceRI.ServerExplode( bullet.charExplosionDamage, bullet.charExplosionRadius, bullet.charExplosionExponent, bullet.charExplosionDamageType, bullet.charExplosionMomentum, hitLocation, bullet.instigator, explosionTarget, Vector(bullet.Rotation), bullet.bStuck ); if (KFMonster(bullet.base) != none && bullet.bStuck && bullet.bStuckToHead) { niceRI.ServerDealDamage( KFMonster(bullet.base), bullet.charExplosionDamage, bullet.instigator, hitLocation, bullet.charExplosionMomentum * vect(0, 0, -1), bullet.charExplosionDamageType, 1.0 ); } } } static function HandleCalibration ( bool isHeadshot, NiceHumanPawn nicePawn, NiceMonster targetZed ) { if (nicePawn == none || nicePawn.currentCalibrationState != CALSTATE_ACTIVE) { return; } nicePawn.ServerUpdateCalibration(isHeadshot, targetZed); } static function HitWall( NiceBullet bullet, NiceReplicationInfo niceRI, Actor targetWall, Vector hitLocation, Vector hitNormal ) { local NicePlayerController nicePlayer; nicePlayer = NicePlayerController(bullet.Instigator.Controller); if (nicePlayer == none) { return; } if (!bullet.bAlreadyHitZed) { HandleCalibration(false, NiceHumanPawn(bullet.Instigator), none); } if ( !targetWall.bStatic && !targetWall.bWorldGeometry && nicePlayer != none && (nicePlayer.wallHitsLeft > 0 || Projectile(targetWall) != none) ) { niceRI.ServerDealDamage( targetWall, bullet.charOrigDamage, bullet.Instigator, hitLocation, bullet.charMomentumTransfer * hitNormal, bullet.charDamageType ); nicePlayer.wallHitsLeft --; } } static function HandleScream( NiceBullet bullet, NiceReplicationInfo niceRI, Vector location, Vector entryDirection ) { bullet.charIsDud = true; } static function HitPawn( NiceBullet bullet, NiceReplicationInfo niceRI, KFPawn targetPawn, Vector hitLocation, Vector hitNormal, array hitPoints ) { local NiceMedicProjectile niceDart; niceDart = NiceMedicProjectile(bullet); if (niceDart == none) { niceRI.ServerDealDamage( targetPawn, bullet.charDamage, bullet.instigator, HitLocation, hitNormal * bullet.charMomentumTransfer, bullet.charDamageType ); } else { niceRI.ServerHealTarget(NiceHumanPawn(targetPawn), bullet.charDamage, bullet.instigator); } } static function HitZed( NiceBullet bullet, NiceReplicationInfo niceRI, KFMonster kfZed, Vector hitLocation, Vector hitNormal, float headshotLevel ) { local bool bIsHeadshot, bIsPreciseHeadshot; local float actualDamage; local int lockonTicks; local float lockOnTickRate; local float angle; local NiceHumanPawn nicePawn; local NicePlayerController nicePlayer; local class niceVet; nicePlayer = NicePlayerController(bullet.Instigator.Controller); if ( nicePlayer != none && nicePlayer.abilityManager != none && nicePlayer.abilityManager.IsAbilityActive(class'NiceSkillEnforcerBruteA'.default.abilityID) ) { headshotLevel = 0.0; } bIsHeadshot = (headshotLevel > 0.0); bIsPreciseHeadshot = (headshotLevel > bullet.charDamageType.default.prReqPrecise); if (!bullet.bAlreadyHitZed || bIsHeadshot) { HandleCalibration(bIsHeadshot, NiceHumanPawn(bullet.Instigator), NiceMonster(kfZed)); } if (bIsHeadshot && bullet.sourceWeapon != none) { bullet.sourceWeapon.lastHeadshotTime = bullet.Level.TimeSeconds; } if (nicePlayer == none) { return; } nicePawn = NiceHumanPawn(bullet.instigator); if ( !bIsHeadshot && nicePawn != none && nicePlayer.abilityManager != none && nicePlayer.abilityManager.IsAbilityActive(class'NiceSkillSharpshooterReaperA'.default.abilityID) ) { nicePawn.ServerCooldownAbility(class'NiceSkillSharpshooterReaperA'.default.abilityID); } niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo)); if (bullet.charCausePain) { actualDamage = bullet.charOrigDamage; } else { actualDamage = bullet.charDamage; } if (headshotLevel > 0) { actualDamage *= bullet.charContiniousBonus; } if (bullet.bGrazing) { actualDamage *= class'NiceSkillSupportGraze'.default.grazeDamageMult; } bullet.bGrazing = false; if ( kfZed == bullet.lockonZed && bullet.lockonTime > bullet.sourceWeapon.stdFireRate && niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterKillConfirmed') ) { lockOnTickRate =class'NiceSkillSharpshooterKillConfirmed'.default.stackDelay; lockonTicks = Ceil(bullet.lockonTime / lockOnTickRate) - 1; lockonTicks = Min(class'NiceSkillSharpshooterKillConfirmed'.default.maxStacks, lockonTicks); // actualDamage *= 1.0 + // 0.5 * lockonTicks * (lockonTicks + 1) * class'NiceSkillSharpshooterKillConfirmed'.default.damageBonus; // damageMod *= 1.0 + lockonTicks * class'NiceSkillSharpshooterKillConfirmed'.default.damageBonus; actualDamage *= 1.0 + lockonTicks * class'NiceSkillSharpshooterKillConfirmed'.default.damageBonus; } if (!bullet.bGhost) { niceRI.ServerDealDamage( kfZed, actualDamage, bullet.instigator, hitLocation, bullet.charMomentumTransfer * hitNormal, bullet.charDamageType, headshotLevel, bullet.lockonTime ); } //// Handle angled shots angle = asin(hitNormal.Z); // Apply angled shots if ((angle > 0.8 || angle < -0.45) && bullet.bCanAngleDamage && kfZed != none) { bullet.bCanAngleDamage = false; bullet.bAlreadyHitZed = true; if (ZedPenetration(bullet.charDamage, bullet, kfZed, bIsHeadshot, bIsPreciseHeadshot)) { HitZed(bullet, niceRI, kfZed, hitLocation, hitNormal, headshotLevel); } } //// 'Bore' support skill if ( niceVet != none && nicePlayer.IsZedTimeActive() && bullet.insideBouncesLeft > 0 && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSupportZEDBore') ) { // Count one bounce bullet.insideBouncesLeft --; // Swap head-shot level if (headshotLevel <= 0.0) { headshotLevel = class'NiceSkillSupportZEDBore'.default.minHeadshotPrecision; } else { headshotLevel = -headshotLevel; } // Deal next batch of damage ZedPenetration(bullet.charDamage, bullet, kfZed, false, false); HitZed(bullet, niceRI, kfZed, hitLocation, hitNormal, headshotLevel); } bullet.insideBouncesLeft = 2; } static function bool ZedPenetration( out float Damage, NiceBullet bullet, KFMonster targetZed, bool bIsHeadshot, bool bIsPreciseHeadshot ) { local float reductionMod; local NiceMonster niceZed; local NicePlayerController nicePlayer; local int actualMaxPenetrations; local class niceVet; local class niceDmgType; // True if we can penetrate even body, but now penetrating a head and shouldn't reduce damage too much local bool bEasyHeadPenetration; // Init variables niceZed = NiceMonster(targetZed); nicePlayer = NicePlayerController(bullet.Instigator.Controller); niceVet = none; if (nicePlayer != none) { niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo)); } niceDmgType = bullet.charDamageType; bEasyHeadPenetration = bIsHeadshot && !niceDmgType.default.bPenetrationHSOnly; reductionMod = 1.0f; // Apply zed reduction and perk reduction of reduction` if (niceZed != none) { // Railgun skill exception if ( niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterZEDRailgun') && nicePlayer.IsZedTimeActive() ) { return true; } if (niceZed.default.Health >= default.BigZedMinHealth && !bEasyHeadPenetration) { reductionMod *= niceDmgType.default.BigZedPenDmgReduction; } else if (niceZed.default.Health >= default.MediumZedMinHealth && !bEasyHeadPenetration) { reductionMod *= niceDmgType.default.MediumZedPenDmgReduction; } } else { reductionMod *= niceDmgType.default.BigZedPenDmgReduction; } if (niceVet != none) { reductionMod = niceVet.static.GetPenetrationDamageMulti( KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo), reductionMod, niceDmgType ); } actualMaxPenetrations = niceDmgType.default.maxPenetrations; if ( niceVet != none && !bullet.charWasHipFired && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterSurgical') && bIsHeadshot ) { actualMaxPenetrations += 1; reductionMod = FMax(reductionMod, class'NiceSkillSharpshooterSurgical'.default.penDmgReduction); } // Assign new damage value and tell us if we should stop with penetration Damage *= reductionMod * niceDmgType.default.PenDmgReduction; bullet.decapMod *= reductionMod * niceDmgType.default.PenDecapReduction; bullet.incapMod *= reductionMod * niceDmgType.default.PenIncapReduction; if (niceVet != none && actualMaxPenetrations >= 0) { actualMaxPenetrations += niceVet.static.GetAdditionalPenetrationAmount(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo)); } if (!bIsHeadshot && niceDmgType.default.bPenetrationHSOnly) { return false; } if (actualMaxPenetrations < 0) { return true; } if (Damage / bullet.charOrigDamage < (niceDmgType.default.PenDmgReduction ** (actualMaxPenetrations + 1)) + 0.0001 || Damage < 1) { return false; } return true; } defaultproperties { BigZedMinHealth=1000 MediumZedMinHealth=500 }