Fix formatting #1 #27

Merged
dkanus merged 4 commits from harpoon into master 2023-05-23 12:17:15 +03:00
3 changed files with 1316 additions and 905 deletions

View File

@ -12,6 +12,7 @@
// E-mail: dkanus@gmail.com // E-mail: dkanus@gmail.com
//====================================================================================================================== //======================================================================================================================
class NiceBullet extends Actor; class NiceBullet extends Actor;
// Link to interaction with the server // Link to interaction with the server
var NiceReplicationInfo niceRI; var NiceReplicationInfo niceRI;
// Controller of our instigator // Controller of our instigator
@ -20,7 +21,6 @@ var NicePlayerController nicePlayer;
var NicePlayerController localPlayer; var NicePlayerController localPlayer;
// Link to our mutator // Link to our mutator
var NicePack niceMutator; var NicePack niceMutator;
//====================================================================================================================== //======================================================================================================================
// Battle bullet characteristic // Battle bullet characteristic
var float charOrigDamage; var float charOrigDamage;
@ -180,22 +180,29 @@ var string ambientSoundRef;
//====================================================================================================================== //======================================================================================================================
// Functions // Functions
static function PreloadAssets() { static function PreloadAssets() {
if(default.ambientSound == none && default.ambientSoundRef != "") if (default.ambientSound == none && default.ambientSoundRef != "") {
default.ambientSound = sound(DynamicLoadObject(default.ambientSoundRef, class'Sound', true)); default.ambientSound = sound(DynamicLoadObject(default.ambientSoundRef, class'Sound', true));
if(default.staticMesh == none && default.staticMeshRef != "") }
if (default.staticMesh == none && default.staticMeshRef != "") {
UpdateDefaultStaticMesh(StaticMesh(DynamicLoadObject(default.staticMeshRef, class'StaticMesh', true))); UpdateDefaultStaticMesh(StaticMesh(DynamicLoadObject(default.staticMeshRef, class'StaticMesh', true)));
if(default.mesh == none && default.meshRef != "") }
if (default.mesh == none && default.meshRef != "") {
UpdateDefaultMesh(Mesh(DynamicLoadObject(default.meshRef, class'Mesh', true))); UpdateDefaultMesh(Mesh(DynamicLoadObject(default.meshRef, class'Mesh', true)));
if(default.regularImpact.noise == none && default.regularImpact.noiseRef != "") }
if (default.regularImpact.noise == none && default.regularImpact.noiseRef != "") {
default.regularImpact.noise = default.regularImpact.noise =
sound(DynamicLoadObject(default.regularImpact.noiseRef, class'Sound', true)); sound(DynamicLoadObject(default.regularImpact.noiseRef, class'Sound', true));
if(default.explosionImpact.noise == none && default.explosionImpact.noiseRef != "") }
if (default.explosionImpact.noise == none && default.explosionImpact.noiseRef != "") {
default.explosionImpact.noise = default.explosionImpact.noise =
sound(DynamicLoadObject(default.explosionImpact.noiseRef, class'Sound', true)); sound(DynamicLoadObject(default.explosionImpact.noiseRef, class'Sound', true));
if(default.disintegrationImpact.noise == none && default.disintegrationImpact.noiseRef != "") }
if (default.disintegrationImpact.noise == none && default.disintegrationImpact.noiseRef != "") {
default.disintegrationImpact.noise = default.disintegrationImpact.noise =
sound(DynamicLoadObject(default.disintegrationImpact.noiseRef, class'Sound', true)); sound(DynamicLoadObject(default.disintegrationImpact.noiseRef, class'Sound', true));
} }
}
static function bool UnloadAssets() { static function bool UnloadAssets() {
default.AmbientSound = none; default.AmbientSound = none;
UpdateDefaultStaticMesh(none); UpdateDefaultStaticMesh(none);
@ -205,20 +212,26 @@ static function bool UnloadAssets(){
default.disintegrationImpact.noise = none; default.disintegrationImpact.noise = none;
return true; return true;
} }
function PostBeginPlay() { function PostBeginPlay() {
super.PostBeginPlay(); super.PostBeginPlay();
bounceHeadMod = 1.0; bounceHeadMod = 1.0;
} }
function UpdateTrails() { function UpdateTrails() {
local Actor trailBase; local Actor trailBase;
// Do nothing on dedicated server // Do nothing on dedicated server
if(Level.NetMode == NM_DedicatedServer) if (Level.NetMode == NM_DedicatedServer) {
return; return;
}
// Spawn necessary trails first // Spawn necessary trails first
if(trailClass != none && bulletTrail == none) if (trailClass != none && bulletTrail == none) {
bulletTrail = Spawn(trailClass, self); bulletTrail = Spawn(trailClass, self);
if(trailXClass != none && bulletXTrail == none) }
if (trailXClass != none && bulletXTrail == none) {
bulletXTrail = Spawn(trailXClass, self); bulletXTrail = Spawn(trailXClass, self);
}
// Handle positioning differently for stuck and regular projectiles // Handle positioning differently for stuck and regular projectiles
if (bStuck && base != none) { if (bStuck && base != none) {
if (bUseBone) { if (bUseBone) {
@ -235,25 +248,30 @@ function UpdateTrails(){
bulletXTrail.SetRelativeRotation(relativeRotation); bulletXTrail.SetRelativeRotation(relativeRotation);
} }
} }
} } else {
else
trailBase = self; trailBase = self;
}
// Update lifetime and base (latter is for non-bone attachments only) // Update lifetime and base (latter is for non-bone attachments only)
if (bulletTrail != none) { if (bulletTrail != none) {
if(trailBase != none) if (trailBase != none) {
bulletTrail.SetBase(trailBase); bulletTrail.SetBase(trailBase);
}
bulletTrail.lifespan = lifeSpan; bulletTrail.lifespan = lifeSpan;
} }
if (bulletXTrail != none) { if (bulletXTrail != none) {
if(trailBase != none) if (trailBase != none) {
bulletXTrail.SetBase(trailBase); bulletXTrail.SetBase(trailBase);
}
bulletXTrail.lifespan = lifeSpan; bulletXTrail.lifespan = lifeSpan;
} }
} }
function ResetPathBuilding() { function ResetPathBuilding() {
finishedSegmentPart = -1.0; finishedSegmentPart = -1.0;
shiftPoint = location; shiftPoint = location;
} }
// Resets default values for this bullet. // Resets default values for this bullet.
// Must be called before each new use of a bullet. // Must be called before each new use of a bullet.
function Renew() { function Renew() {
@ -266,98 +284,129 @@ function Renew(){
ResetIgnoreList(); ResetIgnoreList();
ResetPathBuilding(); ResetPathBuilding();
} }
simulated function Tick(float delta) { simulated function Tick(float delta) {
super.Tick(delta); super.Tick(delta);
if(localPlayer == none)
if (localPlayer == none) {
localPlayer = NicePlayerController(Level.GetLocalPlayerController()); localPlayer = NicePlayerController(Level.GetLocalPlayerController());
}
if (charFuseTime > 0) { if (charFuseTime > 0) {
charFuseTime -= delta; charFuseTime -= delta;
if (charFuseTime < 0) { if (charFuseTime < 0) {
if (charExplodeOnFuse && !charIsDud) { if (charExplodeOnFuse && !charIsDud) {
GenerateImpactEffects(explosionImpact, location, movementDirection); GenerateImpactEffects(explosionImpact, location, movementDirection);
if(bStuck) if (bStuck) {
class'NiceBulletAdapter'.static.Explode(self, niceRI, location, base); class'NiceBulletAdapter'.static.Explode(self, niceRI, location, base);
else } else {
class'NiceBulletAdapter'.static.Explode(self, niceRI, location); class'NiceBulletAdapter'.static.Explode(self, niceRI, location);
} }
if(!charExplodeOnFuse) }
if (!charExplodeOnFuse) {
GenerateImpactEffects(disintegrationImpact, location, movementDirection); GenerateImpactEffects(disintegrationImpact, location, movementDirection);
}
KillBullet(); KillBullet();
} }
} }
if (bInitFinished && !bInitFinishDetected) { if (bInitFinished && !bInitFinishDetected) {
bInitFinishDetected = true; bInitFinishDetected = true;
UpdateTrails(); UpdateTrails();
} }
if(bInitFinished && !bBulletDead && !bStuck) if (bInitFinished && !bBulletDead && !bStuck) {
DoProcessMovement(delta); DoProcessMovement(delta);
}
if (bInitFinished && bStuck) { if (bInitFinished && bStuck) {
if(base == none || (KFMonster(base) != none && KFMonster(base).health <= 0)) if (base == none || (KFMonster(base) != none && KFMonster(base).health <= 0)) {
nicePlayer.ExplodeStuckBullet(stuckID); nicePlayer.ExplodeStuckBullet(stuckID);
} }
} }
}
// Extracts pawn actor from it's auxiliary collision // Extracts pawn actor from it's auxiliary collision
// @param other Actor we collided with // @param other Actor we collided with
// @return Pawn we're interested in // @return Pawn we're interested in
function Actor GetMainActor(Actor other) { function Actor GetMainActor(Actor other) {
if(other == none) if (other == none) {
return none; return none;
}
if (!other.IsA('KFPawn') && !other.IsA('KFMonster')) {
// Try owner // Try owner
if( KFPawn(other) == none && KFMonster(other) == none if (other.owner.IsA('KFPawn') || other.owner.IsA('KFMonster')) {
&& (KFPawn(other.owner) != none || KFMonster(other.owner) != none) ) return other.owner;
other = other.owner; }
// Try base // Try base
if( KFPawn(other) == none && KFMonster(other) == none if (other.base.IsA('KFPawn') || other.base.IsA('KFMonster')) {
&& (KFPawn(other.base) != none || KFMonster(other.base) != none) ) return other.base;
other = other.base; }
}
return other; return other;
} }
// Returns 'true' if passed actor is either world geometry, 'Level' itself or nothing ('none') // Returns 'true' if passed actor is either world geometry, 'Level' itself or nothing ('none')
// Neither of these related to pawn damage dealing // Neither of these related to pawn damage dealing
function bool IsLevelActor(Actor other) { function bool IsLevelActor(Actor other) {
if(other == none) if (other == none) {
return true; return true;
}
return (other.bWorldGeometry || other == Level); return (other.bWorldGeometry || other == Level);
} }
// Adds given actor and every colliding object connected to it to ignore list // Adds given actor and every colliding object connected to it to ignore list
// Removes their collision in case ignore is active (see 'bIgnoreIsActive') // Removes their collision in case ignore is active (see 'bIgnoreIsActive')
function TotalIgnore(Actor other) { function TotalIgnore(Actor other) {
// These mark what objects, associated with 'other' we also need to ignore // These mark what objects, associated with 'other' we also need to ignore
local KFPawn pawnOther; local KFPawn pawnOther;
local KFMonster zedOther; local KFMonster zedOther;
if(other == none)
if (other == none) {
return; return;
}
// Try to find main actor as KFPawn // Try to find main actor as KFPawn
pawnOther = KFPawn(other); pawnOther = KFPawn(other);
if(pawnOther == none) if (pawnOther == none) {
pawnOther = KFPawn(other.base); pawnOther = KFPawn(other.base);
if(pawnOther == none) }
if (pawnOther == none) {
pawnOther = KFPawn(other.owner); pawnOther = KFPawn(other.owner);
}
// Try to find main actor as KFMonster // Try to find main actor as KFMonster
zedOther = KFMonster(other); zedOther = KFMonster(other);
if(zedOther == none) if (zedOther == none) {
zedOther = KFMonster(other.base); zedOther = KFMonster(other.base);
if(zedOther == none) }
if (zedOther == none) {
zedOther = KFMonster(other.owner); zedOther = KFMonster(other.owner);
}
// Ignore everything that's associated with this actor and can have collision // Ignore everything that's associated with this actor and can have collision
IgnoreActor(other); IgnoreActor(other);
IgnoreActor(other.base); IgnoreActor(other.base);
IgnoreActor(other.owner); IgnoreActor(other.owner);
if(pawnOther != none) if (pawnOther != none) {
IgnoreActor(pawnOther.AuxCollisionCylinder); IgnoreActor(pawnOther.AuxCollisionCylinder);
if(zedOther != none) }
if (zedOther != none) {
IgnoreActor(zedOther.MyExtCollision); IgnoreActor(zedOther.MyExtCollision);
} }
}
// Adds a given actor to ignore list and removes it's collision in case ignore is active (see 'bIgnoreIsActive') // Adds a given actor to ignore list and removes it's collision in case ignore is active (see 'bIgnoreIsActive')
function IgnoreActor(Actor other) { function IgnoreActor(Actor other) {
local int i; local int i;
local IgnoreEntry newIgnoredEntry; local IgnoreEntry newIgnoredEntry;
// Check if that's a non-level actor and not already on the list // Check if that's a non-level actor and not already on the list
if(IsLevelActor(other)) if (IsLevelActor(other)) {
return; return;
for(i = 0;i < ignoredActors.Length;i ++) }
if(ignoredActors[i].ignored == other) for (i = 0; i < ignoredActors.Length; i ++) {
if (ignoredActors[i].ignored == other) {
return; return;
}
}
// Add actor to the ignore list & disable collision if needed // Add actor to the ignore list & disable collision if needed
if (other != none) { if (other != none) {
// Make entry // Make entry
@ -365,47 +414,63 @@ function IgnoreActor(Actor other){
newIgnoredEntry.bExtDisabled = !other.bCollideActors; newIgnoredEntry.bExtDisabled = !other.bCollideActors;
// Add and activate it // Add and activate it
ignoredActors[ignoredActors.Length] = newIgnoredEntry; ignoredActors[ignoredActors.Length] = newIgnoredEntry;
if(bIgnoreIsActive) if (bIgnoreIsActive) {
other.SetCollision(false); other.SetCollision(false);
} }
} }
}
// Restores ignored state of the actors and zeroes our ignored arrays // Restores ignored state of the actors and zeroes our ignored arrays
function ResetIgnoreList() { function ResetIgnoreList() {
SetIgnoreActive(false); SetIgnoreActive(false);
ignoredActors.Length = 0; ignoredActors.Length = 0;
} }
// Activates/deactivates ignore for actors on the ignore list. // 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. // 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. // 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. // Ignore deactivation is supposed to be used in the same function call in which activation took place before.
function SetIgnoreActive(bool bActive) { function SetIgnoreActive(bool bActive) {
local int i; local int i;
// Do nothing if we're already in a correct state // Do nothing if we're already in a correct state
if(bActive == bIgnoreIsActive) if (bActive == bIgnoreIsActive) {
return; return;
}
// Change ignore state & disable collision for ignored actors // Change ignore state & disable collision for ignored actors
bIgnoreIsActive = bActive; bIgnoreIsActive = bActive;
for(i = 0;i < ignoredActors.Length;i ++) for (i = 0; i < ignoredActors.Length; i ++) {
if (ignoredActors[i].ignored != none) { if (ignoredActors[i].ignored != none) {
// Mark actors that were set to not collide before activation // Mark actors that were set to not collide before activation
if(bActive && !ignoredActors[i].ignored.bCollideActors) if (bActive && !ignoredActors[i].ignored.bCollideActors) {
ignoredActors[i].bExtDisabled = true; ignoredActors[i].bExtDisabled = true;
}
// Change collision for actors that weren't externally modified // Change collision for actors that weren't externally modified
if(!ignoredActors[i].bExtDisabled) if (!ignoredActors[i].bExtDisabled) {
ignoredActors[i].ignored.SetCollision(!bActive); ignoredActors[i].ignored.SetCollision(!bActive);
}
// After we deactivated our rules - forget about external modifications // After we deactivated our rules - forget about external modifications
if(!bActive) if (!bActive) {
ignoredActors[i].bExtDisabled = false; ignoredActors[i].bExtDisabled = false;
} }
} }
}
}
function SetHumanPawnCollision(bool bEnable) { function SetHumanPawnCollision(bool bEnable) {
local int i; local int i;
if(niceMutator == none)
if (niceMutator == none) {
niceMutator = class'NicePack'.static.Myself(Level); niceMutator = class'NicePack'.static.Myself(Level);
for(i = 0;i < niceMutator.recordedHumanPawns.Length;i ++) }
if(niceMutator.recordedHumanPawns[i] != none)
for (i = 0; i < niceMutator.recordedHumanPawns.Length; i ++) {
if (niceMutator.recordedHumanPawns[i] != none) {
niceMutator.recordedHumanPawns[i].bBlockHitPointTraces = bEnable; niceMutator.recordedHumanPawns[i].bBlockHitPointTraces = bEnable;
} }
}
}
function float CheckHeadshot(KFMonster kfZed, Vector hitLocation, Vector hitDirection) { function float CheckHeadshot(KFMonster kfZed, Vector hitLocation, Vector hitDirection) {
local float hsMod; local float hsMod;
local float precision; local float precision;
@ -413,6 +478,7 @@ function float CheckHeadshot(KFMonster kfZed, Vector hitLocation, Vector hitDire
local NiceMonster niceZed; local NiceMonster niceZed;
local KFPlayerReplicationInfo KFPRI; local KFPlayerReplicationInfo KFPRI;
local class<NiceVeterancyTypes> niceVet; local class<NiceVeterancyTypes> niceVet;
niceZed = NiceMonster(kfZed); niceZed = NiceMonster(kfZed);
hitDirection = Normal(hitDirection); hitDirection = Normal(hitDirection);
bIsShotgunBullet = ClassIsChildOf(charDamageType, class'NiceDamageTypeVetEnforcer'); bIsShotgunBullet = ClassIsChildOf(charDamageType, class'NiceDamageTypeVetEnforcer');
@ -420,27 +486,36 @@ function float CheckHeadshot(KFMonster kfZed, Vector hitLocation, Vector hitDire
hsMod = bounceHeadMod; // NICETODO: Add bounce and perk and damage type head-shot zones bonuses hsMod = bounceHeadMod; // NICETODO: Add bounce and perk and damage type head-shot zones bonuses
hsMod *= charDamageType.default.headSizeModifier; hsMod *= charDamageType.default.headSizeModifier;
hsMod *= bounceHeadMod; hsMod *= bounceHeadMod;
if(nicePlayer != none) if (nicePlayer != none) {
KFPRI = KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo); KFPRI = KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo);
if(KFPRI != none) }
if (KFPRI != none) {
niceVet = class<NiceVeterancyTypes>(KFPRI.ClientVeteranSkill); niceVet = class<NiceVeterancyTypes>(KFPRI.ClientVeteranSkill);
if(niceVet != none) }
if (niceVet != none) {
hsMod *= niceVet.static.GetHeadshotCheckMultiplier(KFPRI, charDamageType); hsMod *= niceVet.static.GetHeadshotCheckMultiplier(KFPRI, charDamageType);
}
precision = niceZed.IsHeadshotClient(hitLocation, hitDirection, niceZed.clientHeadshotScale * hsMod); precision = niceZed.IsHeadshotClient(hitLocation, hitDirection, niceZed.clientHeadshotScale * hsMod);
if(precision <= 0.0 && bIsShotgunBullet && nicePlayer != none && class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillSupportGraze')){ if (
precision <= 0.0 &&
bIsShotgunBullet &&
nicePlayer != none &&
class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillSupportGraze')
) {
bGrazing = true; bGrazing = true;
hsMod *= class'NiceSkillSupportGraze'.default.hsBonusZoneMult; hsMod *= class'NiceSkillSupportGraze'.default.hsBonusZoneMult;
precision = niceZed.IsHeadshotClient(hitLocation, hitDirection, niceZed.clientHeadshotScale * hsMod); precision = niceZed.IsHeadshotClient(hitLocation, hitDirection, niceZed.clientHeadshotScale * hsMod);
} }
return precision; return precision;
} } else {
else{ if (kfZed.IsHeadShot(hitLocation, hitDirection, 1.0)) {
if(kfZed.IsHeadShot(hitLocation, hitDirection, 1.0))
return 1.0; return 1.0;
else } else {
return 0.0; return 0.0;
} }
} }
}
// Makes bullet trace a directed line segment given by start and end points. // 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 // All traced actors and geometry are then properly affected by corresponding 'HandleHitPawn', 'HandleHitZed' and
// 'HandleHitWall' functions. // 'HandleHitWall' functions.
@ -457,6 +532,7 @@ function DoTraceLine(Vector lineStart, Vector lineEnd){
local array<int> hitPoints; local array<int> hitPoints;
local KFMonster tracedZed; local KFMonster tracedZed;
local KFPawn tracedPawn; local KFPawn tracedPawn;
lineDirection = (lineEnd - lineStart); lineDirection = (lineEnd - lineStart);
lineDirection = (lineDirection) / VSize(lineDirection); lineDirection = (lineDirection) / VSize(lineDirection);
// Do not trace for disabled bullets and prevent infinite loops // Do not trace for disabled bullets and prevent infinite loops
@ -464,64 +540,79 @@ function DoTraceLine(Vector lineStart, Vector lineEnd){
iterationCount++; iterationCount++;
// Trace next object // Trace next object
if (!bGhost || localPlayer == none || localPlayer.tracesThisTick <= localPlayer.tracesPerTickLimit) { if (!bGhost || localPlayer == none || localPlayer.tracesThisTick <= localPlayer.tracesPerTickLimit) {
if(Instigator != none) if (Instigator != none) {
tracedActor = Instigator.Trace(hitLocation, hitNormal, lineEnd, lineStart, true); tracedActor = Instigator.Trace(hitLocation, hitNormal, lineEnd, lineStart, true);
else } else {
tracedActor = none; tracedActor = none;
localPlayer.tracesThisTick ++;
} }
else localPlayer.tracesThisTick++;
} else {
tracedActor = none; tracedActor = none;
if(charAffectedByScream && !charIsDud && localPlayer != none && localPlayer.localCollisionManager != none && localPlayer.localCollisionManager.IsCollidingWithAnything(lineStart, lineEnd)) }
if (
charAffectedByScream &&
!charIsDud &&
localPlayer != none &&
localPlayer.localCollisionManager != none &&
localPlayer.localCollisionManager.IsCollidingWithAnything(lineStart, lineEnd)
) {
HandleScream(lineStart, lineDirection); HandleScream(lineStart, lineDirection);
}
if (tracedActor != none && IsLevelActor(tracedActor)) { if (tracedActor != none && IsLevelActor(tracedActor)) {
HandleHitWall(tracedActor, hitLocation, hitNormal); HandleHitWall(tracedActor, hitLocation, hitNormal);
break; break;
} } else {
else{
TotalIgnore(tracedActor); TotalIgnore(tracedActor);
tracedActor = GetMainActor(tracedActor); tracedActor = GetMainActor(tracedActor);
} }
// If tracing between current trace points haven't found anything and tracing step is less than segment's length // If tracing between current trace points haven't found anything and tracing step is less than segment's length
// -- shift tracing bounds // -- shift tracing bounds
if(tracedActor == none) if (tracedActor == none) {
return; return;
}
// First, try to handle pawn like a zed; if fails, - try to handle it like 'KFPawn' // First, try to handle pawn like a zed; if fails, - try to handle it like 'KFPawn'
tracedZed = KFMonster(tracedActor); tracedZed = KFMonster(tracedActor);
tracedPawn = KFPawn(tracedActor); tracedPawn = KFPawn(tracedActor);
if(tracedPawn != none && NiceHumanPawn(instigator) != none && if (
(NiceHumanPawn(instigator).ffScale <= 0 && NiceMedicProjectile(self) == none) ) tracedPawn != none &&
NiceHumanPawn(instigator) != none &&
(NiceHumanPawn(instigator).ffScale <= 0 && NiceMedicProjectile(self) == none)
) {
continue; continue;
}
if (tracedZed != none) { if (tracedZed != none) {
if (tracedZed.Health > 0) { if (tracedZed.Health > 0) {
headshotLevel = CheckHeadshot(tracedZed, hitLocation, lineDirection); headshotLevel = CheckHeadshot(tracedZed, hitLocation, lineDirection);
HandleHitZed(tracedZed, hitLocation, lineDirection, headshotLevel); HandleHitZed(tracedZed, hitLocation, lineDirection, headshotLevel);
} }
} } else if (tracedPawn != none && tracedPawn.Health > 0) {
else if(tracedPawn != none && tracedPawn.Health > 0){ if (tracedPawn.Health > 0) {
if(tracedPawn.Health > 0)
HandleHitPawn(tracedPawn, hitLocation, lineDirection, hitPoints); HandleHitPawn(tracedPawn, hitLocation, lineDirection, hitPoints);
} }
else } else {
HandleHitWall(tracedActor, hitLocation, hitNormal); HandleHitWall(tracedActor, hitLocation, hitNormal);
} }
} }
}
// Replaces current path segment with the next one. // Replaces current path segment with the next one.
// Doesn't check whether or not we've finished with the current segment. // Doesn't check whether or not we've finished with the current segment.
function BuildNextPathSegment() { function BuildNextPathSegment() {
// Only set start point to our location when we build path segment for the first time // 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 // After that we can't even assume that bullet is exactly in the 'pathSegmentE' point
if(finishedSegmentPart < 0.0) if (finishedSegmentPart < 0.0) {
pathSegmentS = Location; pathSegmentS = Location;
else } else {
pathSegmentS = pathSegmentE; pathSegmentS = pathSegmentE;
}
movementDirection += (movementAcceleration * trajUpdFreq) / movementSpeed; movementDirection += (movementAcceleration * trajUpdFreq) / movementSpeed;
pathSegmentE = pathSegmentS + movementDirection * movementSpeed * trajUpdFreq; pathSegmentE = pathSegmentS + movementDirection * movementSpeed * trajUpdFreq;
finishedSegmentPart = 0.0; finishedSegmentPart = 0.0;
shiftPoint = pathSegmentS; shiftPoint = pathSegmentS;
} }
// Updates 'shiftPoint' to the next bullet position in current segment. // Updates 'shiftPoint' to the next bullet position in current segment.
// Does nothing if current segment is finished or no segment was built at all. // 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. // @param delta Amount of time bullet has to move through the segment.
@ -531,9 +622,11 @@ function float ShiftInSegment(float delta){
local float remainingTime; local float remainingTime;
// Part of segment we can pass in a given time // Part of segment we can pass in a given time
local float segmentPartWeCanPass; local float segmentPartWeCanPass;
// Exit if there's no segment in progress // Exit if there's no segment in progress
if(finishedSegmentPart < 0.0 || finishedSegmentPart > 1.0) if (finishedSegmentPart < 0.0 || finishedSegmentPart > 1.0) {
return delta; return delta;
}
// [movementSpeed * delta] / [movementSpeed * trajUpdFreq] = [delta / trajUpdFreq] // [movementSpeed * delta] / [movementSpeed * trajUpdFreq] = [delta / trajUpdFreq]
segmentPartWeCanPass = delta / trajUpdFreq; segmentPartWeCanPass = delta / trajUpdFreq;
// If we can move through the rest of the segment - move to end point and mark it finished // If we can move through the rest of the segment - move to end point and mark it finished
@ -541,19 +634,20 @@ function float ShiftInSegment(float delta){
remainingTime = delta - (1.0 - finishedSegmentPart) * trajUpdFreq; remainingTime = delta - (1.0 - finishedSegmentPart) * trajUpdFreq;
finishedSegmentPart = 1.1; finishedSegmentPart = 1.1;
shiftPoint = pathSegmentE; shiftPoint = pathSegmentE;
} } else {
// Otherwise compute new 'shiftPoint' normally // Otherwise compute new 'shiftPoint' normally
else{
remainingTime = 0.0; remainingTime = 0.0;
finishedSegmentPart += (delta / trajUpdFreq); finishedSegmentPart += (delta / trajUpdFreq);
shiftPoint = pathSegmentS + movementDirection * movementSpeed * trajUpdFreq * finishedSegmentPart; shiftPoint = pathSegmentS + movementDirection * movementSpeed * trajUpdFreq * finishedSegmentPart;
} }
return remainingTime; return remainingTime;
} }
// Moves bullet according to settings and decides when and how much tracing should it do. // 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 // @param delta Amount of time passed after previous bullet movement
function DoProcessMovement(float delta) { function DoProcessMovement(float delta) {
local Vector tempVect; local Vector tempVect;
SetIgnoreActive(true); SetIgnoreActive(true);
//SetHumanPawnCollision(true); //SetHumanPawnCollision(true);
// Simple linear movement // Simple linear movement
@ -567,12 +661,12 @@ function DoProcessMovement(float delta){
// If in future complex movement would be re-enabled, - we want to set first point of the path to // 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. // the location of bullet at a time and not use outdated information.
finishedSegmentPart = -1.0; finishedSegmentPart = -1.0;
} } else {
// Non-linear movement support // Non-linear movement support
else{
while(delta > 0.0) { while(delta > 0.0) {
if(finishedSegmentPart < 0.0 || finishedSegmentPart > 1.0) if (finishedSegmentPart < 0.0 || finishedSegmentPart > 1.0) {
BuildNextPathSegment(); BuildNextPathSegment();
}
// Remember current 'shiftPoint'. That's where we stopped tracing last time and where we must resume. // Remember current 'shiftPoint'. That's where we stopped tracing last time and where we must resume.
tempVect = shiftPoint; tempVect = shiftPoint;
// Update 'shiftPoint' (bullet position) // Update 'shiftPoint' (bullet position)
@ -585,20 +679,27 @@ function DoProcessMovement(float delta){
Move(shiftPoint - location); Move(shiftPoint - location);
} }
SetRotation(Rotator(movementDirection)); SetRotation(Rotator(movementDirection));
if(charMinExplosionDist > 0) if (charMinExplosionDist > 0) {
charMinExplosionDist -= VSize(tempVect); charMinExplosionDist -= VSize(tempVect);
}
SetIgnoreActive(false); SetIgnoreActive(false);
// SetHumanPawnCollision(false); // SetHumanPawnCollision(false);
} }
function Stick(Actor target, Vector hitLocation) { function Stick(Actor target, Vector hitLocation) {
local NiceMonster targetZed;
local name boneStick;
local float distToBone;
local float t;
local Vector boneStrickOrig; local Vector boneStrickOrig;
local ExplosionData expData; local ExplosionData expData;
if(bGhost) local Actor resultTarget;
local NiceMonster targetZed;
local name boneStick;
local float distToBone, t;
if (bGhost) {
return; return;
}
expData.instigator = instigator;
expData.sourceWeapon = sourceWeapon;
expData.bulletClass = class;
expData.explosionDamageType = charExplosionDamageType; expData.explosionDamageType = charExplosionDamageType;
expData.explosionDamage = charExplosionDamage; expData.explosionDamage = charExplosionDamage;
expData.explosionRadius = charExplosionRadius; expData.explosionRadius = charExplosionRadius;
@ -607,24 +708,20 @@ function Stick(Actor target, Vector hitLocation){
expData.fuseTime = charFuseTime; expData.fuseTime = charFuseTime;
expData.explodeOnFuse = charExplodeOnFuse; expData.explodeOnFuse = charExplodeOnFuse;
expData.affectedByScream = charAffectedByScream; expData.affectedByScream = charAffectedByScream;
expData.sourceWeapon = sourceWeapon;
if (!target.IsA('NiceMonster')) {
hitLocation -= target.location;
boneStick = 'None';
resultTarget = target;
} else {
targetZed = NiceMonster(target); 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);
}
else{
expData.bulletClass = class;
expData.instigator = instigator;
boneStick = targetZed.GetClosestBone(hitLocation, movementDirection, distToBone); boneStick = targetZed.GetClosestBone(hitLocation, movementDirection, distToBone);
if(CheckHeadshot(targetZed, hitLocation, movementDirection) > 0.0) if (CheckHeadshot(targetZed, hitLocation, movementDirection) > 0.0) {
boneStick = targetZed.HeadBone; boneStick = targetZed.HeadBone;
if(boneStick == targetZed.HeadBone) }
if (boneStick == targetZed.HeadBone) {
expData.stuckToHead = true; expData.stuckToHead = true;
}
boneStrickOrig = targetZed.GetBoneCoords(boneStick).origin; boneStrickOrig = targetZed.GetBoneCoords(boneStick).origin;
t = movementDirection.x * (boneStrickOrig.x - hitLocation.x) + t = movementDirection.x * (boneStrickOrig.x - hitLocation.x) +
movementDirection.y * (boneStrickOrig.y - hitLocation.y) + movementDirection.y * (boneStrickOrig.y - hitLocation.y) +
@ -632,37 +729,60 @@ function Stick(Actor target, Vector hitLocation){
t /= VSizeSquared(movementDirection); t /= VSizeSquared(movementDirection);
t *= 0.5; t *= 0.5;
hitLocation = hitLocation + t * movementDirection; hitLocation = hitLocation + t * movementDirection;
niceRI.ServerStickProjectile(KFHumanPawn(instigator), targetZed, boneStick, hitLocation -= boneStrickOrig;
hitLocation - boneStrickOrig, Rotator(movementDirection), expData); resultTarget = targetZed;
class'NiceProjectileSpawner'.static.StickProjectile(KFHumanPawn(instigator), targetZed, boneStick,
hitLocation - boneStrickOrig, Rotator(movementDirection), expData);
} }
niceRI.ServerStickProjectile(
KFHumanPawn(instigator),
resultTarget,
boneStick,
hitLocation,
Rotator(movementDirection),
expData
);
class'NiceProjectileSpawner'.static.StickProjectile(
KFHumanPawn(instigator),
resultTarget,
boneStick,
hitLocation,
Rotator(movementDirection),
expData
);
KillBullet(); KillBullet();
} }
function DoExplode(Vector explLocation, Vector impactNormal) { function DoExplode(Vector explLocation, Vector impactNormal) {
if(charIsDud) if (charIsDud) {
return; return;
if(bStuck) }
if (bStuck) {
class'NiceBulletAdapter'.static.Explode(self, niceRI, explLocation, base); class'NiceBulletAdapter'.static.Explode(self, niceRI, explLocation, base);
else } else {
class'NiceBulletAdapter'.static.Explode(self, niceRI, explLocation); class'NiceBulletAdapter'.static.Explode(self, niceRI, explLocation);
}
GenerateImpactEffects(explosionImpact, explLocation, impactNormal, true, true); GenerateImpactEffects(explosionImpact, explLocation, impactNormal, true, true);
if(bShakeViewOnExplosion) if (bShakeViewOnExplosion) {
ShakeView(explLocation); ShakeView(explLocation);
}
KillBullet(); KillBullet();
} }
function HandleHitWall(Actor wall, Vector hitLocation, Vector hitNormal) { function HandleHitWall(Actor wall, Vector hitLocation, Vector hitNormal) {
local bool bBulletTooWeak; local bool bBulletTooWeak;
if (charExplodeOnWallHit && !charIsDud && charMinExplosionDist <= 0.0) { if (charExplodeOnWallHit && !charIsDud && charMinExplosionDist <= 0.0) {
DoExplode(hitLocation, hitNormal); DoExplode(hitLocation, hitNormal);
return; return;
} } else {
else{
class'NiceBulletAdapter'.static.HitWall(self, niceRI, wall, hitLocation, hitNormal); class'NiceBulletAdapter'.static.HitWall(self, niceRI, wall, hitLocation, hitNormal);
GenerateImpactEffects(regularImpact, hitLocation, hitNormal, true, true); GenerateImpactEffects(regularImpact, hitLocation, hitNormal, true, true);
if(charIsSticky) if (charIsSticky) {
Stick(wall, hitLocation); Stick(wall, hitLocation);
} }
}
if (bShouldBounce && !bDisableComplexMovement) { if (bShouldBounce && !bDisableComplexMovement) {
movementDirection = (movementDirection - 2.0 * hitNormal * (movementDirection dot hitNormal)); movementDirection = (movementDirection - 2.0 * hitNormal * (movementDirection dot hitNormal));
bBulletTooWeak = !class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, none, false, false); bBulletTooWeak = !class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, none, false, false);
@ -670,97 +790,133 @@ function HandleHitWall(Actor wall, Vector hitLocation, Vector hitNormal){
ResetPathBuilding(); ResetPathBuilding();
ResetIgnoreList(); ResetIgnoreList();
bounceHeadMod *= 2; bounceHeadMod *= 2;
} } else if (movementFallTime > 0.0) {
else if(movementFallTime > 0.0){
charIsDud = true; charIsDud = true;
lifeSpan = movementFallTime; lifeSpan = movementFallTime;
movementFallTime = 0.0; movementFallTime = 0.0;
movementDirection = vect(0, 0, 0); movementDirection = vect(0, 0, 0);
ResetPathBuilding(); ResetPathBuilding();
ResetIgnoreList(); ResetIgnoreList();
} } else {
else
bBulletTooWeak = true; bBulletTooWeak = true;
if(bBulletTooWeak) }
if (bBulletTooWeak) {
KillBullet(); KillBullet();
} }
}
function HandleHitPawn(KFPawn hitPawn, Vector hitLocation, Vector hitDirection, array<int> hitPoints) { function HandleHitPawn(KFPawn hitPawn, Vector hitLocation, Vector hitDirection, array<int> hitPoints) {
if (charExplodeOnPawnHit && !charIsDud && charMinExplosionDist <= 0.0) { if (charExplodeOnPawnHit && !charIsDud && charMinExplosionDist <= 0.0) {
DoExplode(hitLocation, hitDirection); DoExplode(hitLocation, hitDirection);
GenerateImpactEffects(explosionImpact, hitLocation, hitDirection); GenerateImpactEffects(explosionImpact, hitLocation, hitDirection);
return; return;
} } else {
else{
class'NiceBulletAdapter'.static.HitPawn(self, niceRI, hitPawn, hitLocation, hitDirection, hitPoints); class'NiceBulletAdapter'.static.HitPawn(self, niceRI, hitPawn, hitLocation, hitDirection, hitPoints);
if(bGenRegEffectOnPawn) if (bGenRegEffectOnPawn) {
GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false); GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false);
} }
}
if (!class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, none, false, false)) { if (!class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, none, false, false)) {
charPenetrationCount += 1; charPenetrationCount += 1;
KillBullet(); KillBullet();
} }
} }
function HandleHitZed(KFMonster targetZed, Vector hitLocation, Vector hitDirection, float headshotLevel) { function HandleHitZed(KFMonster targetZed, Vector hitLocation, Vector hitDirection, float headshotLevel) {
local bool bHitZedCalled; local bool bHitZedCalled;
if (class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillDemoDirectApproach')) { if (class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillDemoDirectApproach')) {
class'NiceBulletAdapter'.static.HitZed(self, niceRI, targetZed, hitLocation, hitDirection, headshotLevel); class'NiceBulletAdapter'.static.HitZed(self, niceRI, targetZed, hitLocation, hitDirection, headshotLevel);
if(bGenRegEffectOnPawn) if (bGenRegEffectOnPawn) {
GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false); GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false);
}
bHitZedCalled = true; bHitZedCalled = true;
} }
if (charExplodeOnPawnHit && !charIsDud && charMinExplosionDist <= 0.0) { if (charExplodeOnPawnHit && !charIsDud && charMinExplosionDist <= 0.0) {
class'NiceBulletAdapter'.static.Explode(self, niceRI, hitLocation, targetZed); class'NiceBulletAdapter'.static.Explode(self, niceRI, hitLocation, targetZed);
GenerateImpactEffects(explosionImpact, hitLocation, hitDirection); GenerateImpactEffects(explosionImpact, hitLocation, hitDirection);
if(bShakeViewOnExplosion) if (bShakeViewOnExplosion) {
ShakeView(hitLocation); ShakeView(hitLocation);
}
KillBullet(); KillBullet();
return; return;
} } else {
else{
if (!bHitZedCalled) { if (!bHitZedCalled) {
class'NiceBulletAdapter'.static.HitZed(self, niceRI, targetZed, hitLocation, hitDirection, headshotLevel); class'NiceBulletAdapter'.static.HitZed(
if(bGenRegEffectOnPawn) self,
niceRI,
targetZed,
hitLocation,
hitDirection,
headshotLevel
);
if (bGenRegEffectOnPawn) {
GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false); GenerateImpactEffects(regularImpact, hitLocation, hitDirection, false, false);
} }
}
bHitZedCalled = true; bHitZedCalled = true;
if (!bGhost && !bAlreadyHitZed) { if (!bGhost && !bAlreadyHitZed) {
bAlreadyHitZed = true; bAlreadyHitZed = true;
if(nicePlayer != none && niceRI != none) if (nicePlayer != none && niceRI != none) {
niceRI.ServerJunkieExtension(nicePlayer, headshotLevel > 0.0); niceRI.ServerJunkieExtension(nicePlayer, headshotLevel > 0.0);
} }
if(charIsSticky) }
if (charIsSticky) {
Stick(targetZed, hitLocation); Stick(targetZed, hitLocation);
} }
if(!class'NiceBulletAdapter'.static.ZedPenetration(charDamage, self, targetZed, (headshotLevel > 0.0), (headshotLevel > charDamageType.default.prReqPrecise))){ }
if (!class'NiceBulletAdapter'.static.ZedPenetration(
charDamage,
self,
targetZed,
(headshotLevel > 0.0),
(headshotLevel > charDamageType.default.prReqPrecise)
)
) {
charPenetrationCount += 1; charPenetrationCount += 1;
KillBullet(); KillBullet();
} }
} }
function HandleScream(Vector disintegrationLocation, Vector entryDirection) { function HandleScream(Vector disintegrationLocation, Vector entryDirection) {
if(!charIsDud) if (!charIsDud) {
GenerateImpactEffects(disintegrationImpact, disintegrationLocation, entryDirection); GenerateImpactEffects(disintegrationImpact, disintegrationLocation, entryDirection);
}
class'NiceBulletAdapter'.static.HandleScream(self, niceRI, disintegrationLocation, entryDirection); class'NiceBulletAdapter'.static.HandleScream(self, niceRI, disintegrationLocation, entryDirection);
} }
function GenerateImpactEffects(ImpactEffect effect, Vector hitLocation, Vector hitNormal,
optional bool bWallImpact, optional bool bGenerateDecal){ function GenerateImpactEffects(
ImpactEffect effect,
Vector hitLocation,
Vector hitNormal,
optional bool bWallImpact,
optional bool bGenerateDecal
) {
local float actualCullDistance; local float actualCullDistance;
local float actualImpactShift; local float actualImpactShift;
local bool generatedEffect; 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 // 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) if (Level.NetMode == NM_DedicatedServer || bBulletDead || localPlayer == none) {
return; return;
if(!localPlayer.CanSpawnEffect(bGhost) && !effect.bImportanEffect) }
if (!localPlayer.CanSpawnEffect(bGhost) && !effect.bImportanEffect) {
return; return;
}
// -- Classic effect // -- Classic effect
if(effect.bPlayROEffect && !bBulletDead) if (effect.bPlayROEffect && !bBulletDead) {
Spawn(class'ROBulletHitEffect',,, hitLocation, rotator(-hitNormal)); Spawn(class'ROBulletHitEffect',,, hitLocation, rotator(-hitNormal));
}
// -- Generate decal // -- Generate decal
if (bGenerateDecal && effect.decalClass != none) { if (bGenerateDecal && effect.decalClass != none) {
// Find appropriate cull distance for this decal // Find appropriate cull distance for this decal
actualCullDistance = effect.decalClass.default.cullDistance; actualCullDistance = effect.decalClass.default.cullDistance;
// Double cull distance if local player is an instigator // Double cull distance if local player is an instigator
if(instigator != none && localPlayer == instigator.Controller) if (instigator != none && localPlayer == instigator.Controller) {
actualCullDistance *= 2; // NICETODO: magic number actualCullDistance *= 2; // NICETODO: magic number
}
// Spawn decal // Spawn decal
if (!localPlayer.BeyondViewDistance(hitLocation, actualCullDistance)) { if (!localPlayer.BeyondViewDistance(hitLocation, actualCullDistance)) {
Spawn(effect.decalClass, self,, hitLocation, rotator(- hitNormal)); Spawn(effect.decalClass, self,, hitLocation, rotator(- hitNormal));
@ -769,10 +925,11 @@ function GenerateImpactEffects(ImpactEffect effect, Vector hitLocation, Vector h
} }
// -- Generate custom effect // -- Generate custom effect
if (effect.emitterClass != none && EffectIsRelevant(hitLocation, false)) { if (effect.emitterClass != none && EffectIsRelevant(hitLocation, false)) {
if(bWallImpact) if (bWallImpact) {
actualImpactShift = effect.emitterShiftWall; actualImpactShift = effect.emitterShiftWall;
else } else {
actualImpactShift = effect.emitterShiftPawn; actualImpactShift = effect.emitterShiftPawn;
}
Spawn(effect.emitterClass,,, hitLocation - movementDirection * actualImpactShift, rotator(movementDirection)); Spawn(effect.emitterClass,,, hitLocation - movementDirection * actualImpactShift, rotator(movementDirection));
generatedEffect = true; generatedEffect = true;
} }
@ -783,28 +940,43 @@ function GenerateImpactEffects(ImpactEffect effect, Vector hitLocation, Vector h
Spawn(class'NiceSoundCls',,, hitLocation); Spawn(class'NiceSoundCls',,, hitLocation);
generatedEffect = true; generatedEffect = true;
} }
if(generatedEffect) if (generatedEffect) {
localPlayer.AddEffect(); localPlayer.AddEffect();
} }
}
function ShakeView(Vector hitLocation) { function ShakeView(Vector hitLocation) {
local float distance, scale; local float distance, scale;
if(nicePlayer == none || shakeRadiusMult < 0.0)
if (nicePlayer == none || shakeRadiusMult < 0.0) {
return; return;
}
distance = VSize(hitLocation - nicePlayer.ViewTarget.Location); distance = VSize(hitLocation - nicePlayer.ViewTarget.Location);
if (distance < charExplosionRadius * shakeRadiusMult) { if (distance < charExplosionRadius * shakeRadiusMult) {
if(distance < charExplosionRadius) if (distance < charExplosionRadius) {
scale = 1.0; scale = 1.0;
else } else {
scale = (charExplosionRadius * ShakeRadiusMult - distance) / (charExplosionRadius); scale = (charExplosionRadius * ShakeRadiusMult - distance) / (charExplosionRadius);
nicePlayer.ShakeView(shakeRotMag*scale, shakeRotRate, shakeRotTime, shakeOffsetMag * scale, shakeOffsetRate, shakeOffsetTime); }
nicePlayer.ShakeView(
shakeRotMag * scale,
shakeRotRate,
shakeRotTime,
shakeOffsetMag * scale,
shakeOffsetRate,
shakeOffsetTime
);
} }
} }
function KillBullet() { function KillBullet() {
local int i; local int i;
if (bulletTrail != none) { if (bulletTrail != none) {
for (i = 0; i < bulletTrail.Emitters.Length; i ++) { for (i = 0; i < bulletTrail.Emitters.Length; i ++) {
if(bulletTrail.Emitters[i] == none) if (bulletTrail.Emitters[i] == none) {
continue; continue;
}
bulletTrail.Emitters[i].ParticlesPerSecond = 0; bulletTrail.Emitters[i].ParticlesPerSecond = 0;
bulletTrail.Emitters[i].InitialParticlesPerSecond = 0; bulletTrail.Emitters[i].InitialParticlesPerSecond = 0;
bulletTrail.Emitters[i].RespawnDeadParticles = false; bulletTrail.Emitters[i].RespawnDeadParticles = false;
@ -812,6 +984,7 @@ function KillBullet(){
bulletTrail.SetBase(none); bulletTrail.SetBase(none);
bulletTrail.AutoDestroy = true; bulletTrail.AutoDestroy = true;
} }
if (bulletXTrail != none) { if (bulletXTrail != none) {
bulletXTrail.mRegen = false; bulletXTrail.mRegen = false;
bulletXTrail.LifeSpan = LifeSpan; bulletXTrail.LifeSpan = LifeSpan;
@ -821,12 +994,12 @@ function KillBullet(){
SoundVolume = 0; SoundVolume = 0;
LifeSpan = FMin(LifeSpan, 0.1); LifeSpan = FMin(LifeSpan, 0.1);
} }
event Destroyed() { event Destroyed() {
KillBullet(); KillBullet();
} }
defaultproperties defaultproperties {
{
insideBouncesLeft=2 insideBouncesLeft=2
trajUpdFreq=0.100000 trajUpdFreq=0.100000
maxTraceCycles=128 maxTraceCycles=128

View File

@ -9,57 +9,132 @@
// E-mail: dkanus@gmail.com // E-mail: dkanus@gmail.com
//====================================================================================================================== //======================================================================================================================
class NiceBulletAdapter extends Object; class NiceBulletAdapter extends Object;
var const int BigZedMinHealth; // If zed's base Health >= this value, zed counts as Big 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 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){
static function Explode(
NiceBullet bullet,
NiceReplicationInfo niceRI,
Vector hitLocation,
optional Actor explosionTarget
) {
if (!bullet.bGhost) { if (!bullet.bGhost) {
niceRI.ServerExplode(bullet.charExplosionDamage, bullet.charExplosionRadius, bullet.charExplosionExponent, niceRI.ServerExplode(
bullet.charExplosionDamageType, bullet.charExplosionMomentum, hitLocation, bullet.instigator, true, bullet.charExplosionDamage,
explosionTarget, Vector(bullet.Rotation)); bullet.charExplosionRadius,
if(KFMonster(bullet.base) != none && bullet.bStuck && bullet.bStuckToHead) bullet.charExplosionExponent,
niceRI.ServerDealDamage(KFMonster(bullet.base), bullet.charExplosionDamage, bullet.instigator, hitLocation, bullet.charExplosionDamageType,
bullet.charExplosionMomentum * vect(0,0,-1), bullet.charExplosionDamageType, 1.0); 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
);
} }
} }
static function HandleCalibration }
(
static function HandleCalibration (
bool isHeadshot, bool isHeadshot,
NiceHumanPawn nicePawn, NiceHumanPawn nicePawn,
NiceMonster targetZed NiceMonster targetZed
) { ) {
if(nicePawn == none) return; if (nicePawn == none || nicePawn.currentCalibrationState != CALSTATE_ACTIVE) {
if(nicePawn.currentCalibrationState != CALSTATE_ACTIVE) return; return;
}
nicePawn.ServerUpdateCalibration(isHeadshot, targetZed); 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; local NicePlayerController nicePlayer;
nicePlayer = NicePlayerController(bullet.Instigator.Controller); nicePlayer = NicePlayerController(bullet.Instigator.Controller);
if(nicePlayer == none) if (nicePlayer == none) {
return; return;
if(!bullet.bAlreadyHitZed) }
if (!bullet.bAlreadyHitZed) {
HandleCalibration(false, NiceHumanPawn(bullet.Instigator), none); 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, if (
bullet.charMomentumTransfer * hitNormal, bullet.charDamageType); !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 --; 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; bullet.charIsDud = true;
} }
static function HitPawn(NiceBullet bullet, NiceReplicationInfo niceRI, KFPawn targetPawn, Vector hitLocation,
Vector hitNormal, array<int> hitPoints){ static function HitPawn(
NiceBullet bullet,
NiceReplicationInfo niceRI,
KFPawn targetPawn,
Vector hitLocation,
Vector hitNormal,
array<int> hitPoints
) {
local NiceMedicProjectile niceDart; local NiceMedicProjectile niceDart;
niceDart = NiceMedicProjectile(bullet); niceDart = NiceMedicProjectile(bullet);
if(niceDart == none) if (niceDart == none) {
niceRI.ServerDealDamage(targetPawn, bullet.charDamage, bullet.instigator, HitLocation, niceRI.ServerDealDamage(
hitNormal * bullet.charMomentumTransfer, bullet.charDamageType); targetPawn,
else bullet.charDamage,
bullet.instigator,
HitLocation,
hitNormal * bullet.charMomentumTransfer,
bullet.charDamageType
);
} else {
niceRI.ServerHealTarget(NiceHumanPawn(targetPawn), bullet.charDamage, bullet.instigator); 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 bool bIsHeadshot, bIsPreciseHeadshot;
local float actualDamage; local float actualDamage;
local int lockonTicks; local int lockonTicks;
@ -68,37 +143,54 @@ static function HitZed(NiceBullet bullet, NiceReplicationInfo niceRI, KFMonster
local NiceHumanPawn nicePawn; local NiceHumanPawn nicePawn;
local NicePlayerController nicePlayer; local NicePlayerController nicePlayer;
local class<NiceVeterancyTypes> niceVet; local class<NiceVeterancyTypes> niceVet;
nicePlayer = NicePlayerController(bullet.Instigator.Controller); nicePlayer = NicePlayerController(bullet.Instigator.Controller);
if ( nicePlayer != none && nicePlayer.abilityManager != none if (
&& nicePlayer.abilityManager.IsAbilityActive(class'NiceSkillEnforcerBruteA'.default.abilityID)) { nicePlayer != none &&
nicePlayer.abilityManager != none &&
nicePlayer.abilityManager.IsAbilityActive(class'NiceSkillEnforcerBruteA'.default.abilityID)
) {
headshotLevel = 0.0; headshotLevel = 0.0;
} }
bIsHeadshot = (headshotLevel > 0.0); bIsHeadshot = (headshotLevel > 0.0);
bIsPreciseHeadshot = (headshotLevel > bullet.charDamageType.default.prReqPrecise); bIsPreciseHeadshot = (headshotLevel > bullet.charDamageType.default.prReqPrecise);
if(!bullet.bAlreadyHitZed || bIsHeadshot) if (!bullet.bAlreadyHitZed || bIsHeadshot) {
HandleCalibration(bIsHeadshot, NiceHumanPawn(bullet.Instigator), NiceMonster(kfZed)); HandleCalibration(bIsHeadshot, NiceHumanPawn(bullet.Instigator), NiceMonster(kfZed));
if(bIsHeadshot && bullet.sourceWeapon != none) }
if (bIsHeadshot && bullet.sourceWeapon != none) {
bullet.sourceWeapon.lastHeadshotTime = bullet.Level.TimeSeconds; bullet.sourceWeapon.lastHeadshotTime = bullet.Level.TimeSeconds;
if(nicePlayer == none) }
if (nicePlayer == none) {
return; return;
}
nicePawn = NiceHumanPawn(bullet.instigator); nicePawn = NiceHumanPawn(bullet.instigator);
if( !bIsHeadshot if (
&& nicePawn != none !bIsHeadshot &&
&& nicePlayer.abilityManager != none nicePawn != none &&
&& nicePlayer.abilityManager.IsAbilityActive(class'NiceSkillSharpshooterReaperA'.default.abilityID)) nicePlayer.abilityManager != none &&
nicePlayer.abilityManager.IsAbilityActive(class'NiceSkillSharpshooterReaperA'.default.abilityID)
) {
nicePawn.ServerCooldownAbility(class'NiceSkillSharpshooterReaperA'.default.abilityID); nicePawn.ServerCooldownAbility(class'NiceSkillSharpshooterReaperA'.default.abilityID);
}
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo)); niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo));
if(bullet.charCausePain) if (bullet.charCausePain) {
actualDamage = bullet.charOrigDamage; actualDamage = bullet.charOrigDamage;
else } else {
actualDamage = bullet.charDamage; actualDamage = bullet.charDamage;
if(headshotLevel > 0) }
if (headshotLevel > 0) {
actualDamage *= bullet.charContiniousBonus; actualDamage *= bullet.charContiniousBonus;
if(bullet.bGrazing) }
if (bullet.bGrazing) {
actualDamage *= class'NiceSkillSupportGraze'.default.grazeDamageMult; actualDamage *= class'NiceSkillSupportGraze'.default.grazeDamageMult;
}
bullet.bGrazing = false; bullet.bGrazing = false;
if(kfZed == bullet.lockonZed && bullet.lockonTime > bullet.sourceWeapon.stdFireRate if (
&& niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterKillConfirmed')){ kfZed == bullet.lockonZed &&
bullet.lockonTime > bullet.sourceWeapon.stdFireRate &&
niceVet != none &&
niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterKillConfirmed')
) {
lockOnTickRate =class'NiceSkillSharpshooterKillConfirmed'.default.stackDelay; lockOnTickRate =class'NiceSkillSharpshooterKillConfirmed'.default.stackDelay;
lockonTicks = Ceil(bullet.lockonTime / lockOnTickRate) - 1; lockonTicks = Ceil(bullet.lockonTime / lockOnTickRate) - 1;
lockonTicks = Min(class'NiceSkillSharpshooterKillConfirmed'.default.maxStacks, lockonTicks); lockonTicks = Min(class'NiceSkillSharpshooterKillConfirmed'.default.maxStacks, lockonTicks);
@ -107,35 +199,57 @@ static function HitZed(NiceBullet bullet, NiceReplicationInfo niceRI, KFMonster
// damageMod *= 1.0 + lockonTicks * class'NiceSkillSharpshooterKillConfirmed'.default.damageBonus; // damageMod *= 1.0 + lockonTicks * class'NiceSkillSharpshooterKillConfirmed'.default.damageBonus;
actualDamage *= 1.0 + lockonTicks * class'NiceSkillSharpshooterKillConfirmed'.default.damageBonus; actualDamage *= 1.0 + lockonTicks * class'NiceSkillSharpshooterKillConfirmed'.default.damageBonus;
} }
if(!bullet.bGhost) if (!bullet.bGhost) {
niceRI.ServerDealDamage(kfZed, actualDamage, bullet.instigator, hitLocation, niceRI.ServerDealDamage(
bullet.charMomentumTransfer * hitNormal, bullet.charDamageType, headshotLevel, bullet.lockonTime); kfZed,
actualDamage,
bullet.instigator,
hitLocation,
bullet.charMomentumTransfer * hitNormal,
bullet.charDamageType,
headshotLevel,
bullet.lockonTime
);
}
//// Handle angled shots //// Handle angled shots
angle = asin(hitNormal.Z); angle = asin(hitNormal.Z);
// Apply angled shots // Apply angled shots
if ((angle > 0.8 || angle < -0.45) && bullet.bCanAngleDamage && kfZed != none) { if ((angle > 0.8 || angle < -0.45) && bullet.bCanAngleDamage && kfZed != none) {
bullet.bCanAngleDamage = false; bullet.bCanAngleDamage = false;
bullet.bAlreadyHitZed = true; bullet.bAlreadyHitZed = true;
if(ZedPenetration(bullet.charDamage, bullet, kfZed, bIsHeadshot, bIsPreciseHeadshot)) if (ZedPenetration(bullet.charDamage, bullet, kfZed, bIsHeadshot, bIsPreciseHeadshot)) {
HitZed(bullet, niceRI, kfZed, hitLocation, hitNormal, headshotLevel); HitZed(bullet, niceRI, kfZed, hitLocation, hitNormal, headshotLevel);
} }
}
//// 'Bore' support skill //// 'Bore' support skill
if( niceVet != none && nicePlayer.IsZedTimeActive() && bullet.insideBouncesLeft > 0 if (
&& niceVet.static.hasSkill(nicePlayer, class'NiceSkillSupportZEDBore')){ niceVet != none &&
nicePlayer.IsZedTimeActive() &&
bullet.insideBouncesLeft > 0 &&
niceVet.static.hasSkill(nicePlayer, class'NiceSkillSupportZEDBore')
) {
// Count one bounce // Count one bounce
bullet.insideBouncesLeft --; bullet.insideBouncesLeft --;
// Swap head-shot level // Swap head-shot level
if(headshotLevel <= 0.0) if (headshotLevel <= 0.0) {
headshotLevel = class'NiceSkillSupportZEDBore'.default.minHeadshotPrecision; headshotLevel = class'NiceSkillSupportZEDBore'.default.minHeadshotPrecision;
else } else {
headshotLevel = -headshotLevel; headshotLevel = -headshotLevel;
}
// Deal next batch of damage // Deal next batch of damage
ZedPenetration(bullet.charDamage, bullet, kfZed, false, false); ZedPenetration(bullet.charDamage, bullet, kfZed, false, false);
HitZed(bullet, niceRI, kfZed, hitLocation, hitNormal, headshotLevel); HitZed(bullet, niceRI, kfZed, hitLocation, hitNormal, headshotLevel);
} }
bullet.insideBouncesLeft = 2; 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 float reductionMod;
local NiceMonster niceZed; local NiceMonster niceZed;
local NicePlayerController nicePlayer; local NicePlayerController nicePlayer;
@ -144,31 +258,49 @@ static function bool ZedPenetration(out float Damage, NiceBullet bullet, KFMonst
local class<NiceWeaponDamageType> niceDmgType; local class<NiceWeaponDamageType> niceDmgType;
// True if we can penetrate even body, but now penetrating a head and shouldn't reduce damage too much // True if we can penetrate even body, but now penetrating a head and shouldn't reduce damage too much
local bool bEasyHeadPenetration; local bool bEasyHeadPenetration;
// Init variables // Init variables
niceZed = NiceMonster(targetZed); niceZed = NiceMonster(targetZed);
nicePlayer = NicePlayerController(bullet.Instigator.Controller); nicePlayer = NicePlayerController(bullet.Instigator.Controller);
niceVet = none; niceVet = none;
if(nicePlayer != none) if (nicePlayer != none) {
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo)); niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo));
}
niceDmgType = bullet.charDamageType; niceDmgType = bullet.charDamageType;
bEasyHeadPenetration = bIsHeadshot && !niceDmgType.default.bPenetrationHSOnly; bEasyHeadPenetration = bIsHeadshot && !niceDmgType.default.bPenetrationHSOnly;
reductionMod = 1.0f; reductionMod = 1.0f;
// Apply zed reduction and perk reduction of reduction` // Apply zed reduction and perk reduction of reduction`
if (niceZed != none) { if (niceZed != none) {
// Railgun skill exception // Railgun skill exception
if(niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterZEDRailgun') && nicePlayer.IsZedTimeActive()) if (
niceVet != none &&
niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterZEDRailgun') &&
nicePlayer.IsZedTimeActive()
) {
return true; return true;
if(niceZed.default.Health >= default.BigZedMinHealth && !bEasyHeadPenetration) }
if (niceZed.default.Health >= default.BigZedMinHealth && !bEasyHeadPenetration) {
reductionMod *= niceDmgType.default.BigZedPenDmgReduction; reductionMod *= niceDmgType.default.BigZedPenDmgReduction;
else if(niceZed.default.Health >= default.MediumZedMinHealth && !bEasyHeadPenetration) } else if (niceZed.default.Health >= default.MediumZedMinHealth && !bEasyHeadPenetration) {
reductionMod *= niceDmgType.default.MediumZedPenDmgReduction; reductionMod *= niceDmgType.default.MediumZedPenDmgReduction;
} }
else } else {
reductionMod *= niceDmgType.default.BigZedPenDmgReduction; reductionMod *= niceDmgType.default.BigZedPenDmgReduction;
if(niceVet != none) }
reductionMod = niceVet.static.GetPenetrationDamageMulti(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo), reductionMod, niceDmgType); if (niceVet != none) {
reductionMod = niceVet.static.GetPenetrationDamageMulti(
KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo),
reductionMod,
niceDmgType
);
}
actualMaxPenetrations = niceDmgType.default.maxPenetrations; actualMaxPenetrations = niceDmgType.default.maxPenetrations;
if(niceVet != none && !bullet.charWasHipFired && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterSurgical') && bIsHeadshot){ if (
niceVet != none &&
!bullet.charWasHipFired &&
niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterSurgical') &&
bIsHeadshot
) {
actualMaxPenetrations += 1; actualMaxPenetrations += 1;
reductionMod = FMax(reductionMod, class'NiceSkillSharpshooterSurgical'.default.penDmgReduction); reductionMod = FMax(reductionMod, class'NiceSkillSharpshooterSurgical'.default.penDmgReduction);
} }
@ -176,20 +308,24 @@ static function bool ZedPenetration(out float Damage, NiceBullet bullet, KFMonst
Damage *= reductionMod * niceDmgType.default.PenDmgReduction; Damage *= reductionMod * niceDmgType.default.PenDmgReduction;
bullet.decapMod *= reductionMod * niceDmgType.default.PenDecapReduction; bullet.decapMod *= reductionMod * niceDmgType.default.PenDecapReduction;
bullet.incapMod *= reductionMod * niceDmgType.default.PenIncapReduction; bullet.incapMod *= reductionMod * niceDmgType.default.PenIncapReduction;
if(niceVet != none && actualMaxPenetrations >= 0) if (niceVet != none && actualMaxPenetrations >= 0) {
actualMaxPenetrations += actualMaxPenetrations +=
niceVet.static.GetAdditionalPenetrationAmount(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo)); niceVet.static.GetAdditionalPenetrationAmount(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo));
if(!bIsHeadshot && niceDmgType.default.bPenetrationHSOnly) }
if (!bIsHeadshot && niceDmgType.default.bPenetrationHSOnly) {
return false; return false;
if(actualMaxPenetrations < 0) }
if (actualMaxPenetrations < 0) {
return true; return true;
if(Damage / bullet.charOrigDamage < (niceDmgType.default.PenDmgReduction ** (actualMaxPenetrations + 1)) + 0.0001 || Damage < 1) }
if (Damage / bullet.charOrigDamage < (niceDmgType.default.PenDmgReduction ** (actualMaxPenetrations + 1)) + 0.0001 || Damage < 1) {
return false; return false;
}
return true; return true;
} }
defaultproperties defaultproperties {
{
BigZedMinHealth=1000 BigZedMinHealth=1000
MediumZedMinHealth=500 MediumZedMinHealth=500
} }

