diff --git a/sources/GUI/NiceInteraction.uc b/sources/GUI/NiceInteraction.uc index a52af06..2afc1e1 100644 --- a/sources/GUI/NiceInteraction.uc +++ b/sources/GUI/NiceInteraction.uc @@ -107,6 +107,10 @@ function PostRender(Canvas C) local int x, y, center, barWidth, offset; local int missesWidth, missesHeight, missesSpace; local int missesX, missesY; + local TeamInfo team; + local int healthToGive, totalExpectedHealth; + local float textWidth, textHeight; + local string textToDraw; // local Vector CamPos, ViewDir; // local Rotator CamRot; // local float OffsetX, BarLength, BarHeight, XL, YL, posY; @@ -256,6 +260,47 @@ function PostRender(Canvas C) } } + //// Draw quad damage bar + if (nicePawn != none && nicePawn.quadDamageRemaining > 0.0) + { + C.SetDrawColor(255, 255, 255); + barTexture = redBar; + center = C.ClipX * 0.5; + y = C.ClipY * 0.45; + barWidth = C.ClipX * 0.2; + barWidth *= nicePawn.quadDamageRemaining / class'NiceSkillEnforcerBruteA'.default.maximumDamageAdded; + x = center - (barWidth / 2); + C.SetPos(x, y); + Log("DRAWING" @ x @ y @ barWidth); + C.DrawTile(barTexture, barWidth, 32, 0, 0, barTexture.MaterialUSize(), barTexture.MaterialVSize()); + }//native(466) final function DrawTile( material Mat, float XL, float YL, float U, float V, float UL, float VL ); + + team = C.ViewPort.Actor.Pawn.PlayerReplicationInfo.Team; + //// Draw health still in regen timer + healthToGive = ScrnHumanPawn(C.ViewPort.Actor.Pawn).clientHealthToGive; + if (healthToGive > 0) { + totalExpectedHealth = healthToGive + C.ViewPort.Actor.Pawn.health;; + C.Font = class'ROHUD'.Static.LoadSmallFontStatic(3); + if (totalExpectedHealth >= C.ViewPort.Actor.Pawn.healthMax) { + if(team.teamIndex == 0) { + C.SetDrawColor(255, 64, 64); + } + else { + C.SetDrawColor( + team.teamColor.R, + team.teamColor.G, + team.teamColor.B); + } + } + else { + C.SetDrawColor(128, 128, 128); + } + textToDraw = "+" $ healthToGive; + C.TextSize(textToDraw, textWidth, textHeight); + C.SetPos(C.ClipX * 0.05, C.ClipY * 0.9); + C.DrawText(textToDraw); + } + //// Draw cooldowns if (nicePlayer.abilityManager == none) return; @@ -273,7 +318,7 @@ function PostRender(Canvas C) { if (niceMutator.niceCounterSet[i].value != 0 || niceMutator.niceCounterSet[i].bShowZeroValue) { - DrawCounter(C, niceMutator.niceCounterSet[i], x, y, C.ViewPort.Actor.Pawn.PlayerReplicationInfo.Team); + DrawCounter(C, niceMutator.niceCounterSet[i], x, y, team); x += 128 + 4; } } @@ -283,7 +328,7 @@ function PostRender(Canvas C) function DrawCounter(Canvas C, NicePack.CounterDisplay counter, int x, int y, TeamInfo team){ local float borderSpace; local Texture textureToDraw; - local float textWidth, textHeight; + local float textWidth, textHeight; local string textToDraw; // Some per-defined values for drawing local int iconSize, backgroundWidth, backgroundHeight; @@ -320,7 +365,7 @@ function DrawAbilityCooldown(Canvas C, int abilityIndex){ local class niceVet; local int x, y; local string textToDraw; - local float textWidth, textHeight; + local float textWidth, textHeight; local NiceAbilityManager.EAbilityState abilityState; if(C == none) return; if(C.ViewPort == none) return; diff --git a/sources/NiceGameType.uc b/sources/NiceGameType.uc index ca0aaa7..5eb9578 100644 --- a/sources/NiceGameType.uc +++ b/sources/NiceGameType.uc @@ -74,6 +74,8 @@ State MatchInProgress{ function ScoreKill(Controller Killer, Controller Other) { + local NicePlayerController niceKiller; + local NiceHumanPawn niceKillerPawn; local PlayerReplicationInfo OtherPRI; local float KillScore; local Controller C; @@ -198,7 +200,15 @@ function ScoreKill(Controller Killer, Controller Other) } /* End Marco's Kill Messages */ - + niceKiller = NicePlayerController(killer); + if (niceKiller != none && niceKiller.abilityManager != none) { + niceKillerPawn = NiceHumanPawn(niceKiller.pawn); + niceKiller.abilityManager.AddToAllCooldowns(-1); + } + if ( niceKillerPawn != none && NiceBoomStick(niceKillerPawn.weapon) != none + && other != none && other.pawn != none && other.pawn.default.health >= 1000) { + niceKillerPawn.invincibilityTimer += 1.0; + } } function DramaticEvent(float BaseZedTimePossibility, optional float DesiredZedTimeDuration){ diff --git a/sources/NiceHumanPawn.uc b/sources/NiceHumanPawn.uc index 18205da..58a48f7 100644 --- a/sources/NiceHumanPawn.uc +++ b/sources/NiceHumanPawn.uc @@ -46,10 +46,11 @@ struct InvincExtentions{ var array zedInvExtList; var int headshotStack; var float bruteTimer; +var float quadDamageRemaining; replication{ reliable if(Role == ROLE_Authority) headshotStack, hmgShieldLevel, forcedZedTimeCountDown, maniacTimeout, invincibilityTimer, safeMeleeMisses, ffScale, - currentCalibrationState, calibrationScore, gunslingerTimer; + currentCalibrationState, calibrationScore, gunslingerTimer, quadDamageRemaining; reliable if(Role == ROLE_Authority) ClientChangeWeapon; reliable if(Role < ROLE_AUTHORITY) @@ -69,7 +70,7 @@ function ReplaceRequiredEquipment() RequiredEquipment[0] = string(class'NiceMachete'); RequiredEquipment[1] = string(class'Nice9mmPlus'); RequiredEquipment[2] = string(class'ScrnFrag'); - RequiredEquipment[3] = string(class'NiceSyringe'); + RequiredEquipment[3] = string(class'ScrnSyringe'); RequiredEquipment[4] = string(class'KFMod.Welder'); } @@ -420,10 +421,10 @@ function ServerBuyWeapon(class WClass, float ItemWeight){ Price = WP.Default.Cost; if(KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill != none){ Price *= KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.static.GetCostScaling(KFPlayerReplicationInfo(PlayerReplicationInfo), WP); - if(class'ScrnBalance'.default.Mut.bBuyPerkedWeaponsOnly - && WP.default.CorrespondingPerkIndex != 7 + if(class'ScrnBalance'.default.Mut.bBuyPerkedWeaponsOnly + && WP.default.CorrespondingPerkIndex != 7 && WP.default.CorrespondingPerkIndex != KFPlayerReplicationInfo(PlayerReplicationInfo).ClientVeteranSkill.default.PerkIndex ) - return; + return; } SellValue = Price * 0.75; Price = int(Price); @@ -507,11 +508,11 @@ function bool AddInventory(inventory NewItem){ if(weap != none){ if(Dualies(weap) != none){ if((DualDeagle(weap) != none || Dual44Magnum(weap) != none || DualMK23Pistol(weap) != none) - && weap.InventoryGroup != 4 ) { + && weap.InventoryGroup != 4 ) { if(KFPRI != none && ClassIsChildOf(KFPRI.ClientVeteranSkill, class'ScrnVetGunslinger')) weap.InventoryGroup = 3; - else + else weap.InventoryGroup = 2; GroupChanged = true; } @@ -521,7 +522,7 @@ function bool AddInventory(inventory NewItem){ } weap.bIsTier3Weapon = true; } - if(GroupChanged) + if(GroupChanged) ClientSetInventoryGroup(NewItem.class, NewItem.InventoryGroup); if(super(SRHumanPawn).AddInventory(NewItem)){ if(weap != none && weap.bTorchEnabled) @@ -568,7 +569,7 @@ simulated function ThrowGrenade() super.ThrowGrenade(); return; } - + if(playerGrenade == none) playerGrenade = FindPlayerGrenade(); if(playerGrenade != none && playerGrenade.HasAmmo()){ @@ -650,7 +651,7 @@ simulated function ApplyWeaponStats(Weapon NewWeapon){ InventorySpeedModifier += default.GroundSpeed * (8 - weaponWeight) * 0.025; // ScrN Armor can slow down players (or even boost) -- PooSH InventorySpeedModifier -= default.GroundSpeed * GetCurrentVestClass().default.SpeedModifier; - } + } } simulated function ModifyVelocity(float DeltaTime, vector OldVelocity){ local NicePack NicePackMutator; @@ -699,7 +700,7 @@ simulated function ModifyVelocity(float DeltaTime, vector OldVelocity){ GroundSpeed = StoryInv.ForcedGroundSpeed; return; } - } + } if(bTraderSpeedBoost && !KFGameReplicationInfo(Level.GRI).bWaveInProgress) MovementMod *= TraderSpeedBoost; if(Health < HealthMax && medicAdrenaliteTime > 0){ @@ -736,6 +737,7 @@ simulated function TakeDamage(int Damage, Pawn InstigatedBy, Vector Hitlocation, local float healPotency; local bool bOldArmorStops; local float adrResistance; + local float oldHealthToGive; local NicePlayerController nicePlayer; ApplyWeaponStats(Weapon); if(invincibilityTimer > 0) @@ -766,7 +768,12 @@ simulated function TakeDamage(int Damage, Pawn InstigatedBy, Vector Hitlocation, damageType.default.bArmorStops = true; } lastExplosionDistance = 0.0; // hack, but scrn fucks with usotherwise + oldHealthToGive = healthToGive; // remember this to restore this value, in case we are using safeguard skill super.TakeDamage(Damage, InstigatedBy, hitLocation, Momentum, damageType, HitIndex); + if (class'NiceVeterancyTypes'.static.HasSkill(nicePlayer, class'NiceSkillHeavySafeguard')) { + healthToGive = oldHealthToGive; + clientHealthToGive = healthToGive; + } // Commando's zed time if( forcedZedTimeCountDown <= 0.0 && health < class'NiceSkillCommandoCriticalFocus'.default.healthBoundary && KFGameType(Level.Game) != none @@ -789,7 +796,7 @@ simulated function TakeDamage(int Damage, Pawn InstigatedBy, Vector Hitlocation, if(ShieldStrength < 0) ShieldStrength = 0; health += HealAmount * 0.5; - TakeHealing(self, HealAmount * 0.5, HealPotency); + TakeHealing(self, HealAmount * 0.5 + 1, HealPotency); } if(ShieldStrength <= 0) getFreeJacket(); diff --git a/sources/NicePlayerController.uc b/sources/NicePlayerController.uc index ccd38a9..dabd3d0 100644 --- a/sources/NicePlayerController.uc +++ b/sources/NicePlayerController.uc @@ -212,20 +212,6 @@ simulated function ClientPostLogin(){ // Change HUD parameters class'ScrnHUD'.default.EnemyHealthBarHeight = 4.0; } - -// fix crooked camera after you die with active `ViewShake` -function StopViewShaking() { - ShakeRotMax = vect(0, 0, 0); - ShakeRotRate = vect(0, 0, 0); - ShakeRotTime = vect(0, 0, 0); - ShakeOffsetMax = vect(0, 0, 0); - ShakeOffsetRate = vect(0, 0, 0); - ShakeOffsetTime = vect(0, 0, 0); - // add missing variables - ShakeOffset = vect(0, 0, 0); - ShakeRot = Rot(0, 0, 0); -} - function ShowLobbyMenu(){ Super.ShowLobbyMenu(); } @@ -1239,7 +1225,7 @@ function LoadDualWieldables(){ local class WP; local class W; local int i; - + CPRL = class'ClientPerkRepLink'.Static.FindStats(self); if(CPRL == none || CPRL.ShopInventory.Length == 0) return; diff --git a/sources/NiceReplicationInfo.uc b/sources/NiceReplicationInfo.uc index a685f4e..2267304 100644 --- a/sources/NiceReplicationInfo.uc +++ b/sources/NiceReplicationInfo.uc @@ -71,6 +71,7 @@ simulated function CalculateDamageScales( out float scale1, out float scale2, local Vector victimPoint1, victimPoint2; local float swap; victimPoint1 = victim.location; + victimPoint2.z += victim.CollisionHeight * 0.25; victimPoint2 = victim.location; victimPoint2.z += victim.CollisionHeight * 0.75; scale1 = GetDamageScale(victim, explosionLocation, victimPoint1, @@ -93,40 +94,55 @@ simulated function ServerExplode float momentum, Vector explLocation, Pawn instigator, - optional bool allowDoubleExplosion, optional Actor explosionTarget, - optional vector explosiveDirection + optional vector explosiveDirection, + optional bool preventProximityHeadDamage ){ local Actor victim; local int numKilled; local Vector dirToVictim; local Vector hitLocation; local float scale1, scale2; + local NiceMonster niceVictim; if(Role < ROLE_Authority) return; foreach VisibleActors(class'Actor', victim, explRadius, explLocation){ - if(victim == none || victim == self) continue; - if(victim.role < ROLE_Authority) continue; - if(ExtendedZCollision(victim) != none) continue; - if(Trigger(victim) != none) continue; - dirToVictim = Normal(victim.location - explLocation); - hitLocation = victim.location - 0.5 * - (victim.collisionHeight + victim.collisionRadius) * dirToVictim; - CalculateDamageScales( scale1, scale2, - victim, explLocation, explRadius, explExp); - // Deal main damage - if(scale1 > 0){ - ServerDealDamage( victim, explDamage * scale1, instigator, - hitLocation, scale1 * momentum * dirToVictim, - explDmgType); - } - // Deal secondary damage - if(allowDoubleExplosion && victim != none && scale2 > 0){ - ServerDealDamage( victim, explDamage * scale2, instigator, - hitLocation, scale2 * momentum * dirToVictim, - explDmgType); - } - if(NiceMonster(victim) != none && NiceMonster(victim).health <= 0) - numKilled ++; + if(victim == none || victim == self) continue; + if(victim.role < ROLE_Authority) continue; + if(ExtendedZCollision(victim) != none) continue; + if(Trigger(victim) != none) continue; + + niceVictim = NiceMonster(victim); + dirToVictim = Normal(victim.location - explLocation); + hitLocation = victim.location - 0.5 * + (victim.collisionHeight + victim.collisionRadius) * dirToVictim; + CalculateDamageScales( scale1, scale2, + victim, explLocation, explRadius, explExp); + // Deal head damage if explosion is close enough to the victim's head + if ( niceVictim != none && !preventProximityHeadDamage + && niceVictim.GetDistanceToHead(explLocation) <= explRadius * 0.1) + { + ServerDealDamage( victim, explDamage, instigator, + hitLocation, 0.0 * dirToVictim, + explDmgType, 0.5); + } + // Deal main damage + if(scale1 > 0 || scale2 > 0) { + ServerDealDamage( + victim, + explDamage * FMax(scale1, scale2), + instigator, + hitLocation, + FMax(scale1, scale2) * momentum * dirToVictim, + explDmgType); + } + if(niceVictim != none) { + if (niceVictim.health <= 0) { + numKilled += 1; + } + else { + niceVictim.concussionCountdown = 10.0; + } + } } if(numKilled >= 4) KFGameType(level.game).DramaticEvent(0.05); @@ -203,34 +219,45 @@ simulated function RemovePoisonAndBleed(NiceHumanPawn healed) } // Tells server to heal given human pawn. -simulated function ServerHealTarget(NiceHumanPawn healed, float charPotency, - Pawn instigator){ +simulated function ServerHealTarget( + NiceHumanPawn healed, + float charPotency, + Pawn instigator +) { local NiceHumanPawn healer; + local PlayerController healedPC; local KFPlayerReplicationInfo KFPRI; + local NiceMedicGun healingTool; local float healTotal; local float healPotency; + if(instigator == none || healed == none) return; if(healed.health <= 0 || healed.health >= healed.healthMax) return; KFPRI = KFPlayerReplicationInfo(instigator.PlayerReplicationInfo); - if(KFPRI == none || KFPRI.ClientVeteranSkill == none) - return; + if(KFPRI == none || KFPRI.ClientVeteranSkill == none) return; healer = NiceHumanPawn(instigator); - if(healer == none) - return; + if(healer == none) return; + + healingTool = NiceMedicGun(healer.weapon); healPotency = KFPRI.ClientVeteranSkill.static.GetHealPotency(KFPRI); healTotal = charPotency * healPotency; - healer.AlphaAmount = 255; - if(NiceMedicGun(healer.weapon) != none) - NiceMedicGun(healer.weapon).ClientSuccessfulHeal(healer, healed); - if(healed.health >= healed.healthMax){ + if(healingTool != none) { + healingTool.ClientSuccessfulHeal(healer, healed); + } + healedPC = PlayerController(healed.controller); + if(healedPC != none) { + healedPC.ClientMessage( + "You've been healed by" @ healer.GetPlayerName(), + 'CriticalEvent'); + } + if(healed.health >= healed.healthMax) { healed.GiveHealth(healTotal, healed.healthMax); return; } HandleNiceHealingMechanicsAndSkills(healer, healed, healPotency); - if(healed.health < healed.healthMax){ - healed.TakeHealing( healed, healTotal, healPotency, - KFWeapon(instigator.weapon)); + if(healed.health < healed.healthMax) { + healed.TakeHealing(healed, healTotal, healPotency, healingTool); } RemovePoisonAndBleed(healed); } @@ -261,9 +288,6 @@ simulated function HandleNiceDamageMechanicsAndSkills hasSkill(nicePlayer, class'NiceSkillCommandoTranquilizer'); hasZEDFrenzy = class'NiceVeterancyTypes'.static. hasSkill(nicePlayer, class'NiceSkillMedicZEDFrenzy'); - // Medic's suppression - if(hasTranquilizer) - niceZed.mind = FMin(niceZed.mind, 0.5); // Medic's frenzy if(hasZEDFrenzy && nicePlayer.IsZedTimeActive()){ niceZed.madnessCountDown = @@ -310,7 +334,7 @@ simulated function UpdateMeleeInvincibility nicePawn.TryExtendingInv(niceZed, false, headshotLevel > 0.0); // Handle melee-cases if(mainTarget && class(damageType) != none) - nicePawn.TryExtendingInv(niceZed, true, headshotLevel > 0.0); + nicePawn.TryExtendingInv(niceZed, true, headshotLevel > 0.0); nicePawn.ApplyWeaponStats(nicePawn.weapon); } simulated function UpdateArdour(bool isKill, NicePlayerController nicePlayer){ diff --git a/sources/NiceRules.uc b/sources/NiceRules.uc index b2defeb..e94c7df 100644 --- a/sources/NiceRules.uc +++ b/sources/NiceRules.uc @@ -128,7 +128,7 @@ function bool PreventDeath(Pawn Killed, Controller Killer, class dam class'NiceSkillDemoReactiveArmor'.default.explExponent, class'NiceDamTypeDemoSafeExplosion', class'NiceSkillDemoReactiveArmor'.default.explMomentum, - killed.location, killed, true + killed.location, killed ); return true; } diff --git a/sources/Perks/Abilities/NiceAbilityManager.uc b/sources/Perks/Abilities/NiceAbilityManager.uc index 96058e2..4e96c95 100644 --- a/sources/Perks/Abilities/NiceAbilityManager.uc +++ b/sources/Perks/Abilities/NiceAbilityManager.uc @@ -29,19 +29,19 @@ struct NiceAbilityDescription{ // Image to be used as an ability's icon var Texture icon; // Default cooldown duration - var float cooldownLength; + var int cooldownLength; // Can ability be canceled once activated? - var bool canBeCancelled; + var bool canBeCancelled; }; // Complete description of current status of an ability, // including it's complete description. struct NiceAbilityStatus{ // Complete description of ability in question - var NiceAbilityDescription description; + var NiceAbilityDescription description; // Current cooldown value - var float cooldown; + var int cooldown; // Current state of an ability - var EAbilityState myState; + var EAbilityState myState; }; var NiceAbilityStatus currentAbilities[5]; var int currentAbilitiesAmount; @@ -65,7 +65,7 @@ function AddAbility(NiceAbilityDescription description){ if(currentAbilities[i].description.ID ~= description.ID) return; newRecord.description = description; - newRecord.cooldown = 0.0; + newRecord.cooldown = 0; newRecord.myState = ASTATE_READY; currentAbilities[currentAbilitiesAmount] = newRecord; currentAbilitiesAmount += 1; @@ -120,34 +120,34 @@ function SetAbilityState(int abilityIndex, EAbilityState newState){ if(abilityIndex < 0 || abilityIndex >= currentAbilitiesAmount) return; currentState = currentAbilities[abilityIndex].myState; if(currentState == newState) - return; + return; if( currentState == ASTATE_ACTIVE && newState == ASTATE_READY - && !currentAbilities[abilityIndex].description.canBeCancelled) - return; + && !currentAbilities[abilityIndex].description.canBeCancelled) + return; currentAbilities[abilityIndex].myState = newState; if(newState == ASTATE_COOLDOWN){ - cooldown = currentAbilities[abilityIndex].description.cooldownLength; - events.static.CallModAbilityCooldown( - currentAbilities[abilityIndex].description.ID, - relatedPlayer, - cooldown - ); - currentAbilities[abilityIndex].cooldown = cooldown; + cooldown = currentAbilities[abilityIndex].description.cooldownLength; + events.static.CallModAbilityCooldown( + currentAbilities[abilityIndex].description.ID, + relatedPlayer, + cooldown + ); + currentAbilities[abilityIndex].cooldown = cooldown; } hackCounter ++; netUpdateTime = level.timeSeconds - 1; // Fire off events if(newState == ASTATE_ACTIVE){ - events.static.CallAbilityActivated( - currentAbilities[abilityIndex].description.ID, - relatedPlayer - ); + events.static.CallAbilityActivated( + currentAbilities[abilityIndex].description.ID, + relatedPlayer + ); } } // Changes ability's cooldown by a given amount. // If this brings cooldown to zero or below - // resets current ability to a 'ready' (ASTATE_READY) state. -function AddToCooldown(int abilityIndex, float delta){ +function AddToCooldown(int abilityIndex, int delta){ if(abilityIndex < 0 || abilityIndex >= currentAbilitiesAmount) return; if(currentAbilities[abilityIndex].myState != ASTATE_COOLDOWN) return; currentAbilities[abilityIndex].cooldown += delta; @@ -155,12 +155,21 @@ function AddToCooldown(int abilityIndex, float delta){ SetAbilityState(abilityIndex, ASTATE_READY); hackCounter ++; } -function Tick(float deltaTime){ + +function AddToAllCooldowns(int delta){ local int i; - if(Role != Role_AUTHORITY) return; - for(i = 0;i < currentAbilitiesAmount;i ++) - AddToCooldown(i, -deltaTime); + + for (i = 0; i < currentAbilitiesAmount; i += 1) { + if (currentAbilities[i].myState == ASTATE_COOLDOWN) { + currentAbilities[i].cooldown += delta; + if(currentAbilities[i].cooldown <= 0) { + SetAbilityState(i, ASTATE_READY); + } + } + } + hackCounter ++; } + defaultproperties { maxAbilitiesAmount=5 diff --git a/sources/Perks/Commando/NiceDamTypeMedicDart.uc b/sources/Perks/Commando/NiceDamTypeMedicDart.uc index 260ac7a..c64ead0 100644 --- a/sources/Perks/Commando/NiceDamTypeMedicDart.uc +++ b/sources/Perks/Commando/NiceDamTypeMedicDart.uc @@ -1,4 +1,4 @@ -class NiceDamTypeMedicDart extends NiceDamageTypeVetCommando +class NiceDamTypeMedicDart extends NiceDamageTypeVetDemolitions abstract; defaultproperties { diff --git a/sources/Perks/Commando/NiceVetCommando.uc b/sources/Perks/Commando/NiceVetCommando.uc index db16fbc..7e94b9f 100644 --- a/sources/Perks/Commando/NiceVetCommando.uc +++ b/sources/Perks/Commando/NiceVetCommando.uc @@ -35,6 +35,16 @@ static function float GetMagCapacityMod(KFPlayerReplicationInfo KFPRI, KFWeapon return class'NiceSkillCommandoLargerMags'.default.sizeBonus; return 1.0; } +// Change the cost of particular ammo +static function float GetAmmoCostScaling(KFPlayerReplicationInfo KFPRI, class Item) +{ + local class pickupClass; + pickupClass = class(Item); + if(IsPerkedPickup(pickupClass) && HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillCommandoLargerMags')) { + return class'NiceSkillCommandoLargerMags'.default.sizeBonus; + } + return 1.0; +} static function float GetSyringeChargeRate(KFPlayerReplicationInfo KFPRI){ return 1.5; } @@ -102,7 +112,7 @@ defaultproperties OnHUDIcons(3)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Commando_Blue',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Blue',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(4)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Commando_Purple',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Purple',DrawColor=(B=255,G=255,R=255,A=255)) OnHUDIcons(5)=(PerkIcon=Texture'ScrnTex.Perks.Perk_Commando_Orange',StarIcon=Texture'ScrnTex.Perks.Hud_Perk_Star_Orange',DrawColor=(B=255,G=255,R=255,A=255)) - CustomLevelInfo="Level up by doing damage with perked weapons|15% faster reload with all weapons|10% faster movement speed|You get four additional Zed-Time Extensions|See health and cloacked zeds from 16 meters distance|Better Syringe handling" + CustomLevelInfo="Level up by doing damage with perked weapons|15% faster reload with all weapons|10% faster movement speed|You get four additional Zed-Time Extensions|See health and cloaked zeds from 16 meters distance|Better Syringe handling" PerkIndex=3 OnHUDIcon=Texture'KillingFloorHUD.Perks.Perk_Commando' OnHUDGoldIcon=Texture'KillingFloor2HUD.Perk_Icons.Perk_Commando_Gold' diff --git a/sources/Perks/Demolitions/NiceDamTypeDemoExplosion.uc b/sources/Perks/Demolitions/NiceDamTypeDemoExplosion.uc index a640688..78ab779 100644 --- a/sources/Perks/Demolitions/NiceDamTypeDemoExplosion.uc +++ b/sources/Perks/Demolitions/NiceDamTypeDemoExplosion.uc @@ -8,6 +8,7 @@ static function GetHitEffects(out class HitEffects[4], int VictimHealt } defaultproperties { + stoppingPower=0.5 stunMultiplier=0.600000 bIsExplosive=True DeathString="%o filled %k's body with shrapnel." diff --git a/sources/Perks/Demolitions/NiceVetDemolitions.uc b/sources/Perks/Demolitions/NiceVetDemolitions.uc index a0c1006..ea36af8 100644 --- a/sources/Perks/Demolitions/NiceVetDemolitions.uc +++ b/sources/Perks/Demolitions/NiceVetDemolitions.uc @@ -39,12 +39,13 @@ static function int AddDamage(KFPlayerReplicationInfo KFPRI, KFMonster Injured, perkDamage = float(InDamage); if(DmgType == class'NiceDamTypeDemoExplosion') return 1.6 * perkDamage; - if(IsPerkedPickup(pickupClass)) + if(IsPerkedPickup(pickupClass) && class(DmgType) != none) perkDamage *= 1.25; else if( pickupClass != none && pickupClass.default.weight <= class'NiceSkillDemoOffperk'.default.weightBound && HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillDemoOffperk') ) perkDamage *= class'NiceSkillDemoOffperk'.default.damageBonus; - if( KFPRI != none && class(DmgType) != none + if( KFPRI != none && class(DmgType) == none + && IsPerkedPickup(pickupClass) && SomeoneHasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillDemoOnperk') ) perkDamage *= class'NiceSkillDemoOnperk'.default.damageBonus; return perkDamage; diff --git a/sources/Perks/Enforcer/NiceEnforcerAbilitiesAdapter.uc b/sources/Perks/Enforcer/NiceEnforcerAbilitiesAdapter.uc index 0f5116f..11946da 100644 --- a/sources/Perks/Enforcer/NiceEnforcerAbilitiesAdapter.uc +++ b/sources/Perks/Enforcer/NiceEnforcerAbilitiesAdapter.uc @@ -15,7 +15,6 @@ static function AbilityActivated( NicePlayerController relatedPlayer) { local NiceHumanPawn nicePawn; - local NiceMonster victim; if (relatedPlayer == none) return; nicePawn = NiceHumanPawn(relatedPlayer.pawn); @@ -37,6 +36,23 @@ static function AbilityActivated( { nicePawn.bruteTimer = class'NiceSkillEnforcerBruteA'.default.abilityDuration; + nicePawn.quadDamageRemaining = class'NiceSkillEnforcerBruteA'.default.maximumDamageAdded; + } +} + +static function ModAbilityCooldown( string abilityID, + NicePlayerController relatedPlayer, + out float cooldown) +{ + local NiceHumanPawn nicePawn; + + if (relatedPlayer == none) return; + nicePawn = NiceHumanPawn(relatedPlayer.pawn); + if (nicePawn == none) return; + + if (abilityID == "brute") + { + nicePawn.quadDamageRemaining = 0; } } diff --git a/sources/Perks/Enforcer/NiceVetEnforcer.uc b/sources/Perks/Enforcer/NiceVetEnforcer.uc index 76d120d..141af22 100644 --- a/sources/Perks/Enforcer/NiceVetEnforcer.uc +++ b/sources/Perks/Enforcer/NiceVetEnforcer.uc @@ -16,12 +16,15 @@ static function array GetProgressArray(byte ReqNum, optional out int Double // Other bonuses static function int AddDamage(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, int InDamage, class DmgType) { - local float fDamage; + local int bruteAbilityIndex; + local float fDamage, addedDamage; local NicePlayerController nicePlayer; + local NiceHumanPawn nicePawn; local NiceMonster niceTarget; fDamage = float(InDamage); nicePlayer = NicePlayerController(KFPRI.Owner); + nicePawn = NiceHumanPawn(nicePlayer.pawn); niceTarget = NiceMonster(injured); if ( niceTarget != none && niceTarget.bFrozenZed @@ -31,9 +34,20 @@ static function int AddDamage(KFPlayerReplicationInfo KFPRI, KFMonster Injured, (1 + class'NiceSkillEnforcerFinisherRounds'.default.damageBonus); } if( nicePlayer != none && nicePlayer.abilityManager != none + && nicePawn != none && nicePawn.quadDamageRemaining > 0 && nicePlayer.abilityManager.IsAbilityActive(class'NiceSkillEnforcerBruteA'.default.abilityID)) { - fDamage *= class'NiceSkillEnforcerBruteA'.default.damageMult; + addedDamage = fDamage * class'NiceSkillEnforcerBruteA'.default.damageMult - fDamage; + if (addedDamage >= nicePawn.quadDamageRemaining) { + addedDamage = nicePawn.quadDamageRemaining; + nicePawn.quadDamageRemaining = 0.0; + bruteAbilityIndex = nicePlayer.abilityManager.GetAbilityIndex(class'NiceSkillEnforcerBruteA'.default.abilityID); + nicePlayer.abilityManager.SetAbilityState(bruteAbilityIndex, ASTATE_COOLDOWN); + } + else { + nicePawn.quadDamageRemaining -= addedDamage; + } + fDamage += addedDamage; } return int(fDamage); } @@ -45,7 +59,7 @@ static function float GetPenetrationDamageMulti(KFPlayerReplicationInfo KFPRI, f return DefaultPenDamageReduction; if(HasSkill(NicePlayerController(KFPRI.Owner), class'NiceSkillSupportStubbornness')) bonusReduction = class'NiceSkillSupportStubbornness'.default.penLossRed; - PenDamageInverse = (1.0 - FMax(0, DefaultPenDamageReduction)); + PenDamageInverse = (1.0 - FMax(0, DefaultPenDamageReduction)); return DefaultPenDamageReduction + PenDamageInverse * (0.6 + 0.4 * bonusReduction); // 60% better penetrations + bonus } @@ -64,15 +78,6 @@ static function class GetNadeType(KFPlayerReplicationInfo KFPRI){ return class'NiceCryoNade'; } -static function float AddExtraAmmoFor(KFPlayerReplicationInfo KFPRI, Class AmmoType){ - local float bonusNades; - // Default bonus - bonusNades = 2; - if(AmmoType == class'FragAmmo') - return 1.0 + 0.2 * bonusNades; - return 1.0; -} - static function int ReduceDamage(KFPlayerReplicationInfo KFPRI, KFPawn Injured, Pawn Instigator, int InDamage, class DmgType){ local float fDamage; fDamage = float(inDamage); @@ -180,7 +185,7 @@ defaultproperties SkillGroupA(4)=class'NiceSkillEnforcerZEDBarrage' SkillGroupB(0)=class'NiceSkillEnforcerUnkillable' SkillGroupB(1)=class'NiceSkillEnforcerMultitasker' - SkillGroupB(2)=class'NiceSkillEnforcerFinisherRounds' + SkillGroupB(2)=class'NiceSkillHeavySafeguard' SkillGroupB(3)=class'NiceSkillEnforcerBruteA' SkillGroupB(4)=class'NiceSkillEnforcerZEDIceGiant' progressArray0(0)=100 diff --git a/sources/Perks/Enforcer/Skills/NiceSkillEnforcerBombard.uc b/sources/Perks/Enforcer/Skills/NiceSkillEnforcerBombard.uc index e38133a..8bdedfa 100644 --- a/sources/Perks/Enforcer/Skills/NiceSkillEnforcerBombard.uc +++ b/sources/Perks/Enforcer/Skills/NiceSkillEnforcerBombard.uc @@ -7,5 +7,5 @@ defaultproperties stunMult=3.000000 spreadMult=0.500000 SkillName="Bombard" - SkillEffects="Your perked weapons are 3 times as good at stunning." + SkillEffects="Your perked weapons are 3 times as good at stunning and have omly half as much spread." } diff --git a/sources/Perks/Enforcer/Skills/NiceSkillEnforcerBruteA.uc b/sources/Perks/Enforcer/Skills/NiceSkillEnforcerBruteA.uc index 8bf9399..e7a87df 100644 --- a/sources/Perks/Enforcer/Skills/NiceSkillEnforcerBruteA.uc +++ b/sources/Perks/Enforcer/Skills/NiceSkillEnforcerBruteA.uc @@ -5,6 +5,7 @@ var string abilityID; var float coolDown; var float abilityDuration; var float damageMult; +var float maximumDamageAdded; function static SkillSelected(NicePlayerController nicePlayer) { @@ -29,6 +30,7 @@ function static SkillDeSelected(NicePlayerController nicePlayer) defaultproperties { + maximumDamageAdded=10000 abilityID="brute" cooldown=60.000000 abilityDuration=5.0 diff --git a/sources/Perks/NiceVeterancyTypes.uc b/sources/Perks/NiceVeterancyTypes.uc index 24560b4..418c6b1 100644 --- a/sources/Perks/NiceVeterancyTypes.uc +++ b/sources/Perks/NiceVeterancyTypes.uc @@ -219,8 +219,6 @@ static function int AddRegDamage(KFPlayerReplicationInfo KFPRI, KFMonster Injure } // Allows to buff only fire component of damage. static function int AddFireDamage(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, int InDamage, class DmgType){ - if(DmgType != none) - return InDamage * DmgType.default.heatPart; return InDamage; } static function float stunDurationMult(KFPlayerReplicationInfo KFPRI, KFMonster Injured, KFPawn DamageTaker, class DmgType){ diff --git a/sources/Weapons/BaseWeaponClasses/Heavy/NiceHeavyFire.uc b/sources/Weapons/BaseWeaponClasses/Heavy/NiceHeavyFire.uc index 9077bf8..59b48a3 100644 --- a/sources/Weapons/BaseWeaponClasses/Heavy/NiceHeavyFire.uc +++ b/sources/Weapons/BaseWeaponClasses/Heavy/NiceHeavyFire.uc @@ -2,5 +2,6 @@ class NiceHeavyFire extends NiceFire; defaultproperties { - maxBonusContLenght=3 + maxBonusContLenght = 3 + aimingSpreadReductionCoefficient = 0.0 } diff --git a/sources/Weapons/BaseWeaponClasses/Medic/NiceMedicGun.uc b/sources/Weapons/BaseWeaponClasses/Medic/NiceMedicGun.uc index 4f37338..f18064d 100644 --- a/sources/Weapons/BaseWeaponClasses/Medic/NiceMedicGun.uc +++ b/sources/Weapons/BaseWeaponClasses/Medic/NiceMedicGun.uc @@ -66,15 +66,19 @@ simulated function WeaponTick(float dt){ } super.WeaponTick(dt); } -simulated function ClientSuccessfulHeal(NiceHumanPawn healer, NiceHumanPawn healed){ - if(healed == none) - return; - if(instigator != none && PlayerController(instigator.controller) != none) - PlayerController(instigator.controller). - ClientMessage("You've healed"@healed.GetPlayerName(), 'CriticalEvent'); - if(NiceHumanPawn(instigator) != none && PlayerController(healed.controller) != none) - PlayerController(healed.controller). - ClientMessage("You've been healed by"@healer.GetPlayerName(), 'CriticalEvent'); + +simulated function ClientSuccessfulHeal( + NiceHumanPawn healer, + NiceHumanPawn healed +){ + if(healed == none) { + return; + } + if(instigator != none && PlayerController(instigator.controller) != none) { + PlayerController(instigator.controller).ClientMessage( + "You've healed" @ healed.GetPlayerName(), + 'CriticalEvent'); + } } defaultproperties diff --git a/sources/Weapons/BaseWeaponClasses/Melee/NiceMeleeFire.uc b/sources/Weapons/BaseWeaponClasses/Melee/NiceMeleeFire.uc index 23195ed..f4cfd8c 100644 --- a/sources/Weapons/BaseWeaponClasses/Melee/NiceMeleeFire.uc +++ b/sources/Weapons/BaseWeaponClasses/Melee/NiceMeleeFire.uc @@ -272,19 +272,19 @@ simulated function HandleRecoil(float Rec){} defaultproperties { - weaponRange=70.000000 - damageDelay=0.300000 - ImpactShakeRotMag=(X=50.000000,Y=50.000000,Z=50.000000) - ImpactShakeRotRate=(X=10000.000000,Y=10000.000000,Z=10000.000000) - ImpactShakeRotTime=2.000000 - ImpactShakeOffsetMag=(X=10.000000,Y=10.000000,Z=10.000000) - ImpactShakeOffsetRate=(X=1000.000000,Y=1000.000000,Z=1000.000000) - ImpactShakeOffsetTime=2.000000 - MeleeHitVolume=1.000000 - HitEffectClass=Class'KFMod.KFMeleeHitEffect' - WideDamageMinHitAngle=1.000000 - bFiringDoesntAffectMovement=True - FireEndAnim= - FireForce="ShockRifleFire" - aimerror=100.000000 + weaponRange=70.000000 + damageDelay=0.300000 + ImpactShakeRotMag=(X=50.000000,Y=50.000000,Z=50.000000) + ImpactShakeRotRate=(X=10000.000000,Y=10000.000000,Z=10000.000000) + ImpactShakeRotTime=2.000000 + ImpactShakeOffsetMag=(X=10.000000,Y=10.000000,Z=10.000000) + ImpactShakeOffsetRate=(X=1000.000000,Y=1000.000000,Z=1000.000000) + ImpactShakeOffsetTime=2.000000 + MeleeHitVolume=1.000000 + HitEffectClass=Class'KFMod.KFMeleeHitEffect' + WideDamageMinHitAngle=1.000000 + bFiringDoesntAffectMovement=True + FireEndAnim= + FireForce="ShockRifleFire" + aimerror=100.000000 } diff --git a/sources/Weapons/BaseWeaponClasses/NiceScopedWeapon.uc b/sources/Weapons/BaseWeaponClasses/NiceScopedWeapon.uc index b5c5e03..009bf41 100644 --- a/sources/Weapons/BaseWeaponClasses/NiceScopedWeapon.uc +++ b/sources/Weapons/BaseWeaponClasses/NiceScopedWeapon.uc @@ -3,7 +3,7 @@ class NiceScopedWeapon extends NiceWeapon #exec OBJ LOAD FILE=ScopeShaders.utx #exec OBJ LOAD FILE=..\Textures\NicePackT.utx #exec OBJ LOAD FILE=ScrnWeaponPack_T.utx -#exec OBJ LOAD FILE=ScrnWeaponPack_A.ukx +#exec OBJ LOAD FILE=ScrnWeaponPack_A.ukx var() Material ZoomMat; var() Sound ZoomSound; var() int lenseMaterialID; // used since material id's seem to change alot @@ -18,31 +18,47 @@ var Shader ScopeScriptedShader; // The shader that combi var Material ScriptedTextureFallback; // The texture to render if the users system doesn't support shaders // new scope vars var Combiner ScriptedScopeCombiner; -var texture TexturedScopeTexture; +var Material TexturedScopeTexture; var bool bInitializedScope; // Set to true when the scope has been initialized var string ZoomMatRef; var string ScriptedTextureFallbackRef; -var texture CrosshairTex; +var Material CrosshairTex; var string CrosshairTexRef; + +static function Material PreloadUnknownMaterial(string reference) { + local Material result; + + // Try to load as various types of materials + result = FinalBlend(DynamicLoadObject(reference, class'FinalBlend', true)); + if(result != none) { + return result; + } + result = Combiner(DynamicLoadObject(reference, class'Combiner', true)); + if(result != none) { + return result; + } + result = Shader(DynamicLoadObject(reference, class'Shader', true)); + if(result != none) { + return result; + } + result = Texture(DynamicLoadObject(reference, class'Texture', true)); + if(result != none) { + return result; + } + result = Material(DynamicLoadObject(reference, class'Material')); + return result; +} + static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount){ local NiceScopedWeapon W; super.PreloadAssets(Inv, bSkipRefCount); if(default.ZoomMat == none && default.ZoomMatRef != ""){ - // Try to load as various types of materials - default.ZoomMat = FinalBlend(DynamicLoadObject(default.ZoomMatRef, class'FinalBlend', true)); - if(default.ZoomMat == none) - default.ZoomMat = Combiner(DynamicLoadObject(default.ZoomMatRef, class'Combiner', true)); - if(default.ZoomMat == none) - default.ZoomMat = Shader(DynamicLoadObject(default.ZoomMatRef, class'Shader', true)); - if(default.ZoomMat == none) - default.ZoomMat = Texture(DynamicLoadObject(default.ZoomMatRef, class'Texture', true)); - if(default.ZoomMat == none) - default.ZoomMat = Material(DynamicLoadObject(default.ZoomMatRef, class'Material')); + default.ZoomMat = PreloadUnknownMaterial(default.ZoomMatRef); } if(default.ScriptedTextureFallback == none && default.ScriptedTextureFallbackRef != "") - default.ScriptedTextureFallback = texture(DynamicLoadObject(default.ScriptedTextureFallbackRef, class'texture')); + default.ScriptedTextureFallback = PreloadUnknownMaterial(default.ScriptedTextureFallbackRef); if(default.CrosshairTex == none && default.CrosshairTexRef != "") - default.CrosshairTex = Texture(DynamicLoadObject(default.CrosshairTexRef, class'texture')); + default.CrosshairTex = PreloadUnknownMaterial(default.CrosshairTexRef); W = NiceScopedWeapon(Inv); if(W != none){ W.ZoomMat = default.ZoomMat; diff --git a/sources/Weapons/BaseWeaponClasses/NiceWeaponDamageType.uc b/sources/Weapons/BaseWeaponClasses/NiceWeaponDamageType.uc index 62fc867..2afb911 100644 --- a/sources/Weapons/BaseWeaponClasses/NiceWeaponDamageType.uc +++ b/sources/Weapons/BaseWeaponClasses/NiceWeaponDamageType.uc @@ -14,6 +14,7 @@ var float prReqPrecise; // How precise must head-shot be var float lockonTime; var float flinchMultiplier; // How effective is weapon for flinching zeds var float stunMultiplier; // How effective is weapon for stunning zeds +var float stunLengthMultiplier; // For how long is weapon going to stun zeds var float heatPart; // How much of this damage should be a heat component? var float freezePower; // How good is weapon at freezing? var float bodyDestructionMult; // How much more damage do to body on a head-shot? @@ -27,6 +28,7 @@ var const int MediumZedMinHealth; // If zed's base Health >= this var float PenDmgReduction; // Penetration damage reduction after hitting small zed var float penDecapReduction; // Penetration decapitaion effectiveness reduction after hitting small zed var float penIncapReduction; // Penetration incapacitation (flinch or stun) effectiveness reduction after hitting small zed +var float stoppingPower; // How much stopping power the gun has - % amount zeds will be made to slow down when shot var bool bIsProjectile; // If original damage type's version was derived from 'KFProjectileWeaponDamageType', then set this to true // Scales exp gain according to given HardcoreLevel static function float getScale(int HL){ @@ -83,11 +85,13 @@ defaultproperties prReqPrecise=0.750000 flinchMultiplier=1.000000 stunMultiplier=1.000000 + stunLengthMultiplier=1.000000 bodyDestructionMult=1.000000 headSizeModifier=1.000000 BigZedPenDmgReduction=0.500000 BigZedMinHealth=1000 MediumZedPenDmgReduction=0.750000 + stoppingPower=0.0 MediumZedMinHealth=500 PenDmgReduction=0.700000 PawnDamageEmitter=None diff --git a/sources/Weapons/NiceBullet.uc b/sources/Weapons/NiceBullet.uc index 6a60342..216ee99 100644 --- a/sources/Weapons/NiceBullet.uc +++ b/sources/Weapons/NiceBullet.uc @@ -1,202 +1,209 @@ //====================================================================================================================== -// NicePack / NiceBullet +// NicePack / NiceBullet //====================================================================================================================== -// Bullet class that's supposed to take care of all damage-dealing projectile needs. -// Functionality: -// - Simulation of both linear and piece-wise motion -// - Collision detection that can be handled through the adapter class +// Bullet class that's supposed to take care of all damage-dealing projectile needs. +// Functionality: +// - Simulation of both linear and piece-wise motion +// - Collision detection that can be handled through the adapter class //====================================================================================================================== -// 'Nice pack' source -// Do whatever the fuck you want with it -// Author: dkanus -// E-mail: dkanus@gmail.com +// 'Nice pack' source +// Do whatever the fuck you want with it +// Author: dkanus +// E-mail: dkanus@gmail.com //====================================================================================================================== class NiceBullet extends Actor; -// Link to interaction with the server -var NiceReplicationInfo niceRI; -// Controller of our instigator -var NicePlayerController nicePlayer; -// Controller of local player -var NicePlayerController localPlayer; -// Link to our mutator -var NicePack niceMutator; +// Link to interaction with the server +var NiceReplicationInfo niceRI; +// Controller of our instigator +var NicePlayerController nicePlayer; +// Controller of local player +var NicePlayerController localPlayer; +// Link to our mutator +var NicePack niceMutator; //====================================================================================================================== -// Battle bullet characteristic -var float charOrigDamage; -var float charDamage; -var float decapMod; -var float incapMod; -var int charPenetrationCount; -var float charMomentumTransfer; +// Battle bullet characteristic +var float charOrigDamage; +var float charDamage; +var float decapMod; +var float incapMod; +var int charPenetrationCount; +var float charMomentumTransfer; var class charDamageType; var class charExplosionDamageType; -var float charExplosionDamage; -var float charExplosionRadius; -var float charExplosionExponent; -var float charExplosionMomentum; -var bool charIsDud; -var float charFuseTime; -var bool charExplodeOnFuse; -var bool charExplodeOnPawnHit; -var bool charExplodeOnWallHit; -var bool charAffectedByScream; -var float charMinExplosionDist; -var bool charWasHipFired; -var bool charCausePain; -var bool charIsSticky; -var float charContiniousBonus; -var bool bAlreadyHitZed; -var NiceWeapon sourceWeapon; -var NiceMonster lockonZed; -var float lockonTime; -var float bounceHeadMod; -var int insideBouncesLeft; -var bool bGrazing; +var float charExplosionDamage; +var float charExplosionRadius; +var float charExplosionExponent; +var float charExplosionMomentum; +var bool charIsDud; +var float charFuseTime; +var bool charExplodeOnFuse; +var bool charExplodeOnPawnHit; +var bool charExplodeOnWallHit; +var bool charAffectedByScream; +var float charMinExplosionDist; +var bool charWasHipFired; +var bool charCausePain; +var bool charIsSticky; +var float charContiniousBonus; +var bool bAlreadyHitZed; +var NiceWeapon sourceWeapon; +var NiceMonster lockonZed; +var float lockonTime; +var float bounceHeadMod; +var int insideBouncesLeft; +var bool bGrazing; //====================================================================================================================== -// Sticky projectile-related variables -var bool bStuck, bUseBone, bStuckToHead; -var name stuckBone; -var int stuckID; -// Data about explosive characteristics that must be transfered after projectile sticks on something +// Sticky projectile-related variables +var bool bStuck, bUseBone, bStuckToHead; +var name stuckBone; +var int stuckID; +// Data about explosive characteristics that must be transfered after projectile sticks on something struct ExplosionData{ - var Pawn instigator; - var NiceWeapon sourceWeapon; - var class bulletClass; + var Pawn instigator; + var NiceWeapon sourceWeapon; + var class bulletClass; var class explosionDamageType; - var float explosionDamage; - var float explosionRadius; - var float explosionExponent; - var float explosionMomentum; - var float fuseTime; - var bool explodeOnFuse; - var bool affectedByScream; - var bool stuckToHead; + var float explosionDamage; + var float explosionRadius; + var float explosionExponent; + var float explosionMomentum; + var float fuseTime; + var bool explodeOnFuse; + var bool affectedByScream; + var bool stuckToHead; }; //====================================================================================================================== -// Temporary variables that either need to be moved into config or generalized later -// How often trajectory is allowed to change direction? +// Temporary variables that either need to be moved into config or generalized later +// How often trajectory is allowed to change direction? var const float trajUpdFreq; -// How much tracing cycles to endure before declaring an infinite cycle? -var const int maxTraceCycles; -var bool bCanAngleDamage; +// How much tracing cycles to endure before declaring an infinite cycle? +var const int maxTraceCycles; +var bool bCanAngleDamage; //====================================================================================================================== -// State variables -// Indicates that all necessary values were recorded and we can process this bullet normally -var bool bInitFinished; -var bool bInitFinishDetected; -// Disables all the interaction of this bullet with the world and removes it / marks it for removal -var bool bBulletDead; -var bool bGhost; +// State variables +// Indicates that all necessary values were recorded and we can process this bullet normally +var bool bInitFinished; +var bool bInitFinishDetected; +// Disables all the interaction of this bullet with the world and removes it / marks it for removal +var bool bBulletDead; +var bool bGhost; //====================================================================================================================== -// Collision management -// Describes an actor that we don't wish to collide with +// Collision management +// Describes an actor that we don't wish to collide with struct IgnoreEntry{ - var Actor ignored; - // Set to true when 3rd party already disabled this actor before we had the chance - // Used to avoid re-enabling it later - var bool bExtDisabled; + var Actor ignored; + // Set to true when 3rd party already disabled this actor before we had the chance + // Used to avoid re-enabling it later + var bool bExtDisabled; }; -var array ignoredActors; -// 'true' if we're enforcing our collision rules on actors to ignore them -var bool bIgnoreIsActive; +var array ignoredActors; +// 'true' if we're enforcing our collision rules on actors to ignore them +var bool bIgnoreIsActive; //====================================================================================================================== -// Movement -// If 'true' disables any modifications to the bullet's movement, making it travel in a simple, linear path -var bool bDisableComplexMovement; -// Linear motion -var float movementSpeed; -var Vector movementDirection; -// Added vector acceleration -var Vector movementAcceleration; -var bool bShouldBounce; -// Amount of time our bullet should fall down after hitting a wall -var float movementFallTime; +// Movement +// If 'true' disables any modifications to the bullet's movement, making it travel in a simple, linear path +var bool bDisableComplexMovement; +// Linear motion +var float movementSpeed; +var Vector movementDirection; +// Added vector acceleration +var Vector movementAcceleration; +var bool bShouldBounce; +// Amount of time our bullet should fall down after hitting a wall +var float movementFallTime; //====================================================================================================================== -// Path building -// We will be building a piecewise linear path for projectiles, where each linear segment should be passable by -// projectile in time 'trajUpdFreq'. -// By changing trajectory in only preset point allow client to emulate non-linear paths, -// while keeping them more or less independent from the frame rate. -// Start and End point of the current linear segment +// Path building +// We will be building a piecewise linear path for projectiles, where each linear segment should be passable by +// projectile in time 'trajUpdFreq'. +// By changing trajectory in only preset point allow client to emulate non-linear paths, +// while keeping them more or less independent from the frame rate. +// Start and End point of the current linear segment var Vector pathSegmentS, pathSegmentE; -// Point in the segment, at which we've stopped after last movement +// Point in the segment, at which we've stopped after last movement var Vector shiftPoint; -// The part of current segment that we've already covered, changes from 0.0 to 1.0. -// Values above 1.0 indicate that segment was finished and we need to build another one. -// Values below 0.0 indicate that no segment has yet been built. +// The part of current segment that we've already covered, changes from 0.0 to 1.0. +// Values above 1.0 indicate that segment was finished and we need to build another one. +// Values below 0.0 indicate that no segment has yet been built. var float finishedSegmentPart; //====================================================================================================================== -// Visual effects -var class trailClass; +// Visual effects +var class trailClass; var class trailXClass; -var Emitter bulletTrail; -var xEmitter bulletXTrail; -// Describes effect that projectile should produce on hit -struct ImpactEffect{ - // Is this effect too important to cut it due to effect limit? - var bool bImportanEffect; - // Should we play classic KF's hit effect ('ROBulletHitEffect')? - var bool bPlayROEffect; - // Decal to spawn; null to skip - var class decalClass; - // Emitter to spawn; null to skip - var class emitterClass; - // How much back (against direction of the shot) should we spawn emitter? Can be used to avoid clipping with walls - var float emitterShiftWall; // Shift for wall-hits - var float emitterShiftPawn; // Shift for pawn-hits - // Impact noise parameters - var Sound noise; - var string noiseRef; // Reference to 'Sound' to allow dynamic resource allocation - var float noiseVolume; +var Emitter bulletTrail; +var xEmitter bulletXTrail; +// Describes effect that projectile should produce on hit +struct ImpactEffect { + // Is this effect too important to cut it due to effect limit? + var bool bImportanEffect; + // Should we play classic KF's hit effect ('ROBulletHitEffect')? + var bool bPlayROEffect; + // Decal to spawn; null to skip + var class decalClass; + // Emitter to spawn; null to skip + var class emitterClass; + // How much back (against direction of the shot) should we spawn emitter? Can be used to avoid clipping with walls + var float emitterShiftWall; // Shift for wall-hits + var float emitterShiftPawn; // Shift for pawn-hits + // Impact noise parameters + var Sound noise; + var string noiseRef; // Reference to 'Sound' to allow dynamic resource allocation + var float noiseVolume; }; -var ImpactEffect regularImpact; -var ImpactEffect explosionImpact; -var ImpactEffect disintegrationImpact; -var bool bGenRegEffectOnPawn; -var bool bShakeViewOnExplosion; -var Vector shakeRotMag; // how far to rot view -var Vector shakeRotRate; // how fast to rot view -var float shakeRotTime; // how much time to rot the instigator's view -var Vector shakeOffsetMag; // max view offset vertically -var Vector shakeOffsetRate; // how fast to offset view vertically -var float shakeOffsetTime; // how much time to offset view -var float shakeRadiusMult; +var ImpactEffect regularImpact; +var ImpactEffect explosionImpact; +var ImpactEffect disintegrationImpact; +var bool bGenRegEffectOnPawn; +var bool bShakeViewOnExplosion; +var Vector shakeRotMag; // how far to rot view +var Vector shakeRotRate; // how fast to rot view +var float shakeRotTime; // how much time to rot the instigator's view +var Vector shakeOffsetMag; // max view offset vertically +var Vector shakeOffsetRate; // how fast to offset view vertically +var float shakeOffsetTime; // how much time to offset view +var float shakeRadiusMult; //====================================================================================================================== -// References -// References to allow pre-loading of some resource objects, declared in parent classes +// References +// References to allow pre-loading of some resource objects, declared in parent classes var string meshRef; var string staticMeshRef; var string ambientSoundRef; //====================================================================================================================== -// Functions -static function PreloadAssets(){ - if(default.ambientSound == none && default.ambientSoundRef != "") - default.ambientSound = sound(DynamicLoadObject(default.ambientSoundRef, class'Sound', true)); - if(default.staticMesh == none && default.staticMeshRef != "") - UpdateDefaultStaticMesh(StaticMesh(DynamicLoadObject(default.staticMeshRef, class'StaticMesh', true))); - if(default.mesh == none && default.meshRef != "") - UpdateDefaultMesh(Mesh(DynamicLoadObject(default.meshRef, class'Mesh', true))); - if(default.regularImpact.noise == none && default.regularImpact.noiseRef != "") - default.regularImpact.noise = - sound(DynamicLoadObject(default.regularImpact.noiseRef, class'Sound', true)); - if(default.explosionImpact.noise == none && default.explosionImpact.noiseRef != "") - default.explosionImpact.noise = - sound(DynamicLoadObject(default.explosionImpact.noiseRef, class'Sound', true)); - if(default.disintegrationImpact.noise == none && default.disintegrationImpact.noiseRef != "") - default.disintegrationImpact.noise = - sound(DynamicLoadObject(default.disintegrationImpact.noiseRef, class'Sound', true)); +// Functions +static function PreloadAssets() { + if (default.ambientSound == none && default.ambientSoundRef != "") { + default.ambientSound = sound(DynamicLoadObject(default.ambientSoundRef, class'Sound', true)); + } + if (default.staticMesh == none && default.staticMeshRef != "") { + UpdateDefaultStaticMesh(StaticMesh(DynamicLoadObject(default.staticMeshRef, class'StaticMesh', true))); + } + if (default.mesh == none && default.meshRef != "") { + UpdateDefaultMesh(Mesh(DynamicLoadObject(default.meshRef, class'Mesh', true))); + } + if (default.regularImpact.noise == none && default.regularImpact.noiseRef != "") { + default.regularImpact.noise = + sound(DynamicLoadObject(default.regularImpact.noiseRef, class'Sound', true)); + } + if (default.explosionImpact.noise == none && default.explosionImpact.noiseRef != "") { + default.explosionImpact.noise = + sound(DynamicLoadObject(default.explosionImpact.noiseRef, class'Sound', true)); + } + if (default.disintegrationImpact.noise == none && default.disintegrationImpact.noiseRef != "") { + default.disintegrationImpact.noise = + sound(DynamicLoadObject(default.disintegrationImpact.noiseRef, class'Sound', true)); + } } -static function bool UnloadAssets(){ + +static function bool UnloadAssets() { default.AmbientSound = none; UpdateDefaultStaticMesh(none); UpdateDefaultMesh(none); @@ -205,400 +212,494 @@ static function bool UnloadAssets(){ default.disintegrationImpact.noise = none; return true; } -function PostBeginPlay(){ + +function PostBeginPlay() { super.PostBeginPlay(); - bounceHeadMod = 1.0; + bounceHeadMod = 1.0; } -function UpdateTrails(){ + +function UpdateTrails() { local Actor trailBase; + // Do nothing on dedicated server - if(Level.NetMode == NM_DedicatedServer) - return; + if (Level.NetMode == NM_DedicatedServer) { + return; + } // Spawn necessary trails first - if(trailClass != none && bulletTrail == none) - bulletTrail = Spawn(trailClass, self); - if(trailXClass != none && bulletXTrail == none) - bulletXTrail = Spawn(trailXClass, self); + if (trailClass != none && bulletTrail == none) { + bulletTrail = Spawn(trailClass, self); + } + if (trailXClass != none && bulletXTrail == none) { + bulletXTrail = Spawn(trailXClass, self); + } // Handle positioning differently for stuck and regular projectiles - if(bStuck && base != none){ - if(bUseBone){ - if(bulletTrail != none){ - bulletTrail.SetBase(base); - base.AttachToBone(bulletTrail, stuckBone); - bulletTrail.SetRelativeLocation(relativeLocation); - bulletTrail.SetRelativeRotation(relativeRotation); - } - if(bulletXTrail != none){ - bulletXTrail.SetBase(base); - base.AttachToBone(bulletTrail, stuckBone); - bulletXTrail.SetRelativeLocation(relativeLocation); - bulletXTrail.SetRelativeRotation(relativeRotation); - } - } + if (bStuck && base != none) { + if (bUseBone) { + if (bulletTrail != none) { + bulletTrail.SetBase(base); + base.AttachToBone(bulletTrail, stuckBone); + bulletTrail.SetRelativeLocation(relativeLocation); + bulletTrail.SetRelativeRotation(relativeRotation); + } + if (bulletXTrail != none) { + bulletXTrail.SetBase(base); + base.AttachToBone(bulletTrail, stuckBone); + bulletXTrail.SetRelativeLocation(relativeLocation); + bulletXTrail.SetRelativeRotation(relativeRotation); + } + } + } else { + trailBase = self; } - else - trailBase = self; + // Update lifetime and base (latter is for non-bone attachments only) - if(bulletTrail != none){ - if(trailBase != none) - bulletTrail.SetBase(trailBase); - bulletTrail.lifespan = lifeSpan; + if (bulletTrail != none) { + if (trailBase != none) { + bulletTrail.SetBase(trailBase); + } + bulletTrail.lifespan = lifeSpan; } - if(bulletXTrail != none){ - if(trailBase != none) - bulletXTrail.SetBase(trailBase); - bulletXTrail.lifespan = lifeSpan; + if (bulletXTrail != none) { + if (trailBase != none) { + bulletXTrail.SetBase(trailBase); + } + bulletXTrail.lifespan = lifeSpan; } } -function ResetPathBuilding(){ + +function ResetPathBuilding() { finishedSegmentPart = -1.0; shiftPoint = location; } -// Resets default values for this bullet. -// Must be called before each new use of a bullet. -function Renew(){ - bInitFinished = false; - bBulletDead = false; - bCanAngleDamage = true; - SoundVolume = default.SoundVolume; + +// Resets default values for this bullet. +// Must be called before each new use of a bullet. +function Renew() { + bInitFinished = false; + bBulletDead = false; + bCanAngleDamage = true; + SoundVolume = default.SoundVolume; decapMod = 1.0f; incapMod = 1.0f; ResetIgnoreList(); ResetPathBuilding(); } -simulated function Tick(float delta){ + +simulated function Tick(float delta) { super.Tick(delta); - if(localPlayer == none) - localPlayer = NicePlayerController(Level.GetLocalPlayerController()); - if(charFuseTime > 0){ - charFuseTime -= delta; - if(charFuseTime < 0){ - if(charExplodeOnFuse && !charIsDud){ - GenerateImpactEffects(explosionImpact, location, movementDirection); - if(bStuck) - class'NiceBulletAdapter'.static.Explode(self, niceRI, location, base); - else - class'NiceBulletAdapter'.static.Explode(self, niceRI, location); - } - if(!charExplodeOnFuse) - GenerateImpactEffects(disintegrationImpact, location, movementDirection); - KillBullet(); - } + + if (localPlayer == none) { + localPlayer = NicePlayerController(Level.GetLocalPlayerController()); } - if(bInitFinished && !bInitFinishDetected){ - bInitFinishDetected = true; - UpdateTrails(); + + if (charFuseTime > 0) { + charFuseTime -= delta; + if (charFuseTime < 0) { + if (charExplodeOnFuse && !charIsDud) { + GenerateImpactEffects(explosionImpact, location, movementDirection); + if (bStuck) { + class'NiceBulletAdapter'.static.Explode(self, niceRI, location, base); + } else { + class'NiceBulletAdapter'.static.Explode(self, niceRI, location); + } + } + if (!charExplodeOnFuse) { + GenerateImpactEffects(disintegrationImpact, location, movementDirection); + } + KillBullet(); + } } - if(bInitFinished && !bBulletDead && !bStuck) - DoProcessMovement(delta); - if(bInitFinished && bStuck){ - if(base == none || (KFMonster(base) != none && KFMonster(base).health <= 0)) - nicePlayer.ExplodeStuckBullet(stuckID); + + if (bInitFinished && !bInitFinishDetected) { + bInitFinishDetected = true; + UpdateTrails(); + } + if (bInitFinished && !bBulletDead && !bStuck) { + DoProcessMovement(delta); + } + if (bInitFinished && bStuck) { + if (base == none || (KFMonster(base) != none && KFMonster(base).health <= 0)) { + nicePlayer.ExplodeStuckBullet(stuckID); + } } } -// Extracts pawn actor from it's auxiliary collision -// @param other Actor we collided with -// @return Pawn we're interested in -function Actor GetMainActor(Actor other){ - if(other == none) - return none; - // Try owner - if( KFPawn(other) == none && KFMonster(other) == none - && (KFPawn(other.owner) != none || KFMonster(other.owner) != none) ) - other = other.owner; - // Try base - if( KFPawn(other) == none && KFMonster(other) == none - && (KFPawn(other.base) != none || KFMonster(other.base) != none) ) - other = other.base; + +// Extracts pawn actor from it's auxiliary collision +// @param other Actor we collided with +// @return Pawn we're interested in +function Actor GetMainActor(Actor other) { + if (other == none) { + return none; + } + + if (!other.IsA('KFPawn') && !other.IsA('KFMonster')) { + // Try owner + if (other.owner.IsA('KFPawn') || other.owner.IsA('KFMonster')) { + return other.owner; + } + // Try base + if (other.base.IsA('KFPawn') || other.base.IsA('KFMonster')) { + return other.base; + } + } + return other; } -// Returns 'true' if passed actor is either world geometry, 'Level' itself or nothing ('none') -// Neither of these related to pawn damage dealing -function bool IsLevelActor(Actor other){ - if(other == none) - return true; + +// Returns 'true' if passed actor is either world geometry, 'Level' itself or nothing ('none') +// Neither of these related to pawn damage dealing +function bool IsLevelActor(Actor other) { + if (other == none) { + return true; + } return (other.bWorldGeometry || other == Level); } -// Adds given actor and every colliding object connected to it to ignore list -// Removes their collision in case ignore is active (see 'bIgnoreIsActive') -function TotalIgnore(Actor other){ + +// Adds given actor and every colliding object connected to it to ignore list +// Removes their collision in case ignore is active (see 'bIgnoreIsActive') +function TotalIgnore(Actor other) { // These mark what objects, associated with 'other' we also need to ignore - local KFPawn pawnOther; + local KFPawn pawnOther; local KFMonster zedOther; - if(other == none) - return; + + if (other == none) { + return; + } // Try to find main actor as KFPawn pawnOther = KFPawn(other); - if(pawnOther == none) - pawnOther = KFPawn(other.base); - if(pawnOther == none) - pawnOther = KFPawn(other.owner); + if (pawnOther == none) { + pawnOther = KFPawn(other.base); + } + if (pawnOther == none) { + pawnOther = KFPawn(other.owner); + } // Try to find main actor as KFMonster zedOther = KFMonster(other); - if(zedOther == none) - zedOther = KFMonster(other.base); - if(zedOther == none) - zedOther = KFMonster(other.owner); + if (zedOther == none) { + zedOther = KFMonster(other.base); + } + if (zedOther == none) { + zedOther = KFMonster(other.owner); + } // Ignore everything that's associated with this actor and can have collision IgnoreActor(other); IgnoreActor(other.base); IgnoreActor(other.owner); - if(pawnOther != none) - IgnoreActor(pawnOther.AuxCollisionCylinder); - if(zedOther != none) - IgnoreActor(zedOther.MyExtCollision); -} -// Adds a given actor to ignore list and removes it's collision in case ignore is active (see 'bIgnoreIsActive') -function IgnoreActor(Actor other){ - local int i; - local IgnoreEntry newIgnoredEntry; - // Check if that's a non-level actor and not already on the list - if(IsLevelActor(other)) - return; - for(i = 0;i < ignoredActors.Length;i ++) - if(ignoredActors[i].ignored == other) - return; - // Add actor to the ignore list & disable collision if needed - if(other != none){ - // Make entry - newIgnoredEntry.ignored = other; - newIgnoredEntry.bExtDisabled = !other.bCollideActors; - // Add and activate it - ignoredActors[ignoredActors.Length] = newIgnoredEntry; - if(bIgnoreIsActive) - other.SetCollision(false); + if (pawnOther != none) { + IgnoreActor(pawnOther.AuxCollisionCylinder); + } + if (zedOther != none) { + IgnoreActor(zedOther.MyExtCollision); } } -// Restores ignored state of the actors and zeroes our ignored arrays -function ResetIgnoreList(){ + +// Adds a given actor to ignore list and removes it's collision in case ignore is active (see 'bIgnoreIsActive') +function IgnoreActor(Actor other) { + local int i; + local IgnoreEntry newIgnoredEntry; + + // Check if that's a non-level actor and not already on the list + if (IsLevelActor(other)) { + return; + } + for (i = 0; i < ignoredActors.Length; i ++) { + if (ignoredActors[i].ignored == other) { + return; + } + } + // Add actor to the ignore list & disable collision if needed + if (other != none) { + // Make entry + newIgnoredEntry.ignored = other; + newIgnoredEntry.bExtDisabled = !other.bCollideActors; + // Add and activate it + ignoredActors[ignoredActors.Length] = newIgnoredEntry; + if (bIgnoreIsActive) { + other.SetCollision(false); + } + } +} + +// Restores ignored state of the actors and zeroes our ignored arrays +function ResetIgnoreList() { SetIgnoreActive(false); ignoredActors.Length = 0; } -// Activates/deactivates ignore for actors on the ignore list. -// Ignore deactivation doesn't restore collision if actor was set to not collide prior most recent ignore activation. -// Activating ignore when it's already active does nothing; same with deactivation. -// Ignore deactivation is supposed to be used in the same function call in which activation took place before. -function SetIgnoreActive(bool bActive){ + +// Activates/deactivates ignore for actors on the ignore list. +// Ignore deactivation doesn't restore collision if actor was set to not collide prior most recent ignore activation. +// Activating ignore when it's already active does nothing; same with deactivation. +// Ignore deactivation is supposed to be used in the same function call in which activation took place before. +function SetIgnoreActive(bool bActive) { local int i; + // Do nothing if we're already in a correct state - if(bActive == bIgnoreIsActive) - return; + if (bActive == bIgnoreIsActive) { + return; + } // Change ignore state & disable collision for ignored actors bIgnoreIsActive = bActive; - for(i = 0;i < ignoredActors.Length;i ++) - if(ignoredActors[i].ignored != none){ - // Mark actors that were set to not collide before activation - if(bActive && !ignoredActors[i].ignored.bCollideActors) - ignoredActors[i].bExtDisabled = true; - // Change collision for actors that weren't externally modified - if(!ignoredActors[i].bExtDisabled) - ignoredActors[i].ignored.SetCollision(!bActive); - // After we deactivated our rules - forget about external modifications - if(!bActive) - ignoredActors[i].bExtDisabled = false; - } + for (i = 0; i < ignoredActors.Length; i ++) { + if (ignoredActors[i].ignored != none) { + // Mark actors that were set to not collide before activation + if (bActive && !ignoredActors[i].ignored.bCollideActors) { + ignoredActors[i].bExtDisabled = true; + } + // Change collision for actors that weren't externally modified + if (!ignoredActors[i].bExtDisabled) { + ignoredActors[i].ignored.SetCollision(!bActive); + } + // After we deactivated our rules - forget about external modifications + if (!bActive) { + ignoredActors[i].bExtDisabled = false; + } + } + } } -function SetHumanPawnCollision(bool bEnable){ + +function SetHumanPawnCollision(bool bEnable) { local int i; - if(niceMutator == none) - niceMutator = class'NicePack'.static.Myself(Level); - for(i = 0;i < niceMutator.recordedHumanPawns.Length;i ++) - if(niceMutator.recordedHumanPawns[i] != none) - niceMutator.recordedHumanPawns[i].bBlockHitPointTraces = bEnable; + + if (niceMutator == none) { + niceMutator = class'NicePack'.static.Myself(Level); + } + + for (i = 0; i < niceMutator.recordedHumanPawns.Length; i ++) { + if (niceMutator.recordedHumanPawns[i] != none) { + niceMutator.recordedHumanPawns[i].bBlockHitPointTraces = bEnable; + } + } } -function float CheckHeadshot(KFMonster kfZed, Vector hitLocation, Vector hitDirection){ - local float hsMod; - local float precision; - local bool bIsShotgunBullet; - local NiceMonster niceZed; - local KFPlayerReplicationInfo KFPRI; + +function float CheckHeadshot(KFMonster kfZed, Vector hitLocation, Vector hitDirection) { + local float hsMod; + local float precision; + local bool bIsShotgunBullet; + local NiceMonster niceZed; + local KFPlayerReplicationInfo KFPRI; local class niceVet; + niceZed = NiceMonster(kfZed); hitDirection = Normal(hitDirection); bIsShotgunBullet = ClassIsChildOf(charDamageType, class'NiceDamageTypeVetEnforcer'); - if(niceZed != none){ - hsMod = bounceHeadMod; // NICETODO: Add bounce and perk and damage type head-shot zones bonuses - hsMod *= charDamageType.default.headSizeModifier; - hsMod *= bounceHeadMod; - if(nicePlayer != none) - KFPRI = KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo); - if(KFPRI != none) - niceVet = class(KFPRI.ClientVeteranSkill); - if(niceVet != none) - hsMod *= niceVet.static.GetHeadshotCheckMultiplier(KFPRI, charDamageType); - precision = niceZed.IsHeadshotClient(hitLocation, hitDirection, niceZed.clientHeadshotScale * hsMod); - if(precision <= 0.0 && bIsShotgunBullet && nicePlayer != none && class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillSupportGraze')){ - bGrazing = true; - hsMod *= class'NiceSkillSupportGraze'.default.hsBonusZoneMult; - precision = niceZed.IsHeadshotClient(hitLocation, hitDirection, niceZed.clientHeadshotScale * hsMod); - } - return precision; - } - else{ - if(kfZed.IsHeadShot(hitLocation, hitDirection, 1.0)) - return 1.0; - else - return 0.0; + if (niceZed != none) { + hsMod = bounceHeadMod; // NICETODO: Add bounce and perk and damage type head-shot zones bonuses + hsMod *= charDamageType.default.headSizeModifier; + hsMod *= bounceHeadMod; + if (nicePlayer != none) { + KFPRI = KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo); + } + if (KFPRI != none) { + niceVet = class(KFPRI.ClientVeteranSkill); + } + if (niceVet != none) { + hsMod *= niceVet.static.GetHeadshotCheckMultiplier(KFPRI, charDamageType); + } + precision = niceZed.IsHeadshotClient(hitLocation, hitDirection, niceZed.clientHeadshotScale * hsMod); + if ( + precision <= 0.0 && + bIsShotgunBullet && + nicePlayer != none && + class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillSupportGraze') + ) { + bGrazing = true; + hsMod *= class'NiceSkillSupportGraze'.default.hsBonusZoneMult; + precision = niceZed.IsHeadshotClient(hitLocation, hitDirection, niceZed.clientHeadshotScale * hsMod); + } + return precision; + } else { + if (kfZed.IsHeadShot(hitLocation, hitDirection, 1.0)) { + return 1.0; + } else { + return 0.0; + } } } -// Makes bullet trace a directed line segment given by start and end points. -// All traced actors and geometry are then properly affected by corresponding 'HandleHitPawn', 'HandleHitZed' and -// 'HandleHitWall' functions. -// Might have to do several traces in case it either hits a (several) target(s) -function DoTraceLine(Vector lineStart, Vector lineEnd){ - local float headshotLevel; + +// Makes bullet trace a directed line segment given by start and end points. +// All traced actors and geometry are then properly affected by corresponding 'HandleHitPawn', 'HandleHitZed' and +// 'HandleHitWall' functions. +// Might have to do several traces in case it either hits a (several) target(s) +function DoTraceLine(Vector lineStart, Vector lineEnd) { + local float headshotLevel; // Amount of tracing iterations we had to do - local int iterationCount; + local int iterationCount; // Direction and length of traced line - local Vector lineDirection; + local Vector lineDirection; // Auxiliary variables for retrieving results of tracing - local Vector hitLocation, hitNormal; - local Actor tracedActor; - local array hitPoints; - local KFMonster tracedZed; - local KFPawn tracedPawn; + local Vector hitLocation, hitNormal; + local Actor tracedActor; + local array hitPoints; + local KFMonster tracedZed; + local KFPawn tracedPawn; + lineDirection = (lineEnd - lineStart); lineDirection = (lineDirection) / VSize(lineDirection); // Do not trace for disabled bullets and prevent infinite loops - while(!bBulletDead && iterationCount < maxTraceCycles){ - iterationCount ++; - // Trace next object - if(!bGhost || localPlayer == none || localPlayer.tracesThisTick <= localPlayer.tracesPerTickLimit){ - if(Instigator != none) - tracedActor = Instigator.Trace(hitLocation, hitNormal, lineEnd, lineStart, true); - else - tracedActor = none; - localPlayer.tracesThisTick ++; - } - else - tracedActor = none; - if(charAffectedByScream && !charIsDud && localPlayer != none && localPlayer.localCollisionManager != none && localPlayer.localCollisionManager.IsCollidingWithAnything(lineStart, lineEnd)) - HandleScream(lineStart, lineDirection); - if(tracedActor != none && IsLevelActor(tracedActor)){ - HandleHitWall(tracedActor, hitLocation, hitNormal); - break; - } - else{ - TotalIgnore(tracedActor); - tracedActor = GetMainActor(tracedActor); - } + while (!bBulletDead && iterationCount < maxTraceCycles) { + iterationCount++; + // Trace next object + if (!bGhost || localPlayer == none || localPlayer.tracesThisTick <= localPlayer.tracesPerTickLimit) { + if (Instigator != none) { + tracedActor = Instigator.Trace(hitLocation, hitNormal, lineEnd, lineStart, true); + } else { + tracedActor = none; + } + localPlayer.tracesThisTick++; + } else { + tracedActor = none; + } + if ( + charAffectedByScream && + !charIsDud && + localPlayer != none && + localPlayer.localCollisionManager != none && + localPlayer.localCollisionManager.IsCollidingWithAnything(lineStart, lineEnd) + ) { + HandleScream(lineStart, lineDirection); + } + if (tracedActor != none && IsLevelActor(tracedActor)) { + HandleHitWall(tracedActor, hitLocation, hitNormal); + break; + } else { + TotalIgnore(tracedActor); + tracedActor = GetMainActor(tracedActor); + } - // If tracing between current trace points haven't found anything and tracing step is less than segment's length - // -- shift tracing bounds - if(tracedActor == none) - return; + // If tracing between current trace points haven't found anything and tracing step is less than segment's length + // -- shift tracing bounds + if (tracedActor == none) { + return; + } - // First, try to handle pawn like a zed; if fails, - try to handle it like 'KFPawn' - tracedZed = KFMonster(tracedActor); - tracedPawn = KFPawn(tracedActor); - if(tracedPawn != none && NiceHumanPawn(instigator) != none && - (NiceHumanPawn(instigator).ffScale <= 0 && NiceMedicProjectile(self) == none) ) - continue; - if(tracedZed != none){ - if(tracedZed.Health > 0){ - headshotLevel = CheckHeadshot(tracedZed, hitLocation, lineDirection); - HandleHitZed(tracedZed, hitLocation, lineDirection, headshotLevel); - } - } - else if(tracedPawn != none && tracedPawn.Health > 0){ - if(tracedPawn.Health > 0) - HandleHitPawn(tracedPawn, hitLocation, lineDirection, hitPoints); - } - else - HandleHitWall(tracedActor, hitLocation, hitNormal); + // First, try to handle pawn like a zed; if fails, - try to handle it like 'KFPawn' + tracedZed = KFMonster(tracedActor); + tracedPawn = KFPawn(tracedActor); + if ( + tracedPawn != none && + NiceHumanPawn(instigator) != none && + (NiceHumanPawn(instigator).ffScale <= 0 && NiceMedicProjectile(self) == none) + ) { + continue; + } + if (tracedZed != none) { + if (tracedZed.Health > 0) { + headshotLevel = CheckHeadshot(tracedZed, hitLocation, lineDirection); + HandleHitZed(tracedZed, hitLocation, lineDirection, headshotLevel); + } + } else if (tracedPawn != none && tracedPawn.Health > 0) { + if (tracedPawn.Health > 0) { + HandleHitPawn(tracedPawn, hitLocation, lineDirection, hitPoints); + } + } else { + HandleHitWall(tracedActor, hitLocation, hitNormal); + } } } -// Replaces current path segment with the next one. -// Doesn't check whether or not we've finished with the current segment. -function BuildNextPathSegment(){ + +// Replaces current path segment with the next one. +// Doesn't check whether or not we've finished with the current segment. +function BuildNextPathSegment() { // Only set start point to our location when we build path segment for the first time // After that we can't even assume that bullet is exactly in the 'pathSegmentE' point - if(finishedSegmentPart < 0.0) - pathSegmentS = Location; - else - pathSegmentS = pathSegmentE; + if (finishedSegmentPart < 0.0) { + pathSegmentS = Location; + } else { + pathSegmentS = pathSegmentE; + } movementDirection += (movementAcceleration * trajUpdFreq) / movementSpeed; pathSegmentE = pathSegmentS + movementDirection * movementSpeed * trajUpdFreq; finishedSegmentPart = 0.0; shiftPoint = pathSegmentS; } -// Updates 'shiftPoint' to the next bullet position in current segment. -// Does nothing if current segment is finished or no segment was built at all. -// @param delta Amount of time bullet has to move through the segment. -// @return Amount of time left for bullet to move after this segment -function float ShiftInSegment(float delta){ + +// Updates 'shiftPoint' to the next bullet position in current segment. +// Does nothing if current segment is finished or no segment was built at all. +// @param delta Amount of time bullet has to move through the segment. +// @return Amount of time left for bullet to move after this segment +function float ShiftInSegment(float delta) { // Time that bullet still has available to move after this segment local float remainingTime; // Part of segment we can pass in a given time local float segmentPartWeCanPass; + // Exit if there's no segment in progress - if(finishedSegmentPart < 0.0 || finishedSegmentPart > 1.0) - return delta; + if (finishedSegmentPart < 0.0 || finishedSegmentPart > 1.0) { + return delta; + } // [movementSpeed * delta] / [movementSpeed * trajUpdFreq] = [delta / trajUpdFreq] segmentPartWeCanPass = delta / trajUpdFreq; // If we can move through the rest of the segment - move to end point and mark it finished - if(segmentPartWeCanPass >= (1.0 - finishedSegmentPart)){ - remainingTime = delta - (1.0 - finishedSegmentPart) * trajUpdFreq; - finishedSegmentPart = 1.1; - shiftPoint = pathSegmentE; - } - // Otherwise compute new 'shiftPoint' normally - else{ - remainingTime = 0.0; - finishedSegmentPart += (delta / trajUpdFreq); - shiftPoint = pathSegmentS + movementDirection * movementSpeed * trajUpdFreq * finishedSegmentPart; + if (segmentPartWeCanPass >= (1.0 - finishedSegmentPart)) { + remainingTime = delta - (1.0 - finishedSegmentPart) * trajUpdFreq; + finishedSegmentPart = 1.1; + shiftPoint = pathSegmentE; + } else { + // Otherwise compute new 'shiftPoint' normally + remainingTime = 0.0; + finishedSegmentPart += (delta / trajUpdFreq); + shiftPoint = pathSegmentS + movementDirection * movementSpeed * trajUpdFreq * finishedSegmentPart; } return remainingTime; } -// Moves bullet according to settings and decides when and how much tracing should it do. -// @param delta Amount of time passed after previous bullet movement -function DoProcessMovement(float delta){ - local Vector tempVect; + +// Moves bullet according to settings and decides when and how much tracing should it do. +// @param delta Amount of time passed after previous bullet movement +function DoProcessMovement(float delta) { + local Vector tempVect; + SetIgnoreActive(true); //SetHumanPawnCollision(true); - // Simple linear movement - if(bDisableComplexMovement){ - // Use 'traceStart' as a shift variable here - // Naming is bad in this case, but it avoids - tempVect = movementDirection * movementSpeed * delta; - DoTraceLine(location, location + tempVect); - Move(tempVect); - // Reset path building - // If in future complex movement would be re-enabled, - we want to set first point of the path to - // the location of bullet at a time and not use outdated information. - finishedSegmentPart = -1.0; - } - // Non-linear movement support - else{ - while(delta > 0.0){ - if(finishedSegmentPart < 0.0 || finishedSegmentPart > 1.0) - BuildNextPathSegment(); - // Remember current 'shiftPoint'. That's where we stopped tracing last time and where we must resume. - tempVect = shiftPoint; - // Update 'shiftPoint' (bullet position) - // and update how much time we've got left after we wasted some to move. - delta = ShiftInSegment(delta); - // Trace between end point of previous tracing and end point of the new one. - DoTraceLine(tempVect, shiftPoint); - } - tempVect = shiftPoint - location; - Move(shiftPoint - location); + // Simple linear movement + if (bDisableComplexMovement) { + // Use 'traceStart' as a shift variable here + // Naming is bad in this case, but it avoids + tempVect = movementDirection * movementSpeed * delta; + DoTraceLine(location, location + tempVect); + Move(tempVect); + // Reset path building + // If in future complex movement would be re-enabled, - we want to set first point of the path to + // the location of bullet at a time and not use outdated information. + finishedSegmentPart = -1.0; + } else { + // Non-linear movement support + while(delta > 0.0) { + if (finishedSegmentPart < 0.0 || finishedSegmentPart > 1.0) { + BuildNextPathSegment(); + } + // Remember current 'shiftPoint'. That's where we stopped tracing last time and where we must resume. + tempVect = shiftPoint; + // Update 'shiftPoint' (bullet position) + // and update how much time we've got left after we wasted some to move. + delta = ShiftInSegment(delta); + // Trace between end point of previous tracing and end point of the new one. + DoTraceLine(tempVect, shiftPoint); + } + tempVect = shiftPoint - location; + Move(shiftPoint - location); } SetRotation(Rotator(movementDirection)); - if(charMinExplosionDist > 0) - charMinExplosionDist -= VSize(tempVect); + if (charMinExplosionDist > 0) { + charMinExplosionDist -= VSize(tempVect); + } SetIgnoreActive(false); - //SetHumanPawnCollision(false); + // SetHumanPawnCollision(false); } -function Stick(Actor target, Vector hitLocation){ - local NiceMonster targetZed; - local name boneStick; - local float distToBone; - local float t; - local Vector boneStrickOrig; + +function Stick(Actor target, Vector hitLocation) { + local Vector boneStrickOrig; local ExplosionData expData; - if(bGhost) - return; + local Actor resultTarget; + local NiceMonster targetZed; + local name boneStick; + local float distToBone, t; + + if (bGhost) { + return; + } + expData.instigator = instigator; + expData.sourceWeapon = sourceWeapon; + expData.bulletClass = class; expData.explosionDamageType = charExplosionDamageType; expData.explosionDamage = charExplosionDamage; expData.explosionRadius = charExplosionRadius; @@ -607,238 +708,310 @@ function Stick(Actor target, Vector hitLocation){ expData.fuseTime = charFuseTime; expData.explodeOnFuse = charExplodeOnFuse; expData.affectedByScream = charAffectedByScream; - expData.sourceWeapon = sourceWeapon; - targetZed = NiceMonster(target); - if(targetZed == none){ - expData.bulletClass = class; - expData.instigator = instigator; - niceRI.ServerStickProjectile(KFHumanPawn(instigator), target, 'None', hitLocation - target.location, - Rotator(movementDirection), expData); - class'NiceProjectileSpawner'.static.StickProjectile(KFHumanPawn(instigator), target, 'None', - hitLocation - target.location, Rotator(movementDirection), expData); + + if (!target.IsA('NiceMonster')) { + hitLocation = (hitLocation - target.location) << target.rotation; + boneStick = 'None'; + resultTarget = target; + } else { + targetZed = NiceMonster(target); + boneStick = targetZed.GetClosestBone(hitLocation, movementDirection, distToBone); + if (CheckHeadshot(targetZed, hitLocation, movementDirection) > 0.0) { + boneStick = targetZed.HeadBone; + } + if (boneStick == targetZed.HeadBone) { + expData.stuckToHead = true; + } + boneStrickOrig = targetZed.GetBoneCoords(boneStick).origin; + t = movementDirection.x * (boneStrickOrig.x - hitLocation.x) + + movementDirection.y * (boneStrickOrig.y - hitLocation.y) + + movementDirection.z * (boneStrickOrig.z - hitLocation.z); + t /= VSizeSquared(movementDirection); + t *= 0.5; + hitLocation = hitLocation + t * movementDirection; + hitLocation -= boneStrickOrig; + resultTarget = targetZed; } - else{ - expData.bulletClass = class; - expData.instigator = instigator; - boneStick = targetZed.GetClosestBone(hitLocation, movementDirection, distToBone); - if(CheckHeadshot(targetZed, hitLocation, movementDirection) > 0.0) - boneStick = targetZed.HeadBone; - if(boneStick == targetZed.HeadBone) - expData.stuckToHead = true; - boneStrickOrig = targetZed.GetBoneCoords(boneStick).origin; - t = movementDirection.x * (boneStrickOrig.x - hitLocation.x) + - movementDirection.y * (boneStrickOrig.y - hitLocation.y) + - movementDirection.z * (boneStrickOrig.z - hitLocation.z); - t /= VSizeSquared(movementDirection); - t *= 0.5; - hitLocation = hitLocation + t * movementDirection; - niceRI.ServerStickProjectile(KFHumanPawn(instigator), targetZed, boneStick, - hitLocation - boneStrickOrig, Rotator(movementDirection), expData); - class'NiceProjectileSpawner'.static.StickProjectile(KFHumanPawn(instigator), targetZed, boneStick, - hitLocation - boneStrickOrig, Rotator(movementDirection), expData); - } - KillBullet(); -} -function DoExplode(Vector explLocation, Vector impactNormal){ - if(charIsDud) - return; - if(bStuck) - class'NiceBulletAdapter'.static.Explode(self, niceRI, explLocation, base); - else - class'NiceBulletAdapter'.static.Explode(self, niceRI, explLocation); - GenerateImpactEffects(explosionImpact, explLocation, impactNormal, true, true); - if(bShakeViewOnExplosion) - ShakeView(explLocation); - KillBullet(); -} -function HandleHitWall(Actor wall, Vector hitLocation, Vector hitNormal){ - local bool bBulletTooWeak; - if(charExplodeOnWallHit && !charIsDud && charMinExplosionDist <= 0.0){ - DoExplode(hitLocation, hitNormal); - return; - } - else{ - class'NiceBulletAdapter'.static.HitWall(self, niceRI, wall, hitLocation, hitNormal); - GenerateImpactEffects(regularImpact, hitLocation, hitNormal, true, true); - if(charIsSticky) - Stick(wall, hitLocation); - } - if(bShouldBounce && !bDisableComplexMovement){ - movementDirection = (movementDirection - 2.0 * hitNormal * (movementDirection dot hitNormal)); - bBulletTooWeak = !class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, none, false, false); - charPenetrationCount += 1; - ResetPathBuilding(); - ResetIgnoreList(); - bounceHeadMod *= 2; - } - else if(movementFallTime > 0.0){ - charIsDud = true; - lifeSpan = movementFallTime; - movementFallTime = 0.0; - movementDirection = vect(0,0,0); - ResetPathBuilding(); - ResetIgnoreList(); - } - else - bBulletTooWeak = true; - if(bBulletTooWeak) - KillBullet(); -} -function HandleHitPawn(KFPawn hitPawn, Vector hitLocation, Vector hitDirection, array hitPoints){ - if(charExplodeOnPawnHit && !charIsDud && charMinExplosionDist <= 0.0){ - DoExplode(hitLocation, hitDirection); - GenerateImpactEffects(explosionImpact, hitLocation, hitDirection); - return; - } - else{ - class'NiceBulletAdapter'.static.HitPawn(self, niceRI, hitPawn, hitLocation, hitDirection, hitPoints); - if(bGenRegEffectOnPawn) - GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false); - } - if(!class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, none, false, false)){ - charPenetrationCount += 1; - KillBullet(); - } -} -function HandleHitZed(KFMonster targetZed, Vector hitLocation, Vector hitDirection, float headshotLevel){ - local bool bHitZedCalled; - if(class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillDemoDirectApproach')){ - class'NiceBulletAdapter'.static.HitZed(self, niceRI, targetZed, hitLocation, hitDirection, headshotLevel); - if(bGenRegEffectOnPawn) - GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false); - bHitZedCalled = true; - } - if(charExplodeOnPawnHit && !charIsDud && charMinExplosionDist <= 0.0){ - class'NiceBulletAdapter'.static.Explode(self, niceRI, hitLocation, targetZed); - GenerateImpactEffects(explosionImpact, hitLocation, hitDirection); - if(bShakeViewOnExplosion) - ShakeView(hitLocation); - KillBullet(); - return; - } - else{ - if(!bHitZedCalled){ - class'NiceBulletAdapter'.static.HitZed(self, niceRI, targetZed, hitLocation, hitDirection, headshotLevel); - if(bGenRegEffectOnPawn) - GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false); - } - bHitZedCalled = true; - if(!bGhost && !bAlreadyHitZed){ - bAlreadyHitZed = true; - if(nicePlayer != none && niceRI != none) - niceRI.ServerJunkieExtension(nicePlayer, headshotLevel > 0.0); - } - if(charIsSticky) - Stick(targetZed, hitLocation); - } - if(!class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, targetZed, (headshotLevel > 0.0), (headshotLevel > charDamageType.default.prReqPrecise))){ - charPenetrationCount += 1; - KillBullet(); - } -} -function HandleScream(Vector disintegrationLocation, Vector entryDirection){ - if(!charIsDud) - GenerateImpactEffects(disintegrationImpact, disintegrationLocation, entryDirection); - class'NiceBulletAdapter'.static.HandleScream(self, niceRI, disintegrationLocation, entryDirection); -} -function GenerateImpactEffects(ImpactEffect effect, Vector hitLocation, Vector hitNormal, - optional bool bWallImpact, optional bool bGenerateDecal){ - local float actualCullDistance; - local float actualImpactShift; - local bool generatedEffect; - // No need to play visuals on a server, for a dead bullets or in case there's no local player at all - if(Level.NetMode == NM_DedicatedServer || bBulletDead || localPlayer == none) - return; - if(!localPlayer.CanSpawnEffect(bGhost) && !effect.bImportanEffect) - return; - // -- Classic effect - if(effect.bPlayROEffect && !bBulletDead) - Spawn(class'ROBulletHitEffect',,, hitLocation, rotator(-hitNormal)); - // -- Generate decal - if(bGenerateDecal && effect.decalClass != none){ - // Find appropriate cull distance for this decal - actualCullDistance = effect.decalClass.default.cullDistance; - // Double cull distance if local player is an instigator - if(instigator != none && localPlayer == instigator.Controller) - actualCullDistance *= 2; // NICETODO: magic number - // Spawn decal - if(!localPlayer.BeyondViewDistance(hitLocation, actualCullDistance)){ - Spawn(effect.decalClass, self,, hitLocation, rotator(- hitNormal)); - generatedEffect = true; - } - } - // -- Generate custom effect - if(effect.emitterClass != none && EffectIsRelevant(hitLocation, false)){ - if(bWallImpact) - actualImpactShift = effect.emitterShiftWall; - else - actualImpactShift = effect.emitterShiftPawn; - Spawn(effect.emitterClass,,, hitLocation - movementDirection * actualImpactShift, rotator(movementDirection)); - generatedEffect = true; - } - // -- Generate custom sound - if(effect.noise != none){ - class'NiceSoundCls'.default.effectSound = effect.noise; - class'NiceSoundCls'.default.effectVolume = effect.noiseVolume; - Spawn(class'NiceSoundCls',,, hitLocation); - generatedEffect = true; - } - if(generatedEffect) - localPlayer.AddEffect(); -} -function ShakeView(Vector hitLocation){ - local float distance, scale; - if(nicePlayer == none || shakeRadiusMult < 0.0) - return; - distance = VSize(hitLocation - nicePlayer.ViewTarget.Location); - if(distance < charExplosionRadius * shakeRadiusMult){ - if(distance < charExplosionRadius) - scale = 1.0; - else - scale = (charExplosionRadius * ShakeRadiusMult - distance) / (charExplosionRadius); - nicePlayer.ShakeView(shakeRotMag*scale, shakeRotRate, shakeRotTime, shakeOffsetMag * scale, shakeOffsetRate, shakeOffsetTime); - } -} -function KillBullet(){ - local int i; - if(bulletTrail != none){ - for(i = 0;i < bulletTrail.Emitters.Length;i ++){ - if(bulletTrail.Emitters[i] == none) - continue; - bulletTrail.Emitters[i].ParticlesPerSecond = 0; - bulletTrail.Emitters[i].InitialParticlesPerSecond = 0; - bulletTrail.Emitters[i].RespawnDeadParticles = false; - } - bulletTrail.SetBase(none); - bulletTrail.AutoDestroy = true; - } - if(bulletXTrail != none){ - bulletXTrail.mRegen = false; - bulletXTrail.LifeSpan = LifeSpan; - } - bBulletDead = true; - bHidden = true; - SoundVolume = 0; - LifeSpan = FMin(LifeSpan, 0.1); -} -event Destroyed(){ + + niceRI.ServerStickProjectile( + KFHumanPawn(instigator), + resultTarget, + boneStick, + hitLocation, + Rotator(movementDirection), + expData + ); + class'NiceProjectileSpawner'.static.StickProjectile( + KFHumanPawn(instigator), + resultTarget, + boneStick, + hitLocation, + Rotator(movementDirection), + expData + ); + KillBullet(); } -defaultproperties -{ - insideBouncesLeft=2 - trajUpdFreq=0.100000 - maxTraceCycles=128 - bDisableComplexMovement=True - trailXClass=Class'KFMod.KFTracer' - regularImpact=(bPlayROEffect=True) - StaticMeshRef="kf_generic_sm.Shotgun_Pellet" - DrawType=DT_StaticMesh - bAcceptsProjectors=False - LifeSpan=15.000000 - Texture=Texture'Engine.S_Camera' - bGameRelevant=True - bCanBeDamaged=True - SoundVolume=255 +function DoExplode(Vector explLocation, Vector impactNormal) { + if (charIsDud) { + return; + } + if (bStuck) { + class'NiceBulletAdapter'.static.Explode(self, niceRI, explLocation, base); + } else { + class'NiceBulletAdapter'.static.Explode(self, niceRI, explLocation); + } + GenerateImpactEffects(explosionImpact, explLocation, impactNormal, true, true); + if (bShakeViewOnExplosion) { + ShakeView(explLocation); + } + KillBullet(); } + +function HandleHitWall(Actor wall, Vector hitLocation, Vector hitNormal) { + local bool bBulletTooWeak; + + if (charExplodeOnWallHit && !charIsDud && charMinExplosionDist <= 0.0) { + DoExplode(hitLocation, hitNormal); + return; + } else { + class'NiceBulletAdapter'.static.HitWall(self, niceRI, wall, hitLocation, hitNormal); + GenerateImpactEffects(regularImpact, hitLocation, hitNormal, true, true); + if (charIsSticky) { + Stick(wall, hitLocation); + } + } + + if (bShouldBounce && !bDisableComplexMovement) { + movementDirection = (movementDirection - 2.0 * hitNormal * (movementDirection dot hitNormal)); + bBulletTooWeak = !class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, none, false, false); + charPenetrationCount += 1; + ResetPathBuilding(); + ResetIgnoreList(); + bounceHeadMod *= 2; + } else if (movementFallTime > 0.0) { + charIsDud = true; + lifeSpan = movementFallTime; + movementFallTime = 0.0; + movementDirection = vect(0, 0, 0); + ResetPathBuilding(); + ResetIgnoreList(); + } else { + bBulletTooWeak = true; + } + + if (bBulletTooWeak) { + KillBullet(); + } +} + +function HandleHitPawn(KFPawn hitPawn, Vector hitLocation, Vector hitDirection, array hitPoints) { + if (charExplodeOnPawnHit && !charIsDud && charMinExplosionDist <= 0.0) { + DoExplode(hitLocation, hitDirection); + GenerateImpactEffects(explosionImpact, hitLocation, hitDirection); + return; + } else { + class'NiceBulletAdapter'.static.HitPawn(self, niceRI, hitPawn, hitLocation, hitDirection, hitPoints); + if (bGenRegEffectOnPawn) { + GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false); + } + } + if (!class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, none, false, false)) { + charPenetrationCount += 1; + KillBullet(); + } +} + +function HandleHitZed(KFMonster targetZed, Vector hitLocation, Vector hitDirection, float headshotLevel) { + local bool bHitZedCalled; + + if (class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillDemoDirectApproach')) { + class'NiceBulletAdapter'.static.HitZed(self, niceRI, targetZed, hitLocation, hitDirection, headshotLevel); + if (bGenRegEffectOnPawn) { + GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false); + } + bHitZedCalled = true; + } + + if (charExplodeOnPawnHit && !charIsDud && charMinExplosionDist <= 0.0) { + class'NiceBulletAdapter'.static.Explode(self, niceRI, hitLocation, targetZed); + GenerateImpactEffects(explosionImpact, hitLocation, hitDirection); + if (bShakeViewOnExplosion) { + ShakeView(hitLocation); + } + KillBullet(); + return; + } else { + if (!bHitZedCalled) { + class'NiceBulletAdapter'.static.HitZed( + self, + niceRI, + targetZed, + hitLocation, + hitDirection, + headshotLevel + ); + if (bGenRegEffectOnPawn) { + GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false); + } + } + bHitZedCalled = true; + if (!bGhost && !bAlreadyHitZed) { + bAlreadyHitZed = true; + if (nicePlayer != none && niceRI != none) { + niceRI.ServerJunkieExtension(nicePlayer, headshotLevel > 0.0); + } + } + if (charIsSticky) { + Stick(targetZed, hitLocation); + } + } + if (!class'NiceBulletAdapter'.static.ZedPenetration( + charDamage, + self, + targetZed, + (headshotLevel > 0.0), + (headshotLevel > charDamageType.default.prReqPrecise) + ) + ) { + charPenetrationCount += 1; + KillBullet(); + } +} + +function HandleScream(Vector disintegrationLocation, Vector entryDirection) { + if (!charIsDud) { + GenerateImpactEffects(disintegrationImpact, disintegrationLocation, entryDirection); + } + class'NiceBulletAdapter'.static.HandleScream(self, niceRI, disintegrationLocation, entryDirection); +} + +function GenerateImpactEffects( + ImpactEffect effect, + Vector hitLocation, + Vector hitNormal, + optional bool bWallImpact, + optional bool bGenerateDecal +) { + local float actualCullDistance; + local float actualImpactShift; + local bool generatedEffect; + + // No need to play visuals on a server, for a dead bullets or in case there's no local player at all + if (Level.NetMode == NM_DedicatedServer || bBulletDead || localPlayer == none) { + return; + } + if (!localPlayer.CanSpawnEffect(bGhost) && !effect.bImportanEffect) { + return; + } + // -- Classic effect + if (effect.bPlayROEffect && !bBulletDead) { + Spawn(class'ROBulletHitEffect',,, hitLocation, rotator(-hitNormal)); + } + // -- Generate decal + if (bGenerateDecal && effect.decalClass != none) { + // Find appropriate cull distance for this decal + actualCullDistance = effect.decalClass.default.cullDistance; + // Double cull distance if local player is an instigator + if (instigator != none && localPlayer == instigator.Controller) { + actualCullDistance *= 2; // NICETODO: magic number + } + // Spawn decal + if (!localPlayer.BeyondViewDistance(hitLocation, actualCullDistance)) { + Spawn(effect.decalClass, self,, hitLocation, rotator(- hitNormal)); + generatedEffect = true; + } + } + // -- Generate custom effect + if (effect.emitterClass != none && EffectIsRelevant(hitLocation, false)) { + if (bWallImpact) { + actualImpactShift = effect.emitterShiftWall; + } else { + actualImpactShift = effect.emitterShiftPawn; + } + Spawn(effect.emitterClass,,, hitLocation - movementDirection * actualImpactShift, rotator(movementDirection)); + generatedEffect = true; + } + // -- Generate custom sound + if (effect.noise != none) { + class'NiceSoundCls'.default.effectSound = effect.noise; + class'NiceSoundCls'.default.effectVolume = effect.noiseVolume; + Spawn(class'NiceSoundCls',,, hitLocation); + generatedEffect = true; + } + if (generatedEffect) { + localPlayer.AddEffect(); + } +} + +function ShakeView(Vector hitLocation) { + local float distance, scale; + + if (nicePlayer == none || shakeRadiusMult < 0.0) { + return; + } + distance = VSize(hitLocation - nicePlayer.ViewTarget.Location); + if (distance < charExplosionRadius * shakeRadiusMult) { + if (distance < charExplosionRadius) { + scale = 1.0; + } else { + scale = (charExplosionRadius * ShakeRadiusMult - distance) / (charExplosionRadius); + } + nicePlayer.ShakeView( + shakeRotMag * scale, + shakeRotRate, + shakeRotTime, + shakeOffsetMag * scale, + shakeOffsetRate, + shakeOffsetTime + ); + } +} + +function KillBullet() { + local int i; + + if (bulletTrail != none) { + for (i = 0; i < bulletTrail.Emitters.Length; i ++) { + if (bulletTrail.Emitters[i] == none) { + continue; + } + bulletTrail.Emitters[i].ParticlesPerSecond = 0; + bulletTrail.Emitters[i].InitialParticlesPerSecond = 0; + bulletTrail.Emitters[i].RespawnDeadParticles = false; + } + bulletTrail.SetBase(none); + bulletTrail.AutoDestroy = true; + } + + if (bulletXTrail != none) { + bulletXTrail.mRegen = false; + bulletXTrail.LifeSpan = LifeSpan; + } + bBulletDead = true; + bHidden = true; + SoundVolume = 0; + LifeSpan = FMin(LifeSpan, 0.1); +} + +event Destroyed() { + KillBullet(); +} + +defaultproperties { + insideBouncesLeft=2 + trajUpdFreq=0.100000 + maxTraceCycles=128 + bDisableComplexMovement=True + trailXClass=Class'KFMod.KFTracer' + regularImpact=(bPlayROEffect=True) + StaticMeshRef="kf_generic_sm.Shotgun_Pellet" + DrawType=DT_StaticMesh + bAcceptsProjectors=False + LifeSpan=15.000000 + Texture=Texture'Engine.S_Camera' + bGameRelevant=True + bCanBeDamaged=True + SoundVolume=255 +} \ No newline at end of file diff --git a/sources/Weapons/NiceBulletAdapter.uc b/sources/Weapons/NiceBulletAdapter.uc index 1ab2f91..beb7401 100644 --- a/sources/Weapons/NiceBulletAdapter.uc +++ b/sources/Weapons/NiceBulletAdapter.uc @@ -9,57 +9,132 @@ // 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, true, - explosionTarget, Vector(bullet.Rotation)); - 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); + +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) return; - if(nicePawn.currentCalibrationState != CALSTATE_ACTIVE) return; + +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){ + +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 --; + 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){ + +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){ + +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); + 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){ + +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; @@ -68,74 +143,113 @@ static function HitZed(NiceBullet bullet, NiceReplicationInfo niceRI, KFMonster 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)) { + 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.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 + ); } - 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); + 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); + 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){ + +static function bool ZedPenetration( + out float Damage, + NiceBullet bullet, + KFMonster targetZed, + bool bIsHeadshot, + bool bIsPreciseHeadshot +) { local float reductionMod; local NiceMonster niceZed; local NicePlayerController nicePlayer; @@ -144,52 +258,74 @@ static function bool ZedPenetration(out float Damage, NiceBullet bullet, KFMonst 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)); + 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 + 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); - } + } + 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; + 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 -} +defaultproperties { + BigZedMinHealth=1000 + MediumZedMinHealth=500 +} \ No newline at end of file diff --git a/sources/Weapons/NiceFire.uc b/sources/Weapons/NiceFire.uc index a752d16..969d8ec 100644 --- a/sources/Weapons/NiceFire.uc +++ b/sources/Weapons/NiceFire.uc @@ -20,6 +20,7 @@ var() bool bSemiMustBurst; var() int MaxBurstLength; var() int burstShotsMade; var bool bResetRecoil; // Set this flag to 'true' to disable recoil for the next shot; flag will be automatically reset to 'false' after that +var float aimingSpreadReductionCoefficient; var bool zoomOutOnShot; var bool bShouldBounce; var bool bCausePain; @@ -38,6 +39,10 @@ var bool projAffectedByScream; var bool bShouldStick; var int resetTicks; var float niceNextFireTime; +var float minimalSpreadScale; +var float activeSpreadScale; +var float spreadGainedPerShot; +var float spreadLostPerSecond; struct FireModeContext{ var bool bHipfire; var NiceWeapon sourceWeapon; @@ -152,9 +157,15 @@ simulated function int GetBurstLength(){ } return currentContext.burstLength; } + simulated function ModeTick(float delta){ local float headLevel; local NiceMonster currTarget; + if (spreadLostPerSecond > 0 && activeSpreadScale > minimalSpreadScale + && niceNextFireTime + fireRate <= Level.TimeSeconds) { + activeSpreadScale -= spreadLostPerSecond * delta; + activeSpreadScale = FMax(minimalSpreadScale, activeSpreadScale); + } if(currentContext.Instigator == none) currentContext.Instigator = NiceHumanPawn(Instigator); if(currentContext.sourceWeapon == none) @@ -477,7 +488,7 @@ simulated function HandleRecoil(float Rec) KFW= KFWeapon(Weapon); if (KFW.bAimingRifle) { - Rec *= 0.5; + Rec *= aimingSpreadReductionCoefficient; } if (nicePawn.stationaryTime > 0.0 && class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillHeavyStablePosition')) { @@ -548,7 +559,7 @@ function DoFireEffect(){ if(!Weapon.WeaponCentered() && !KFWeap.bAimingRifle) StartProj = StartProj + Weapon.Hand * Y * ProjSpawnOffset.Y + Z * ProjSpawnOffset.Z; other = Weapon.Trace(HitLocation, HitNormal, StartProj, StartTrace, false); - activeSpread = fireShots[currentShot].spread; + activeSpread = fireShots[currentShot].spread * activeSpreadScale; if(class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillEnforcerBombard')){ bPinpoint = true; activeSpread *= class'NiceSkillEnforcerBombard'.default.spreadMult; @@ -607,6 +618,15 @@ function DoFireEffect(){ else if(Instigator.Physics == PHYS_Falling && Instigator.PhysicsVolume.Gravity.Z > class'PhysicsVolume'.default.Gravity.Z) Instigator.AddVelocity((KickMomentum * LowGravKickMomentumScale) >> Instigator.GetViewRotation()); } + if (activeSpreadScale < 1.0) { + if (KFWeap.bAimingRifle) { + activeSpreadScale += spreadGainedPerShot * 0.5; + } + else { + activeSpreadScale += spreadGainedPerShot; + } + activeSpreadScale = FMin(1.0, activeSpreadScale); + } } simulated function float TraceZed(out NiceMonster tracedZed, optional out Vector hitLoc, optional out Vector hitNorm, optional float hsMultiplier){ @@ -678,7 +698,8 @@ simulated function UpdateFireSpeed(){ ReloadAnimRate = default.ReloadAnimRate * fireSpeedMod; } // This function is called when next fire time needs to be updated -simulated function float UpdateNextFireTime(float fireTimeVar){ +simulated function float UpdateNextFireTime(float fireTimeVar) { + local float usedFireRate; local float burstSlowDown; local NiceHumanPawn nicePawn; local class niceVet; @@ -686,11 +707,19 @@ simulated function float UpdateNextFireTime(float fireTimeVar){ if(nicePawn != none) niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(nicePawn.PlayerReplicationInfo); fireTimeVar = FMax(fireTimeVar, Level.TimeSeconds); + usedFireRate = fireRate; + if (maxBonusContLenght > 1) { + if (currentContLenght <= maxBonusContLenght) { + usedFireRate *= 0.8 + 0.2 * (maxBonusContLenght - currentContLenght); + } else { + usedFireRate *= 0.8; + } + } if(bFireOnRelease){ if(bIsFiring) - fireTimeVar += MaxHoldTime + FireRate; + fireTimeVar += MaxHoldTime + usedFireRate; else - fireTimeVar = Level.TimeSeconds + FireRate; + fireTimeVar = Level.TimeSeconds + usedFireRate; } else{ if(currentContext.bIsBursting && GetBurstLength() > 1){ @@ -701,10 +730,10 @@ simulated function float UpdateNextFireTime(float fireTimeVar){ burstSlowDown = 1.0; else burstSlowDown = 1.3; - fireTimeVar += FireRate * burstSlowDown; + fireTimeVar += usedFireRate * burstSlowDown; } else - fireTimeVar += FireRate; + fireTimeVar += usedFireRate; fireTimeVar = FMax(fireTimeVar, Level.TimeSeconds); } return fireTimeVar; @@ -712,13 +741,19 @@ simulated function float UpdateNextFireTime(float fireTimeVar){ defaultproperties { - zedTimeFireSpeedUp=1.000000 - ProjPerFire=1 - ProjectileSpeed=1524.000000 - MaxBurstLength=3 - bulletClass=class'NiceBullet' - contBonus=1.200000 - contBonusReset=True - maxBonusContLenght=1 - AmmoPerFire=1 + zedTimeFireSpeedUp=1.000000 + ProjPerFire=1 + ProjectileSpeed=1524.000000 + MaxBurstLength=3 + bulletClass=class'NiceBullet' + contBonus=1.200000 + contBonusReset=True + maxBonusContLenght=1 + AmmoPerFire=1 + minimalSpreadScale=1 + activeSpreadScale=1 + spreadGainedPerShot=0 + spreadLostPerSecond=0 + RecoilVelocityScale = 0 + aimingSpreadReductionCoefficient = 0.5 } diff --git a/sources/Weapons/NiceProjectileSpawner.uc b/sources/Weapons/NiceProjectileSpawner.uc index 05dd281..a8ee953 100644 --- a/sources/Weapons/NiceProjectileSpawner.uc +++ b/sources/Weapons/NiceProjectileSpawner.uc @@ -1,76 +1,160 @@ class NiceProjectileSpawner extends Actor dependson(NiceBullet); + // NICETODO: use flags correctly -static function MakeProjectile(Vector start, Rotator dir, NiceFire.ShotType shotParams, NiceFire.FireModeContext fireContext, optional bool bForceComplexTraj, - optional bool bDuplReal, optional bool bSkipGhosts){ +static function MakeProjectile( + Vector start, + Rotator dir, + NiceFire.ShotType shotParams, + NiceFire.FireModeContext fireContext, + optional bool bForceComplexTraj, + optional bool bDuplReal, + optional bool bSkipGhosts +) { local int i; local NicePack niceMut; + niceMut = class'NicePack'.static.Myself(fireContext.Instigator.Level); - if(niceMut == none) - return; - if(fireContext.Instigator.Role < ROLE_Authority || bDuplReal) - SpawnProjectile(Start, Dir, shotParams, fireContext, false, bForceComplexTraj); - if(fireContext.Instigator.Role == ROLE_Authority && niceMut != none && !bSkipGhosts){ - for(i = 0;i < niceMut.playersList.Length;i ++){ - if(niceMut.playersList[i] != fireContext.Instigator.Controller) - niceMut.playersList[i].ClientSpawnGhostProjectile(start, dir.pitch, dir.yaw, dir.roll, shotParams, fireContext, bForceComplexTraj); - } + if (niceMut == none) { + return; + } + if (fireContext.Instigator.Role < ROLE_Authority || bDuplReal) { + SpawnProjectile(Start, Dir, shotParams, fireContext, false, bForceComplexTraj); + } + if (fireContext.Instigator.Role == ROLE_Authority && niceMut != none && !bSkipGhosts) { + for (i = 0; i < niceMut.playersList.Length; i++) { + if (niceMut.playersList[i] != fireContext.Instigator.Controller) { + niceMut.playersList[i].ClientSpawnGhostProjectile( + start, + dir.pitch, + dir.yaw, + dir.roll, + shotParams, + fireContext, + bForceComplexTraj + ); + } + } } } -static function StickProjectile(KFHumanPawn instigator, Actor base, name bone, Vector shift, Rotator direction, - NiceBullet.ExplosionData expData, optional bool bDuplReal, optional bool bSkipGhosts){ + +static function StickProjectile( + KFHumanPawn instigator, + Actor base, + name bone, + Vector shift, + Rotator direction, + NiceBullet.ExplosionData expData, + optional bool bDuplReal, + optional bool bSkipGhosts +) { local int i; local NicePack niceMut; + niceMut = class'NicePack'.static.Myself(expData.Instigator.Level); - if(niceMut == none) - return; + if (niceMut == none) { + return; + } niceMut.stuckCounter ++; - if(expData.Instigator.Role < ROLE_Authority) - SpawnStuckProjectile(instigator, base, bone, shift, direction, expData, false, niceMut.stuckCounter); - if(expData.Instigator.Role == ROLE_Authority && niceMut != none){ - for(i = 0;i < niceMut.playersList.Length;i ++){ - if( (niceMut.playersList[i] != expData.Instigator.Controller && !bSkipGhosts) - || (niceMut.playersList[i] == expData.Instigator.Controller && bDuplReal) ) - niceMut.playersList[i].ClientStickGhostProjectile(instigator, base, bone, shift, direction, expData, - niceMut.stuckCounter); - } + if (expData.Instigator.Role < ROLE_Authority) { + SpawnStuckProjectile( + instigator, + base, + bone, + shift, + direction, + expData, + false, + niceMut.stuckCounter + ); + } + if (expData.Instigator.Role == ROLE_Authority && niceMut != none) { + for (i = 0; i < niceMut.playersList.Length; i++) { + if ( + (niceMut.playersList[i] != expData.Instigator.Controller && !bSkipGhosts) || + (niceMut.playersList[i] == expData.Instigator.Controller && bDuplReal) + ) { + niceMut.playersList[i].ClientStickGhostProjectile( + instigator, + base, + bone, + shift, + direction, + expData, + niceMut.stuckCounter + ); + } + } } } -static function NiceBullet SpawnProjectile(Vector Start, Rotator Dir, NiceFire.ShotType shotParams, NiceFire.FireModeContext fireContext, optional bool bIsGhost, optional bool bForceComplexTraj){ + +static function NiceBullet SpawnProjectile( + Vector Start, + Rotator Dir, + NiceFire.ShotType shotParams, + NiceFire.FireModeContext fireContext, + optional bool bIsGhost, + optional bool bForceComplexTraj +) { local Actor other; local NiceBullet niceProj; local Vector HitLocation, HitNormal; local NicePlayerController nicePlayer; local class niceVet; + // No class - no projectile - if(shotParams.bulletClass == none) - return none; + if (shotParams.bulletClass == none) { + return none; + } // Try to spawn - if(fireContext.Instigator != none) - niceProj = fireContext.Instigator.Spawn(shotParams.bulletClass,,, Start, Dir); + if (fireContext.Instigator != none) { + niceProj = fireContext.Instigator.Spawn(shotParams.bulletClass,,, Start, Dir); + } // Try harder - if(niceProj == none && fireContext.Instigator != none){ - other = fireContext.Instigator.Trace(HitLocation, HitNormal, Start, fireContext.Instigator.Location + fireContext.Instigator.EyePosition(), false, Vect(0,0,1)); - if(other != none) - Start = HitLocation; - niceProj = fireContext.Instigator.Spawn(shotParams.bulletClass,,, Start, Dir); + if (niceProj == none && fireContext.Instigator != none) { + other = fireContext.Instigator.Trace( + HitLocation, + HitNormal, + Start, + fireContext.Instigator.Location + fireContext.Instigator.EyePosition(), + false, + Vect(0, 0, 1) + ); + if (other != none) { + Start = HitLocation; + } + niceProj = fireContext.Instigator.Spawn(shotParams.bulletClass,,, Start, Dir); } // Give up if failed after these two attempts - if(niceProj == none) - return none; + if (niceProj == none) { + return none; + } niceProj.Renew(); // Initialize projectile - if(fireContext.Instigator != none) - nicePlayer = NicePlayerController(fireContext.Instigator.Controller); - if(nicePlayer != none) - niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(nicePlayer.PlayerReplicationInfo); + if (fireContext.Instigator != none) { + nicePlayer = NicePlayerController(fireContext.Instigator.Controller); + } + if (nicePlayer != none) { + niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(nicePlayer.PlayerReplicationInfo); + } niceProj.bGhost = bIsGhost; // Fill-up data about what damage should projectile deal niceProj.charDamage = shotParams.damage; - if(niceVet != none && fireContext.bIsBursting && niceVet.static.hasSkill(nicePlayer, class'NiceSkillCommandoExplosivePower')) + if ( + niceVet != none && + fireContext.bIsBursting && + niceVet.static.hasSkill(nicePlayer, class'NiceSkillCommandoExplosivePower') + ) { niceProj.charDamage *= class'NiceSkillCommandoExplosivePower'.default.dmgMod; - if(niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSupportZEDBulletStorm') && nicePlayer.IsZedTimeActive()) + } + if ( + niceVet != none && + niceVet.static.hasSkill(nicePlayer, class'NiceSkillSupportZEDBulletStorm') && + nicePlayer.IsZedTimeActive() + ) { niceProj.charDamage = shotParams.damage * class'NiceSkillSupportZEDBulletStorm'.default.damageCut; + } + niceProj.charOrigDamage = niceProj.charDamage; niceProj.charDamageType = shotParams.shotDamageType; niceProj.charExplosionDamageType = shotParams.explosionDamageType; @@ -92,76 +176,95 @@ static function NiceBullet SpawnProjectile(Vector Start, Rotator Dir, NiceFire.S niceProj.charContiniousBonus = fireContext.continiousBonus; // Fill-up data about at what speed should projectile travel niceProj.movementSpeed = shotParams.projSpeed; - if(niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillDemoOnperk')) + if (niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillDemoOnperk')) { niceProj.movementSpeed *= class'NiceSkillDemoOnperk'.default.speedBonus; + } niceProj.movementDirection = Vector(niceProj.rotation); niceProj.charAffectedByScream = shotParams.projAffectedByScream; niceProj.charIsSticky = shotParams.bShouldStick; niceProj.nicePlayer = nicePlayer; - if(niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillDemoVolatile')){ + if (niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillDemoVolatile')) { niceProj.charExplosionRadius *= class'NiceSkillDemoVolatile'.default.explRangeMult; niceProj.charExplosionExponent *= class'NiceSkillDemoVolatile'.default.falloffMult; niceProj.charMinExplosionDist *= class'NiceSkillDemoVolatile'.default.safeDistanceMult; } - if(niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillDemoZEDFullBlast') && nicePlayer.IsZedTimeActive()){ - niceProj.charExplosionRadius *= class'NiceSkillDemoZEDFullBlast'.default.explRadiusMult; - niceProj.charExplosionExponent = 0.0; + if ( + niceVet != none && + niceVet.static.hasSkill(nicePlayer, class'NiceSkillDemoZEDFullBlast') && + nicePlayer.IsZedTimeActive() + ) { + niceProj.charExplosionRadius *= class'NiceSkillDemoZEDFullBlast'.default.explRadiusMult; + niceProj.charExplosionExponent = 0.0; + } + if (bForceComplexTraj) { + niceProj.bDisableComplexMovement = false; + } + if (niceProj.Instigator != none && NicePlayerController(niceProj.Instigator.Controller) != none) { + niceProj.niceRI = NicePlayerController(niceProj.Instigator.Controller).NiceRI; } - if(bForceComplexTraj) - niceProj.bDisableComplexMovement = false; - if(niceProj.Instigator != none && NicePlayerController(niceProj.Instigator.Controller) != none) - niceProj.niceRI = NicePlayerController(niceProj.Instigator.Controller).NiceRI; // And some leftovers //niceProj.bShouldBounce = shotParams.bShouldBounce; niceProj.bInitFinished = true; + return niceProj; } -static function SpawnStuckProjectile(KFHumanPawn instigator, Actor base, name bone, Vector shift, Rotator direction, - NiceBullet.ExplosionData expData, bool bIsGhost, int stuckID){ - local Pawn justPawn; - local NiceFire.ShotType shotParams; - local NiceFire.FireModeContext fireContext; - local NiceBullet spawnedBullet; - local NicePlayerController nicePlayer; + +static function SpawnStuckProjectile( + KFHumanPawn instigator, + Actor base, + name bone, + Vector shift, + Rotator direction, + NiceBullet.ExplosionData expData, + bool bIsGhost, + int stuckID +) { + local Pawn justPawn; + local NiceFire.ShotType shotParams; + local NiceFire.FireModeContext fireContext; + local NiceBullet spawnedBullet; + local NicePlayerController nicePlayer; + nicePlayer = NicePlayerController(instigator.Controller); - if(base == none || nicePlayer == none) - return; + if (base == none || nicePlayer == none) { + return; + } justPawn = Pawn(base); - fireContext.instigator = NiceHumanPawn(instigator); - fireContext.sourceWeapon = expData.sourceWeapon; - shotParams.bulletClass = expData.bulletClass; - shotParams.explosionDamageType = expData.explosionDamageType; - shotParams.explosionDamage = expData.explosionDamage; - shotParams.explosionRadius = expData.explosionRadius; - shotParams.explosionExponent = expData.explosionExponent; - shotParams.explosionMomentum = expData.explosionMomentum; - shotParams.fuseTime = expData.fuseTime; - shotParams.explodeOnFuse = expData.explodeOnFuse; + fireContext.instigator = NiceHumanPawn(instigator); + fireContext.sourceWeapon = expData.sourceWeapon; + shotParams.bulletClass = expData.bulletClass; + shotParams.explosionDamageType = expData.explosionDamageType; + shotParams.explosionDamage = expData.explosionDamage; + shotParams.explosionRadius = expData.explosionRadius; + shotParams.explosionExponent = expData.explosionExponent; + shotParams.explosionMomentum = expData.explosionMomentum; + shotParams.fuseTime = expData.fuseTime; + shotParams.explodeOnFuse = expData.explodeOnFuse; shotParams.projAffectedByScream = expData.affectedByScream; spawnedBullet = SpawnProjectile(base.location, direction, shotParams, fireContext, bIsGhost); - if(spawnedBullet == none) - return; + if (spawnedBullet == none) { + return; + } spawnedBullet.stuckID = stuckID; spawnedBullet.bStuck = true; nicePlayer.RegisterStuckBullet(spawnedBullet); - if(justPawn != none){ - spawnedBullet.bStuckToHead = expData.stuckToHead; - spawnedBullet.SetBase(base); - justPawn.AttachToBone(spawnedBullet, bone); - spawnedBullet.SetRelativeLocation(shift); - spawnedBullet.SetRelativeRotation(Rotator(Vector(direction) << justPawn.GetBoneRotation(bone, 0))); - spawnedBullet.bUseBone = true; - spawnedBullet.stuckBone = bone; - } - else{ - spawnedBullet.SetBase(base); - spawnedBullet.SetRelativeLocation(shift); + if (justPawn != none) { + spawnedBullet.bStuckToHead = expData.stuckToHead; + spawnedBullet.SetBase(base); + justPawn.AttachToBone(spawnedBullet, bone); + spawnedBullet.SetRelativeLocation(shift); + spawnedBullet.SetRelativeRotation(Rotator(Vector(direction) << justPawn.GetBoneRotation(bone, 0))); + spawnedBullet.bUseBone = true; + spawnedBullet.stuckBone = bone; + } else { + spawnedBullet.SetBase(base); + spawnedBullet.SetRelativeLocation(shift); + spawnedBullet.SetRelativeRotation(direction - base.rotation); } } -defaultproperties -{ - bHidden=True - RemoteRole=ROLE_SimulatedProxy - LifeSpan=1.000000 -} +defaultproperties { + bHidden=True + RemoteRole=ROLE_SimulatedProxy + LifeSpan=1.000000 +} \ No newline at end of file diff --git a/sources/Weapons/NiceWeapon.uc b/sources/Weapons/NiceWeapon.uc index b975465..7cada8c 100644 --- a/sources/Weapons/NiceWeapon.uc +++ b/sources/Weapons/NiceWeapon.uc @@ -146,6 +146,7 @@ var bool bAutoReloadPaused; // This is used to 'pause' auto relo var float autoReloadPauseFrame; // Frame at which current pause began var bool bAutoReloadRateApplied; // Flag that remembers whether or not we've already applied reload speed up for current auto reload (to avoid constant animation's speed updates) var float autoReloadSpeedModifier; +var bool updatedDefaultReloadValues; // Acrtive reload-related variables // Active reload state enum EActiveReloadState{ @@ -219,6 +220,8 @@ static function bool UnloadAssets(){ return default.ReferenceCount == 0; } simulated function PostBeginPlay(){ + local float swapSpeedMod, reloadSpeedMod; + if(default.recordedZoomTime < 0) default.recordedZoomTime = ZoomTime; recordedZoomTime = default.recordedZoomTime; @@ -240,6 +243,31 @@ simulated function PostBeginPlay(){ if(FireModeClass[0] != none) stdFireRate = FireModeClass[0].default.fireRate; super.PostBeginPlay(); + // Hack solution - speed up reload and swap speed + swapSpeedMod = 2.0; + reloadSpeedMod = 1.5; + bringUpTime /= swapSpeedMod; + putDownTime /= swapSpeedMod; + selectAnimRate *= swapSpeedMod; + putDownAnimRate *= swapSpeedMod; + quickPutDownTime /= swapSpeedMod; + quickBringUpTime /= swapSpeedMod; + if (!default.updatedDefaultReloadValues) { + if(reloadType == RTYPE_AUTO) { + if (fireModeClass[0] != none) { + fireModeClass[0].default.FireAnimRate *= reloadSpeedMod; + } + if (fireModeClass[1] != none) { + fireModeClass[1].default.FireAnimRate *= reloadSpeedMod; + } + } else { + reloadRate /= reloadSpeedMod; + reloadAnimRate *= reloadSpeedMod; + default.reloadRate = reloadRate; + default.reloadAnimRate = reloadAnimRate; + } + default.updatedDefaultReloadValues = true; + } } // Allows to prevent leaving iron sights unwillingly @@ -1094,6 +1122,7 @@ simulated function int GetMagazineAmmo(){ else return MagAmmoRemaining; } + simulated function bool AllowReload(){ local int actualMagSize; actualMagSize = GetMagazineAmmo(); @@ -1127,6 +1156,7 @@ simulated function float GetCurrentReloadMult(){ local NiceHumanPawn nicePawn; local NicePlayerController nicePlayer; local class niceVet; + nicePawn = NiceHumanPawn(Instigator); nicePlayer = NicePlayerController(Instigator.Controller); if(nicePawn != none) @@ -1624,17 +1654,17 @@ simulated function float GetAmmoMulti() defaultproperties { - recordedZoomTime=-1.000000 - SecondaryCharge=1 - LaserAttachmentClass=Class'ScrnLaserAttachmentFirstPerson' - LaserDotClass=Class'ScrnLocalLaserDot' - LaserAttachmentBone="LightBone" - MagazineBone="Magazine" - bHasChargePhase=True - autoReloadSpeedModifier=1.000000 - bCanActiveReload=True - activeSlowdown=0.850000 - activeSpeedup=1.150000 - activeWindow=0.060000 - bModeZeroCanDryFire=True + recordedZoomTime=-1.000000 + SecondaryCharge=1 + LaserAttachmentClass=Class'ScrnLaserAttachmentFirstPerson' + LaserDotClass=Class'ScrnLocalLaserDot' + LaserAttachmentBone="LightBone" + MagazineBone="Magazine" + bHasChargePhase=True + autoReloadSpeedModifier=1.000000 + bCanActiveReload=True + activeSlowdown=0.850000 + activeSpeedup=1.150000 + activeWindow=0.060000 + bModeZeroCanDryFire=True } diff --git a/sources/Weapons/Playable/AssaultRifles/AK12/NiceAK12Pickup.uc b/sources/Weapons/Playable/AssaultRifles/AK12/NiceAK12Pickup.uc index a9379e2..d910bd9 100644 --- a/sources/Weapons/Playable/AssaultRifles/AK12/NiceAK12Pickup.uc +++ b/sources/Weapons/Playable/AssaultRifles/AK12/NiceAK12Pickup.uc @@ -3,7 +3,7 @@ defaultproperties { Weight=6.000000 cost=750 - AmmoCost=19 + AmmoCost=25 BuyClipSize=40 PowerValue=55 SpeedValue=80 diff --git a/sources/Weapons/Playable/AssaultRifles/AK47/NiceAK47Pickup.uc b/sources/Weapons/Playable/AssaultRifles/AK47/NiceAK47Pickup.uc index db19d61..6dad7d2 100644 --- a/sources/Weapons/Playable/AssaultRifles/AK47/NiceAK47Pickup.uc +++ b/sources/Weapons/Playable/AssaultRifles/AK47/NiceAK47Pickup.uc @@ -3,7 +3,7 @@ defaultproperties { Weight=6.000000 cost=750 - AmmoCost=19 + AmmoCost=26 BuyClipSize=30 PowerValue=40 SpeedValue=80 diff --git a/sources/Weapons/Playable/AssaultRifles/MKb42/NiceMKb42Pickup.uc b/sources/Weapons/Playable/AssaultRifles/MKb42/NiceMKb42Pickup.uc index c97c589..01e2aa8 100644 --- a/sources/Weapons/Playable/AssaultRifles/MKb42/NiceMKb42Pickup.uc +++ b/sources/Weapons/Playable/AssaultRifles/MKb42/NiceMKb42Pickup.uc @@ -3,7 +3,7 @@ defaultproperties { Weight=6.000000 cost=750 - AmmoCost=22 + AmmoCost=19 BuyClipSize=30 PowerValue=40 SpeedValue=85 diff --git a/sources/Weapons/Playable/Explosives/LAW/NiceLAWFire.uc b/sources/Weapons/Playable/Explosives/LAW/NiceLAWFire.uc index 096355b..93016d8 100644 --- a/sources/Weapons/Playable/Explosives/LAW/NiceLAWFire.uc +++ b/sources/Weapons/Playable/Explosives/LAW/NiceLAWFire.uc @@ -19,7 +19,7 @@ defaultproperties StereoFireSoundRef="KF_LAWSnd.LAW_FireST" NoAmmoSoundRef="KF_LAWSnd.LAW_DryFire" DamageType=class'NiceDamTypeLAWBlunt' - DamageMax=750 + DamageMax=350 bSplashDamage=True bRecommendSplashDamage=True bWaitForRelease=True diff --git a/sources/Weapons/Playable/Grenades/NiceNade.uc b/sources/Weapons/Playable/Grenades/NiceNade.uc index 48b778b..b984b18 100644 --- a/sources/Weapons/Playable/Grenades/NiceNade.uc +++ b/sources/Weapons/Playable/Grenades/NiceNade.uc @@ -39,114 +39,32 @@ function TakeDamage(int Damage, Pawn InstigatedBy, Vector HitLocation, Vector Mo Explode(HitLocation, vect(0,0,1)); } } -simulated function HurtRadius( float DamageAmount, float DamageRadius, class DamageType, float Momentum, vector HitLocation ) -{ - local actor Victims; - local float damageScale, dist; - local vector dir; - local int NumKilled; - local KFMonster KFMonsterVictim; - local bool bMonster; - local Pawn P; - local KFPawn KFP; - local array CheckedPawns; - local int i; - local bool bAlreadyChecked; - local SRStatsBase Stats; - if ( bHurtEntry ) - return; - bHurtEntry = true; - - if( Role == ROLE_Authority && Instigator != none && Instigator.PlayerReplicationInfo != none ) - Stats = SRStatsBase(Instigator.PlayerReplicationInfo.SteamStatsAndAchievements); - - foreach CollidingActors (class 'Actor', Victims, DamageRadius, HitLocation) - { - P = none; - KFMonsterVictim = none; - bMonster = false; - KFP = none; - bAlreadyChecked = false; +simulated function HurtRadius( + float damageAmount, + float damageRadius, + class damageType, + float momentum, + Vector hitLocation +) { + local NicePlayerController niceController; + local NiceReplicationInfo niceRI; - // don't let blast damage affect fluid - VisibleCollisingActors doesn't really work for them - jag - if( (Victims != self) && (Hurtwall != Victims) && (Victims.Role == ROLE_Authority) && !Victims.IsA('FluidSurfaceInfo') - && ExtendedZCollision(Victims)==None ) - { - if( (Instigator==None || Instigator.Health<=0) && KFPawn(Victims)!=None ) - Continue; - dir = Victims.Location - HitLocation; - dist = FMax(1,VSize(dir)); - dir = dir/dist; - damageScale = 1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius); + if (instigator == none) return; + niceController = NicePlayerController(instigator.controller); + if (niceController == none) return; + niceRI = niceController.niceRI; + if (niceRI == none) return; - if ( Instigator == None || Instigator.Controller == None ) - { - Victims.SetDelayedDamageInstigatorController( InstigatorController ); - } + Destroy(); - P = Pawn(Victims); - if( P != none ) { - for (i = 0; i < CheckedPawns.Length; i++) { - if (CheckedPawns[i] == P) { - bAlreadyChecked = true; - break; - } - } - if( bAlreadyChecked ) - continue; - CheckedPawns[CheckedPawns.Length] = P; - - KFMonsterVictim = KFMonster(Victims); - if( KFMonsterVictim != none && KFMonsterVictim.Health <= 0 ) - KFMonsterVictim = none; - - KFP = KFPawn(Victims); - - if( KFMonsterVictim != none ) { - damageScale *= KFMonsterVictim.GetExposureTo(Location + 15 * -Normal(PhysicsVolume.Gravity)); - bMonster = true; // in case TakeDamage() and further Die() deletes the monster - } - else if( KFP != none ) { - damageScale *= KFP.GetExposureTo(Location + 15 * -Normal(PhysicsVolume.Gravity)); - } - - if ( damageScale <= 0) - continue; - } - if(NiceMonster(Victims) != none) - Victims.TakeDamage(damageScale * DamageAmount,Instigator,Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dir - ,(damageScale * Momentum * dir), niceExplosiveDamage); - else - Victims.TakeDamage(damageScale * DamageAmount,Instigator,Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dir - ,(damageScale * Momentum * dir), DamageType); - - if( bMonster && (KFMonsterVictim == none || KFMonsterVictim.Health < 1) ) { - NumKilled++; - } - - if (Vehicle(Victims) != None && Vehicle(Victims).Health > 0) - { - Vehicle(Victims).DriverRadiusDamage(DamageAmount, DamageRadius, InstigatorController, DamageType, Momentum, HitLocation); - } - } - } - - if( Role == ROLE_Authority ) - { - if ( bBlewInHands && NumKilled >= 5 && Stats != none ) - class'ScrnAchievements'.static.ProgressAchievementByID(Stats.Rep, 'SuicideBomber', 1); - - if ( NumKilled >= 4 ) - { - KFGameType(Level.Game).DramaticEvent(0.05); - } - else if ( NumKilled >= 2 ) - { - KFGameType(Level.Game).DramaticEvent(0.03); - } - } - bHurtEntry = false; + niceRI.ServerExplode(damageAmount, + damageRadius, + 1.0, + niceExplosiveDamage, + momentum, + hitLocation, + instigator); } // Overridden to spawn different AvoidMarker simulated function HitWall( vector HitNormal, actor Wall ){ diff --git a/sources/Weapons/Playable/Heavy/M249/NiceM249Fire.uc b/sources/Weapons/Playable/Heavy/M249/NiceM249Fire.uc index f531707..536e2ad 100644 --- a/sources/Weapons/Playable/Heavy/M249/NiceM249Fire.uc +++ b/sources/Weapons/Playable/Heavy/M249/NiceM249Fire.uc @@ -4,8 +4,8 @@ defaultproperties ProjectileSpeed=48250.000000 FireAimedAnim="Fire" RecoilRate=0.040000 - maxVerticalRecoilAngle=550 - maxHorizontalRecoilAngle=225 + maxVerticalRecoilAngle=115 + maxHorizontalRecoilAngle=0 ShellEjectClass=Class'ROEffects.KFShellEjectAK' ShellEjectBoneName="Shell_eject" bAccuracyBonusForSemiAuto=True diff --git a/sources/Weapons/Playable/Heavy/M41A/NiceDamTypeM41AAssaultRifle.uc b/sources/Weapons/Playable/Heavy/M41A/NiceDamTypeM41AAssaultRifle.uc index d7f796b..ea086e8 100644 --- a/sources/Weapons/Playable/Heavy/M41A/NiceDamTypeM41AAssaultRifle.uc +++ b/sources/Weapons/Playable/Heavy/M41A/NiceDamTypeM41AAssaultRifle.uc @@ -10,4 +10,6 @@ defaultproperties KDeathVel=1400.000000 KDeathUpKick=150.000000 VehicleDamageScaling=0.700000 + stunMultiplier=3.0 + stunLengthMultiplier=2.0 } diff --git a/sources/Weapons/Playable/Heavy/M41A/NiceM41AAmmo.uc b/sources/Weapons/Playable/Heavy/M41A/NiceM41AAmmo.uc index 6f7b45b..06e02e2 100644 --- a/sources/Weapons/Playable/Heavy/M41A/NiceM41AAmmo.uc +++ b/sources/Weapons/Playable/Heavy/M41A/NiceM41AAmmo.uc @@ -4,8 +4,8 @@ defaultproperties { WeaponPickupClass=class'NiceM41APickup' AmmoPickupAmount=66 - MaxAmmo=300 - InitialAmount=75 + MaxAmmo=264 + InitialAmount=66 PickupClass=class'NiceM41AAmmoPickup' IconMaterial=Texture'KillingFloorHUD.Generic.HUD' IconCoords=(X1=336,Y1=82,X2=382,Y2=125) diff --git a/sources/Weapons/Playable/Heavy/M41A/NiceM41APickup.uc b/sources/Weapons/Playable/Heavy/M41A/NiceM41APickup.uc index 610f503..4dc3f6f 100644 --- a/sources/Weapons/Playable/Heavy/M41A/NiceM41APickup.uc +++ b/sources/Weapons/Playable/Heavy/M41A/NiceM41APickup.uc @@ -3,7 +3,7 @@ class NiceM41APickup extends NiceM41APrimaryPickup; defaultproperties { crossPerkIndecies(0)=6 - AmmoCost=60 + AmmoCost=24 BuyClipSize=1 SecondaryAmmoShortName="M41A Frag Grenades" PrimaryWeaponPickup=class'NiceM41APrimaryPickup' diff --git a/sources/Weapons/Playable/Heavy/M41A/NiceM41APrimaryPickup.uc b/sources/Weapons/Playable/Heavy/M41A/NiceM41APrimaryPickup.uc index 0f05cc6..808f48a 100644 --- a/sources/Weapons/Playable/Heavy/M41A/NiceM41APrimaryPickup.uc +++ b/sources/Weapons/Playable/Heavy/M41A/NiceM41APrimaryPickup.uc @@ -3,7 +3,7 @@ defaultproperties { cost=750 Weight=7.000000 - AmmoCost=66 + AmmoCost=25 BuyClipSize=66 PowerValue=70 SpeedValue=100 diff --git a/sources/Weapons/Playable/Heavy/M41A/NiceM41AProjectileAmmo.uc b/sources/Weapons/Playable/Heavy/M41A/NiceM41AProjectileAmmo.uc index a778ca5..1887b81 100644 --- a/sources/Weapons/Playable/Heavy/M41A/NiceM41AProjectileAmmo.uc +++ b/sources/Weapons/Playable/Heavy/M41A/NiceM41AProjectileAmmo.uc @@ -3,7 +3,7 @@ defaultproperties { WeaponPickupClass=class'NiceM41APickup' AmmoPickupAmount=1 - MaxAmmo=8 + MaxAmmo=5 InitialAmount=2 IconMaterial=Texture'KillingFloorHUD.Generic.HUD' IconCoords=(X1=434,Y1=253,X2=506,Y2=292) diff --git a/sources/Weapons/Playable/Heavy/RPK47/NiceRPK47Fire.uc b/sources/Weapons/Playable/Heavy/RPK47/NiceRPK47Fire.uc index 79b5528..0bbd5bb 100644 --- a/sources/Weapons/Playable/Heavy/RPK47/NiceRPK47Fire.uc +++ b/sources/Weapons/Playable/Heavy/RPK47/NiceRPK47Fire.uc @@ -5,8 +5,8 @@ defaultproperties contBonus=1.400000 FireAimedAnim="Fire_Iron" RecoilRate=0.050000 - maxVerticalRecoilAngle=400 - maxHorizontalRecoilAngle=200 + maxVerticalRecoilAngle=100 + maxHorizontalRecoilAngle=0 ShellEjectClass=Class'ROEffects.KFShellEjectAK' ShellEjectBoneName="Shell_eject" bAccuracyBonusForSemiAuto=True diff --git a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSW.uc b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSW.uc index a74b185..99f9056 100644 --- a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSW.uc +++ b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSW.uc @@ -17,7 +17,7 @@ defaultproperties MagazineBone="clip" bHasScope=True ZoomedDisplayFOVHigh=50.000000 - MagCapacity=30 + MagCapacity=60 ReloadRate=3.500000 ReloadAnim="Reload" ReloadAnimRate=1.000000 diff --git a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWAmmo.uc b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWAmmo.uc index f6abd5d..0fc562c 100644 --- a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWAmmo.uc +++ b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWAmmo.uc @@ -2,7 +2,7 @@ class NiceSA80LSWAmmo extends NiceAmmo; defaultproperties { WeaponPickupClass=class'NiceSA80LSWPickup' - AmmoPickupAmount=30 + AmmoPickupAmount=60 MaxAmmo=360 InitialAmount=90 PickupClass=class'NiceSA80LSWAmmoPickup' diff --git a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWAmmoPickup.uc b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWAmmoPickup.uc index 6c6ea5b..058a8e1 100644 --- a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWAmmoPickup.uc +++ b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWAmmoPickup.uc @@ -1,7 +1,7 @@ class NiceSA80LSWAmmoPickup extends NiceAmmoPickup; defaultproperties { - AmmoAmount=30 + AmmoAmount=60 InventoryType=class'NiceSA80LSWAmmo' PickupMessage="5.56x45" StaticMesh=StaticMesh'KillingFloorStatics.L85Ammo' diff --git a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWFire.uc b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWFire.uc index 5108bae..033030e 100644 --- a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWFire.uc +++ b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWFire.uc @@ -4,8 +4,8 @@ defaultproperties ProjectileSpeed=46500.000000 FireAimedAnim="Iron_Idle" RecoilRate=0.050000 - maxVerticalRecoilAngle=300 - maxHorizontalRecoilAngle=150 + maxVerticalRecoilAngle=75 + maxHorizontalRecoilAngle=0 ShellEjectClass=Class'ROEffects.KFShellEjectBullpup' ShellEjectBoneName="Shell_eject" bAccuracyBonusForSemiAuto=True diff --git a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWPickup.uc b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWPickup.uc index f57be35..0083a16 100644 --- a/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWPickup.uc +++ b/sources/Weapons/Playable/Heavy/SA80LSW/NiceSA80LSWPickup.uc @@ -3,8 +3,8 @@ defaultproperties { cost=200 Weight=5.000000 - AmmoCost=5 - BuyClipSize=30 + AmmoCost=10 + BuyClipSize=60 PowerValue=41 SpeedValue=60 RangeValue=60 diff --git a/sources/Weapons/Playable/Heavy/XMV/NiceXMV850Fire.uc b/sources/Weapons/Playable/Heavy/XMV/NiceXMV850Fire.uc index d266c98..1042ce3 100644 --- a/sources/Weapons/Playable/Heavy/XMV/NiceXMV850Fire.uc +++ b/sources/Weapons/Playable/Heavy/XMV/NiceXMV850Fire.uc @@ -12,12 +12,12 @@ simulated function HandleRecoil(float Rec) defaultproperties { ProjectileSpeed=42650.000000 - maxBonusContLenght=5 + maxBonusContLenght=10 contBonusReset=false FireAimedAnim="FireLoop" RecoilRate=0.040000 - maxVerticalRecoilAngle=450 - maxHorizontalRecoilAngle=225 + maxVerticalRecoilAngle=25 + maxHorizontalRecoilAngle=0 ShellEjectClass=Class'ROEffects.KFShellEjectSCAR' ShellEjectBoneName="ejector" FireSoundRef="HMG_S.XMV.XMV-Fire-1" diff --git a/sources/Weapons/Playable/Incendiary/HFR/NiceDamTypeHFRAssaultRifle.uc b/sources/Weapons/Playable/Incendiary/HFR/NiceDamTypeHFRAssaultRifle.uc deleted file mode 100644 index 4bd3a15..0000000 --- a/sources/Weapons/Playable/Incendiary/HFR/NiceDamTypeHFRAssaultRifle.uc +++ /dev/null @@ -1,19 +0,0 @@ -class NiceDamTypeHFRAssaultRifle extends NiceDamTypeFire - abstract; -defaultproperties -{ - heatPart=0.500000 - HeadShotDamageMult=6.000000 - bCheckForHeadShots=True - WeaponClass=class'NiceHFR' - DeathString="%k killed %o (Horzine Flame Rifle)." - FemaleSuicide="%o shot herself in the foot." - MaleSuicide="%o shot himself in the foot." - bRagdollBullet=True - PawnDamageEmitter=Class'ROEffects.ROBloodPuff' - LowGoreDamageEmitter=Class'ROEffects.ROBloodPuffNoGore' - LowDetailEmitter=Class'ROEffects.ROBloodPuffSmall' - KDamageImpulse=5500.000000 - KDeathVel=175.000000 - KDeathUpKick=15.000000 -} diff --git a/sources/Weapons/Playable/Incendiary/HFR/NiceHFR.uc b/sources/Weapons/Playable/Incendiary/HFR/NiceHFR.uc index 15a1683..e5d0d55 100644 --- a/sources/Weapons/Playable/Incendiary/HFR/NiceHFR.uc +++ b/sources/Weapons/Playable/Incendiary/HFR/NiceHFR.uc @@ -1,316 +1,5 @@ -// Modification of the AAR525 weapons by: [B.R]HekuT -class NiceHFR extends KFWeapon; -#exec OBJ LOAD FILE=KillingFloorWeapons.utx -#exec OBJ LOAD FILE=KillingFloorHUD.utx -#exec OBJ LOAD FILE=Inf_Weapons_Foley.uax -#exec OBJ LOAD FILE=KF_Weapons5_Scopes_Trip_T.utx -var() Material ZoomMat; -var() int lenseMaterialID; -var() float scopePortalFOVHigh; -var() float scopePortalFOV; -var() vector XoffsetScoped; -var() vector XoffsetHighDetail; -var() int scopePitch; -var() int scopeYaw; -var() int scopePitchHigh; -var() int scopeYawHigh; -var ScriptedTexture ScopeScriptedTexture; -var Shader ScopeScriptedShader; -var Material ScriptedTextureFallback; -var Combiner ScriptedScopeCombiner; -var Combiner ScriptedScopeStatic; -var texture TexturedScopeTexture; -var bool bInitializedScope; -var string ZoomMatRef; -var string ScriptedTextureFallbackRef; -static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount) -{ - super.PreloadAssets(Inv, bSkipRefCount); - default.ZoomMat = FinalBlend(DynamicLoadObject(default.ZoomMatRef, class'FinalBlend', true)); - default.ScriptedTextureFallback = texture(DynamicLoadObject(default.ScriptedTextureFallbackRef, class'texture', true)); - if ( M99SniperRifle(Inv) != none ) - { - M99SniperRifle(Inv).ZoomMat = default.ZoomMat; - M99SniperRifle(Inv).ScriptedTextureFallback = default.ScriptedTextureFallback; - } -} -static function bool UnloadAssets() -{ - if ( super.UnloadAssets() ) - { - default.ZoomMat = none; - default.ScriptedTextureFallback = none; - } - return true; -} -exec function pfov(int thisFOV) -{ - if( !class'ROEngine.ROLevelInfo'.static.RODebugMode() ) - return; - scopePortalFOV = thisFOV; -} -exec function pPitch(int num) -{ - if( !class'ROEngine.ROLevelInfo'.static.RODebugMode() ) - return; - scopePitch = num; - scopePitchHigh = num; -} -exec function pYaw(int num) -{ - if( !class'ROEngine.ROLevelInfo'.static.RODebugMode() ) - return; - scopeYaw = num; - scopeYawHigh = num; -} -simulated exec function TexSize(int i, int j) -{ - if( !class'ROEngine.ROLevelInfo'.static.RODebugMode() ) - return; - ScopeScriptedTexture.SetSize(i, j); -} -simulated function bool ShouldDrawPortal() -{ - if( bAimingRifle ) - return true; - else - return false; -} -simulated function PostBeginPlay() -{ - super.PostBeginPlay(); - KFScopeDetail = class'KFMod.KFWeapon'.default.KFScopeDetail; - UpdateScopeMode(); -} -simulated function UpdateScopeMode() -{ - if (Level.NetMode != NM_DedicatedServer && Instigator != none && Instigator.IsLocallyControlled() && - Instigator.IsHumanControlled() ) - { - if( KFScopeDetail == KF_ModelScope ) - { - scopePortalFOV = default.scopePortalFOV; - ZoomedDisplayFOV = CalcAspectRatioAdjustedFOV(default.ZoomedDisplayFOV); - if (bAimingRifle) - { - PlayerViewOffset = XoffsetScoped; - } +class NiceHFR extends NiceScopedWeapon; - if( ScopeScriptedTexture == none ) - { - ScopeScriptedTexture = ScriptedTexture(Level.ObjectPool.AllocateObject(class'ScriptedTexture')); - } - - ScopeScriptedTexture.FallBackMaterial = ScriptedTextureFallback; - ScopeScriptedTexture.SetSize(512,512); - ScopeScriptedTexture.Client = Self; - - if( ScriptedScopeCombiner == none ) - { - ScriptedScopeCombiner = Combiner(Level.ObjectPool.AllocateObject(class'Combiner')); - ScriptedScopeCombiner.Material1 = Texture'KF_Weapons5_Scopes_Trip_T.Scope.MilDot'; - ScriptedScopeCombiner.FallbackMaterial = Shader'ScopeShaders.Zoomblur.LensShader'; - ScriptedScopeCombiner.CombineOperation = CO_Multiply; - ScriptedScopeCombiner.AlphaOperation = AO_Use_Mask; - ScriptedScopeCombiner.Material2 = ScopeScriptedTexture; - } - - if( ScopeScriptedShader == none ) - { - ScopeScriptedShader = Shader(Level.ObjectPool.AllocateObject(class'Shader')); - ScopeScriptedShader.Diffuse = ScriptedScopeCombiner; - ScopeScriptedShader.SelfIllumination = ScriptedScopeCombiner; - ScopeScriptedShader.FallbackMaterial = Shader'ScopeShaders.Zoomblur.LensShader'; - } - - bInitializedScope = true; - } - else if( KFScopeDetail == KF_ModelScopeHigh ) - { - scopePortalFOV = scopePortalFOVHigh; - ZoomedDisplayFOV = CalcAspectRatioAdjustedFOV(default.ZoomedDisplayFOVHigh); - if (bAimingRifle) - { - PlayerViewOffset = XoffsetHighDetail; - } - - if( ScopeScriptedTexture == none ) - { - ScopeScriptedTexture = ScriptedTexture(Level.ObjectPool.AllocateObject(class'ScriptedTexture')); - } - ScopeScriptedTexture.FallBackMaterial = ScriptedTextureFallback; - ScopeScriptedTexture.SetSize(1024,1024); - ScopeScriptedTexture.Client = Self; - - if( ScriptedScopeCombiner == none ) - { - ScriptedScopeCombiner = Combiner(Level.ObjectPool.AllocateObject(class'Combiner')); - ScriptedScopeCombiner.Material1 = Texture'KF_Weapons5_Scopes_Trip_T.Scope.MilDot'; - ScriptedScopeCombiner.FallbackMaterial = Shader'ScopeShaders.Zoomblur.LensShader'; - ScriptedScopeCombiner.CombineOperation = CO_Multiply; - ScriptedScopeCombiner.AlphaOperation = AO_Use_Mask; - ScriptedScopeCombiner.Material2 = ScopeScriptedTexture; - } - - if( ScopeScriptedShader == none ) - { - ScopeScriptedShader = Shader(Level.ObjectPool.AllocateObject(class'Shader')); - ScopeScriptedShader.Diffuse = ScriptedScopeCombiner; - ScopeScriptedShader.SelfIllumination = ScriptedScopeCombiner; - ScopeScriptedShader.FallbackMaterial = Shader'ScopeShaders.Zoomblur.LensShader'; - } - - bInitializedScope = true; - } - else if (KFScopeDetail == KF_TextureScope) - { - ZoomedDisplayFOV = CalcAspectRatioAdjustedFOV(default.ZoomedDisplayFOV); - PlayerViewOffset.X = default.PlayerViewOffset.X; - - bInitializedScope = true; - } - } -} -simulated event RenderTexture(ScriptedTexture Tex) -{ - local rotator RollMod; - RollMod = Instigator.GetViewRotation(); - if(Owner != none && Instigator != none && Tex != none && Tex.Client != none) - Tex.DrawPortal(0,0,Tex.USize,Tex.VSize,Owner,(Instigator.Location + Instigator.EyePosition()), RollMod, scopePortalFOV ); -} -/** - * Handles all the functionality for zooming in including - * setting the parameters for the weapon, pawn, and playercontroller - * - * @param bAnimateTransition whether or not to animate this zoom transition - */ -simulated function ZoomIn(bool bAnimateTransition) -{ - super(BaseKFWeapon).ZoomIn(bAnimateTransition); - bAimingRifle = True; - if( KFHumanPawn(Instigator)!=none ) - KFHumanPawn(Instigator).SetAiming(True); - if( Level.NetMode != NM_DedicatedServer && KFPlayerController(Instigator.Controller) != none ) - { - if( AimInSound != none ) - { - PlayOwnedSound(AimInSound, SLOT_Interact,,,,, false); - } - } -} -/** - * Handles all the functionality for zooming out including - * setting the parameters for the weapon, pawn, and playercontroller - * - * @param bAnimateTransition whether or not to animate this zoom transition - */ -simulated function ZoomOut(bool bAnimateTransition) -{ - super.ZoomOut(bAnimateTransition); - bAimingRifle = False; - if( KFHumanPawn(Instigator)!=none ) - KFHumanPawn(Instigator).SetAiming(False); - if( Level.NetMode != NM_DedicatedServer && KFPlayerController(Instigator.Controller) != none ) - { - if( AimOutSound != none ) - { - PlayOwnedSound(AimOutSound, SLOT_Interact,,,,, false); - } - KFPlayerController(Instigator.Controller).TransitionFOV(KFPlayerController(Instigator.Controller).DefaultFOV,0.0); - } -} -simulated event OnZoomInFinished() -{ - local name anim; - local float frame, rate; - GetAnimParams(0, anim, frame, rate); - if (ClientState == WS_ReadyToFire) - { - if (anim == IdleAnim) - { - PlayIdle(); - } - } - if( Level.NetMode != NM_DedicatedServer && KFPlayerController(Instigator.Controller) != none && - KFScopeDetail == KF_TextureScope ) - { - KFPlayerController(Instigator.Controller).TransitionFOV(PlayerIronSightFOV,0.0); - } -} -simulated event RenderOverlays(Canvas Canvas) -{ - local int m; - local PlayerController PC; - if (Instigator == none) - return; - PC = PlayerController(Instigator.Controller); - if(PC == none) - return; - if(!bInitializedScope && PC != none ) - { - UpdateScopeMode(); - } - Canvas.DrawActor(none, false, true); - for (m = 0; m < NUM_FIRE_MODES; m++) - { - if (FireMode[m] != none) - { - FireMode[m].DrawMuzzleFlash(Canvas); - } - } - - SetLocation( Instigator.Location + Instigator.CalcDrawOffset(self) ); - SetRotation( Instigator.GetViewRotation() + ZoomRotInterp); - PreDrawFPWeapon(); - - if(bAimingRifle && PC != none && (KFScopeDetail == KF_ModelScope || KFScopeDetail == KF_ModelScopeHigh)) - { - if (ShouldDrawPortal()) - { - if ( ScopeScriptedTexture != none ) - { - Skins[LenseMaterialID] = ScopeScriptedShader; - ScopeScriptedTexture.Client = Self; - ScopeScriptedTexture.Revision = (ScopeScriptedTexture.Revision +1); - } - } - - bDrawingFirstPerson = true; - Canvas.DrawBoundActor(self, false, false,DisplayFOV,PC.Rotation,rot(0,0,0),Instigator.CalcZoomedDrawOffset(self)); - bDrawingFirstPerson = false; - } - else if( KFScopeDetail == KF_TextureScope && PC.DesiredFOV == PlayerIronSightFOV && bAimingRifle) - { - Skins[LenseMaterialID] = ScriptedTextureFallback; - - SetZoomBlendColor(Canvas); - - Canvas.Style = ERenderStyle.STY_Normal; - Canvas.SetPos(0, 0); - Canvas.DrawTile(ZoomMat, (Canvas.SizeX - Canvas.SizeY) / 2, Canvas.SizeY, 0.0, 0.0, 8, 8); - Canvas.SetPos(Canvas.SizeX, 0); - Canvas.DrawTile(ZoomMat, -(Canvas.SizeX - Canvas.SizeY) / 2, Canvas.SizeY, 0.0, 0.0, 8, 8); - - Canvas.Style = 255; - Canvas.SetPos((Canvas.SizeX - Canvas.SizeY) / 2,0); - Canvas.DrawTile(ZoomMat, Canvas.SizeY, Canvas.SizeY, 0.0, 0.0, 1024, 1024); - - Canvas.Font = Canvas.MedFont; - Canvas.SetDrawColor(200,150,0); - - Canvas.SetPos(Canvas.SizeX * 0.16, Canvas.SizeY * 0.43); - Canvas.DrawText("Zoom: 3.0"); - - Canvas.SetPos(Canvas.SizeX * 0.16, Canvas.SizeY * 0.47); - } - else - { - Skins[LenseMaterialID] = ScriptedTextureFallback; - bDrawingFirstPerson = true; - Canvas.DrawActor(self, false, false, DisplayFOV); - bDrawingFirstPerson = false; - } -} simulated function float CalcAspectRatioAdjustedFOV(float AdjustFOV) { local KFPlayerController KFPC; @@ -333,204 +22,15 @@ simulated function float CalcAspectRatioAdjustedFOV(float AdjustFOV) return AdjustFOV; } } -simulated function AdjustIngameScope() -{ - local PlayerController PC; - if(Instigator == none || PlayerController(Instigator.Controller) == none) - return; - PC = PlayerController(Instigator.Controller); - if( !bHasScope ) - return; - switch (KFScopeDetail) - { - case KF_ModelScope: - if( bAimingRifle ) - DisplayFOV = CalcAspectRatioAdjustedFOV(default.ZoomedDisplayFOV); - if ( PC.DesiredFOV == PlayerIronSightFOV && bAimingRifle ) - { - if( Level.NetMode != NM_DedicatedServer && KFPlayerController(Instigator.Controller) != none ) - { - KFPlayerController(Instigator.Controller).TransitionFOV(KFPlayerController(Instigator.Controller).DefaultFOV,0.0); -} - } - break; - case KF_TextureScope: - if( bAimingRifle ) - DisplayFOV = CalcAspectRatioAdjustedFOV(default.ZoomedDisplayFOV); - if ( bAimingRifle && PC.DesiredFOV != PlayerIronSightFOV ) - { - if( Level.NetMode != NM_DedicatedServer && KFPlayerController(Instigator.Controller) != none ) - { - KFPlayerController(Instigator.Controller).TransitionFOV(PlayerIronSightFOV,0.0); - } - } - break; - - case KF_ModelScopeHigh: - if( bAimingRifle ) - { - if( ZoomedDisplayFOVHigh > 0 ) - { - DisplayFOV = CalcAspectRatioAdjustedFOV(default.ZoomedDisplayFOVHigh); - } - else - { - DisplayFOV = CalcAspectRatioAdjustedFOV(default.ZoomedDisplayFOV); - } - } - if ( bAimingRifle && PC.DesiredFOV == PlayerIronSightFOV ) - { - if( Level.NetMode != NM_DedicatedServer && KFPlayerController(Instigator.Controller) != none ) - { - KFPlayerController(Instigator.Controller).TransitionFOV(KFPlayerController(Instigator.Controller).DefaultFOV,0.0); - } - } - break; - } - UpdateScopeMode(); -} -simulated event Destroyed() -{ - if (ScopeScriptedTexture != none) - { - ScopeScriptedTexture.Client = none; - Level.ObjectPool.FreeObject(ScopeScriptedTexture); - ScopeScriptedTexture=none; - } - if (ScriptedScopeCombiner != none) - { - ScriptedScopeCombiner.Material2 = none; - Level.ObjectPool.FreeObject(ScriptedScopeCombiner); - ScriptedScopeCombiner = none; - } - if (ScopeScriptedShader != none) - { - ScopeScriptedShader.Diffuse = none; - ScopeScriptedShader.SelfIllumination = none; - Level.ObjectPool.FreeObject(ScopeScriptedShader); - ScopeScriptedShader = none; - } - Super.Destroyed(); -} -simulated function PreTravelCleanUp() -{ - if (ScopeScriptedTexture != none) - { - ScopeScriptedTexture.Client = none; - Level.ObjectPool.FreeObject(ScopeScriptedTexture); - ScopeScriptedTexture=none; - } - if (ScriptedScopeCombiner != none) - { - ScriptedScopeCombiner.Material2 = none; - Level.ObjectPool.FreeObject(ScriptedScopeCombiner); - ScriptedScopeCombiner = none; - } - if (ScopeScriptedShader != none) - { - ScopeScriptedShader.Diffuse = none; - ScopeScriptedShader.SelfIllumination = none; - Level.ObjectPool.FreeObject(ScopeScriptedShader); - ScopeScriptedShader = none; - } -} -state PendingClientWeaponSet -{ - simulated function Timer() - { - if ( Pawn(Owner) != none && !bIsReloading ) - { - ClientWeaponSet(bPendingSwitch); - } - - if ( IsInState('PendingClientWeaponSet') ) - { - SetTimer(0.1, false); - } - } - simulated function BeginState() - { - SetTimer(0.1, false); - } - simulated function EndState() - { - } -} -simulated function SetZoomBlendColor(Canvas c) -{ - local Byte val; - local Color clr; - local Color fog; - clr.R = 255; - clr.G = 255; - clr.B = 255; - clr.A = 255; - if( Instigator.Region.Zone.bDistanceFog ) - { - fog = Instigator.Region.Zone.DistanceFogColor; - val = 0; - val = Max( val, fog.R); - val = Max( val, fog.G); - val = Max( val, fog.B); - if( val > 128 ) - { - val -= 128; - clr.R -= val; - clr.G -= val; - clr.B -= val; - } - } - c.DrawColor = clr; -} -function bool RecommendRangedAttack() -{ - return true; -} -function float SuggestAttackStyle() -{ - return -1.0; -} -function bool RecommendLongRangedAttack() -{ - return true; -} -simulated function AnimEnd(int channel) -{ - if(!FireMode[1].IsInState('FireLoop')) - { - Super.AnimEnd(channel); - } -} -simulated function WeaponTick(float dt) -{ - Super.WeaponTick(dt); -} -simulated function bool StartFire(int Mode) -{ - if( Mode == 0 ) - return super.StartFire(Mode); - if( !super.StartFire(Mode) ) - return false; - - if( AmmoAmount(0) <= 0 ) - { - return false; - } - AnimStopLooping(); - if( !FireMode[Mode].IsInState('FireLoop') && (AmmoAmount(0) > 0) ) - { - FireMode[Mode].StartFiring(); - return true; - } - else - { - return false; - } - return true; -} defaultproperties { + reloadPreEndFrame=0.339 + reloadEndFrame=0.732 + reloadChargeEndFrame=-1.000000 + reloadMagStartFrame=0.643 + reloadChargeStartFrame=-1.000000 + magazineBone="Magazine" lenseMaterialID=3 scopePortalFOVHigh=22.000000 scopePortalFOV=12.000000 @@ -538,13 +38,13 @@ defaultproperties ScriptedTextureFallbackRef="NicePackT.HFR.CBLens_cmb" bHasScope=True ZoomedDisplayFOVHigh=35.000000 - MagCapacity=10 + MagCapacity=50 ReloadRate=3.000000 ReloadAnim="Reload" ReloadAnimRate=0.600000 WeaponReloadAnim="Reload_M4" bSteadyAim=True - Weight=7.000000 + Weight=5.000000 bHasAimingMode=True IdleAimAnim="Idle" StandardDisplayFOV=60.000000 @@ -562,7 +62,7 @@ defaultproperties PlayerIronSightFOV=65.000000 ZoomedDisplayFOV=32.000000 FireModeClass(0)=class'NiceHFRPFire' - FireModeClass(1)=class'NiceHFRBurstFire' + FireModeClass(1)=Class'KFMod.NoFire' PutDownAnim="PutDown" AIRating=0.700000 CurrentRating=0.700000 diff --git a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRAmmo.uc b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRAmmo.uc index 2d11ca5..04466fc 100644 --- a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRAmmo.uc +++ b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRAmmo.uc @@ -1,10 +1,10 @@ -class NiceHFRAmmo extends KFAmmunition; +class NiceHFRAmmo extends NiceAmmo; #EXEC OBJ LOAD FILE=KillingFloorHUD.utx defaultproperties { - AmmoPickupAmount=15 - MaxAmmo=100 - InitialAmount=40 + AmmoPickupAmount=75 + MaxAmmo=300 + InitialAmount=75 PickupClass=class'NiceHFRAmmoPickup' IconMaterial=Texture'KillingFloorHUD.Generic.HUD' IconCoords=(X1=336,Y1=82,X2=382,Y2=125) diff --git a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRAmmoPickup.uc b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRAmmoPickup.uc index 40d9353..6eeaba4 100644 --- a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRAmmoPickup.uc +++ b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRAmmoPickup.uc @@ -1,7 +1,7 @@ -class NiceHFRAmmoPickup extends KFAmmoPickup; +class NiceHFRAmmoPickup extends NiceAmmoPickup; defaultproperties { - AmmoAmount=15 + AmmoAmount=50 InventoryType=class'NiceHFRAmmo' PickupMessage="Fire balloon" StaticMesh=StaticMesh'KillingFloorStatics.L85Ammo' diff --git a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRBullet.uc b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRBullet.uc new file mode 100644 index 0000000..09fc990 --- /dev/null +++ b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRBullet.uc @@ -0,0 +1,11 @@ +class NiceHFRBullet extends NiceBullet; + +defaultproperties +{ + bDisableComplexMovement=False + trailXClass=None + StaticMeshRef="ZED_FX_SM.Energy.ZED_FX_Energy_Card" + DrawScale=0.500000 + ambientSoundRef="KF_FY_ZEDV2SND.WEP_ZEDV2_Projectile_Loop" + explosionImpact=(bImportanEffect=True,decalClass=Class'KFMod.FlameThrowerBurnMark_Medium',EmitterClass=Class'KFMod.ZEDMKIIPrimaryProjectileImpact',emitterShiftWall=20.000000,emitterShiftPawn=20.000000,noiseRef="KF_FY_ZEDV2SND.WEP_ZEDV2_Projectile_Explode",noiseVolume=2.000000) +} diff --git a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRPFire.uc b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRPFire.uc index 142fb8d..5d2d770 100644 --- a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRPFire.uc +++ b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRPFire.uc @@ -1,25 +1,29 @@ -class NiceHFRPFire extends KFFire; +class NiceHFRPFire extends NiceFire; + defaultproperties { + ProjectileSpeed=2000.000000 FireAimedAnim="Fire_Iron" - RecoilRate=0.120000 - maxVerticalRecoilAngle=500 + RecoilRate=0.070000 + maxVerticalRecoilAngle=70 + maxHorizontalRecoilAngle=35 bAccuracyBonusForSemiAuto=True bRandomPitchFireSound=False - FireSoundRef="KF_SP_LongmusketSnd.KFO_Sniper_Fire_M" - StereoFireSoundRef="KF_SP_LongmusketSnd.KFO_Sniper_Fire_S" - NoAmmoSoundRef="KF_AK47Snd.AK47_DryFire" - DamageType=class'NiceDamTypeHFRAssaultRifle' + FireSoundRef="KF_FY_ZEDV2SND.WEP_ZEDV2_Fire_M" + StereoFireSoundRef="KF_FY_ZEDV2SND.WEP_ZEDV2_Fire_S" + NoAmmoSoundRef="KF_ZEDGunSnd.KF_WEP_ZED_Dryfire" + DamageType=class'NiceDamTypeHFR' DamageMax=50 Momentum=8500.000000 - bWaitForRelease=True + bWaitForRelease=False TransientSoundVolume=1.200000 TransientSoundRadius=500.000000 FireLoopAnim="Fire" FireAnimRate=0.909000 TweenTime=0.025000 FireForce="AssaultRifleFire" - FireRate=0.600000 + FireRate=0.096000 + bulletClass=class'NiceHFRBullet' AmmoClass=class'NiceHFRAmmo' AmmoPerFire=1 ShakeRotMag=(X=50.000000,Y=50.000000,Z=350.000000) @@ -32,5 +36,4 @@ defaultproperties FlashEmitterClass=Class'ROEffects.MuzzleFlash1stSPSniper' aimerror=42.000000 Spread=0.015000 - SpreadStyle=SS_Random } diff --git a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRPickup.uc b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRPickup.uc index 8fc434a..295e41d 100644 --- a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRPickup.uc +++ b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRPickup.uc @@ -1,18 +1,19 @@ -class NiceHFRPickup extends KFWeaponPickup; +class NiceHFRPickup extends NiceWeaponPickup; defaultproperties { - Weight=7.000000 - AmmoCost=30 - BuyClipSize=15 + Weight=5.000000 + AmmoCost=26 + BuyClipSize=50 PowerValue=100 SpeedValue=100 RangeValue=40 + cost=750 Description="Advanced horzine flame rifle." ItemName="Horzine flame rifle" ItemShortName="HFR" AmmoItemName="Fire balloon" AmmoMesh=StaticMesh'KillingFloorStatics.FT_AmmoMesh' - CorrespondingPerkIndex=5 + CorrespondingPerkIndex=3 EquipmentCategoryID=3 InventoryType=class'NiceHFR' PickupMessage="You got the HFR." diff --git a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRTendril.uc b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRTendril.uc index c175971..4d6c567 100644 --- a/sources/Weapons/Playable/Incendiary/HFR/NiceHFRTendril.uc +++ b/sources/Weapons/Playable/Incendiary/HFR/NiceHFRTendril.uc @@ -1,6 +1,6 @@ class NiceHFRTendril extends FlameTendril; defaultproperties { - Damage=36.000000 + Damage=16.000000 MyDamageType=class'NiceDamTypeHFR' } diff --git a/sources/Weapons/Playable/SMG/Kriss/NiceDamTypeKrissM.uc b/sources/Weapons/Playable/SMG/Kriss/NiceDamTypeKrissM.uc index f728723..48b3dad 100644 --- a/sources/Weapons/Playable/SMG/Kriss/NiceDamTypeKrissM.uc +++ b/sources/Weapons/Playable/SMG/Kriss/NiceDamTypeKrissM.uc @@ -1,6 +1,8 @@ -class NiceDamTypeKrissM extends NiceDamageTypeVetCommando +class NiceDamTypeKrissM extends NiceDamageTypeVetDemolitions abstract; defaultproperties { + stoppingPower=0.25 + HeadShotDamageMult=1.500000 WeaponClass=class'NiceKrissMMedicGun' } diff --git a/sources/Weapons/Playable/SMG/Kriss/NiceKrissMFire.uc b/sources/Weapons/Playable/SMG/Kriss/NiceKrissMFire.uc index e47aedf..60029e5 100644 --- a/sources/Weapons/Playable/SMG/Kriss/NiceKrissMFire.uc +++ b/sources/Weapons/Playable/SMG/Kriss/NiceKrissMFire.uc @@ -13,8 +13,8 @@ defaultproperties ShellEjectBoneName="Shell_eject" NoAmmoSoundRef="KF_MP7Snd.MP7_DryFire" DamageType=class'NiceDamTypeKrissM' - DamageMin=35 - DamageMax=35 + DamageMin=48 + DamageMax=48 Momentum=12500.000000 FireRate=0.040000 AmmoClass=class'NiceKrissMAmmo' @@ -27,4 +27,8 @@ defaultproperties FlashEmitterClass=Class'ROEffects.MuzzleFlash1stMP' Spread=500.0 SpreadStyle=SS_Random + minimalSpreadScale=0.0 + activeSpreadScale=0.0 + spreadGainedPerShot=0.125 + spreadLostPerSecond=0.5 } diff --git a/sources/Weapons/Playable/SMG/Kriss/NiceKrissMPickup.uc b/sources/Weapons/Playable/SMG/Kriss/NiceKrissMPickup.uc index d8ec776..043b94d 100644 --- a/sources/Weapons/Playable/SMG/Kriss/NiceKrissMPickup.uc +++ b/sources/Weapons/Playable/SMG/Kriss/NiceKrissMPickup.uc @@ -17,7 +17,7 @@ defaultproperties AmmoItemName="45. ACP Ammo" AmmoMesh=StaticMesh'KillingFloorStatics.L85Ammo' EquipmentCategoryID=3 - CorrespondingPerkIndex=3 + CorrespondingPerkIndex=6 InventoryType=class'NiceKrissMMedicGun' PickupMessage="You got the KRISS Vector Medic Gun" PickupSound=Sound'KF_KrissSND.Handling.KF_WEP_KRISS_Handling_Pickup' diff --git a/sources/Weapons/Playable/SMG/M7A3/NiceDamTypeM7A3M.uc b/sources/Weapons/Playable/SMG/M7A3/NiceDamTypeM7A3M.uc index e27b99e..9c584ce 100644 --- a/sources/Weapons/Playable/SMG/M7A3/NiceDamTypeM7A3M.uc +++ b/sources/Weapons/Playable/SMG/M7A3/NiceDamTypeM7A3M.uc @@ -1,7 +1,8 @@ -class NiceDamTypeM7A3M extends NiceDamageTypeVetCommando +class NiceDamTypeM7A3M extends NiceDamageTypeVetDemolitions abstract; defaultproperties { + stoppingPower=0.15 HeadShotDamageMult=2.000000 WeaponClass=class'NiceM7A3MMedicGun' } diff --git a/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MAmmo.uc b/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MAmmo.uc index 0eda0d3..e900e0c 100644 --- a/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MAmmo.uc +++ b/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MAmmo.uc @@ -3,8 +3,8 @@ defaultproperties { WeaponPickupClass=class'NiceM7A3MPickup' AmmoPickupAmount=30 - MaxAmmo=180 - InitialAmount=45 + MaxAmmo=160 + InitialAmount=40 PickupClass=class'NiceM7A3MAmmoPickup' IconMaterial=Texture'KillingFloorHUD.Generic.HUD' IconCoords=(X1=336,Y1=82,X2=382,Y2=125) diff --git a/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MAmmoPickup.uc b/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MAmmoPickup.uc index 0f8acfc..220b8fb 100644 --- a/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MAmmoPickup.uc +++ b/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MAmmoPickup.uc @@ -1,7 +1,7 @@ class NiceM7A3MAmmoPickup extends NiceAmmoPickup; defaultproperties { - AmmoAmount=15 + AmmoAmount=30 InventoryType=class'NiceM7A3MAmmo' PickupMessage="Rounds 7.6x40mm" StaticMesh=StaticMesh'KillingFloorStatics.L85Ammo' diff --git a/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MFire.uc b/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MFire.uc index 0376bf8..f8d867b 100644 --- a/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MFire.uc +++ b/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MFire.uc @@ -34,4 +34,8 @@ defaultproperties aimerror=42.000000 Spread=500.0 SpreadStyle=SS_Random + minimalSpreadScale=0.0 + activeSpreadScale=0.0 + spreadGainedPerShot=0.25 + spreadLostPerSecond=0.5 } diff --git a/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MPickup.uc b/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MPickup.uc index 3454139..826c735 100644 --- a/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MPickup.uc +++ b/sources/Weapons/Playable/SMG/M7A3/NiceM7A3MPickup.uc @@ -3,7 +3,7 @@ defaultproperties { Weight=5.000000 cost=1250 - AmmoCost=33 + AmmoCost=50 BuyClipSize=30 PowerValue=45 SpeedValue=60 @@ -14,7 +14,7 @@ defaultproperties AmmoItemName="7.6x40mm Ammo" AmmoMesh=StaticMesh'KillingFloorStatics.L85Ammo' EquipmentCategoryID=3 - CorrespondingPerkIndex=3 + CorrespondingPerkIndex=6 InventoryType=class'NiceM7A3MMedicGun' PickupMessage="You got the M7A3 Medic Gun" PickupSound=Sound'KF_M7A3Snd.M7A3_Pickup' diff --git a/sources/Weapons/Playable/SMG/MP5M/NiceDamTypeMP5M.uc b/sources/Weapons/Playable/SMG/MP5M/NiceDamTypeMP5M.uc index 3af2db7..89f2bcb 100644 --- a/sources/Weapons/Playable/SMG/MP5M/NiceDamTypeMP5M.uc +++ b/sources/Weapons/Playable/SMG/MP5M/NiceDamTypeMP5M.uc @@ -1,7 +1,8 @@ -class NiceDamTypeMP5M extends NiceDamageTypeVetCommando +class NiceDamTypeMP5M extends NiceDamageTypeVetDemolitions abstract; defaultproperties { + stoppingPower=0.15 HeadShotDamageMult=2.000000 WeaponClass=class'NiceMP5MMedicGun' } diff --git a/sources/Weapons/Playable/SMG/MP5M/NiceMP5MFire.uc b/sources/Weapons/Playable/SMG/MP5M/NiceMP5MFire.uc index ab4be61..d636895 100644 --- a/sources/Weapons/Playable/SMG/MP5M/NiceMP5MFire.uc +++ b/sources/Weapons/Playable/SMG/MP5M/NiceMP5MFire.uc @@ -5,9 +5,9 @@ defaultproperties FireEndStereoSoundRef="KF_MP5Snd.MP5_Fire_Loop_End_S" AmbientFireSoundRef="KF_MP5Snd.MP5_Fire_Loop" ProjectileSpeed=21250.000000 - RecoilRate=0.0075000 - maxVerticalRecoilAngle=160 - maxHorizontalRecoilAngle=80 + RecoilRate=0.0100000 + maxVerticalRecoilAngle=40 + maxHorizontalRecoilAngle=20 RecoilVelocityScale=0.000000 ShellEjectClass=Class'ROEffects.KFShellEjectMP5SMG' ShellEjectBoneName="Shell_eject" @@ -15,8 +15,12 @@ defaultproperties DamageType=class'NiceDamTypeMP5M' DamageMin=35 DamageMax=35 - Spread=500.0 + Spread=750.0 SpreadStyle=SS_Random + minimalSpreadScale=0.0 + activeSpreadScale=0.0 + spreadGainedPerShot=0.25 + spreadLostPerSecond=1.0 Momentum=5500.000000 FireRate=0.075000 AmmoClass=class'NiceMP5MAmmo' diff --git a/sources/Weapons/Playable/SMG/MP5M/NiceMP5MPickup.uc b/sources/Weapons/Playable/SMG/MP5M/NiceMP5MPickup.uc index 39f5464..dbd1e37 100644 --- a/sources/Weapons/Playable/SMG/MP5M/NiceMP5MPickup.uc +++ b/sources/Weapons/Playable/SMG/MP5M/NiceMP5MPickup.uc @@ -14,7 +14,7 @@ defaultproperties AmmoItemName="9x19mm Ammo" AmmoMesh=StaticMesh'KillingFloorStatics.L85Ammo' EquipmentCategoryID=3 - CorrespondingPerkIndex=3 + CorrespondingPerkIndex=6 VariantClasses(0)=Class'KFMod.CamoMP5MPickup' InventoryType=class'NiceMP5MMedicGun' PickupMessage="You got the MP5M Medic Gun" diff --git a/sources/Weapons/Playable/SMG/MP7M/NiceDamTypeMP7M.uc b/sources/Weapons/Playable/SMG/MP7M/NiceDamTypeMP7M.uc index 1076d20..a6274cc 100644 --- a/sources/Weapons/Playable/SMG/MP7M/NiceDamTypeMP7M.uc +++ b/sources/Weapons/Playable/SMG/MP7M/NiceDamTypeMP7M.uc @@ -1,9 +1,10 @@ -class NiceDamTypeMP7M extends NiceDamageTypeVetCommando +class NiceDamTypeMP7M extends NiceDamageTypeVetDemolitions abstract; defaultproperties { bPenetrationHSOnly=True MaxPenetrations=1 HeadShotDamageMult=2.250000 + stoppingPower=0.15 WeaponClass=class'NiceMP7MMedicGun' } diff --git a/sources/Weapons/Playable/SMG/MP7M/NiceMP7MFire.uc b/sources/Weapons/Playable/SMG/MP7M/NiceMP7MFire.uc index 9806704..cc238c3 100644 --- a/sources/Weapons/Playable/SMG/MP7M/NiceMP7MFire.uc +++ b/sources/Weapons/Playable/SMG/MP7M/NiceMP7MFire.uc @@ -25,6 +25,10 @@ defaultproperties ShakeOffsetRate=(X=1000.000000,Y=1000.000000,Z=1000.000000) ShakeOffsetTime=1.250000 FlashEmitterClass=Class'ROEffects.MuzzleFlash1stMP' - Spread=500.0 + Spread=750.0 SpreadStyle=SS_Random + minimalSpreadScale=0.0 + activeSpreadScale=0.0 + spreadGainedPerShot=0.1 + spreadLostPerSecond=0.5 } diff --git a/sources/Weapons/Playable/SMG/MP7M/NiceMP7MPickup.uc b/sources/Weapons/Playable/SMG/MP7M/NiceMP7MPickup.uc index 95104e2..cf4f30b 100644 --- a/sources/Weapons/Playable/SMG/MP7M/NiceMP7MPickup.uc +++ b/sources/Weapons/Playable/SMG/MP7M/NiceMP7MPickup.uc @@ -15,7 +15,7 @@ defaultproperties AmmoItemName="4.6x30mm Ammo" AmmoMesh=StaticMesh'KillingFloorStatics.L85Ammo' EquipmentCategoryID=3 - CorrespondingPerkIndex=3 + CorrespondingPerkIndex=6 InventoryType=class'NiceMP7MMedicGun' PickupMessage="You got the MP7M Medic Gun" PickupSound=Sound'KF_MP7Snd.MP7_Pickup' diff --git a/sources/Weapons/Playable/Shotguns/Boomstick/NiceBoomStickAltFire.uc b/sources/Weapons/Playable/Shotguns/Boomstick/NiceBoomStickAltFire.uc index 4365656..82bcb3c 100644 --- a/sources/Weapons/Playable/Shotguns/Boomstick/NiceBoomStickAltFire.uc +++ b/sources/Weapons/Playable/Shotguns/Boomstick/NiceBoomStickAltFire.uc @@ -1,13 +1,13 @@ class NiceBoomStickAltFire extends NiceBoomStickFire; // Overload to force last shot to have a different animation with reload // NICETODO: uncomment this -function name GetCorrectAnim(bool bLoop, bool bAimed){ +function name GetCorrectAnim(bool bLoop, bool bAimed) { if(currentContext.sourceWeapon != none && currentContext.sourceWeapon.MagAmmoRemainingClient > 0) - return super.GetCorrectAnim(bLoop, bAimed); + return super.GetCorrectAnim(bLoop, bAimed); if(bAimed) - return 'Fire_Last_Iron'; + return 'Fire_Last_Iron'; else - return 'Fire_Last'; + return 'Fire_Last'; return FireAnim; } defaultproperties diff --git a/sources/Weapons/Playable/Shotguns/Boomstick/NiceBoomStickFire.uc b/sources/Weapons/Playable/Shotguns/Boomstick/NiceBoomStickFire.uc index ce35d5a..837c195 100644 --- a/sources/Weapons/Playable/Shotguns/Boomstick/NiceBoomStickFire.uc +++ b/sources/Weapons/Playable/Shotguns/Boomstick/NiceBoomStickFire.uc @@ -58,5 +58,6 @@ defaultproperties ShakeOffsetTime=3.500000 BotRefireRate=2.500000 aimerror=2.000000 - Spread=3000.000000 + Spread=2000.000000 + FireAnimRate=1.25 } diff --git a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGun.uc b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGun.uc index b7d85ae..6eaf758 100644 --- a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGun.uc +++ b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGun.uc @@ -10,7 +10,7 @@ defaultproperties reloadMagStartFrame=0.278000 reloadChargeStartFrame=-1.000000 FirstPersonFlashlightOffset=(X=-20.000000,Y=-22.000000,Z=8.000000) - MagCapacity=28 + MagCapacity=42 ReloadRate=2.600000 ReloadAnim="Reload" ReloadAnimRate=1.000000 diff --git a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunAltFire.uc b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunAltFire.uc index 5650ed5..059a239 100644 --- a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunAltFire.uc +++ b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunAltFire.uc @@ -3,6 +3,9 @@ defaultproperties { bCanFireIncomplete=True ProjectileSpeed=3500.000000 + maxVerticalRecoilAngle=1250 + maxHorizontalRecoilAngle=750 + FireRate=0.600000 DamageType=class'NiceDamTypeNailGunWeak' AmmoPerFire=7 SpreadStyle=SS_Random diff --git a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunAmmo.uc b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunAmmo.uc index a005df5..b0596d7 100644 --- a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunAmmo.uc +++ b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunAmmo.uc @@ -3,9 +3,9 @@ class NiceNailGunAmmo extends NiceAmmo; defaultproperties { WeaponPickupClass=class'NiceNailGunPickup' - AmmoPickupAmount=28 - MaxAmmo=168 - InitialAmount=84 + AmmoPickupAmount=42 + MaxAmmo=210 + InitialAmount=52 IconMaterial=Texture'KillingFloorHUD.Generic.HUD' IconCoords=(X1=451,Y1=445,X2=510,Y2=500) } diff --git a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunFire.uc b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunFire.uc index f812f62..969bcdf 100644 --- a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunFire.uc +++ b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunFire.uc @@ -10,8 +10,8 @@ defaultproperties bShouldBounce=True bCausePain=True bulletClass=class'NiceNail' - maxVerticalRecoilAngle=1250 - maxHorizontalRecoilAngle=750 + maxVerticalRecoilAngle=0 + maxHorizontalRecoilAngle=0 bRandomPitchFireSound=True FireSoundRef="KF_NailShotgun.NailShotgun_Fire_Single_M" StereoFireSoundRef="KF_NailShotgun.NailShotgun_Fire_Single_S" @@ -19,7 +19,7 @@ defaultproperties DamageType=class'NiceDamTypeNailGun' DamageMax=66 FireAnimRate=1.250000 - FireRate=0.400000 + FireRate=0.300000 AmmoClass=class'NiceNailGunAmmo' ShakeRotTime=3.000000 ShakeOffsetTime=2.000000 diff --git a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunPickup.uc b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunPickup.uc index fc10888..cfb7a50 100644 --- a/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunPickup.uc +++ b/sources/Weapons/Playable/Shotguns/Nailgun/NiceNailGunPickup.uc @@ -3,8 +3,8 @@ defaultproperties { Weight=8.000000 cost=250 - AmmoCost=17 - BuyClipSize=28 + AmmoCost=27 + BuyClipSize=42 PowerValue=70 SpeedValue=55 RangeValue=25 diff --git a/sources/Weapons/Playable/Shotguns/Spas/NiceSpasAltFire.uc b/sources/Weapons/Playable/Shotguns/Spas/NiceSpasAltFire.uc index 8b97ecb..a5af9ef 100644 --- a/sources/Weapons/Playable/Shotguns/Spas/NiceSpasAltFire.uc +++ b/sources/Weapons/Playable/Shotguns/Spas/NiceSpasAltFire.uc @@ -1,6 +1,7 @@ class NiceSpasAltFire extends NiceSpasFire; defaultproperties { + ProjPerFire=8 maxVerticalRecoilAngle=300 maxHorizontalRecoilAngle=180 FireAnimRate=0.650000 diff --git a/sources/Weapons/Playable/SniperWeapons/HuntingRifle/NiceHuntingRiflePickup.uc b/sources/Weapons/Playable/SniperWeapons/HuntingRifle/NiceHuntingRiflePickup.uc index 555932b..55477da 100644 --- a/sources/Weapons/Playable/SniperWeapons/HuntingRifle/NiceHuntingRiflePickup.uc +++ b/sources/Weapons/Playable/SniperWeapons/HuntingRifle/NiceHuntingRiflePickup.uc @@ -6,7 +6,7 @@ defaultproperties { Weight=6.000000 cost=750 - AmmoCost=34 + AmmoCost=22 BuyClipSize=5 PowerValue=55 SpeedValue=42 diff --git a/sources/Weapons/Playable/Tools/NiceSyringe.uc b/sources/Weapons/Playable/Tools/NiceSyringe.uc index 48116c4..56ac0d6 100644 --- a/sources/Weapons/Playable/Tools/NiceSyringe.uc +++ b/sources/Weapons/Playable/Tools/NiceSyringe.uc @@ -1,8 +1,108 @@ -class NiceSyringe extends ScrnSyringe; +class NiceSyringe extends NiceMeleeWeapon; -defaultproperties { - ItemName="Nice Med-Syringe" - FireModeClass(0)=class'NiceSyringeFire' - FireModeClass(1)=class'NiceSyringeAltFire' - PickupClass=class'NiceSyringePickup' -} \ No newline at end of file +var () int HealBoostAmount; +var float RegenTimer; +var localized string SuccessfulHealMessage; + +replication +{ + reliable if( Role == ROLE_Authority ) + ClientSuccessfulHeal; + +} + +simulated function PostBeginPlay() +{ + // Weapon will handle FireMode instantiation + Super.PostBeginPlay(); + + if( Role == ROLE_Authority ) { + HealBoostAmount = default.HealBoostAmount; + } +} + +// The server lets the client know they successfully healed someone +simulated function ClientSuccessfulHeal(String HealedName) +{ + if( PlayerController(Instigator.Controller) != none ) + { + PlayerController(Instigator.controller).ClientMessage(SuccessfulHealMessage$HealedName, 'CriticalEvent'); + } +} + +simulated function Timer() +{ + Super.Timer(); + if( KFPawn(Instigator)!=None && KFPawn(Instigator).bIsQuickHealing>0 && ClientState==WS_ReadyToFire ) + { + if( KFPawn(Instigator).bIsQuickHealing==1 ) + { + if( !HackClientStartFire() ) + { + if( Instigator.Health>=Instigator.HealthMax || ChargeBar()<0.75 ) + KFPawn(Instigator).bIsQuickHealing = 2; // Was healed by someone else or some other error occurred. + SetTimer(0.2,False); + return; + } + KFPawn(Instigator).bIsQuickHealing = 2; + SetTimer(FireMode[1].FireRate+0.5,False); + } + else + { + Instigator.SwitchToLastWeapon(); + KFPawn(Instigator).bIsQuickHealing = 0; + } + } + else if( ClientState==WS_Hidden && KFPawn(Instigator)!=None ) + KFPawn(Instigator).bIsQuickHealing = 0; // Weapon was changed, ensure to reset this. +} + +simulated function bool HackClientStartFire() +{ + if( StartFire(1) ) + { + if( Role 1 && KFPlayerController(Instigator.Controller) != none && + KFSteamStatsAndAchievements(KFPlayerController(Instigator.Controller).SteamStatsAndAchievements) != none ) + { + KFSteamStatsAndAchievements(KFPlayerController(Instigator.Controller).SteamStatsAndAchievements).AddSelfHeal(); + } +} + +function Timer() +{ + local float HealSum, HealPotency; + local KFPlayerReplicationInfo KFPRI; + + KFPRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo); + + HealSum = NiceSyringe(Weapon).HealBoostAmount; + + HealPotency = 1.0; + + if ( KFPRI != none && KFPRI.ClientVeteranSkill != none ) + HealPotency = KFPRI.ClientVeteranSkill.Static.GetHealPotency(KFPRI); + HealSum *= HealPotency; + + Load = 1; + ReduceAmmoClient(); + if ( NiceHumanPawn(Instigator) != none ) + NiceHumanPawn(Instigator).TakeHealing(NiceHumanPawn(Instigator), HealSum, HealPotency, KFWeapon(Instigator.Weapon)); + else + KFPawn(Instigator).GiveHealth(HealSum, Instigator.HealthMax); +} + +function bool AllowFire() +{ + if (Instigator.Health >= Instigator.HealthMax) + return false; + + return Weapon.AmmoAmount(ThisModeNum) >= AmmoPerFire; +} + +event ModeDoFire() +{ + Load = 1; + Super.ModeDoFire(); +} + +function PlayFiring() +{ + if ( Weapon.Mesh != None ) + { + if ( FireCount > 0 ) + { + if ( Weapon.HasAnim(FireLoopAnim) ) + { + Weapon.PlayAnim(FireLoopAnim, FireLoopAnimRate, 0.0); + } + else + { + Weapon.PlayAnim(FireAnim, FireAnimRate, 0.0); + } + } + else + { + Weapon.PlayAnim(FireAnim, FireAnimRate, 0.0); + } + } + Weapon.PlayOwnedSound(FireSound,SLOT_Interact,TransientSoundVolume,,TransientSoundRadius,Default.FireAnimRate/FireAnimRate,false); + ClientPlayForceFeedback(FireForce); // jdf + + FireCount++; +} + +defaultproperties { + AmmoClass=class'NiceSyringeAmmo' + AmmoPerFire=1 + TweenTime=0.1 + TransientSoundVolume=1.8 + FireAnim="AltFire" + FireRate=3.60000 + bModeExclusive=true + InjectDelay=0.1 + HealeeRange=70.000000 +} diff --git a/sources/Weapons/Playable/Tools/NiceSyringeAmmo.uc b/sources/Weapons/Playable/Tools/NiceSyringeAmmo.uc new file mode 100644 index 0000000..dc7731f --- /dev/null +++ b/sources/Weapons/Playable/Tools/NiceSyringeAmmo.uc @@ -0,0 +1,12 @@ +class NiceSyringeAmmo extends NiceAmmo; + +defaultproperties { + WeaponPickupClass=class'NiceSyringePickup' + AmmoPickupAmount=0 + MaxAmmo=4 + InitialAmount=1 + PickupClass=class'NiceSyringeAmmoPickup' + IconMaterial=Texture'KillingFloorHUD.Generic.HUD' + IconCoords=(X1=336,Y1=82,X2=382,Y2=125) + ItemName="Healing juice" +} diff --git a/sources/Weapons/Playable/Tools/NiceSyringeAmmoPickup.uc b/sources/Weapons/Playable/Tools/NiceSyringeAmmoPickup.uc new file mode 100644 index 0000000..600369e --- /dev/null +++ b/sources/Weapons/Playable/Tools/NiceSyringeAmmoPickup.uc @@ -0,0 +1,8 @@ +class NiceSyringeAmmoPickup extends NiceAmmoPickup; + +defaultproperties { + AmmoAmount=1 + InventoryType=class'NiceSyringe' + PickupMessage="Healing juice" + StaticMesh=StaticMesh'KillingFloorStatics.L85Ammo' +} diff --git a/sources/Weapons/Playable/Tools/NiceSyringeFire.uc b/sources/Weapons/Playable/Tools/NiceSyringeFire.uc index a632d12..287a10a 100644 --- a/sources/Weapons/Playable/Tools/NiceSyringeFire.uc +++ b/sources/Weapons/Playable/Tools/NiceSyringeFire.uc @@ -1,23 +1,208 @@ -class NiceSyringeFire extends ScrnSyringeFire; +class NiceSyringeFire extends NiceMeleeFire; -// default == 80 -const SEARCH_RADIUS=120.0; +var float LastHealAttempt; +var float HealAttemptDelay; +var float LastHealMessageTime; +var float HealMessageDelay; +var localized string NoHealTargetMessage; +var KFHumanPawn CachedHealee; +var transient float PendingHealTime; -function KFHumanPawn GetHealee() { +simulated function DestroyEffects() +{ + super.DestroyEffects(); + + if (CachedHealee != None) + CachedHealee = none; +} + +simulated function bool AllowFire() { + local KFHumanPawn Healtarget; + local string healeeName; + if (!super.AllowFire()) { + return false; + } + if (CanFindHealee()) { + if( CachedHealee.PlayerReplicationInfo != none && + CachedHealee.PlayerReplicationInfo.PlayerName != "") + { + HealeeName = CachedHealee.PlayerReplicationInfo.PlayerName; + } + else { + HealeeName = CachedHealee.MenuName; + } + NiceSyringe(Weapon).ClientSuccessfulHeal(HealeeName); + // Give the messages if we missed our heal, can't find a target, etc + if ( KFPlayerController(Instigator.Controller) != none ) + { + if ( LastHealAttempt + HealAttemptDelay < Level.TimeSeconds) + { + PlayerController(Instigator.controller).ClientMessage(NoHealTargetMessage, 'CriticalEvent'); + LastHealAttempt = Level.TimeSeconds; + } + + if ( Level.TimeSeconds - LastHealMessageTime > HealMessageDelay ) + { + // if there's a Player within 2 meters who needs healing, say that we're trying to heal them + foreach Instigator.VisibleCollidingActors(class'KFHumanPawn', Healtarget, 100) + { + if ( Healtarget != Instigator && Healtarget.Health < Healtarget.HealthMax ) + { + PlayerController(Instigator.Controller).Speech('AUTO', 5, ""); + LastHealMessageTime = Level.TimeSeconds; + + break; + } + } + } + } + return true; + } + return false; +} + +function Timer() +{ + local KFPlayerReplicationInfo PRI; + local int MedicReward; + local KFHumanPawn Healed; + local float HealSum, HealPotency; // for modifying based on perks + + PRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo); + Healed = CachedHealee; + HealPotency = 1.0; + CachedHealee = none; + if ( Healed != none && Healed.Health > 0 && Healed != Instigator ) + { + Load = 1; + ReduceAmmoClient(); + + if ( PRI != none && PRI.ClientVeteranSkill != none ) + HealPotency = PRI.ClientVeteranSkill.Static.GetHealPotency(PRI); + + HealSum = NiceSyringe(Weapon).HealBoostAmount; + + HealSum *= HealPotency; + MedicReward = HealSum; + + if ( (Healed.Health + Healed.healthToGive + MedicReward) > Healed.HealthMax ) + { + MedicReward = Healed.HealthMax - (Healed.Health + Healed.healthToGive); + if ( MedicReward < 0 ) + { + MedicReward = 0; + } + } + + if ( NiceHumanPawn(Healed) != none ) + NiceHumanPawn(Healed).TakeHealing(NiceHumanPawn(Instigator), HealSum, HealPotency, KFWeapon(Instigator.Weapon)); + else + Healed.GiveHealth(HealSum, Healed.HealthMax); + + // Tell them we're healing them + PlayerController(Instigator.Controller).Speech('AUTO', 5, ""); + LastHealMessageTime = Level.TimeSeconds; + + if ( PRI != None ) + { + if ( MedicReward > 0 && KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements) != none ) + { + KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements).AddDamageHealed(MedicReward); + } + + // Give the medic reward money as a percentage of how much of the person's health they healed + MedicReward = int((FMin(float(MedicReward),Healed.HealthMax)/Healed.HealthMax) * 60); // Increased to 80 in Balance Round 6, reduced to 60 in Round 7 + + if ( class'ScrnBalance'.default.Mut.bMedicRewardFromTeam && Healed.PlayerReplicationInfo != none && Healed.PlayerReplicationInfo.Team != none ) { + // give money from team wallet + if ( Healed.PlayerReplicationInfo.Team.Score >= MedicReward ) { + Healed.PlayerReplicationInfo.Team.Score -= MedicReward; + PRI.Score += MedicReward; + } + } + else + PRI.Score += MedicReward; + + if ( KFHumanPawn(Instigator) != none ) + { + KFHumanPawn(Instigator).AlphaAmount = 255; + } + } + } +} + +function KFHumanPawn GetHealee() +{ local KFHumanPawn KFHP, BestKFHP; local vector Dir; local float TempDot, BestDot; Dir = vector(Instigator.GetViewRotation()); - foreach Instigator.VisibleCollidingActors(class'KFHumanPawn', KFHP, SEARCH_RADIUS) { - if (KFHP.Health < KFHP.HealthMax && KFHP.Health > 0) { + foreach Instigator.VisibleCollidingActors(class'KFHumanPawn', KFHP, 80.0) + { + if ( KFHP.Health < KFHP.HealthMax && KFHP.Health > 0 ) + { TempDot = Dir dot (KFHP.Location - Instigator.Location); - if (TempDot > 0.7 && TempDot > BestDot) { + if ( TempDot > 0.7 && TempDot > BestDot ) + { BestKFHP = KFHP; BestDot = TempDot; } } } + return BestKFHP; -} \ No newline at end of file +} + +// Can we find someone to heal +function bool CanFindHealee() +{ + local KFHumanPawn Healtarget; + + Healtarget = GetHealee(); + CachedHealee = Healtarget; + + // Can't use syringe if we can't find a target + if ( Healtarget == none ) + { + if ( KFPlayerController(Instigator.Controller) != none ) + { + KFPlayerController(Instigator.Controller).CheckForHint(53); + } + + return false; + } + + // Can't use syringe if our target is already being healed to full health. + if ( (Healtarget.Health == Healtarget.Healthmax) || ((Healtarget.healthToGive + Healtarget.Health) >= Healtarget.Healthmax) ) + { + return false; + } + + return true; +} + +function float GetFireSpeed() +{ + if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none ) + { + return KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetFireSpeedMod(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), Weapon); + } + + return 1; +} + +defaultproperties { + AmmoClass=class'NiceSyringeAmmo' + ammoPerFire=1 + + FireAnims(0)="Fire" + FireRate=2.800000 + damageDelay=0.36 + + HealAttemptDelay=0.5 + HealMessageDelay=10.0 + NoHealTargetMessage="You must be near another player to heal them!" + bWaitForRelease=true +} diff --git a/sources/Weapons/Playable/Tools/NiceSyringePickup.uc b/sources/Weapons/Playable/Tools/NiceSyringePickup.uc index a9673b6..424c4e4 100644 --- a/sources/Weapons/Playable/Tools/NiceSyringePickup.uc +++ b/sources/Weapons/Playable/Tools/NiceSyringePickup.uc @@ -1,6 +1,19 @@ -class NiceSyringePickup extends ScrnSyringePickup; +class NiceSyringePickup extends NiceWeaponPickup; defaultproperties { - ItemName="Nice Med-Syringe" - InventoryType=class'NiceSyringe' -} \ No newline at end of file + ItemName="Med-Syringe" + InventoryType=Class'NicePack.NiceSyringe' + Weight=0.000000 + cost=100 + AmmoCost=40 + BuyClipSize=1 + PickupMessage="You got the Med-Syringe." + PickupSound=Sound'Inf_Weapons_Foley.AmmoPickup' + PickupForce="AssaultRiflePickup" + StaticMesh=StaticMesh'KF_pickups_Trip.Syringe_pickup' + CollisionHeight=5.000000 + EquipmentCategoryID=0 + ItemShortName="Syringe" + AmmoItemName="Healing juice" + Description="Basic equipment, necessary for survival." +} diff --git a/sources/Zeds/Mean/MeanZombieFleshPound.uc b/sources/Zeds/Mean/MeanZombieFleshPound.uc index 3bb82a0..b7ac20b 100644 --- a/sources/Zeds/Mean/MeanZombieFleshPound.uc +++ b/sources/Zeds/Mean/MeanZombieFleshPound.uc @@ -27,23 +27,20 @@ Ignores StartChargingFP; bFrustrated = false; if(Controller != none) NiceZombieFleshPoundController(Controller).RageFrustrationTimer = 0; - if( Health>0 && !bZapped ) - { - SetGroundSpeed(GetOriginalGroundSpeed()); - } if( Level.NetMode!=NM_DedicatedServer ) ClientChargingAnims(); NetUpdateTime = Level.TimeSeconds - 1; } + simulated function UpdateGroundSpeed() { + super(NiceMonster).UpdateGroundSpeed(); + if (!bShotAnim) { + groundSpeed *= 2.3; + } + } function Tick( float Delta ) { - if( !bShotAnim ) - { - SetGroundSpeed(OriginalGroundSpeed * 2.3);//2.0; - } - // Keep the flesh pound moving toward its target when attacking if( Role == ROLE_Authority && bShotAnim) { diff --git a/sources/Zeds/Mean/MeanZombieHusk.uc b/sources/Zeds/Mean/MeanZombieHusk.uc index b0ada50..efbb5fb 100644 --- a/sources/Zeds/Mean/MeanZombieHusk.uc +++ b/sources/Zeds/Mean/MeanZombieHusk.uc @@ -37,7 +37,7 @@ function RangedAttack(Actor A) { //Increment the number of consecutive shtos taken and apply the cool down if needed totalShots ++; consecutiveShots ++; - if(consecutiveShots < 3 && totalShots > maxNormalShots) + if(consecutiveShots < 3 && totalShots > maxNormalShots && VSize(a.location - location) <= 900) NextFireProjectileTime = Level.TimeSeconds; else{ NextFireProjectileTime = Level.TimeSeconds + ProjectileFireInterval + (FRand() * 2.0); diff --git a/sources/Zeds/Nice/NiceBloatVomit.uc b/sources/Zeds/Nice/NiceBloatVomit.uc deleted file mode 100644 index 7f3d37c..0000000 --- a/sources/Zeds/Nice/NiceBloatVomit.uc +++ /dev/null @@ -1,30 +0,0 @@ -class NiceBloatVomit extends KFBloatVomit; - -// limit how much you can damage zeds -const DAMAGECOUNT=10; -var private transient int DamageTicked; - -auto state Flying { - simulated function ProcessTouch(Actor Other, Vector HitLocation) { - // add damage limit - if (DamageTicked >= DAMAGECOUNT) { - BlowUp(HitLocation); - return; - } - if (ExtendedZCollision(Other) != none) { - return; - } - if ( - Other != Instigator && - (Other.IsA('Pawn') || Other.IsA('DestroyableObjective') || Other.bProjTarget) - ) { - DamageTicked += 1; - // warn("DamageTicked: " $ DamageTicked); - // use server DelayedHurtRadius() instead? - HurtRadius(Damage, DamageRadius, MyDamageType, MomentumTransfer, HitLocation); - } - else if (Other != Instigator && Other.bBlockActors) { - HitWall(Normal(HitLocation - Location), Other); - } - } -} \ No newline at end of file diff --git a/sources/Zeds/Nice/NiceZombieBloat.uc b/sources/Zeds/Nice/NiceZombieBloat.uc index 459e04e..c3ab99b 100644 --- a/sources/Zeds/Nice/NiceZombieBloat.uc +++ b/sources/Zeds/Nice/NiceZombieBloat.uc @@ -173,8 +173,7 @@ function SpawnTwoShots() if ( !SavedFireProperties.bInitialized ) { SavedFireProperties.AmmoClass = Class'SkaarjAmmo'; - // use fixed bile class, to prevent super high damage to zeds - SavedFireProperties.ProjectileClass = Class'NiceBloatVomit'; + SavedFireProperties.ProjectileClass = Class'KFBloatVomit'; SavedFireProperties.WarnTargetPct = 1; SavedFireProperties.MaxRange = 500; SavedFireProperties.bTossed = False; @@ -186,13 +185,13 @@ function SpawnTwoShots() // Turn off extra collision before spawning vomit, otherwise spawn fails ToggleAuxCollision(false); FireRotation = Controller.AdjustAim(SavedFireProperties,FireStart,600); - Spawn(SavedFireProperties.ProjectileClass,,,FireStart,FireRotation); + Spawn(Class'KFBloatVomit',,,FireStart,FireRotation); FireStart-=(0.5*CollisionRadius*Y); FireRotation.Yaw -= 1200; - spawn(SavedFireProperties.ProjectileClass,,,FireStart, FireRotation); + spawn(Class'KFBloatVomit',,,FireStart, FireRotation); FireStart+=(CollisionRadius*Y); FireRotation.Yaw += 2400; - spawn(SavedFireProperties.ProjectileClass,,,FireStart, FireRotation); + spawn(Class'KFBloatVomit',,,FireStart, FireRotation); // Turn extra collision back on ToggleAuxCollision(true); } diff --git a/sources/Zeds/Nice/NiceZombieBoss.uc b/sources/Zeds/Nice/NiceZombieBoss.uc index 8384766..2c53c56 100644 --- a/sources/Zeds/Nice/NiceZombieBoss.uc +++ b/sources/Zeds/Nice/NiceZombieBoss.uc @@ -915,9 +915,16 @@ state Charging // How many charge attacks we can do randomly 1-3 NumChargeAttacks = Rand(2) + 1; } + simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + if (bShotAnim) { + groundSpeed *= 1.25; + } else { + groundSpeed *= 2.5; + } + } function EndState() { - SetGroundSpeed(GetOriginalGroundSpeed()); bChargingPlayer = False; ChargeDamage = 0; if( Level.NetMode!=NM_DedicatedServer ) @@ -942,7 +949,6 @@ state Charging if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); } - SetGroundSpeed(OriginalGroundSpeed * 1.25); if( LookTarget!=none ) { Acceleration = AccelRate * Normal(LookTarget.Location - Location); @@ -956,16 +962,6 @@ state Charging if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); } - - // Zapping slows him down, but doesn't stop him - if( bZapped ) - { - SetGroundSpeed(OriginalGroundSpeed * 1.5); - } - else - { - SetGroundSpeed(OriginalGroundSpeed * 2.5); - } } Global.Tick(Delta); @@ -1071,7 +1067,6 @@ State Escaping extends Charging // Got hurt and running away... if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); } - SetGroundSpeed(GetOriginalGroundSpeed()); } else { @@ -1081,23 +1076,20 @@ State Escaping extends Charging // Got hurt and running away... if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); } - - // Zapping slows him down, but doesn't stop him - if( bZapped ) - { - SetGroundSpeed(OriginalGroundSpeed * 1.5); - } - else - { - SetGroundSpeed(OriginalGroundSpeed * 2.5); - } } Global.Tick(Delta); } + simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + if (bShotAnim) { + groundSpeed *= 1.25; + } else { + groundSpeed *= 2.5; + } + } function EndState() { - SetGroundSpeed(GetOriginalGroundSpeed()); bChargingPlayer = False; if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); diff --git a/sources/Zeds/Nice/NiceZombieBossBase.uc b/sources/Zeds/Nice/NiceZombieBossBase.uc index aa6cade..3e5eea6 100644 --- a/sources/Zeds/Nice/NiceZombieBossBase.uc +++ b/sources/Zeds/Nice/NiceZombieBossBase.uc @@ -52,7 +52,6 @@ defaultproperties ClawMeleeDamageRange=85.000000 ImpaleMeleeDamageRange=45.000000 fuelRatio=0.400000 - bFrugalFuelUsage=False clientHeadshotScale=1.200000 ZapThreshold=5.000000 ZappedDamageMod=1.250000 @@ -98,6 +97,9 @@ defaultproperties HealthMax=8000.000000 Health=8000 HeadScale=1.300000 + stoppingRecoveryRate=0.1 + maxStoppingEffect=0.2 + minStoppingThreshold=0.6 MenuName="Nice Patriarch" MovementAnims(0)="WalkF" MovementAnims(1)="WalkF" diff --git a/sources/Zeds/Nice/NiceZombieBrute.uc b/sources/Zeds/Nice/NiceZombieBrute.uc index 8e6c7f1..26860fc 100644 --- a/sources/Zeds/Nice/NiceZombieBrute.uc +++ b/sources/Zeds/Nice/NiceZombieBrute.uc @@ -182,18 +182,6 @@ function TakeDamageClient(int Damage, Pawn InstigatedBy, Vector HitLocation, Vec if (bDecapitated) Died(InstigatedBy.Controller, damageType, HitLocation); } -function TakeFireDamage(int Damage, Pawn Instigator) -{ - Super.TakeFireDamage(Damage, Instigator); - // Adjust movement speed if not charging - if (!bChargingPlayer) - { - if (bBurnified) - GroundSpeed = GetOriginalGroundSpeed() * BurnGroundSpeedMul; - else - GroundSpeed = GetOriginalGroundSpeed(); - } -} function ClawDamageTarget() { local KFHumanPawn HumanTarget; @@ -311,19 +299,16 @@ Ignores StartCharging; NetUpdateTime = Level.TimeSeconds - 1; } + simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + groundSpeed = groundSpeed + ((groundSpeed * 0.75 / maxRageCounter * (rageCounter + 1) * rageSpeedTween)); + } function EndState() { bChargingPlayer = false; NiceZombieBruteController(Controller).RageFrustrationTimer = 0; - if (Health > 0) - { - GroundSpeed = GetOriginalGroundSpeed(); - if (bBurnified) - GroundSpeed *= BurnGroundSpeedMul; - } - if( Level.NetMode!=NM_DedicatedServer ) ClientChargingAnims(); @@ -331,12 +316,8 @@ Ignores StartCharging; } function Tick(float Delta) { - if (!bShotAnim) - { + if (!bShotAnim) { RageSpeedTween = FClamp(RageSpeedTween + (Delta * 0.75), 0, 1.0); - GroundSpeed = OriginalGroundSpeed + ((OriginalGroundSpeed * 0.75 / MaxRageCounter * (RageCounter + 1) * RageSpeedTween)); - if (bBurnified) - GroundSpeed *= BurnGroundSpeedMul; } Global.Tick(Delta); diff --git a/sources/Zeds/Nice/NiceZombieBruteBase.uc b/sources/Zeds/Nice/NiceZombieBruteBase.uc index 58af2a0..5780f19 100644 --- a/sources/Zeds/Nice/NiceZombieBruteBase.uc +++ b/sources/Zeds/Nice/NiceZombieBruteBase.uc @@ -33,7 +33,6 @@ var bool bServerBlock; var bool bClientBlock; var float BlockDmgMul; // Multiplier for damage taken from blocked shots var float BlockFireDmgMul; -var float BurnGroundSpeedMul; // Multiplier for ground speed when burning replication { reliable if(Role == ROLE_Authority) @@ -61,7 +60,6 @@ defaultproperties BlockAddScale=2.500000 BlockDmgMul=0.100000 BlockFireDmgMul=1.000000 - BurnGroundSpeedMul=0.700000 StunThreshold=4.000000 flameFuel=0.500000 clientHeadshotScale=1.300000 @@ -110,6 +108,7 @@ defaultproperties Health=1000 HeadHeight=2.500000 HeadScale=1.300000 + minStoppingThreshold=0.1 MenuName="Brute" MovementAnims(0)="BruteWalkC" MovementAnims(1)="BruteWalkC" @@ -123,7 +122,7 @@ defaultproperties AmbientSound=SoundGroup'ScrnZedPack_S.Brute.BruteIdle1Shot' Mesh=SkeletalMesh'ScrnZedPack_A.BruteMesh' PrePivot=(Z=0.000000) - Skins(0)=Combiner'ScrnZedPack_T.Brute.Brute_Final' + Skins(0)=Texture'NicePackT.MonsterBrute.WPCBruteT' Mass=600.000000 RotationRate=(Yaw=45000,Roll=0) } diff --git a/sources/Zeds/Nice/NiceZombieClot.uc b/sources/Zeds/Nice/NiceZombieClot.uc index 57875e8..71f8939 100644 --- a/sources/Zeds/Nice/NiceZombieClot.uc +++ b/sources/Zeds/Nice/NiceZombieClot.uc @@ -5,6 +5,8 @@ class NiceZombieClot extends NiceZombieClotBase; #exec OBJ LOAD FILE=KF_Specimens_Trip_T.utx #exec OBJ LOAD FILE=MeanZedSkins.utx +var float sirenBoostTimeout; + function ClawDamageTarget() { local vector PushDir; @@ -109,9 +111,33 @@ simulated function int DoAnimAction( name AnimName ) } return super.DoAnimAction( AnimName ); } +function DealDecapDamage( int damage, + Pawn instigatedBy, + Vector hitLocation, + Vector momentum, + class damageType, + float headshotLevel, + KFPlayerReplicationInfo KFPRI, + optional float lockonTime) { + if (sirenBoostTimeout > 0) { + RemoveHead(); + } else { + super.DealDecapDamage(damage, instigatedBy, hitLocation, momentum, + damageType, headshotLevel, KFPRI, lockonTime); + } +} +simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + if (sirenBoostTimeout > 0) { + groundSpeed *= 1.5; + } +} simulated function Tick(float DeltaTime) { super.Tick(DeltaTime); + if (sirenBoostTimeout >= 0) { + sirenBoostTimeout -= deltaTime; + } if( bShotAnim && Role == ROLE_Authority ) { if( LookTarget!=none ) diff --git a/sources/Zeds/Nice/NiceZombieCrawler.uc b/sources/Zeds/Nice/NiceZombieCrawler.uc index a4ce6cf..43c0ad1 100644 --- a/sources/Zeds/Nice/NiceZombieCrawler.uc +++ b/sources/Zeds/Nice/NiceZombieCrawler.uc @@ -34,17 +34,20 @@ event Landed(vector HitNormal) } event Bump(actor Other) { + local int actualDamage; // TODO: is there a better way if(bPouncing && KFHumanPawn(Other)!=none ) { - KFHumanPawn(Other).TakeDamage(((MeleeDamage - (MeleeDamage * 0.05)) + (MeleeDamage * (FRand() * 0.1))), self ,self.Location,self.velocity, class'NiceZedMeleeDamageType'); - if (KFHumanPawn(Other).Health <=0) - { - //TODO - move this to humanpawn.takedamage? Also see KFMonster.MeleeDamageTarget - KFHumanPawn(Other).SpawnGibs(self.rotation, 1); - } - //After impact, there'll be no momentum for further bumps - bPouncing=false; + actualDamage = MeleeDamage; + ModDamageFromZed(actualDamage, class'NiceZedMeleeDamageType'); + KFHumanPawn(Other).TakeDamage(((actualDamage * 0.95) + (actualDamage * (FRand() * 0.1))), self ,self.Location,self.velocity, class'NiceZedMeleeDamageType'); + if (KFHumanPawn(Other).Health <=0) + { + //TODO - move this to humanpawn.takedamage? Also see KFMonster.MeleeDamageTarget + KFHumanPawn(Other).SpawnGibs(self.rotation, 1); + } + //After impact, there'll be no momentum for further bumps + bPouncing=false; } } // Blend his attacks so he can hit you in mid air. diff --git a/sources/Zeds/Nice/NiceZombieFleshPound.uc b/sources/Zeds/Nice/NiceZombieFleshPound.uc index 1a7ea05..17c0fa5 100644 --- a/sources/Zeds/Nice/NiceZombieFleshPound.uc +++ b/sources/Zeds/Nice/NiceZombieFleshPound.uc @@ -49,7 +49,6 @@ function SetMindControlled(bool bNewMindControlled) if( bNewMindControlled != bZedUnderControl ) { - SetGroundSpeed(OriginalGroundSpeed * 1.25); Health *= 1.25; HealthMax *= 1.25; } @@ -252,21 +251,21 @@ Ignores StartChargingFP; if(fpController == none) fpController.RageFrustrationTimer = 0; - if( Health>0 && !bZapped ) - { - SetGroundSpeed(GetOriginalGroundSpeed()); - } - if( Level.NetMode!=NM_DedicatedServer ) ClientChargingAnims(); NetUpdateTime = Level.TimeSeconds - 1; } + simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + if (!bShotAnim) { + groundSpeed *= 2.3; + } + } function Tick( float Delta ) { if( !bShotAnim ) { - SetGroundSpeed(OriginalGroundSpeed * 2.3);//2.0; if( !bFrustrated && !bZedUnderControl && Level.TimeSeconds>RageEndTime ) { GoToState(''); @@ -330,11 +329,16 @@ Ignores StartChargingFP; state ChargeToMarker extends RageCharging { Ignores StartChargingFP; + simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + if (!bShotAnim) { + groundSpeed *= 2.3; + } + } function Tick( float Delta ) { if( !bShotAnim ) { - SetGroundSpeed(OriginalGroundSpeed * 2.3); if( !bFrustrated && !bZedUnderControl && Level.TimeSeconds>RageEndTime ) { GoToState(''); @@ -437,7 +441,7 @@ function SpinDamage(actor Target) local vector HitLocation; local Name TearBone; local Float dummy; - local float DamageAmount; + local int damageAmount; local vector PushDir; local KFHumanPawn HumanTarget; if(target==none) @@ -452,8 +456,9 @@ function SpinDamage(actor Target) } if (Target !=none && Target.IsA('KFDoorMover')) { - Target.TakeDamage(DamageAmount , self ,HitLocation,pushdir, class'NiceZedMeleeDamageType'); - PlaySound(MeleeAttackHitSound, SLOT_Interact, 1.25); + ModDamageFromZed(DamageAmount, class'NiceZedMeleeDamageType'); + Target.TakeDamage(DamageAmount , self ,HitLocation,pushdir, class'NiceZedMeleeDamageType'); + PlaySound(MeleeAttackHitSound, SLOT_Interact, 1.25); } if (KFHumanPawn(Target)!=none) { @@ -461,8 +466,9 @@ function SpinDamage(actor Target) if (HumanTarget.Controller != none) HumanTarget.Controller.ShakeView(RotMag, RotRate, RotTime, OffsetMag, OffsetRate, OffsetTime); - //TODO - line below was KFPawn. Does this whole block need to be KFPawn, or is it OK as KFHumanPawn? - KFHumanPawn(Target).TakeDamage(DamageAmount, self ,HitLocation,pushdir, class'NiceZedMeleeDamageType'); + ModDamageFromZed(DamageAmount, class'NiceZedMeleeDamageType'); + //TODO - line below was KFPawn. Does this whole block need to be KFPawn, or is it OK as KFHumanPawn? + KFHumanPawn(Target).TakeDamage(DamageAmount, self ,HitLocation,pushdir, class'NiceZedMeleeDamageType'); if (KFHumanPawn(Target).Health <=0) { diff --git a/sources/Zeds/Nice/NiceZombieFleshpoundBase.uc b/sources/Zeds/Nice/NiceZombieFleshpoundBase.uc index 6380eb1..54fc8c3 100644 --- a/sources/Zeds/Nice/NiceZombieFleshpoundBase.uc +++ b/sources/Zeds/Nice/NiceZombieFleshpoundBase.uc @@ -80,6 +80,8 @@ defaultproperties Health=1650 HeadHeight=2.500000 HeadScale=1.300000 + maxStoppingEffect=0.05 + minStoppingThreshold=0.68 MenuName="Nice Flesh Pound" MovementAnims(0)="PoundWalk" MovementAnims(1)="WalkB" diff --git a/sources/Zeds/Nice/NiceZombieGorefast.uc b/sources/Zeds/Nice/NiceZombieGorefast.uc index 6b75e97..a696b0e 100644 --- a/sources/Zeds/Nice/NiceZombieGorefast.uc +++ b/sources/Zeds/Nice/NiceZombieGorefast.uc @@ -45,7 +45,6 @@ function SetMindControlled(bool bNewMindControlled) if( bNewMindControlled != bZedUnderControl ) { - SetGroundSpeed(OriginalGroundSpeed * 1.25); Health *= 1.25; HealthMax *= 1.25; } @@ -73,13 +72,6 @@ function RangedAttack(Actor A){ if(!bShotAnim && !bDecapitated && VSize(A.Location - Location) <= 700) GoToState('RunningState'); } -simulated function Tick(float DeltaTime){ - super.Tick(DeltaTime); - if(IsInState('RunningState')) - SetGroundSpeed(GetOriginalGroundSpeed() * 1.875); - else - SetGroundSpeed(GetOriginalGroundSpeed()); -} state RunningState{ // Set the zed to the zapped behavior simulated function SetZappedBehavior(){ @@ -94,7 +86,6 @@ state RunningState{ if(bZapped) GoToState(''); else{ - SetGroundSpeed(OriginalGroundSpeed * 1.875); bRunning = true; if(Level.NetMode != NM_DedicatedServer) PostNetReceive(); @@ -103,7 +94,6 @@ state RunningState{ } } function EndState(){ - SetGroundSpeed(GetOriginalGroundSpeed()); bRunning = false; if(Level.NetMode != NM_DedicatedServer) PostNetReceive(); @@ -112,6 +102,10 @@ state RunningState{ NetUpdateTime = Level.TimeSeconds - 1; } + simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + groundSpeed *= 1.875; + } function RemoveHead(){ GoToState(''); Global.RemoveHead(); diff --git a/sources/Zeds/Nice/NiceZombieHuskBase.uc b/sources/Zeds/Nice/NiceZombieHuskBase.uc index 7c93117..89b8a58 100644 --- a/sources/Zeds/Nice/NiceZombieHuskBase.uc +++ b/sources/Zeds/Nice/NiceZombieHuskBase.uc @@ -60,6 +60,7 @@ defaultproperties HeadHeight=1.000000 HeadScale=1.350000 AmbientSoundScaling=8.000000 + stoppingRecoveryRate=0.05 MenuName="Nice Husk" MovementAnims(0)="WalkF" MovementAnims(1)="WalkB" diff --git a/sources/Zeds/Nice/NiceZombieJason.uc b/sources/Zeds/Nice/NiceZombieJason.uc index ab0a1f6..c32c255 100644 --- a/sources/Zeds/Nice/NiceZombieJason.uc +++ b/sources/Zeds/Nice/NiceZombieJason.uc @@ -105,15 +105,11 @@ State SawingLoop else GoToState(''); } } -simulated function float GetOriginalGroundSpeed() -{ - local float result; - result = OriginalGroundSpeed; - if ( bWasRaged || bCharging ) - result *= 3.5; - else if( bZedUnderControl ) - result *= 1.25; - return result; +simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + if (bWasRaged || bCharging) { + groundSpeed *= 3.5; + } } state RunningState { @@ -124,7 +120,6 @@ state RunningState GoToState(''); else { bCharging = true; - SetGroundSpeed(GetOriginalGroundSpeed()); if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); NetUpdateTime = Level.TimeSeconds - 1; @@ -133,8 +128,6 @@ state RunningState function EndState() { bCharging = False; - if( !bZapped ) - SetGroundSpeed(GetOriginalGroundSpeed()); if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); } @@ -163,6 +156,8 @@ defaultproperties ChallengeSound(2)=None ChallengeSound(3)=None ScoringValue=300 + maxStoppingEffect=0.25 + minStoppingThreshold=0.25 MenuName="Jason" AmbientSound=Sound'ScrnZedPack_S.Jason.Jason_Sound' Mesh=SkeletalMesh'ScrnZedPack_A.JasonMesh' diff --git a/sources/Zeds/Nice/NiceZombieScrake.uc b/sources/Zeds/Nice/NiceZombieScrake.uc index 190e4fb..22f2797 100644 --- a/sources/Zeds/Nice/NiceZombieScrake.uc +++ b/sources/Zeds/Nice/NiceZombieScrake.uc @@ -83,7 +83,6 @@ function SetMindControlled(bool bNewMindControlled) if( bNewMindControlled != bZedUnderControl ) { - SetGroundSpeed(OriginalGroundSpeed * 1.25); Health *= 1.25; HealthMax *= 1.25; } @@ -185,8 +184,9 @@ state RunningState { return false; } - simulated function float GetOriginalGroundSpeed() { - return 3.5 * OriginalGroundSpeed; + simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + groundSpeed *= 3.5; } function BeginState(){ local NiceHumanPawn rageTarget, rageCause; @@ -214,7 +214,6 @@ state RunningState if(bZapped) GoToState(''); else{ - SetGroundSpeed(OriginalGroundSpeed * 3.5); bCharging = true; if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); @@ -224,10 +223,6 @@ state RunningState } function EndState() { - if( !bZapped ) - { - SetGroundSpeed(GetOriginalGroundSpeed()); - } bCharging = False; if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); @@ -265,8 +260,9 @@ State SawingLoop { return false; } - simulated function float GetOriginalGroundSpeed() { - return OriginalGroundSpeed * AttackChargeRate; + simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + groundSpeed *= attackChargeRate; } function bool CanGetOutOfWay() { @@ -279,7 +275,6 @@ State SawingLoop // Randomly have the scrake charge during an attack so it will be less predictable if(Health/HealthMax < 0.5 || FRand() <= 0.95) { - SetGroundSpeed(OriginalGroundSpeed * AttackChargeRate); bCharging = true; if( Level.NetMode!=NM_DedicatedServer ) PostNetReceive(); @@ -327,8 +322,6 @@ State SawingLoop { AmbientSound=default.AmbientSound; MeleeDamage = Max( DifficultyDamageModifer() * default.MeleeDamage, 1 ); - - SetGroundSpeed(GetOriginalGroundSpeed()); bCharging = False; if(Level.NetMode != NM_DedicatedServer) PostNetReceive(); diff --git a/sources/Zeds/Nice/NiceZombieScrakeBase.uc b/sources/Zeds/Nice/NiceZombieScrakeBase.uc index 6ccd9f6..2905831 100644 --- a/sources/Zeds/Nice/NiceZombieScrakeBase.uc +++ b/sources/Zeds/Nice/NiceZombieScrakeBase.uc @@ -63,6 +63,8 @@ defaultproperties HealthMax=1000.000000 Health=1000 HeadHeight=2.200000 + maxStoppingEffect=0.15 + minStoppingThreshold=0.15 MenuName="Nice Scrake" MovementAnims(0)="SawZombieWalk" MovementAnims(1)="SawZombieWalk" diff --git a/sources/Zeds/Nice/NiceZombieShiver.uc b/sources/Zeds/Nice/NiceZombieShiver.uc index fbd612a..a28b0d1 100644 --- a/sources/Zeds/Nice/NiceZombieShiver.uc +++ b/sources/Zeds/Nice/NiceZombieShiver.uc @@ -3,6 +3,7 @@ class NiceZombieShiver extends NiceZombieShiverBase; var float TeleportBlockTime; var float HeadOffsetY; var transient bool bRunning, bClientRunning; +var float teleportAttackCooldownEndTime; replication { reliable if ( Role == ROLE_Authority) @@ -38,6 +39,39 @@ simulated function PostBeginPlay() } } } + +function bool CanAttack(Actor target) { + if (level.timeSeconds < teleportAttackCooldownEndTime) + return false; + return super.CanAttack(target); +} + +simulated event SetAnimAction(name NewAction) { + local int meleeAnimIndex; + + if (bFrozenZed) return; + if (newAction == '') return; + + if (newAction == 'Claw') { + meleeAnimIndex = Rand(2); // Shivers only have two animations now + newAction = meleeAnims[meleeAnimIndex]; + currentDamtype = zombieDamType[meleeAnimIndex]; + } else if(newAction == 'DoorBash') { + currentDamtype = zombieDamType[Rand(3)]; + } + expectingChannel = DoAnimAction(NewAction); + if (AnimNeedsWait(newAction)) { + bWaitForAnim = true; + } else { + bWaitForAnim = false; + } + if (level.netMode != NM_Client) { + animAction = newAction; + bResetAnimAct = True; + resetAnimActTime = level.timeSeconds + 0.3; + } +} + simulated function Destroyed() { if (Level.NetMode != NM_DedicatedServer && MatAlphaSkin != none) @@ -179,7 +213,6 @@ state Running Global.Tick(Delta); if (RunUntilTime < Level.TimeSeconds) GotoState(''); - GroundSpeed = GetOriginalGroundSpeed(); } function BeginState() { @@ -190,13 +223,12 @@ state Running function EndState() { bRunning = false; - GroundSpeed = global.GetOriginalGroundSpeed(); RunCooldownEnd = Level.TimeSeconds + PeriodRunCoolBase + FRand() * PeriodRunCoolRan; MovementAnims[0] = WalkAnim; } - function float GetOriginalGroundSpeed() - { - return global.GetOriginalGroundSpeed() * 2.5; + simulated function UpdateGroundSpeed() { + super.UpdateGroundSpeed(); + groundSpeed *= 2.5; } function bool CanSpeedAdjust() { @@ -219,14 +251,6 @@ simulated function bool AnimNeedsWait(name TestAnim) } return ExpectingChannel == 0; } -simulated function float GetOriginalGroundSpeed() -{ - local float result; - result = OriginalGroundSpeed; - if( bZedUnderControl ) - result *= 1.25; - return result; -} simulated function HandleAnimation(float Delta) { // hehehe @@ -291,7 +315,7 @@ simulated function Tick(float Delta) { SetCollision(true, true); FlashTeleport(); - SetCollision(false, false); + SetCollision(true, false); FadeStage = 2; } } @@ -332,7 +356,7 @@ function StartTeleport() { FadeStage = 1; AlphaFader = 255; - SetCollision(false, false); + SetCollision(true, false); bFlashTeleporting = true; } function FlashTeleport() @@ -390,6 +414,7 @@ function FlashTeleport() Teleported: bFlashTeleporting = false; LastFlashTime = Level.TimeSeconds; + teleportAttackCooldownEndTime = level.timeSeconds + 0.5; } function Died(Controller Killer, class damageType, vector HitLocation) { @@ -439,10 +464,16 @@ simulated function int DoAnimAction( name AnimName ) } defaultproperties { - HeadOffsetY=-3.000000 + headOffsetY=-3.000000 idleInsertFrame=0.468000 - OnlineHeadshotOffset=(X=19.000000,Z=39.000000) - ScoringValue=15 - HeadRadius=8.000000 - HeadHeight=3.000000 + onlineHeadshotOffset=(X=19.000000,Z=39.000000) + scoringValue=15 + headRadius=8.000000 + headHeight=3.000000 + // Override third animation just in case. + // However it shouldn't be required since we've already changed + // `SetAnimAction` function to only use first two animations + meleeAnims(0)="Claw" + meleeAnims(1)="Claw2" + meleeAnims(2)="Claw" } diff --git a/sources/Zeds/Nice/NiceZombieSiren.uc b/sources/Zeds/Nice/NiceZombieSiren.uc index ad5b69b..aa15090 100644 --- a/sources/Zeds/Nice/NiceZombieSiren.uc +++ b/sources/Zeds/Nice/NiceZombieSiren.uc @@ -223,9 +223,10 @@ simulated function HurtRadius(float DamageAmount, float DamageRadius, class niceVet; + local NiceZombieClot niceClot; if (bHurtEntry || Health <= 0 || HeadHealth <= 0 || bIsStunned) return; @@ -243,6 +244,10 @@ simulated function HurtRadius(float DamageAmount, float DamageRadius, class 0) @@ -281,6 +286,12 @@ simulated function HurtRadius(float DamageAmount, float DamageRadius, class 0){ currScreamTime = Level.TimeSeconds - screamStartTime; diff --git a/sources/Zeds/Nice/NiceZombieTeslaHusk.uc b/sources/Zeds/Nice/NiceZombieTeslaHusk.uc index 030c45f..ff60b33 100644 --- a/sources/Zeds/Nice/NiceZombieTeslaHusk.uc +++ b/sources/Zeds/Nice/NiceZombieTeslaHusk.uc @@ -709,7 +709,6 @@ defaultproperties HealEnergyDrain=0.200000 ProjectileFireInterval=5.000000 BurnDamageScale=1.000000 - mind=0.000000 bFireImmune=False MoanVoice=SoundGroup'KF_EnemiesFinalSnd_CIRCUS.Husk.Husk_Talk' BleedOutDuration=5.000000 diff --git a/sources/Zeds/NiceMonster.uc b/sources/Zeds/NiceMonster.uc index 04bb11d..64b37f5 100644 --- a/sources/Zeds/NiceMonster.uc +++ b/sources/Zeds/NiceMonster.uc @@ -24,6 +24,7 @@ class NiceMonster extends KFMonster #exec OBJ LOAD FILE=KF_EnemyGlobalSndTwo.uax #exec OBJ LOAD FILE=KFZED_FX_T.utx +var bool initializationComplete; //============================================================================== //============================================================================== // > Affliction system @@ -75,13 +76,15 @@ var float stunLoopStart, stunLoopEnd, idleInsertFrame; var bool bWasIdleStun; // Were we using idleanimation for stun? var float prevStunAnimFrame; // At which tick we were? //============================================================================== -// >> Another default stun system allows tostuns zeds by repeatedly dealing +// >> Another default stun system allows to stun zeds by repeatedly dealing // head damage to them fast enough: // 1. Dealing head damage increases accumulated damage // 2. If head damage was received for a certain time period, - // accumulated damage starts to decrease // 3. If accumulated damage is high enough, passes 'IsStunPossible' check -// and has low enough mind level - normal duration stun activates +// - normal duration stun activates +// How much more time will this zed spend concussed? +var float concussionCountdown; // Accumulated head damage var float accHeadDamage; // Rate (per second) at which accumulated head damage diminishes @@ -91,16 +94,6 @@ var float headRecoveryTime; // Count down variable for above mentioned time var float headRecoveryCountDown; -//============================================================================== -//============================================================================== -// > Mind system -// Largly underdeveloped and currently only exists to decide whether or not -// zed can be stunned by accumulating head damage -// Current mind level (1.0 - default and maximum value) -var float mind; -// Treshold, required for stun by accumulated head damage -var float accStunMindLvl; - //============================================================================== //============================================================================== // > Temperature system @@ -134,10 +127,25 @@ var float heatDissipationRate; var float heatTicksPerSecond; // Tracks last time heat tick occured var float lastHeatTick; -// If set to 'true' - low-value ticks of fire DoT will waste accordingly small -// amount of fuel, otherwise they will always waste some minimal amount, -// resulting in a loss of potential damage -var bool bFrugalFuelUsage; +var float scorchmarkDamage; +var float MIN_HEAT, MAX_HEAT; + +//============================================================================== +//============================================================================== +// > Speed system +// Manages speed modifications from weapon attacks and other effects. +// +// This variable stores with how much stopping power zed was affected. +// Is a value from 0.0 to 1.0 and `1 - stoppingEffect` acts as speed multiplier +// for the zed +var float stoppingEffect; +// How much stopping effect would be recovred in a second +var float stoppingRecoveryRate; +// Maximum `stoppingEffect` value zed can accumulate +var float maxStoppingEffect; +// Minimal stopping threshold for the zed (supposed to be subtracted from +// incoming effects' strenght). +var float minStoppingThreshold; //============================================================================== //============================================================================== @@ -222,6 +230,7 @@ simulated function PostBeginPlay(){ SavedExtCollision = MyExtCollision.bCollideActors; } } + initializationComplete = true; } //============================================================================== @@ -362,6 +371,15 @@ simulated function FearTick(float deltaTime){ + 0.75 * accelRate * Normal(Location - fearCenter); } //============================================================================== +// >> Decrease active stopping power on the zed as the time goes by +simulated function StoppingPowerTick(float deltaTime) { + if (stoppingEffect <= 0.0 || concussionCountdown > 0.0) { + return; + } + stoppingEffect -= deltaTime * stoppingRecoveryRate; + stoppingEffect = FMax(0, stoppingEffect); +} +//============================================================================== // >> Set of functions to handle animation changes during stun simulated function CalcRemainigStunStructure( name seqName, float oFrame, @@ -451,14 +469,14 @@ simulated function StunTick(float deltaTime){ } //============================================================================== // >> Set of functions to handle stun from head damage accumulation -function AccumulateHeadDamage( float addDamage, +function AccumulateHeadDamage( float addDamage, bool bIsHeadshot, NicePlayerController nicePlayer){ if(bIsHeadshot){ - AccHeadDamage += addDamage; + AccHeadDamage += addDamage * 0.5; HeadRecoveryCountDown = HeadRecoveryTime; if(AccHeadDamage > (default.HeadHealth / 1.5) - && (Mind <= AccStunMindLvl && IsStunPossible())) + && (concussionCountdown > 0.0 && IsStunPossible())) DoStun(nicePlayer.pawn,,,, 1.0); } else if(HeadRecoveryCountDown > 0.0) @@ -466,11 +484,13 @@ function AccumulateHeadDamage( float addDamage, HeadRecoveryTime / 2); } function HeadDamageRecoveryTick(float delta){ - HeadRecoveryCountDown -= delta; - HeadRecoveryCountDown = FMax(0.0, HeadRecoveryCountDown); - if(HeadRecoveryCountDown <= 0.0) - AccHeadDamage -= delta * HeadDamageRecoveryRate; - AccHeadDamage = FMax(AccHeadDamage, 0.0); + concussionCountdown -= delta; + concussionCountdown = FMax(0.0, concussionCountdown); + headRecoveryCountDown -= delta; + headRecoveryCountDown = FMax(0.0, headRecoveryCountDown); + if(headRecoveryCountDown <= 0.0) + accHeadDamage -= delta * HeadDamageRecoveryRate; + accHeadDamage = FMax(accHeadDamage, 0.0); } //============================================================================== // >> Function that calls actual 'HeatTick' when needed @@ -480,6 +500,11 @@ simulated function FakeHeatTick(float deltaTime){ local float oFrame; local float oRate; local NiceMonsterController niceZedController; + if (bOnFire) { + // 100 of the scorchmark damage should restore every 1/10 of a second + scorchmarkDamage += deltaTime * 10 * 100; + scorchmarkDamage = FMin(scorchmarkDamage, 100); + } if(lastHeatTick + (1 / HeatTicksPerSecond) < Level.TimeSeconds){ if(bOnFire && !bBurningBehavior) SetBurningBehavior(); @@ -527,15 +552,6 @@ simulated function FakeHeatTick(float deltaTime){ // >> Ticks from TWI's code // Updates zed's speed if it's not relevant; // code, specific to standalone game and listen servers was cut out -simulated function NonRelevantSpeedupTick(float deltaTime){ - if(Level.netMode == NM_Client || !CanSpeedAdjust()) return; - if(Level.TimeSeconds - LastReplicateTime > 0.5) - SetGroundSpeed(default.GroundSpeed * (300.0 / default.GroundSpeed)); - else{ - LastSeenOrRelevantTime = Level.TimeSeconds; - SetGroundSpeed(GetOriginalGroundSpeed()); - } -} // Kill zed if it has been bleeding long enough simulated function BleedOutTick(float deltaTick) @@ -586,7 +602,6 @@ simulated function TWITick(float deltaTime){ // If we've flagged this character to be destroyed next tick, handle that if(bDestroyNextTick && TimeSetDestroyNextTickTime < Level.TimeSeconds) Destroy(); - NonRelevantSpeedupTick(deltaTime); // Reset AnimAction if(bResetAnimAct && ResetAnimActTime < Level.TimeSeconds){ AnimAction = ''; @@ -609,8 +624,10 @@ simulated function Tick(float deltaTime){ DecapTick(deltaTime); FearTick(deltaTime); StunTick(deltaTime); + StoppingPowerTick(deltaTime); HeadDamageRecoveryTick(deltaTime); FakeHeatTick(deltaTime); + UpdateGroundSpeed(); // TWI's tick TWITick(deltaTime); } @@ -667,6 +684,19 @@ simulated function float IsHeadshotClient( Vector Loc, return 1.0 - (distance / (headRadius * headScale * additionalScale)); return 0.0; } +// Calculates distance from `location` to this zed's head. +simulated function float GetDistanceToHead(Vector location) { + local Coords headBoneCoords; + local Vector headLocation; + + if(headBone == '') { + return 0.0; + } + headBoneCoords = GetBoneCoords(headBone); + headLocation = + headBoneCoords.Origin + headHeight * headScale * headBoneCoords.XAxis; + return VSize(location - headLocation); +} // In case of a future modifications: // check if it's a player doing damage before relying on it function ModDamage( out int damage, @@ -677,28 +707,28 @@ function ModDamage( out int damage, float headshotLevel, KFPlayerReplicationInfo KFPRI, optional float lockonTime){ - local NicePlayerController nicePlayer; - local bool hasGiantSlayer; - local int bonusDamageStacks; - if(KFPRI == none || KFPRI.ClientVeteranSkill == none) return; - // Add perked damage - damage = KFPRI.ClientVeteranSkill.Static.AddDamage( KFPRI, self, - KFPawn(instigatedBy), - damage, damageType); - // Skill bonuses - if(instigatedBy == none) - return; - nicePlayer = NicePlayerController(instigatedBy.controller); - if(nicePlayer == none) - return; - hasGiantSlayer = class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, - class'NiceSkillCommandoGiantSlayer'); - if(!hasGiantSlayer) - return; - bonusDamageStacks = - int(health / class'NiceSkillCommandoGiantSlayer'.default.healthStep); - damage *= 1.0f + bonusDamageStacks * - class'NiceSkillCommandoGiantSlayer'.default.bonusDamageMult; + local NicePlayerController nicePlayer; + local bool hasGiantSlayer; + local int bonusDamageStacks; + if(KFPRI == none || KFPRI.ClientVeteranSkill == none) return; + // Add perked damage + damage = KFPRI.ClientVeteranSkill.Static.AddDamage( KFPRI, self, + KFPawn(instigatedBy), + damage, damageType); + // Skill bonuses + if(instigatedBy == none) + return; + nicePlayer = NicePlayerController(instigatedBy.controller); + if(nicePlayer == none) + return; + hasGiantSlayer = class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, + class'NiceSkillCommandoGiantSlayer'); + if(!hasGiantSlayer) + return; + bonusDamageStacks = + int(health / class'NiceSkillCommandoGiantSlayer'.default.healthStep); + damage *= 1.0f + bonusDamageStacks * + class'NiceSkillCommandoGiantSlayer'.default.bonusDamageMult; } function ModRegularDamage( out int damage, Pawn instigatedBy, @@ -720,9 +750,6 @@ function ModRegularDamage( out int damage, damage = niceVet.static.AddRegDamage( KFPRI, self, KFPawn(instigatedBy), damage, damageType); - // Add some damage against crispy zeds - if(bCrispified) - damage += (Max(1200 - default.Health, 0) * damage) / 1200; // Skills bonuses if(nicePlayer == none) return; hasOverkillSkill = class'NiceVeterancyTypes'.static. @@ -798,26 +825,30 @@ function int ModBodyDamage( out int damage, local NicePlayerController nicePlayer; painDamage = damage; bIsHeadShot = (headshotLevel > 0.0); - if(instigatedBy != none) + if (instigatedBy != none) nicePlayer = NicePlayerController(instigatedBy.Controller); + if (bFrozenZed && damageType != none && damageType.default.bIsExplosive) { + damage *= 1.5; + } // On damaging critical spot (so far only head) - do body destruction - if(bIsHeadShot && damageType != none) + if (bIsHeadShot && damageType != none) damage *= damageType.default.bodyDestructionMult; // Skill bonuses - if(nicePlayer == none) + if (nicePlayer == none) return painDamage; bHasMessy = class'NiceVeterancyTypes'.static. someoneHasSkill(nicePlayer, class'NiceSkillSharpshooterDieAlready'); return painDamage; } // Do effects, based on fire damage dealt to monster -function FireDamageEffects( int damage, +function FireDamageEffects(out int damage, Pawn instigatedBy, Vector hitLocation, Vector momentum, class damageType, float headshotLevel, KFPlayerReplicationInfo KFPRI){ + local float heatDelta, bonusFireDamage; damage = FMax(0.0, damage); iceCrustStrenght = FMax(0.0, iceCrustStrenght); if(bFrozenZed){ @@ -835,24 +866,37 @@ function FireDamageEffects( int damage, } damage /= 10; } - if(damage <= 0) return; + if(damage <= 0) { + return; + } // Turn up the heat! // (we can only make it twice as hot with that damage, // but set limit at least at 50, as if we've dealt at least 25 heat damage) - heat += (damage * HeatIncScale()) + heatDelta = (damage * HeatIncScale()) * FMin(1.0, FMax(0.0, (2 - Abs(heat) / FMax(25, Abs(damage) )))); + if (concussionCountdown > 0) { + heat += heatDelta * 2; + } else { + heat += heatDelta; + } CapHeat(); // Change damage type if new one was stronger if(!bOnFire || damage * HeatIncScale() > lastBurnDamage){ fireDamageClass = damageType; burnInstigator = instigatedBy; } + // Double heat damage at the cost of the fuel, if zed is already on fire + if (bOnFire) { + bonusFireDamage = FMax(FMin(damage, flameFuel) * 0.25, 0); + flameFuel -= bonusFireDamage; + damage += bonusFireDamage; + } // Set on fire, if necessary if(heat > GetIgnitionPoint() && !bOnFire && bCanBurn){ bBurnified = true; bOnFire = true; burnInstigator = instigatedBy; - fireDamageClass = damageType; + fireDamageClass = damageType; lastHeatTick = Level.TimeSeconds; } } @@ -969,7 +1013,7 @@ function DealDecapDamage( int damage, hasSkill(nicePlayer, class'NiceSkillSharpshooterDieAlready')) ServerDropFaster(NiceHumanPawn(nicePlayer.pawn)); } -function DealHeadDamage( int damage, +function DealHeadDamage( int damage, Pawn instigatedBy, Vector hitLocation, Vector momentum, @@ -987,6 +1031,11 @@ function DealHeadDamage( int damage, // Actual damage effects // Skull injury killed a zed if(HeadHealth <= 0) return; + // Additional weakpoint damage to burning zeds from non-flame weapons + if (bOnFire) { + damage += scorchmarkDamage * (1 - damageType.default.heatPart); + scorchmarkDamage *= damageType.default.heatPart; + } HeadHealth -= damage; if(nicePlayer != none && IsFinisher(damage, damageType, nicePlayer, true)) HeadHealth -= damage; @@ -1169,6 +1218,9 @@ function EPainReaction GetRightPainReaction(int painDamage, local int stunScore, flinchScore; local bool bStunPass, bFlinchPass, bMiniFlinshPass; local class niceVet; + if (bOnFire) { + return PREACTION_NONE; + } if(KFPRI != none) niceVet = class(KFPRI.ClientVeteranSkill); stunScore = painDamage; @@ -1237,8 +1289,9 @@ function float GetstunDurationMult( Pawn instigatedBy, if(KFPRI == none) return stunDurationMultiplier; niceVet = class(KFPRI.ClientVeteranSkill); if(niceVet == none) return stunDurationMultiplier; + if(damageType == none) return stunDurationMultiplier; // Perk's bonuses out - return stunDurationMultiplier * + return stunDurationMultiplier * damageType.default.stunLengthMultiplier * niceVet.static.stunDurationMult( KFPRI, self, KFPawn(instigatedBy), damageType); } @@ -1570,13 +1623,13 @@ function Freeze(){ StopMovement(); Disable('AnimEnd'); StopAnimating(); - + if(Controller != none){ Controller.FocalPoint = Location + 512*vector(Rotation); Controller.Enemy = none; Controller.Focus = none; if(!Controller.IsInState('Freeze')) - Controller.GoToState('Freeze'); + Controller.GoToState('Freeze'); KFMonsterController(Controller).bUseFreezeHack = true; } bFrozenZed = true; @@ -1594,7 +1647,7 @@ function UnFreeze(){ GroundSpeed = GetOriginalGroundSpeed(); bFrozenZed = false; } -function TakeDamageClient( int damage, +function TakeDamageClient( int damage, Pawn instigatedBy, Vector hitLocation, Vector momentum, @@ -1613,24 +1666,26 @@ function TakeDamageClient( int damage, KFPRI = KFPlayerReplicationInfo(instigatedBy.PlayerReplicationInfo); if(headHealth <= 0) headshotLevel = 0.0; + // Handle special weapon effects + HandleStoppingPower(damageType, headshotLevel); // Handle elemental damage components - ExtractElementalDamage( regDamage, heatDamage, damage, + ExtractElementalDamage(regDamage, heatDamage, damage, instigatedBy, hitLocation, momentum, damageType, KFPRI, headshotLevel, lockonTime); - FireDamageEffects( HeatDamage, instigatedBy, hitLocation, momentum, - damageType, headshotLevel, KFPRI); - FrostEffects( instigatedBy, hitLocation, momentum, + FireDamageEffects(HeatDamage, instigatedBy, hitLocation, + momentum, damageType, headshotLevel, KFPRI); + FrostEffects( instigatedBy, hitLocation, momentum, damageType, headshotLevel, KFPRI); // Handle body parts damage components - ExtractPartsDamage( bodyDamage, headDamage, painDamage, + ExtractPartsDamage( bodyDamage, headDamage, painDamage, RegDamage + HeatDamage, instigatedBy, hitLocation, momentum, damageType, KFPRI, headshotLevel, lockonTime); - DoRightPainReaction( painDamage, instigatedBy, hitLocation, momentum, + DoRightPainReaction( painDamage, instigatedBy, hitLocation, momentum, damageType, headshotLevel, KFPRI); - DealPartsDamage( bodyDamage, headDamage, instigatedBy, - hitLocation, momentum, damageType, KFPRI, - headshotLevel, lockonTime); + DealPartsDamage( bodyDamage, headDamage, + instigatedBy, hitLocation, momentum, damageType, + KFPRI, headshotLevel, lockonTime); AddKillAssistant(instigatedBy, bodyDamage); // Rewrite values of last deal damage, instigator, etc. UpdateLastDamageVars( instigatedBy, bodyDamage, damageType, @@ -1639,6 +1694,28 @@ function TakeDamageClient( int damage, // like why the fuck is it being done HERE? Makes no fucking sense bBackstabbed = false; } +function HandleStoppingPower( + class damageType, + float headshotLevel +) { + local float strength; + local float actualMinStoppingThreshold, actualMaxStoppingEffect; + + strength = damageType.default.stoppingPower; + if (headshotLevel > 0.0) { + strength *= 2; + } + if (concussionCountdown > 0) { + actualMinStoppingThreshold = FMax(0.0, minStoppingThreshold - 0.2); + actualMaxStoppingEffect = FMin(0.9, maxStoppingEffect + 0.2); + } + else { + actualMinStoppingThreshold = minStoppingThreshold; + actualMaxStoppingEffect = maxStoppingEffect; + } + strength = FMax(0, strength - actualMinStoppingThreshold); + stoppingEffect = FMin(actualMaxStoppingEffect, stoppingEffect + strength); +} function TakeDamage(int damage, Pawn instigatedBy, Vector hitLocation, @@ -1684,15 +1761,12 @@ function TakeDamage(int damage, } } function TakeFireDamage(int damage, Pawn instigator){ - local bool bLowFuel, bHighHeat; local Vector DummyHitLoc, DummyMomentum; super(Skaarj).TakeDamage( damage, instigator, dummyHitLoc, dummyMomentum, fireDamageClass); lastBurnDamage = damage; // Melt em' :) - bHighHeat = heat > default.health / 20; - bLowFuel = FlameFuel < 0.75 * InitFlameFuel; - if(FlameFuel <= 0 || bHighHeat && bLowFuel) + if(FlameFuel <= 0) ZombieCrispUp(); } function TakeFrostDamage(int damage, Pawn instigator){ @@ -1716,33 +1790,40 @@ simulated function ZombieCrispUp(){ } simulated function HeatTick(){ local float iceDamage; + local float heatRelativeLevel, heatMultiplier; + + heatRelativeLevel = FMin(heat, flameFuel) / initFlameFuel; + if (heatRelativeLevel < 0.05) { + heatMultiplier = 1.5; + } else { + heatMultiplier = 1.1; + } // Update heat value if(!bOnFire || flameFuel <= 0) heat *= heatDissipationRate; - else{ - if(flameFuel < heat) - heat = flameFuel * 1.1 + (heat - flameFuel) * heatDissipationRate; - else - heat = heat * 1.1; - if(bFrugalFuelUsage) - flameFuel -= heat; - else - flameFuel -= FMax(heat, InitFlameFuel / 15); + else { + if(flameFuel < heat) { + heat = flameFuel * heatMultiplier + (heat - flameFuel) * heatDissipationRate; + } else { + heat = heat * heatMultiplier; + } } + flameFuel = FMax(0, flameFuel - heat); CapHeat(); if(Abs(heat) < 1) heat = 0.0; // Update on-fire status if(bOnFire){ - if(heat > 0) - TakeFireDamage(heat + rand(5), burnInstigator); - else{ - bBurnified = false; - UnSetBurningBehavior(); - RemoveFlamingEffects(); - StopBurnFX(); - bOnFire = false; - } + if(heat > 0) { + TakeFireDamage(heat, burnInstigator); + } + else { + bBurnified = false; + UnSetBurningBehavior(); + RemoveFlamingEffects(); + StopBurnFX(); + bOnFire = false; + } } // Update frozen status (always deal frost damage) iceCrustStrenght = FMax(iceCrustStrenght, heat); @@ -1761,9 +1842,9 @@ simulated function HeatTick(){ } simulated function SetBurningBehavior(){ bBurningBehavior = true; - if(default.Health >= 1000) return; - if(Role == Role_Authority) - Intelligence = BRAINS_Retarded; + if(default.Health >= 1000) { + return; + } MovementAnims[0] = BurningWalkFAnims[Rand(3)]; WalkAnims[0] = BurningWalkFAnims[Rand(3)]; MovementAnims[1] = BurningWalkAnims[0]; @@ -1779,7 +1860,6 @@ simulated function UnSetBurningBehavior(){ if(Role == Role_Authority){ Intelligence = default.Intelligence; if(!bZapped){ - SetGroundSpeed(GetOriginalGroundSpeed()); AirSpeed = default.AirSpeed; WaterSpeed = default.WaterSpeed; } @@ -1791,6 +1871,50 @@ simulated function UnSetBurningBehavior(){ WalkAnims[i] = default.WalkAnims[i]; } } +simulated function SetGroundSpeed(float newGroundSpeed) { + if (initializationComplete) { + UpdateGroundSpeed(); + } else { + // Let `KFMonster`'s code setup original speed for this zed. + // This is a hack to be removed later, when we'll be untangling + // initialization code + super.SetGroundSpeed(newGroundSpeed); + } +} +simulated function UpdateGroundSpeed() { + if (TryNonRelevantSpeedup()) { + return; + } + groundSpeed = GetOriginalGroundSpeed(); + groundSpeed *= (1.0 - stoppingEffect); + if (bDecapitated) { + groundSpeed *= 0.8; + } + if (bCrispified) { + groundSpeed *= 1.25; + } +} +simulated function ModDamageFromZed( + out int damage, + class damageType +) { + if (bCrispified) { + damage *= 2; + } +} +// If this function returns `true`, then we shouldn't touch speed further, +// because a speed hack was used for the zed +simulated function bool TryNonRelevantSpeedup(){ + if(level.netMode == NM_Client || !CanSpeedAdjust()) { + return false; + } + if(level.timeSeconds - lastReplicateTime > 0.5) { + groundSpeed = default.groundSpeed * (300.0 / default.groundSpeed); + return true; + } + lastSeenOrRelevantTime = level.timeSeconds; + return false; +} simulated function ServerDropFaster(NiceHumanPawn nicePawn){ if(nicePawn == none) return; if(Health > 0) @@ -1808,7 +1932,7 @@ simulated function RemoveHead(){ if(kfDmgType != none && kfDmgType.default.bIsMeleeDamage) bMeleeDecapitated = true; SetAnimAction('HitF'); - SetGroundSpeed(GroundSpeed *= 0.80); + UpdateGroundSpeed(); // No more raspy breathin'...cuz he has no throat or mouth :S AmbientSound = MiscSound; if(Health > 0) @@ -2007,8 +2131,8 @@ function float HeatIncScale(){ return 100.0 / default.health; } function CapHeat(){ - heat = FMin(heat, 135 + rand(10) - 5); - heat = FMax(heat, -150 + rand(10) - 5); + heat = FMin(heat, MAX_HEAT); + heat = FMax(heat, MIN_HEAT); } function bool TryMeleeReachTarget(out Vector hitLocation){ local Actor hitActor; @@ -2049,6 +2173,7 @@ function bool MeleeDamageTarget(int hitDamage, Vector pushDir){ local KFHumanPawn kfHumanPawn; if(Level.netMode == NM_Client) return false; if(controller == none || controller.target == none) return false; + ModDamageFromZed(hitDamage, niceZombieDamType); // Melee for doors kfHumanPawn = KFHumanPawn(controller.target); bTargetIsDoor = controller.target.IsA('KFDoorMover'); @@ -2201,13 +2326,10 @@ defaultproperties lastStunTime=-1.000000 headDamageRecoveryRate=100.000000 headRecoveryTime=1.000000 - mind=1.000000 - accStunMindLvl=0.500000 bCanBurn=True fuelRatio=0.750000 heatDissipationRate=0.666000 heatTicksPerSecond=3.000000 - bFrugalFuelUsage=True clientHeadshotScale=1.000000 FrozenMaterial=Texture'HTec_A.Overlay.IceOverlay' ShatteredIce=class'NiceIceChunkEmitter' @@ -2216,7 +2338,12 @@ defaultproperties DamageToMonsterScale=5.000000 RagdollLifeSpan=120.000000 ControllerClass=class'NiceMonsterController' - + stoppingEffect=0.0 + stoppingRecoveryRate=0.025 + maxStoppingEffect=0.25 + minStoppingThreshold=0.0 + MIN_HEAT = -150.0 + MAX_HEAT = 200.0 Begin Object Class=KarmaParamsSkel Name=KarmaParamsSkelN KConvulseSpacing=(Max=2.200000) KLinearDamping=0.150000 diff --git a/sources/Zeds/NiceMonsterController.uc b/sources/Zeds/NiceMonsterController.uc index 1bcb5ab..59fd849 100644 --- a/sources/Zeds/NiceMonsterController.uc +++ b/sources/Zeds/NiceMonsterController.uc @@ -480,6 +480,7 @@ function bool SetEnemy( pawn newEnemy, // Do fight if we can if(bCanForceFight) { + moveTarget = newEnemy; ChangeEnemy(newEnemy, true); FightEnemy(false); return true;