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 ) { 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 ); } } } } 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; } 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 ) { 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; } // Try to spawn 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); } // Give up if failed after these two attempts 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); } 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') ) { niceProj.charDamage *= class'NiceSkillCommandoExplosivePower'.default.dmgMod; } 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; niceProj.charExplosionDamage = shotParams.explosionDamage; niceProj.charExplosionRadius = shotParams.explosionRadius; niceProj.charExplosionExponent = shotParams.explosionExponent; niceProj.charExplosionMomentum = shotParams.explosionMomentum; niceProj.charFuseTime = shotParams.fuseTime; niceProj.charExplodeOnFuse = shotParams.explodeOnFuse; niceProj.charExplodeOnPawnHit = shotParams.explodeOnPawnHit; niceProj.charExplodeOnWallHit = shotParams.explodeOnWallHit; niceProj.charMomentumTransfer = shotParams.momentum; niceProj.charWasHipFired = fireContext.bHipfire; niceProj.charCausePain = shotParams.bCausePain; niceProj.lockonTime = fireContext.lockonTime; niceProj.lockonZed = fireContext.lockonZed; niceProj.instigator = fireContext.instigator; niceProj.sourceWeapon = fireContext.sourceWeapon; 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')) { 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')) { 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 (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; nicePlayer = NicePlayerController(instigator.Controller); 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; shotParams.projAffectedByScream = expData.affectedByScream; spawnedBullet = SpawnProjectile(base.location, direction, shotParams, fireContext, bIsGhost); 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); } } defaultproperties { bHidden=True RemoteRole=ROLE_SimulatedProxy LifeSpan=1.000000 }