View File

@ -1,76 +1,160 @@
class NiceProjectileSpawner extends Actor class NiceProjectileSpawner extends Actor
dependson(NiceBullet); dependson(NiceBullet);
// NICETODO: use flags correctly // NICETODO: use flags correctly
static function MakeProjectile(Vector start, Rotator dir, NiceFire.ShotType shotParams, NiceFire.FireModeContext fireContext, optional bool bForceComplexTraj, static function MakeProjectile(
optional bool bDuplReal, optional bool bSkipGhosts){ Vector start,
Rotator dir,
NiceFire.ShotType shotParams,
NiceFire.FireModeContext fireContext,
optional bool bForceComplexTraj,
optional bool bDuplReal,
optional bool bSkipGhosts
) {
local int i; local int i;
local NicePack niceMut; local NicePack niceMut;
niceMut = class'NicePack'.static.Myself(fireContext.Instigator.Level); niceMut = class'NicePack'.static.Myself(fireContext.Instigator.Level);
if(niceMut == none) if (niceMut == none) {
return; return;
if(fireContext.Instigator.Role < ROLE_Authority || bDuplReal) }
if (fireContext.Instigator.Role < ROLE_Authority || bDuplReal) {
SpawnProjectile(Start, Dir, shotParams, fireContext, false, bForceComplexTraj); SpawnProjectile(Start, Dir, shotParams, fireContext, false, bForceComplexTraj);
}
if (fireContext.Instigator.Role == ROLE_Authority && niceMut != none && !bSkipGhosts) { if (fireContext.Instigator.Role == ROLE_Authority && niceMut != none && !bSkipGhosts) {
for (i = 0; i < niceMut.playersList.Length; i++) { for (i = 0; i < niceMut.playersList.Length; i++) {
if(niceMut.playersList[i] != fireContext.Instigator.Controller) if (niceMut.playersList[i] != fireContext.Instigator.Controller) {
niceMut.playersList[i].ClientSpawnGhostProjectile(start, dir.pitch, dir.yaw, dir.roll, shotParams, fireContext, bForceComplexTraj); 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 int i;
local NicePack niceMut; local NicePack niceMut;
niceMut = class'NicePack'.static.Myself(expData.Instigator.Level); niceMut = class'NicePack'.static.Myself(expData.Instigator.Level);
if(niceMut == none) if (niceMut == none) {
return; return;
}
niceMut.stuckCounter ++; niceMut.stuckCounter ++;
if(expData.Instigator.Role < ROLE_Authority) if (expData.Instigator.Role < ROLE_Authority) {
SpawnStuckProjectile(instigator, base, bone, shift, direction, expData, false, niceMut.stuckCounter); SpawnStuckProjectile(
instigator,
base,
bone,
shift,
direction,
expData,
false,
niceMut.stuckCounter
);
}
if (expData.Instigator.Role == ROLE_Authority && niceMut != none) { if (expData.Instigator.Role == ROLE_Authority && niceMut != none) {
for (i = 0; i < niceMut.playersList.Length; i++) { for (i = 0; i < niceMut.playersList.Length; i++) {
if( (niceMut.playersList[i] != expData.Instigator.Controller && !bSkipGhosts) if (
|| (niceMut.playersList[i] == expData.Instigator.Controller && bDuplReal) ) (niceMut.playersList[i] != expData.Instigator.Controller && !bSkipGhosts) ||
niceMut.playersList[i].ClientStickGhostProjectile(instigator, base, bone, shift, direction, expData, (niceMut.playersList[i] == expData.Instigator.Controller && bDuplReal)
niceMut.stuckCounter); ) {
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 Actor other;
local NiceBullet niceProj; local NiceBullet niceProj;
local Vector HitLocation, HitNormal; local Vector HitLocation, HitNormal;
local NicePlayerController nicePlayer; local NicePlayerController nicePlayer;
local class<NiceVeterancyTypes> niceVet; local class<NiceVeterancyTypes> niceVet;
// No class - no projectile // No class - no projectile
if(shotParams.bulletClass == none) if (shotParams.bulletClass == none) {
return none; return none;
}
// Try to spawn // Try to spawn
if(fireContext.Instigator != none) if (fireContext.Instigator != none) {
niceProj = fireContext.Instigator.Spawn(shotParams.bulletClass,,, Start, Dir); niceProj = fireContext.Instigator.Spawn(shotParams.bulletClass,,, Start, Dir);
}
// Try harder // Try harder
if (niceProj == none && fireContext.Instigator != none) { if (niceProj == none && fireContext.Instigator != none) {
other = fireContext.Instigator.Trace(HitLocation, HitNormal, Start, fireContext.Instigator.Location + fireContext.Instigator.EyePosition(), false, Vect(0,0,1)); other = fireContext.Instigator.Trace(
if(other != none) HitLocation,
HitNormal,
Start,
fireContext.Instigator.Location + fireContext.Instigator.EyePosition(),
false,
Vect(0, 0, 1)
);
if (other != none) {
Start = HitLocation; Start = HitLocation;
}
niceProj = fireContext.Instigator.Spawn(shotParams.bulletClass,,, Start, Dir); niceProj = fireContext.Instigator.Spawn(shotParams.bulletClass,,, Start, Dir);
} }
// Give up if failed after these two attempts // Give up if failed after these two attempts
if(niceProj == none) if (niceProj == none) {
return none; return none;
}
niceProj.Renew(); niceProj.Renew();
// Initialize projectile // Initialize projectile
if(fireContext.Instigator != none) if (fireContext.Instigator != none) {
nicePlayer = NicePlayerController(fireContext.Instigator.Controller); nicePlayer = NicePlayerController(fireContext.Instigator.Controller);
if(nicePlayer != none) }
if (nicePlayer != none) {
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(nicePlayer.PlayerReplicationInfo); niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(nicePlayer.PlayerReplicationInfo);
}
niceProj.bGhost = bIsGhost; niceProj.bGhost = bIsGhost;
// Fill-up data about what damage should projectile deal // Fill-up data about what damage should projectile deal
niceProj.charDamage = shotParams.damage; 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; 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.charDamage = shotParams.damage * class'NiceSkillSupportZEDBulletStorm'.default.damageCut;
}
niceProj.charOrigDamage = niceProj.charDamage; niceProj.charOrigDamage = niceProj.charDamage;
niceProj.charDamageType = shotParams.shotDamageType; niceProj.charDamageType = shotParams.shotDamageType;
niceProj.charExplosionDamageType = shotParams.explosionDamageType; niceProj.charExplosionDamageType = shotParams.explosionDamageType;
@ -92,8 +176,9 @@ static function NiceBullet SpawnProjectile(Vector Start, Rotator Dir, NiceFire.S
niceProj.charContiniousBonus = fireContext.continiousBonus; niceProj.charContiniousBonus = fireContext.continiousBonus;
// Fill-up data about at what speed should projectile travel // Fill-up data about at what speed should projectile travel
niceProj.movementSpeed = shotParams.projSpeed; 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.movementSpeed *= class'NiceSkillDemoOnperk'.default.speedBonus;
}
niceProj.movementDirection = Vector(niceProj.rotation); niceProj.movementDirection = Vector(niceProj.rotation);
niceProj.charAffectedByScream = shotParams.projAffectedByScream; niceProj.charAffectedByScream = shotParams.projAffectedByScream;
niceProj.charIsSticky = shotParams.bShouldStick; niceProj.charIsSticky = shotParams.bShouldStick;
@ -103,29 +188,47 @@ static function NiceBullet SpawnProjectile(Vector Start, Rotator Dir, NiceFire.S
niceProj.charExplosionExponent *= class'NiceSkillDemoVolatile'.default.falloffMult; niceProj.charExplosionExponent *= class'NiceSkillDemoVolatile'.default.falloffMult;
niceProj.charMinExplosionDist *= class'NiceSkillDemoVolatile'.default.safeDistanceMult; niceProj.charMinExplosionDist *= class'NiceSkillDemoVolatile'.default.safeDistanceMult;
} }
if(niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillDemoZEDFullBlast') && nicePlayer.IsZedTimeActive()){ if (
niceVet != none &&
niceVet.static.hasSkill(nicePlayer, class'NiceSkillDemoZEDFullBlast') &&
nicePlayer.IsZedTimeActive()
) {
niceProj.charExplosionRadius *= class'NiceSkillDemoZEDFullBlast'.default.explRadiusMult; niceProj.charExplosionRadius *= class'NiceSkillDemoZEDFullBlast'.default.explRadiusMult;
niceProj.charExplosionExponent = 0.0; niceProj.charExplosionExponent = 0.0;
} }
if(bForceComplexTraj) if (bForceComplexTraj) {
niceProj.bDisableComplexMovement = false; niceProj.bDisableComplexMovement = false;
if(niceProj.Instigator != none && NicePlayerController(niceProj.Instigator.Controller) != none) }
if (niceProj.Instigator != none && NicePlayerController(niceProj.Instigator.Controller) != none) {
niceProj.niceRI = NicePlayerController(niceProj.Instigator.Controller).NiceRI; niceProj.niceRI = NicePlayerController(niceProj.Instigator.Controller).NiceRI;
}
// And some leftovers // And some leftovers
//niceProj.bShouldBounce = shotParams.bShouldBounce; //niceProj.bShouldBounce = shotParams.bShouldBounce;
niceProj.bInitFinished = true; niceProj.bInitFinished = true;
return niceProj; return niceProj;
} }
static function SpawnStuckProjectile(KFHumanPawn instigator, Actor base, name bone, Vector shift, Rotator direction,
NiceBullet.ExplosionData expData, bool bIsGhost, int stuckID){ static function SpawnStuckProjectile(
KFHumanPawn instigator,
Actor base,
name bone,
Vector shift,
Rotator direction,
NiceBullet.ExplosionData expData,
bool bIsGhost,
int stuckID
) {
local Pawn justPawn; local Pawn justPawn;
local NiceFire.ShotType shotParams; local NiceFire.ShotType shotParams;
local NiceFire.FireModeContext fireContext; local NiceFire.FireModeContext fireContext;
local NiceBullet spawnedBullet; local NiceBullet spawnedBullet;
local NicePlayerController nicePlayer; local NicePlayerController nicePlayer;
nicePlayer = NicePlayerController(instigator.Controller); nicePlayer = NicePlayerController(instigator.Controller);
if(base == none || nicePlayer == none) if (base == none || nicePlayer == none) {
return; return;
}
justPawn = Pawn(base); justPawn = Pawn(base);
fireContext.instigator = NiceHumanPawn(instigator); fireContext.instigator = NiceHumanPawn(instigator);
fireContext.sourceWeapon = expData.sourceWeapon; fireContext.sourceWeapon = expData.sourceWeapon;
@ -139,8 +242,9 @@ static function SpawnStuckProjectile(KFHumanPawn instigator, Actor base, name bo
shotParams.explodeOnFuse = expData.explodeOnFuse; shotParams.explodeOnFuse = expData.explodeOnFuse;
shotParams.projAffectedByScream = expData.affectedByScream; shotParams.projAffectedByScream = expData.affectedByScream;
spawnedBullet = SpawnProjectile(base.location, direction, shotParams, fireContext, bIsGhost); spawnedBullet = SpawnProjectile(base.location, direction, shotParams, fireContext, bIsGhost);
if(spawnedBullet == none) if (spawnedBullet == none) {
return; return;
}
spawnedBullet.stuckID = stuckID; spawnedBullet.stuckID = stuckID;
spawnedBullet.bStuck = true; spawnedBullet.bStuck = true;
nicePlayer.RegisterStuckBullet(spawnedBullet); nicePlayer.RegisterStuckBullet(spawnedBullet);
@ -152,15 +256,13 @@ static function SpawnStuckProjectile(KFHumanPawn instigator, Actor base, name bo
spawnedBullet.SetRelativeRotation(Rotator(Vector(direction) << justPawn.GetBoneRotation(bone, 0))); spawnedBullet.SetRelativeRotation(Rotator(Vector(direction) << justPawn.GetBoneRotation(bone, 0)));
spawnedBullet.bUseBone = true; spawnedBullet.bUseBone = true;
spawnedBullet.stuckBone = bone; spawnedBullet.stuckBone = bone;
} } else {
else{
spawnedBullet.SetBase(base); spawnedBullet.SetBase(base);
spawnedBullet.SetRelativeLocation(shift); spawnedBullet.SetRelativeLocation(shift);
} }
} }
defaultproperties defaultproperties {
{
bHidden=True bHidden=True
RemoteRole=ROLE_SimulatedProxy RemoteRole=ROLE_SimulatedProxy
LifeSpan=1.000000 LifeSpan=1.000000