First commit

This commit is contained in:
Anton Tarasenko 2020-02-16 19:53:59 +07:00
commit 5b48414900
263 changed files with 24830 additions and 0 deletions

View file

@ -0,0 +1,10 @@
class NiceAmmo extends KFAmmunition;
var class<NiceWeaponPickup> WeaponPickupClass;
function UpdateAmmoAmount(){
MaxAmmo = Default.MaxAmmo;
if(KFPawn(Owner) != none && KFPlayerReplicationInfo(KFPawn(Owner).PlayerReplicationInfo) != none && KFPlayerReplicationInfo(KFPawn(Owner).PlayerReplicationInfo).ClientVeteranSkill != none) MaxAmmo = float(MaxAmmo) * KFPlayerReplicationInfo(KFPawn(Owner).PlayerReplicationInfo).ClientVeteranSkill.Static.AddExtraAmmoFor(KFPlayerReplicationInfo(KFPawn(Owner).PlayerReplicationInfo), Class);
AmmoAmount = Min(AmmoAmount, MaxAmmo);
}
defaultproperties
{
}

View file

@ -0,0 +1,15 @@
class NiceAmmoPickup extends ScrnAmmoPickup;
state Pickup
{
// When touched by an actor.
function Touch(Actor Other){ local Inventory CurInv; local bool bPickedUp; local int AmmoPickupAmount; if(Pawn(Other) != none && Pawn(Other).bCanPickupInventory && Pawn(Other).Controller != none && FastTrace(Other.Location, Location)){ for(CurInv = Other.Inventory;CurInv != none;CurInv = CurInv.Inventory){
if(KFAmmunition(CurInv) != none && KFAmmunition(CurInv).bAcceptsAmmoPickups){ if(KFAmmunition(CurInv).AmmoPickupAmount > 0){ if(KFAmmunition(CurInv).AmmoAmount < KFAmmunition(CurInv).MaxAmmo){ if(KFPlayerReplicationInfo(Pawn(Other).PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Pawn(Other).PlayerReplicationInfo).ClientVeteranSkill != none) AmmoPickupAmount = float(KFAmmunition(CurInv).AmmoPickupAmount) * KFPlayerReplicationInfo(Pawn(Other).PlayerReplicationInfo).ClientVeteranSkill.static.GetAmmoPickupMod(KFPlayerReplicationInfo(Pawn(Other).PlayerReplicationInfo), KFAmmunition(CurInv)); else AmmoPickupAmount = KFAmmunition(CurInv).AmmoPickupAmount;
KFAmmunition(CurInv).AmmoAmount = Min(KFAmmunition(CurInv).MaxAmmo, KFAmmunition(CurInv).AmmoAmount + AmmoPickupAmount); bPickedUp = true; } } else if(KFAmmunition(CurInv).AmmoAmount < KFAmmunition(CurInv).MaxAmmo){ bPickedUp = true; if(FRand() <= (1.0 / Level.Game.GameDifficulty)) KFAmmunition(CurInv).AmmoAmount++; } } }
if(bPickedUp){
AnnouncePickup(Pawn(Other)); GotoState('Sleeping', 'Begin');
if(KFGameType(Level.Game) != none) KFGameType(Level.Game).AmmoPickedUp(self); } }
}
}
defaultproperties
{
}

View file

@ -0,0 +1,63 @@
class NiceAttachment extends ScrnLaserWeaponAttachment
abstract;
var array<string> SkinRefs;
var bool bSpawnLight;
var bool bSecondaryModeNoEffects;
static function PreloadAssets(optional KFWeaponAttachment Spawned){
local int i;
if(default.Mesh == none && default.MeshRef != "") UpdateDefaultMesh(Mesh(DynamicLoadObject(default.MeshRef, class'Mesh', true)));
if(default.AmbientSound == none && default.AmbientSoundRef != "") default.AmbientSound = sound(DynamicLoadObject(default.AmbientSoundRef, class'Sound', true));
if(Spawned != none){ Spawned.LinkMesh(default.Mesh); Spawned.AmbientSound = default.AmbientSound;
}
for(i = 0; i < default.SkinRefs.Length;i ++){ if(default.SkinRefs[i] != "" && (default.Skins.Length < i + 1 || default.Skins[i] == none)) default.Skins[i] = Material(DynamicLoadObject(default.SkinRefs[i], class'Material')); if(Spawned != none) Spawned.Skins[i] = default.Skins[i];
}
}
static function bool UnloadAssets(){
local int i;
UpdateDefaultMesh(none);
default.AmbientSound = none;
for(i = 0;i < default.Skins.Length;i ++) default.Skins[i] = none;
return super.UnloadAssets();
}
simulated event ThirdPersonEffects(){
local NicePlayerController PC;
if((Level.NetMode == NM_DedicatedServer) || (Instigator == none)) return;
PC = NicePlayerController(Level.GetLocalPlayerController());
if(FiringMode == 0){ if(OldSpawnHitCount != SpawnHitCount){ OldSpawnHitCount = SpawnHitCount; GetHitInfo(); if(((Instigator != none) && (Instigator.Controller == PC)) || (VSize(PC.ViewTarget.Location - mHitLocation) < 4000)){ if(PC != Instigator.Controller){ if(mHitActor != none) Spawn(class'ROBulletHitEffect',,, mHitLocation, Rotator(-mHitNormal)); CheckForSplash(); SpawnTracer(); } } }
}
if(FlashCount > 0){ if(KFPawn(Instigator) != none){ if(FiringMode == 0) KFPawn(Instigator).StartFiringX(false, bRapidFire); else KFPawn(Instigator).StartFiringX(true, bRapidFire); } if(bDoFiringEffects && (!bSecondaryModeNoEffects || FiringMode == 0)){ if((Level.TimeSeconds - LastRenderTime > 0.2) && (Instigator.Controller != PC)) return; if(bSpawnLight) WeaponLight(); DoFlashEmitter(); ThirdPersonShellEject(); }
}
else{ GotoState(''); if(KFPawn(Instigator) != none) KFPawn(Instigator).StopFiring();
}
}
function UpdateHit(Actor HitActor, vector HitLocation, vector HitNormal){
SpawnHitCount++;
mHitLocation = HitLocation;
mHitActor = HitActor;
mHitNormal = HitNormal;
NetUpdateTime = Level.TimeSeconds - 1;
}
simulated function ThirdPersonShellEject(){
if((mShellCaseEmitter == none) && (Level.DetailMode != DM_Low) && !Level.bDropDetail){ mShellCaseEmitter = Spawn(mShellCaseEmitterClass); if(mShellCaseEmitter != none) AttachToBone(mShellCaseEmitter, 'ShellPort');
}
if(mShellCaseEmitter != none) mShellCaseEmitter.mStartParticles++;
}
simulated function SpawnTracerAtLocation(vector HitLocation){
local vector SpawnLoc, SpawnDir, SpawnVel;
local float hitDist;
if(!bDoFiringEffects) return;
if(mTracer == none) mTracer = Spawn(mTracerClass);
if(mTracer != none){ SpawnLoc = GetTracerStart(); mTracer.SetLocation(SpawnLoc); hitDist = VSize(HitLocation - SpawnLoc) - mTracerPullback; SpawnDir = Normal(HitLocation - SpawnLoc); if(hitDist > mTracerMinDistance){ SpawnVel = SpawnDir * mTracerSpeed; mTracer.Emitters[0].StartVelocityRange.X.Min = SpawnVel.X; mTracer.Emitters[0].StartVelocityRange.X.Max = SpawnVel.X; mTracer.Emitters[0].StartVelocityRange.Y.Min = SpawnVel.Y; mTracer.Emitters[0].StartVelocityRange.Y.Max = SpawnVel.Y; mTracer.Emitters[0].StartVelocityRange.Z.Min = SpawnVel.Z; mTracer.Emitters[0].StartVelocityRange.Z.Max = SpawnVel.Z;
mTracer.Emitters[0].LifetimeRange.Min = hitDist / mTracerSpeed; mTracer.Emitters[0].LifetimeRange.Max = mTracer.Emitters[0].LifetimeRange.Min;
mTracer.SpawnParticle(1); }
}
}
simulated function CheckForSplashAtLocation(vector HitLoc){
local Actor HitActor;
local vector HitNormal, HitLocation;
if(!Level.bDropDetail && (Level.DetailMode != DM_Low) && (SplashEffect != none) && !Instigator.PhysicsVolume.bWaterVolume){ // check for splash bTraceWater = true; HitActor = Trace(HitLocation, HitNormal, HitLoc, Instigator.Location, true); bTraceWater = false; if((FluidSurfaceInfo(HitActor) != none) || ((PhysicsVolume(HitActor) != none) && PhysicsVolume(HitActor).bWaterVolume)) Spawn(SplashEffect,,,HitLocation, rot(16384,0,0));
}
}
defaultproperties
{ bSpawnLight=True
}

View file

@ -0,0 +1,16 @@
class NiceDamTypeFire extends NiceWeaponDamageType
abstract;
static function AwardDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount)
{
KFStatsAndAchievements.AddFlameThrowerDamage(Amount * default.heatPart);
}
defaultproperties
{
heatPart=1.000000
bDealBurningDamage=True
bCheckForHeadShots=False
//WeaponClass=Class'NicePack.NiceFlame9mm'
DeathString="%k incinerated %o."
FemaleSuicide="%o roasted herself alive."
MaleSuicide="%o roasted himself alive."
}

View file

@ -0,0 +1,5 @@
class NiceDamTypeSPAM extends NiceDamageTypeVetEnforcerBullets
abstract;
defaultproperties
{ bodyDestructionMult=1.000000 HeadShotDamageMult=1.100000 DeathString="%k killed %o (with SPAM)." FemaleSuicide="%o shot herself in the foot." MaleSuicide="%o shot himself in the foot." bRagdollBullet=True bBulletHit=True
}

View file

@ -0,0 +1,96 @@
class NiceWeaponDamageType extends KFProjectileWeaponDamageType
abstract;
enum DecapitationBehaviour{
DB_PERKED, // Decap result depends on whether weapon is perked or not
DB_DROP, // Weapon always drops decapped zeds
DB_NODROP // Weapon never drops decapped zeds
};
var DecapitationBehaviour decapType;
var float badDecapMod;
var float goodDecapMod;
var bool bFinisher; // If set to true, target will recieve double damage if that's would kill it
var float prReqMultiplier; // How precise must head-shot be for damage multiplier to kick-in?
var float prReqPrecise; // How precise must head-shot be to be considered precise?
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 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?
var float headSizeModifier; // How much bigger (smaller) head should be to be detected by a shot with this damage type
var bool bPenetrationHSOnly; // Only allow penetrations on head-shots
var int MaxPenetrations; // Maximum of penetrations; 0 = no penetration, -1 = infinite penetration
var float BigZedPenDmgReduction; // Additional penetration effect reduction after hitting big zeds. 0.5 = 50% red.
var const int BigZedMinHealth; // If zed's base Health >= this value, zed counts as Big
var float MediumZedPenDmgReduction; // Additional penetration effect reduction after hitting medium-size zeds. 0.5 = 50% red.
var const int MediumZedMinHealth; // If zed's base Health >= this value, zed counts as Medium-size
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 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){
HL = Max(0, HL);
return 0.5 + Float(HL) * 0.1;
}
static function ScoredNiceHeadshot(KFSteamStatsAndAchievements KFStatsAndAchievements, class<KFMonster> monsterClass, int HL){
ScoredHeadshot(KFStatsAndAchievements, monsterClass, false);
}
// New function for awarding damage to nice perks
static function AwardNiceDamage(KFSteamStatsAndAchievements KFStatsAndAchievements, int Amount, int HL){}
// New function for awarding kills to nice perks
static function AwardNiceKill(KFSteamStatsAndAchievements KFStatsAndAchievements, KFPlayerController Killer, KFMonster Killed, int HL){}
// Function that governs damage reduction on penetration
// Return false if weapon shouldn't be allowed to penetrate anymore
static function bool ReduceDamageAfterPenetration(out float Damage, float origDamage, Actor target, class<NiceWeaponDamageType> niceDmgType, bool bIsHeadshot, KFPlayerReplicationInfo KFPRI){
local float penReduction;
local NiceMonster niceZed;
local NicePlayerController nicePlayer;
local class<NiceVeterancyTypes> niceVet;
// 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(target);
nicePlayer = NicePlayerController(KFPRI.Owner);
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(KFPRI);
bEasyHeadPenetration = bIsHeadshot && !niceDmgType.default.bPenetrationHSOnly;
penReduction = niceDmgType.default.PenDmgReduction;
// Apply zed reduction and perk reduction of reduction`
if(niceZed != none){
if(niceZed.default.Health >= default.BigZedMinHealth && (!bEasyHeadPenetration || niceDmgType.default.BigZedPenDmgReduction <= 0.0))
penReduction *= niceDmgType.default.BigZedPenDmgReduction;
else if(niceZed.default.Health >= default.MediumZedMinHealth && (!bEasyHeadPenetration || niceDmgType.default.MediumZedPenDmgReduction <= 0.0))
penReduction *= niceDmgType.default.MediumZedPenDmgReduction;
}
else
penReduction *= niceDmgType.default.BigZedPenDmgReduction;
if(niceVet != none)
penReduction = niceVet.static.GetPenetrationDamageMulti(KFPRI, penReduction, niceDmgType);
// Assign new damage value and tell us if we should stop with penetration
Damage *= penReduction;
if(!bIsHeadshot && niceDmgType.default.bPenetrationHSOnly)
return false;
if(niceDmgType.default.MaxPenetrations < 0)
return true;
if(niceDmgType.default.MaxPenetrations == 0 || Damage / origDamage < (niceDmgType.default.PenDmgReduction ** (niceDmgType.default.MaxPenetrations + 1)) + 0.0001)
return false;
return true;
}
defaultproperties
{
badDecapMod=0.500000
goodDecapMod=1.000000
prReqPrecise=0.750000
flinchMultiplier=1.000000
stunMultiplier=1.000000
bodyDestructionMult=1.000000
headSizeModifier=1.000000
BigZedPenDmgReduction=0.500000
BigZedMinHealth=1000
MediumZedPenDmgReduction=0.750000
MediumZedMinHealth=500
PenDmgReduction=0.700000
PawnDamageEmitter=None
LowGoreDamageEmitter=None
LowDetailEmitter=None
}

View file

@ -0,0 +1,944 @@
//==============================================================================
// 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
// - Ability to 'stick' to zeds and walls
// - Ability to explode upon reaching various conditions
// - Ability to detect collisions from 'NiceCollisionManager'
//==============================================================================
// Class hierarchy: Object > Actor > NiceBullet
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceBullet extends Actor
dependson(NiceFire);
//==============================================================================
//==============================================================================
// > State of this bullet
//==============================================================================
// >> Implementation-level state details
// Link to interaction with the server
var NiceReplicationInfo niceRI;
// Controller of our instigator
var NicePlayerController nicePlayer;
// Controller of local player
var NicePlayerController localPlayer;
// Indicates that all necessary values were recorded and
// we can process this bullet normally
var bool bInitFinished;
// Disables all the interaction of this bullet with the world
// and removes it / marks it for removal
var bool bBulletDead;
// Ghost bullets produce visual effects, get stuck, but never deal damage;
// they're used for emulating shooting effects of other players
var bool bGhost;
// How often trajectory is allowed to change direction?
var float trajUpdFreq;
//==============================================================================
// >> Gameplay-related state details
// Info and state, inherited from weapon that fired us
var NiceFire.NWFireType fireType;
var NiceFire.NWCFireState fireState;
// Damage our bullet deals can decrease as we
// penetrate enemies or bounce off the walls;
// this variable reflects that by recording current damage we can deal
var float damage;
// For some of the skills we need to distinguish the first bullet target from
// everything else
var bool bAlreadyHitZed;
// 'true' means that this bullet cannot explode
var bool bIsDud;
// Count-down until our projectile explodes
var float fuseCountDown;
// Head-shot detection multiplier, introduced to allow projectiles that
// have bounced off the walls to hit more reliably
var float bounceHeadMod;
// Used for a support zed-time skill 'Bore', denotes how many more times
// our bullet can 'bounce' between it's head and body
var int insideBouncesLeft;
// Can bullet still perform angle damage?
var bool bCanAngleDamage;
//==============================================================================
// >> Details about bullet's 'stuck' state
// Are we stuck in something?
var bool bStuck;
// (For sticking in zeds only) Data about where exactly we got stuck
var bool bStuckToHead;
var name stuckBone;
//==============================================================================
//==============================================================================
// > Collision management
// Sole role of these variables is to remember actors
// we've already hit to avoid them in future
// 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 array<IgnoreEntry> ignoredActors;
// 'true' if we're enforcing our collision rules on actors to ignore them
var bool bIgnoreIsActive;
//==============================================================================
//==============================================================================
// > Movement
// This class of bullets supports both linear
// and piece-wise movement, which allows to emulate bullets
// bouncing off the walls and falling down because of gravity;
// but system can be extended to reflect any kinds of changes to the trajectory
// by altering it's direction at certain points in time
//==============================================================================
// >> Movement 'settings'
// If 'true' disables any modifications to the bullet's movement,
// making it travel in a simple, linear path,
// but reducing amount of performed computation
var bool bDisableComplexMovement;
//==============================================================================
// >> Movement state
// Linear motion
var float speed;
var Vector direction;
// Acceleration that affects this bullet
// Different naming scheme is due to 'acceleration' being already taken and
// not suiting our needs, since we wanted to handle movement on our own
var Vector bulletAccel;
var float distancePassed;
//==============================================================================
// >> Path building
// We will be building a piecewise linear path for projectiles,
// where each linear segment should be passable by projectile
// in time 'NBulletState.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
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.
var float finishedSegmentPart;
//==============================================================================
//==============================================================================
// > Visual effects
// This class allows to set 3 different type of effect for 3 distinct cases:
// 1. When bullet exploded
// 2. When bullet hit actor without explosion
// 3. When bullet was disintegrated (usually by siren's scream)
//==============================================================================
// >> Impact effects
// Describes effect that projectile can 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<Projector> decalClass;
// Emitter to spawn; null to skip
var class<Emitter> 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;
// Reference to 'Sound' to allow dynamic resource allocation
var string noiseRef;
var float noiseVolume;
};
var ImpactEffect regularImpact; // Effect on imact, no eplosion
var ImpactEffect explosionImpact; // Effect in case of the explosion
var ImpactEffect disintegrationImpact; // Disintegration, nuff said
// Should we play 'regularImpact' (when bullet hit actor without explosion)
// effects after hitting a 'Pawn'?
// It normally produces badly looking results,
// but if set this flag to 'true' if you want it to anyway
var bool bGenRegEffectOnPawn;
//==============================================================================
// >> Bullet trails
// Bullet supports 2 different types of trails: 'Emitter' and 'xEmitter'.
// Just define class for the one (or both) you want to use.
var class<Emitter> trailClass;
var class<xEmitter> trailXClass;
var Emitter bulletTrail;
var xEmitter bulletXTrail;
//==============================================================================
// >> Explosion view shaking
// Should we even do any shaking at all?
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;
//==============================================================================
//==============================================================================
// > Functions
// Initialises bullet before it's use
function InitBullet(){
// Easy references to 'NiceReplicationInfo'
// + local and instigator controllers
localPlayer = NicePlayerController(Level.GetLocalPlayerController());
instigator = fireState.base.instigator;
nicePlayer = fireState.base.instigatorCtrl;
if(nicePlayer != none)
niceRI = nicePlayer.niceRI;
// Bullet should only replicate damage on instigator's side
bGhost = (localPlayer != nicePlayer);
// We haven't yet do anything,
// so our damage is maxed out and we can do angle damage,
// but still dealing with regular head sizes
bCanAngleDamage = true;
damage = fireType.bullet.damage;
bounceHeadMod = 1.0;
// No countdown could yet take place
fuseCountDown = fireType.explosion.fuseTime;
// Setup movement
speed = fireType.movement.speed;
direction = Vector(rotation);
//bDisableComplexMovement = NICETODO: update as necessary
bDisableComplexMovement = true;
ResetPathBuilding();
// Setup visual effects
UpdateTrails();
// Allow tick to handle the bullet
bInitFinished = true;
}
function UpdateTrails(){
local Actor trailBase;
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);
// Handle positioning differently for stuck and non-stuck projectiles
if(bStuck && base != none){
if(stuckBone != ''){
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;
// Update lifetime and base (latter is for non-bone attachments only)
if(bulletTrail != none){
if(trailBase != none)
bulletTrail.SetBase(trailBase);
bulletTrail.lifespan = lifeSpan;
}
if(bulletXTrail != none){
if(trailBase != none)
bulletXTrail.SetBase(trailBase);
bulletXTrail.lifespan = lifeSpan;
}
}
function ResetPathBuilding(){
finishedSegmentPart = -1.0;
shiftPoint = location;
}
simulated function Tick(float delta){
local bool bBaseIsDead;
local bool bFuseJustRunOut;
super.Tick(delta);
// Fuse didn't run out before this tick, but should after
if(fireType.explosion.bOnFuse){
bFuseJustRunOut = (fuseCountDown > 0) && (fuseCountDown < delta);
fuseCountDown -= delta;
}
// Explode when fuse runs out
if(bFuseJustRunOut)
DoExplode(location, direction);
// Explode stuck bullet if the target it was attached to died
if(bInitFinished && bStuck){
bBaseIsDead = (base == none);
if(NiceMonster(base) != none)
bBaseIsDead = NiceMonster(base).health <= 0;
/*if(bBaseIsDead) NICETODO: finish it
nicePlayer.ExplodeStuckBullet(stuckID);*/
}
// Progress movemnt
if(bInitFinished && !bBulletDead && !bStuck)
DoProcessMovement(delta);
}
// 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;
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;
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){
// These mark what objects, associated with 'other' we also need to ignore
local KFPawn pawnOther;
local KFMonster zedOther;
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);
// Try to find main actor as KFMonster
zedOther = KFMonster(other);
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);
}
}
// 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
// to avoid unwanted editing of the collision flags
function SetIgnoreActive(bool bActive){
local int i;
// Do nothing if we're already in a correct state
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;
}
}
function float CheckHeadshot( KFMonster kfZed,
Vector hitLocation,
Vector hitDirection){
local float hsMod;
local NiceMonster niceZed;
local KFPlayerReplicationInfo KFPRI;
local class<NiceVeterancyTypes> niceVet;
// If one of these variables is 'none' -
// something went terribly wrong and we might as well bail
niceZed = NiceMonster(kfZed);
if(niceZed == none || nicePlayer == none) return 0.0;
KFPRI = KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo);
if(KFPRI == none) return 0.0;
niceVet = class<NiceVeterancyTypes>(KFPRI.ClientVeteranSkill);
if(niceVet == none) return 0.0;
hitDirection = Normal(hitDirection);
// Compute proper head-shot check multiplier
hsMod = bounceHeadMod;
hsMod *= fireType.bullet.shotDamageType.default.headSizeModifier;
hsMod *= niceVet.static.
GetHeadshotCheckMultiplier(KFPRI, fireType.bullet.shotDamageType);
return niceZed.IsHeadshotClient(hitLocation, hitDirection,
niceZed.clientHeadshotScale * hsMod);
}
function bool CheckSirenBallCollision(Vector lineStart, Vector lineEnd){
if(localPlayer == none || localPlayer.localCollisionManager == none)
return false;
return localPlayer.localCollisionManager.
IsCollidingWithAnything(lineStart, lineEnd);
}
// Makes bullet trace a directed line segment given by start and end points.
// All traced actors and geometry are then properly
// affected by either 'HandleHitActor' or 'HandleHitWall'.
// Might have to do several traces in case it either hits a (several) target(s)
function DoTraceLine(Vector lineStart, Vector lineEnd){
// Amount of tracing iterations we had to do
local int iterationCount;
// Direction and length of traced line
local Vector lineDirection;
// Auxiliary variables for retrieving results of tracing
local Vector hitLocation, hitNormal;
local Actor tracedActor;
if(localPlayer == none || instigator == none) return;
lineDirection = (lineEnd - lineStart);
lineDirection = (lineDirection) / VSize(lineDirection);
// Do not trace for disabled bullets and prevent infinite loops
while(!bBulletDead && iterationCount < 128){
iterationCount ++;
// Find next collision.
// > Trace next object.
// But only if:
// 1. It isn't a ghost and can actually deal damage;
// 2. It's a ghost projectile,
// but we still haven't gone over our traces per tick limit.
if( !bGhost
|| localPlayer.tracesThisTick <= localPlayer.tracesPerTickLimit){
tracedActor = instigator.Trace( hitLocation, hitNormal,
lineEnd, lineStart, true);
localPlayer.tracesThisTick ++;
}
else
tracedActor = none;
// > Check and handle collision with siren's scream ball
if( fireType.bullet.bAffectedByScream && !bIsDud
&& CheckSirenBallCollision(lineStart, lineEnd))
HandleScream(lineStart, lineDirection);
// If we hit level actor (wall) - bail
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;
HandleHitActor(tracedActor, hitLocation, lineDirection, hitNormal);
}
}
// Handles bullet collision with an actor,
// it calls 'HandleHitPawn', 'HandleHitZed' or 'HandleHitWall',
// depending on the type of the actor.
// This function takes two direction parameters:
// - 'hitDirection' is bullet's direction before the impact
// - 'hitNormal' normal of the surface we've hit,
// used to handle effects upon wall hits
function HandleHitActor(Actor hitActor,
Vector hitLocation,
Vector hitDirection,
Vector hitNormal){
local float headshotLevel;
local KFPawn hitPawn;
local NiceMonster hitZed;
hitZed = NiceMonster(hitActor);
hitPawn = KFPawn(hitActor);
if( hitPawn != none && NiceHumanPawn(instigator).ffScale <= 0
/* && NiceMedicProjectile(self) == none */) return;//MEANTODO
if(hitZed != none){
if(hitZed.health > 0){
headshotLevel = CheckHeadshot(hitZed, hitLocation, hitDirection);
HandleHitZed(hitZed, hitLocation, hitDirection, headshotLevel);
}
}
else if(hitPawn != none && hitPawn.health > 0){
if(hitPawn.health > 0)
HandleHitPawn(hitPawn, hitLocation, hitDirection);
}
else
HandleHitWall(hitActor, 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(){
// 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;
direction += (bulletAccel * trajUpdFreq) / speed;
pathSegmentE = pathSegmentS + direction * speed * 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){
// 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;
// [speed * delta] / [speed * 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 +
direction * speed * trajUpdFreq * finishedSegmentPart;
}
return remainingTime;
}
// Moves bullet according to settings,
// 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);
// Simple linear movement
if(bDisableComplexMovement){
// Use 'traceStart' as a shift variable here
// Naming is bad in this case, but it avoids
tempVect = direction * speed * 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);
}
SetRotation(Rotator(direction));
if(distancePassed > 0)
distancePassed -= VSize(tempVect);
SetIgnoreActive(false);
}
function Stick(Actor target, Vector hitLocation){
/* local NiceMonster targetZed;
local name boneStick;
local float distToBone;
local float t;
local Vector boneStrickOrig;
local ExplosionData expData;
if(bGhost)
return;
expData.explosionDamageType = charExplosionDamageType;
expData.explosionDamage = charExplosionDamage;
expData.explosionRadius = charExplosionRadius;
expData.explosionExponent = charExplosionExponent;
expData.explosionMomentum = charExplosionMomentum;
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);
}
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){
local ImpactEffect visualEffect;
if(!bIsDud){
class'NiceBulletAdapter'.static.Explode(self, explLocation);
if(bShakeViewOnExplosion)
ShakeView(explLocation);
visualEffect = explosionImpact;
}
else
visualEffect = disintegrationImpact;
GenerateImpactEffects(visualEffect, explLocation, impactNormal, true, true);
KillBullet();
}
function HandleHitWall(Actor wall, Vector hitLocation, Vector hitNormal){
local bool bCanExplode;
local bool bBulletTooWeak;
bCanExplode = !bIsDud && distancePassed < fireType.explosion.minArmDistance;
if(fireType.explosion.bOnWallHit && bCanExplode){
DoExplode(hitLocation, hitNormal);
return;
}
class'NiceBulletAdapter'.static.HitWall(self, wall,
hitLocation, hitNormal);
GenerateImpactEffects(regularImpact, hitLocation, hitNormal, true, true);
if(fireType.bullet.bStickToWalls)
Stick(wall, hitLocation);
else if(bBounce && !bDisableComplexMovement){
direction = direction - 2.0 * hitNormal * (direction dot hitNormal);
bBulletTooWeak = !class'NiceBulletAdapter'.static.
ZedPenetration(damage, self, none, 0.0);
ResetPathBuilding();
ResetIgnoreList();
bounceHeadMod *= 2;
}
else if(fireType.movement.fallTime > 0.0){
bIsDud = true;
lifeSpan = fireType.movement.fallTime;
fireType.movement.fallTime = 0.0;
direction = vect(0,0,0);
ResetPathBuilding();
ResetIgnoreList();
}
else
bBulletTooWeak = true;
if(bBulletTooWeak)
KillBullet();
}
// Decide whether to explode or just hit after non-zed pawn collision
function HandleHitPawn(KFPawn hitPawn, Vector hitLocation, Vector hitDirection){
local bool bCanExplode;
// Deal damage due to impact + effects
class'NiceBulletAdapter'.static.HitPawn(self, hitPawn, hitLocation,
hitDirection);
if(bGenRegEffectOnPawn)
GenerateImpactEffects( regularImpact, hitLocation, hitDirection,
false, false);
// Explode if you can
bCanExplode = !bIsDud && distancePassed < fireType.explosion.minArmDistance;
if(fireType.explosion.bOnPawnHit && bCanExplode){
DoExplode(hitLocation, hitDirection);
return;
}
// Kill weakened bullets
if(!class'NiceBulletAdapter'.static.
ZedPenetration(damage, self, none, 0.0))
KillBullet();
}
// Decide whether to explode or just hit after zed collision;
// Kill the bullet on explosion or when can't penetrate anymore
function HandleHitZed( NiceMonster targetZed,
Vector hitLocation,
Vector hitDirection,
float headshotLevel){
local bool bCanExplode;
if(nicePlayer == none || niceRI == none) return;
// Deal damage due to impact + effects +
// some skill-related stuff ('ServerJunkieExtension')
class'NiceBulletAdapter'.static.HitZed( self, targetZed,
hitLocation, hitDirection,
headshotLevel);
if(!bGhost && !bAlreadyHitZed){
bAlreadyHitZed = true;// NICETODO: send only when actually used
niceRI.ServerJunkieExtension(nicePlayer, headshotLevel > 0.0);
}
if(bGenRegEffectOnPawn)
GenerateImpactEffects( regularImpact, hitLocation, hitDirection,
false, false);
// Explode if you can...
bCanExplode = !bIsDud && distancePassed < fireType.explosion.minArmDistance;
if(fireType.explosion.bOnPawnHit && bCanExplode){
DoExplode(hitLocation, hitDirection);
return;
}
// ...otherwise try sticking
else if(fireType.bullet.bStickToZeds)
Stick(targetZed, hitLocation);
// Kill weakened bullets
if(!class'NiceBulletAdapter'.static.
ZedPenetration(damage, self, targetZed, headshotLevel))
KillBullet();
}
function HandleScream(Vector disintegrationLocation, Vector entryDirection){
if(!bIsDud)
GenerateImpactEffects( disintegrationImpact, disintegrationLocation,
entryDirection);
class'NiceBulletAdapter'.static.HandleScream( self,
disintegrationLocation,
entryDirection);
}
function GenerateImpactEffects( ImpactEffect effect,
Vector hitLocation,
Vector hitNormal,
optional bool bWallImpact,
optional bool bGenerateDecal){
local bool generatedEffect;
local float actualCullDistance, actualImpactShift;
if(localPlayer == none) return;
// No need to play visuals on a server or for dead bullets
if(Level.NetMode == NM_DedicatedServer || bBulletDead) 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 - direction * actualImpactShift,
Rotator(direction));
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 explRadius;
local float distance, scale;
if(nicePlayer == none || shakeRadiusMult < 0.0) return;
explRadius = fireType.explosion.radius;
distance = VSize(hitLocation - nicePlayer.ViewTarget.Location);
if(distance < explRadius * shakeRadiusMult){
if(distance < explRadius)
scale = 1.0;
else
scale = (explRadius * ShakeRadiusMult - distance) / explRadius;
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
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
}

View file

@ -0,0 +1,225 @@
//==============================================================================
// NicePack / NiceBulletAdapter
//==============================================================================
// Temporary stand-in for future functionality.
//==============================================================================
// Class hierarchy: Object > NiceBulletAdapter
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceBulletAdapter extends Object;
var const int BigZedMinHealth; // If zed's base Health >= this value, zed counts as Big
var const int MediumZedMinHealth; // If zed's base Health >= this value, zed counts as Medium-size
static function Explode(NiceBullet bullet, Vector hitLocation){
/*local NiceReplicationInfo niceRI;
niceRI = bullet.niceRI;
if(!bullet.bGhost){
niceRI.ServerExplode(bullet.fireType.explosion.damage, bullet.fireType.explosion.radius, bullet.fireType.explosion.exponent,
bullet.fireType.explosion.damageType, bullet.fireType.explosion.momentum, hitLocation, bullet.instigator, true,
Vector(bullet.Rotation));
if(KFMonster(bullet.base) != none && bullet.bStuck && bullet.bStuckToHead)
niceRI.ServerDealDamage(KFMonster(bullet.base), bullet.fireType.explosion.damage, bullet.instigator, hitLocation,
bullet.fireType.explosion.momentum * vect(0,0,-1), bullet.fireType.explosion.damageType, 1.0);
}*/
}
/*static function HitWall(NiceBullet bullet, Actor targetWall,
Vector hitLocation, Vector hitNormal){
local NicePlayerController nicePlayer;
local NiceReplicationInfo niceRI;
niceRI = bullet.niceRI;
nicePlayer = NicePlayerController(bullet.Instigator.Controller);
if(nicePlayer == none)
return;
if(!bullet.bAlreadyHitZed)
HandleCalibration(false, NiceHumanPawn(bullet.Instigator), none);
if(!targetWall.bStatic && !targetWall.bWorldGeometry && nicePlayer != none && (nicePlayer.wallHitsLeft > 0 || Projectile(targetWall) != none)){
niceRI.ServerDealDamage(targetWall, bullet.charOrigDamage, bullet.Instigator, hitLocation,
bullet.charMomentumTransfer * hitNormal, bullet.charDamageType);
nicePlayer.wallHitsLeft --;
}
}*/
static function HitWall//Actor
(
NiceBullet bullet,
Actor targetWall,
Vector hitLocation,
Vector hitNormal
)
{
local NicePlayerController nicePlayer;
local NiceReplicationInfo niceRI;
if(bullet == none || bullet.instigator == none)
return;
niceRI = bullet.niceRI;
nicePlayer = NicePlayerController(bullet.instigator.controller);
if(nicePlayer == none)
return;
// No need to deal damage to geometry or static actors
if(targetWall.bStatic || targetWall.bWorldGeometry)
return;
// If target is a projectile - we must send message about damage,
// otherwise it's probably a wall. And if we hit our limits of reporting
// about wall damages - avoid sending too many replication messages
// about damage.
// NICETODO: should probably find another way to solve the
// `ServerDealDamage` spam issue, this is bullshit.
if(Projectile(targetWall) == none && nicePlayer.wallHitsLeft <= 0)
return;
niceRI.ServerDealDamage(targetWall, bullet.fireType.bullet.damage, bullet.instigator, hitLocation,
bullet.fireType.bullet.momentum * hitNormal, bullet.fireType.bullet.shotDamageType);
// We've sent a reliable message about hitting a wall
nicePlayer.wallHitsLeft --;
}
static function HandleScream(NiceBullet bullet, Vector location, Vector entryDirection){
bullet.bIsDud = true;
}
static function HitPawn(NiceBullet bullet, KFPawn targetPawn, Vector hitLocation,
Vector hitNormal){
// local NiceMedicProjectile niceDart;
local NiceReplicationInfo niceRI;
niceRI = bullet.niceRI;
/*niceDart = NiceMedicProjectile(bullet);
if(niceDart == none)
niceRI.ServerDealDamage(targetPawn, bullet.damage, bullet.instigator, HitLocation,
hitNormal * bullet.fireType.bullet.momentum, bullet.fireType.bullet.shotDamageType);
else*/ //MEANTODO
//niceRI.ServerHealTarget(targetPawn, bullet.damage, bullet.instigator);
}
static function HitZed(NiceBullet bullet, NiceMonster niceZed, Vector hitLocation,
Vector hitNormal, float headshotLevel){
local bool bIsHeadshot;
local float actualDamage;
local int lockonTicks;
local float angle;
local NicePlayerController nicePlayer;
local class<NiceVeterancyTypes> niceVet;
local NiceReplicationInfo niceRI;
niceRI = bullet.niceRI;
bIsHeadshot = (headshotLevel > 0.0);
/* if(bIsHeadshot && bullet.fireState.base.sourceWeapon != none){
if(bullet.level.TimeSeconds - bullet.fireState.base.sourceWeapon.lastHeadshotTime <=
class'NiceSkillGunslingerPlayful'.default.quickWindow)
bullet.fireState.base.sourceWeapon.quickHeadshots ++;
bullet.fireState.base.sourceWeapon.lastHeadshotTime = bullet.Level.TimeSeconds;
}*/
// Try to get necessary variables and bail in case they're unaccessible
nicePlayer = NicePlayerController(bullet.Instigator.Controller);
if(nicePlayer == none)
return;
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo));
if(bullet.fireType.bullet.bCausePain)
actualDamage = bullet.fireType.bullet.damage;
else
actualDamage = bullet.damage;
if(niceZed == bullet.fireState.lockon.target && bullet.fireState.lockon.time > 0.5
&& niceVet != none && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterKillConfirmed')){
lockonTicks = Ceil(2 * bullet.fireState.lockon.time) - 1;
//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(niceVet == class'NiceVetGunslinger' && !bullet.bAlreadyHitZed)
niceRI.ServerGunslingerConfirm(niceZed, actualDamage, bullet.instigator, hitLocation,
bullet.fireType.bullet.momentum * hitNormal, bullet.fireType.bullet.shotDamageType, headshotLevel, bullet.fireState.lockon.time);*/
if(!bullet.bGhost)
niceRI.ServerDealDamage(niceZed, actualDamage, bullet.instigator, hitLocation,
bullet.fireType.bullet.momentum * hitNormal, bullet.fireType.bullet.shotDamageType, headshotLevel, bullet.fireState.lockon.time);
//// Handle angled shots
angle = asin(hitNormal.Z);
// Gunslinger skill check
/*bGunslingerAngleShot = class'NiceVeterancyTypes'.static.hasSkill(nicePlayer, class'NiceSkillGunslingerCloseAndPersonal');
if(bGunslingerAngleShot)
bGunslingerAngleShot =
VSizeSquared(bullet.instigator.location - niceZed.location) <=
class'NiceSkillGunslingerCloseAndPersonal'.default.closeDistance ** 2;*/
// Apply angled shots
if((angle > 0.8 || angle < -0.45) && bullet.bCanAngleDamage && niceZed != none){
bullet.bCanAngleDamage = false;
bullet.bAlreadyHitZed = true;
if(ZedPenetration(bullet.damage, bullet, niceZed, headshotLevel))
HitZed(bullet, niceZed, 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.damage, bullet, niceZed, 0.0);
HitZed(bullet, niceZed, hitLocation, hitNormal, headshotLevel);
}
bullet.insideBouncesLeft = 2;
}
static function bool ZedPenetration(out float Damage, NiceBullet bullet, NiceMonster niceZed, float headshotLevel){
local float penReduction;
local bool bIsHeadshot, bIsPreciseHeadshot;
local NicePlayerController nicePlayer;
local int actualMaxPenetrations;
local class<NiceVeterancyTypes> niceVet;
local class<NiceWeaponDamageType> 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
nicePlayer = NicePlayerController(bullet.Instigator.Controller);
niceVet = class'NiceVeterancyTypes'.static.GetVeterancy(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo));
niceDmgType = bullet.fireType.bullet.shotDamageType;
bIsHeadshot = (headshotLevel > 0.0);
bIsPreciseHeadshot = (headshotLevel > bullet.fireType.bullet.shotDamageType.default.prReqPrecise);
bEasyHeadPenetration = bIsHeadshot && !niceDmgType.default.bPenetrationHSOnly;
penReduction = niceDmgType.default.PenDmgReduction;
// 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)
penReduction *= niceDmgType.default.BigZedPenDmgReduction;
else if(niceZed.default.Health >= default.MediumZedMinHealth && !bEasyHeadPenetration)
penReduction *= niceDmgType.default.MediumZedPenDmgReduction;
}
else
penReduction *= niceDmgType.default.BigZedPenDmgReduction;
if(niceVet != none)
penReduction = niceVet.static.GetPenetrationDamageMulti(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo), penReduction, niceDmgType);
if(niceVet != none && nicePlayer.pawn.bIsCrouched && niceVet.static.hasSkill(nicePlayer, class'NiceSkillSharpshooterSurgical') && bIsHeadshot)
penReduction = FMax(penReduction, class'NiceSkillSharpshooterSurgical'.default.penDmgReduction);
// Assign new damage value and tell us if we should stop with penetration
Damage *= penReduction;
actualMaxPenetrations = niceDmgType.default.maxPenetrations;
if(actualMaxPenetrations >= 0)
actualMaxPenetrations +=
niceVet.static.GetAdditionalPenetrationAmount(KFPlayerReplicationInfo(nicePlayer.PlayerReplicationInfo));
if(!bIsHeadshot && niceDmgType.default.bPenetrationHSOnly)
return false;
if(actualMaxPenetrations < 0)
return true;
if(Damage / bullet.fireType.bullet.damage < (niceDmgType.default.PenDmgReduction ** (actualMaxPenetrations + 1)) + 0.0001 || Damage < 1)
return false;
return true;
}
defaultproperties
{
BigZedMinHealth=1000
MediumZedMinHealth=500
}

View file

@ -0,0 +1,218 @@
//==============================================================================
// NicePack / NiceBulletSpawner
//==============================================================================
// Class that is supposed to handle bullet spawning.
// It's main purpose is to allow spawning of large amounts of bullets with
// minimal replication between server and clients, which is supposed to be
// achieved via commands that can spawn multiple bullets at once,
// while 'syncing' any randomness by replicating seeds to it's own RNG.
// Functionality:
// - 'Xorshift' RNG implementation
// - Ability to spawn both single bullets and groups of them
// via single replication call
//==============================================================================
// Class hierarchy: Object > Actor > NiceBulletSpawner
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceBulletSpawner extends Actor
dependson(NiceFire);
//==============================================================================
//==============================================================================
// > Random number generation
// Variables and structures related to generating pseudo-random numbers, but
// completly determined by a random state object ('NiceRandomState').
// For that task we use xorshift algorithm, described here:
// https://en.wikipedia.org/wiki/Xorshift
// (page version as of 21 September 2016)
//
// This class doesn't bother with replicating random states, and all the work
// for their syncronization must be done via some other means.
//==============================================================================
// >> State of the psudo-random number generator
// This structure contains four integer values used in our version of xorshift
struct NiceRandomState{
var int x, y, z, w;
};
//==============================================================================
//==============================================================================
// > RNG-related functions
// Generates new random state (seed).
// This must be called on one machine only (server or client) and then
// replicated to other meachines that are required to generate the same
// sequence of random numbers.
// Separetely calling it on different machines will produce different seeds
// and different random sequences.
static function NiceRandomState GenerateRandomState(){
local NiceRandomState newState;
newState.x = Rand(MaxInt);
newState.y = Rand(MaxInt);
newState.z = Rand(MaxInt);
newState.w = Rand(MaxInt);
return newState;
}
// Generates new random float between 0 and 'maxValue'
// and modifies the used state as a result.
// In case 'maxValue' is less than 1, - it'll be treated as 1.
static function int GetRandomInt( out NiceRandomState randomState,
int maxValue){
local int t;
local int randomValue;
// This part was taken from:
// https://en.wikipedia.org/wiki/Xorshift
// (page version as of 21 September 2016)
t = randomState.x;
t = t ^ (t << 11);
t = t ^ (t >> 8);
randomState.x = randomState.y;
randomState.y = randomState.z;
randomState.z = randomState.w;
randomState.w = randomState.w ^ (randomState.w >> 19);
randomState.w = randomState.w ^ t;
// This is the supposed output random value,
// but since it can be negative...
randomValue = randomState.w;
// ...we will force it to be positive;
// (the case when 'randomValue' turns out to be the minimal possible value
// won't compromise anything for us)
if(randomValue < 0)
randomValue = -randomValue;
// Now quit if the value generated is indeed lower than 'maxValue'...
maxValue = Max(maxValue, 1);
if(randomState.w <= maxValue)
return randomState.w;
// ...because this will mess things up when 'maxValue' == 'MaxInt'
return (randomState.w % (maxValue + 1)) / maxValue;
}
// Generates new random float between 0 and 1
// and modifies the used state as a result.
static function float GetRandomFloat(out NiceRandomState randomState){
return GetRandomInt(randomState, MaxInt) / MaxInt;
}
//==============================================================================
//==============================================================================
// > Bullet spawning-related functions
// When called on a server -
// replicates to all players a message about spawned bullets
// (to cause them to spawn their ghost versions);
//
// 'bSkipOwner' flag allows to skip replicating this information
// to the owner (instigator) of the bullets,
// which is useful when used in 'DoNiceFireEffect' in 'NiceFire' class that's
// called on both client and server.
//
// When called on a client - instantly terminates itself
static function ReplicateBullets( int amount,
Vector start,
Rotator dir,
float spread,
NiceFire.NWFireType fireType,
NiceFire.NWCFireState fireState,
bool bSkipOwner){
local int i;
local NicePack niceMut;
local NicePlayerController bulletOwner;
if(fireState.base.instigator == none) return;
if(fireState.base.instigator.role < ROLE_Authority) return;
niceMut = class'NicePack'.static.Myself(fireState.base.instigator.level);
bulletOwner = fireState.base.instigatorCtrl;
for(i = 0;i < niceMut.playersList.length;i ++){
if(niceMut.playersList[i] == bulletOwner && bSkipOwner)
continue;
niceMut.playersList[i].ClientSpawnGhosts(amount, start,
dir.pitch, dir.yaw, dir.roll,
spread, fireType, fireState);
}
}
// Spawns a single bullet with no spread, exactly in the specified direction
static function SpawnSingleBullet( Vector start,
Rotator dir,
NiceFire.NWFireType fireType,
NiceFire.NWCFireState fireState){
local Actor other;
local NiceBullet niceBullet;
local Vector hitLocation, hitNormal, traceDir;
if(fireType.movement.bulletClass == none) return;
if(fireState.base.instigator == none) return;
// Try to spawn
niceBullet = fireState.base.instigator.
Spawn(fireType.movement.bulletClass,,, start, dir);
// If the first projectile spawn failed it's probably because we're trying
// to spawn inside the collision bounds of an object with properties that
// ignore zero extent traces.
// We need to do a non-zero extent trace so
// we can find a safe spawn loc for our projectile
if(niceBullet == none){
traceDir = fireState.base.instigator.location +
fireState.base.instigator.EyePosition();
other = fireState.base.instigator.Trace(hitLocation, hitNormal, start,
traceDir, false, Vect(0,0,1));
if(other != none)
start = hitLocation;
niceBullet = fireState.base.instigator.
Spawn( fireType.movement.bulletClass,,, start, dir);
}
// Give up if failed after these two attempts
if(niceBullet == none)
return;
// Initialize bullet's data
niceBullet.fireType = fireType;
niceBullet.fireState = fireState;
niceBullet.InitBullet();
}
// Spawns a several bullets at once from the same location, but possibly
// spreads them in different directions (if 'spread' is greater than zero)
// by at most 'spread' angle (given in rotator units).
static function SpawnBullets( int amount,
Vector start,
Rotator dir,
float spread,
NiceFire.NWFireType fireType,
NiceFire.NWCFireState fireState){
local int i;
local Vector dirVector;
local Rotator randomRot;
dirVector = Vector(dir);
for(i = 0;i < amount;i ++){
if(spread > 0.0){
randomRot.yaw = spread * (FRand() - 0.5); // NICETODO: replace with proper fucking RNG, after adding syncronization of seeds
randomRot.pitch = spread * (FRand() - 0.5);
}
SpawnSingleBullet( start, Rotator(dirVector >> randomRot),
fireType, fireState);
}
}
// A usability function;
// it calls 'SpawnBullets' on client (instigator) and
// 'ReplicateBullets' on server, without duplicating shots on the client.
//
// Just a shortcut to use to fire bullets from 'NiceFire' class
static function FireBullets(int amount,
Vector start,
Rotator dir,
float spread,
NiceFire.NWFireType fireType,
NiceFire.NWCFireState fireState){
if(fireState.base.instigator == none) return;
if(fireState.base.instigator.role == ROLE_Authority)
ReplicateBullets(amount, start, dir, spread, fireType, fireState, true);
else
SpawnBullets(amount, start, dir, spread, fireType, fireState);
}

View file

@ -0,0 +1,69 @@
class NiceCollisionManager extends Actor;
struct SphereCollision{
var int ID;
var float radius;
var NiceMonster base;
var bool bDiscarded;
var float endTime;
};
var float lastCleanupTime;
var array<SphereCollision> collisionSpheres;
function bool IsCollisionSpoiled(SphereCollision collision){
return (collision.base == none || collision.base.health <= 0 || collision.bDiscarded || Level.TimeSeconds > collision.endTime);
}
function bool CubeCheck(Vector a, Vector b, float minX, float minY, float minZ, float cubeSide){
if( (a.x < minX && b.x < minX) || (a.x > minX + 2 * cubeSide && b.x > minX + 2 * cubeSide) ) return false;
if( (a.y < minY && b.y < minY) || (a.y > minY + 2 * cubeSide && b.y > minY + 2 * cubeSide) ) return false;
if( (a.z < minZ && b.z < minZ) || (a.z > minZ + 2 * cubeSide && b.z > minZ + 2 * cubeSide) ) return false;
return true;
}
function AddSphereCollision(int ID, float radius, NiceMonster colOwner, float endTiming){
local SphereCollision newCollision;
newCollision.ID = ID;
newCollision.radius = radius;
newCollision.base = colOwner;
newCollision.endTime = endTiming;
CleanCollisions();
collisionSpheres[collisionSpheres.Length] = newCollision;
}
function RemoveSphereCollision(int ID){
local int i;
for(i = 0;i < collisionSpheres.Length;i ++) if(collisionSpheres[i].ID == ID) collisionSpheres[i].bDiscarded = true;
CleanCollisions();
}
function bool CheckSphereCollision(Vector a, Vector b, SphereCollision collision){
local Vector segmentVector;
local float sqDistToProjCenter;
local float squaredRadius;
if(IsCollisionSpoiled(collision)) return false;
if(!CubeCheck(a, b, collision.base.location.x - collision.radius, collision.base.location.y - collision.radius, collision.base.location.z - collision.radius, collision.radius)) return false;
squaredRadius = collision.radius ** 2;
if(VSizeSquared(a - collision.base.location) <= squaredRadius) return true;
if(VSizeSquared(b - collision.base.location) <= squaredRadius) return true;
segmentVector = b - a;
sqDistToProjCenter = (collision.base.location - a) dot segmentVector;
if(sqDistToProjCenter < 0) return false;
sqDistToProjCenter = sqDistToProjCenter ** 2;
sqDistToProjCenter = sqDistToProjCenter / (segmentVector dot segmentVector);
if(sqDistToProjCenter < squaredRadius) return true;
return false;
}
function bool IsCollidingWithAnything(Vector a, Vector b){
local int i;
for(i = 0;i < collisionSpheres.Length;i ++) if(CheckSphereCollision(a, b, collisionSpheres[i])) return true;
return false;
}
function CleanCollisions(){
local int i;
local bool bNeedsCleaning;
local array<SphereCollision> newSpheresArray;
if(lastCleanupTime + 1.0 > Level.TimeSeconds) return;
lastCleanupTime = Level.TimeSeconds;
for(i = 0;i < collisionSpheres.Length;i ++) if(IsCollisionSpoiled(collisionSpheres[i])){ bNeedsCleaning = true; break; }
if(bNeedsCleaning){ for(i = 0;i < collisionSpheres.Length;i ++) if(!IsCollisionSpoiled(collisionSpheres[i])) newSpheresArray[newSpheresArray.Length] = collisionSpheres[i];
}
collisionSpheres = newSpheresArray;
}
defaultproperties
{ bHidden=True
}

1003
sources/Weapons/NiceFire.uc Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
class NiceScopedWeapon extends NiceWeapon
abstract;
#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
var() Material ZoomMat;
var() Sound ZoomSound;
var() int lenseMaterialID; // used since material id's seem to change alot
var() float scopePortalFOVHigh; // The FOV to zoom the scope portal by.
var() float scopePortalFOV; // The FOV to zoom the scope portal by.
var() vector XoffsetScoped;
var() vector XoffsetHighDetail;
var() int tileSize;
// 3d Scope vars
var ScriptedTexture ScopeScriptedTexture; // Scripted texture for 3d scopes
var Shader ScopeScriptedShader; // The shader that combines the scripted texture with the sight overlay
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 bool bInitializedScope; // Set to true when the scope has been initialized
var string ZoomMatRef;
var string ScriptedTextureFallbackRef;
var texture CrosshairTex;
var string CrosshairTexRef;
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'));
}
if(default.ScriptedTextureFallback == none && default.ScriptedTextureFallbackRef != "") default.ScriptedTextureFallback = texture(DynamicLoadObject(default.ScriptedTextureFallbackRef, class'texture'));
if(default.CrosshairTex == none && default.CrosshairTexRef != "") default.CrosshairTex = Texture(DynamicLoadObject(default.CrosshairTexRef, class'texture'));
W = NiceScopedWeapon(Inv);
if(W != none){ W.ZoomMat = default.ZoomMat; W.ScriptedTextureFallback = default.ScriptedTextureFallback; W.CrosshairTex = default.CrosshairTex;
}
}
static function bool UnloadAssets(){
if(super.UnloadAssets()){ default.ZoomMat = none; default.ScriptedTextureFallback = none; default.CrosshairTex = none;
}
return true;
}
simulated function bool ShouldDrawPortal()
{
if(bAimingRifle) return true;
else return false;
}
simulated function PostBeginPlay()
{
super.PostBeginPlay();
// Get new scope detail value from KFWeapon
KFScopeDetail = class'KFMod.KFWeapon'.default.KFScopeDetail;
UpdateScopeMode();
}
// Handles initializing and swithing between different scope modes
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 (bUsingSights || bAimingRifle) PlayerViewOffset = XoffsetScoped;
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 = CrosshairTex; 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(bUsingSights || 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 = CrosshairTex; 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 );
}
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;
}
//Handles all the functionality for zooming in including
// setting the parameters for the weapon, pawn, and playercontroller
simulated function ZoomIn(bool bAnimateTransition)
{
default.ZoomTime = default.recordedZoomTime;
PlayerIronSightFOV = default.PlayerIronSightFOV;
scopePortalFOVHigh = default.scopePortalFOVHigh;
scopePortalFOV = default.scopePortalFOV;
PlayerIronSightFOV = default.PlayerIronSightFOV;
if(instigator != none && instigator.bIsCrouched && class'NiceVeterancyTypes'.static.hasSkill(NicePlayerController(Instigator.Controller), class'NiceSkillSharpshooterHardWork')){ default.ZoomTime *= class'NiceSkillSharpshooterHardWork'.default.zoomSpeedBonus; if(instigator != none && instigator.bIsCrouched){ PlayerIronSightFOV *= class'NiceSkillSharpshooterHardWork'.default.zoomBonus; scopePortalFOVHigh *= class'NiceSkillSharpshooterHardWork'.default.zoomBonus; scopePortalFOV *= class'NiceSkillSharpshooterHardWork'.default.zoomBonus; PlayerIronSightFOV *= class'NiceSkillSharpshooterHardWork'.default.zoomBonus; }
}
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
simulated function ZoomOut(bool bAnimateTransition)
{
default.ZoomTime = default.recordedZoomTime;
PlayerIronSightFOV = default.PlayerIronSightFOV;
scopePortalFOVHigh = default.scopePortalFOVHigh;
scopePortalFOV = default.scopePortalFOV;
PlayerIronSightFOV = default.PlayerIronSightFOV;
if(class'NiceVeterancyTypes'.static.hasSkill(NicePlayerController(Instigator.Controller), class'NiceSkillSharpshooterHardWork')){ default.ZoomTime *= class'NiceSkillSharpshooterHardWork'.default.zoomSpeedBonus; PlayerIronSightFOV *= class'NiceSkillSharpshooterHardWork'.default.zoomBonus; scopePortalFOVHigh *= class'NiceSkillSharpshooterHardWork'.default.zoomBonus; scopePortalFOV *= class'NiceSkillSharpshooterHardWork'.default.zoomBonus; PlayerIronSightFOV *= class'NiceSkillSharpshooterHardWork'.default.zoomBonus;
}
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 function WeaponTick(float dt)
{
super.WeaponTick(dt);
if(bAimingRifle && ForceZoomOutTime > 0 && Level.TimeSeconds - ForceZoomOutTime > 0)
{ ForceZoomOutTime = 0;
ZoomOut(false);
if(Role < ROLE_Authority) ServerZoomOut(false);
}
}
// Called by the native code when the interpolation of the first person weapon to the zoomed position finishes
simulated event OnZoomInFinished()
{
local name anim;
local float frame, rate;
GetAnimParams(0, anim, frame, rate);
if (ClientState == WS_ReadyToFire)
{ // Play the iron idle anim when we're finished zooming in if (anim == IdleAnim) { PlayIdle(); }
}
if( Level.NetMode != NM_DedicatedServer && KFPlayerController(Instigator.Controller) != none && KFScopeDetail == KF_TextureScope )
{ KFPlayerController(Instigator.Controller).TransitionFOV(PlayerIronSightFOV,0.0);
}
}
simulated function bool CanZoomNow()
{
Return (!FireMode[0].bIsFiring && !FireMode[1].bIsFiring && Instigator!=none && Instigator.Physics!=PHYS_Falling);
}
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, tileSize, tileSize);
Canvas.Font = Canvas.MedFont; Canvas.SetDrawColor(200,150,0);
Canvas.SetPos(Canvas.SizeX * 0.16, Canvas.SizeY * 0.43); Canvas.DrawText(" ");
Canvas.SetPos(Canvas.SizeX * 0.16, Canvas.SizeY * 0.47);
}
else{ Skins[LenseMaterialID] = ScriptedTextureFallback; bDrawingFirstPerson = true; Canvas.DrawActor(self, false, false, DisplayFOV); bDrawingFirstPerson = false;
}
}
// Adjust a single FOV based on the current aspect ratio. Adjust FOV is the default NON-aspect ratio adjusted FOV to adjust
simulated function float CalcAspectRatioAdjustedFOV(float AdjustFOV)
{
local KFPlayerController KFPC;
local float ResX, ResY;
local float AspectRatio;
KFPC = KFPlayerController(Level.GetLocalPlayerController());
if( KFPC == none )
{ return AdjustFOV;
}
ResX = float(GUIController(KFPC.Player.GUIController).ResX);
ResY = float(GUIController(KFPC.Player.GUIController).ResY);
AspectRatio = ResX / ResY;
if ( KFPC.bUseTrueWideScreenFOV && AspectRatio >= 1.60 ) //1.6 = 16/10 which is 16:10 ratio and 16:9 comes to 1.77
{ return CalcFOVForAspectRatio(AdjustFOV);
}
else
{ return AdjustFOV;
}
}
// AdjustIngameScope(RO) - Takes the changes to the ScopeDetail variable and
// sets the scope to the new detail mode. Called when the player switches the
// scope setting ingame, or when the scope setting is changed from the menu
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(default.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;
}
// Make any chagned to the scope setup
UpdateScopeMode();
}
simulated event Destroyed()
{
PreTravelCleanUp();
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;
}
}
defaultproperties
{ tileSize=1024
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
class NiceWeaponPickup extends KFWeaponPickup
dependson(NicePlainData)
placeable;
var bool bBackupWeapon;
var array<int> crossPerkIndecies; // List of indices for perks that also should recive bonuses from this weapon
// Data that should be transferred between various instances of 'NiceWeapon' classes, corresponding to this pickup class
var NicePlainData.Data weaponData;
simulated function NicePlainData.Data GetNiceData(){
return weaponData;
}
simulated function SetNiceData(NicePlainData.Data newData){
weaponData = newData;
}
simulated function InitDroppedPickupFor(Inventory Inv){
local NiceWeapon niceWeap;
niceWeap = NiceWeapon(Inv);
if(niceWeap != none) SetNiceData(niceWeap.GetNiceData());
// Do as usual
if(Role == ROLE_Authority) super.InitDroppedPickupFor(Inv);
}
function Destroyed(){
if(bDropped && Inventory != none && class<Weapon>(Inventory.Class) != none && KFGameType(Level.Game) != none) KFGameType(Level.Game).WeaponDestroyed(class<Weapon>(Inventory.Class));
super(WeaponPickup).Destroyed();
}
defaultproperties
{
cost=1000
}

View file

@ -0,0 +1,14 @@
class NiceBallisticNade extends NiceBullet;
defaultproperties
{
//charMinExplosionDist=250.000000
bDisableComplexMovement=False
//movementAcceleration=(Z=-490.000000)
//movementFallTime=1.000000
TrailClass=Class'ROEffects.PanzerfaustTrail'
trailXClass=None
explosionImpact=(bImportanEffect=True,decalClass=Class'KFMod.KFScorchMark',EmitterClass=Class'KFMod.KFNadeLExplosion',emitterShiftWall=20.000000,emitterShiftPawn=20.000000,noiseRef="KF_GrenadeSnd.Nade_Explode_1",noiseVolume=2.000000)
disintegrationImpact=(EmitterClass=Class'KFMod.SirenNadeDeflect',noiseRef="Inf_Weapons.faust_explode_distant02",noiseVolume=2.000000)
//StaticMeshRef="kf_generic_sm.40mm_Warhead"
DrawScale=3.000000
}

View file

@ -0,0 +1,88 @@
// ScrN copy
class NiceCryoNade extends Nade;
#exec OBJ LOAD FILE=KF_GrenadeSnd.uax
#exec OBJ LOAD FILE=Inf_WeaponsTwo.uax
#exec OBJ LOAD FILE=KF_LAWSnd.uax
// How many times do freezing
var int totalFreezes;
// How often to do freezeing
var float freezeRate;
// The next time that this nade will freeze
var float nextFreezeTime;
// The sound of nade's explosion
var sound explosionSound;
// Whether or not effects have been played yet
var bool bNeedToPlayEffects;
replication
{
reliable if (Role==ROLE_Authority) bNeedToPlayEffects;
}
simulated function PostNetReceive()
{
super.PostNetReceive();
if(!bHasExploded && bNeedToPlayEffects){ bNeedToPlayEffects = false; Explode(Location, vect(0,0,1));
}
}
simulated function Explode(vector hitLocation, vector hitNormal){
bHasExploded = true;
BlowUp(hitLocation);
PlaySound(ExplosionSound,,TransientSoundVolume);
if(Role == ROLE_Authority){ bNeedToPlayEffects = true; AmbientSound=Sound'Inf_WeaponsTwo.smoke_loop';
}
if(EffectIsRelevant(location, false)){ Spawn(class'NiceCryoNadeCloud',,, hitLocation, rotator(vect(0,0,1))); Spawn(explosionDecal, self,, hitLocation, rotator(-hitNormal)); if(level.detailMode >= DM_High) Spawn(class'NiceNitroGroundEffect', self,, location);
}
}
function Timer(){
if(!bHidden){ if(!bHasExploded) Explode(location, vect(0,0,1));
}
else if(bDisintegrated){ AmbientSound = none; Destroy();
}
}
simulated function BlowUp(vector hitLocation){
DoFreeze(damage, damageRadius, MyDamageType, momentumTransfer, hitLocation);
if(role == ROLE_Authority) MakeNoise(1.0);
}
function DoFreeze( float DamageAmount, float DamageRadius, class<DamageType> DamageType, float Momentum, vector HitLocation){
local NiceMonster niceZed;
if(bHurtEntry) return;
bHurtEntry = true;
nextFreezeTime = level.timeSeconds + freezeRate;
foreach CollidingActors(class 'NiceMonster', niceZed, damageRadius, hitLocation){ if(niceZed.Health <= 0) continue; if(instigator == none || instigator.controller == none) niceZed.SetDelayedDamageInstigatorController(instigatorController); niceZed.TakeDamage( damageAmount, instigator, niceZed.location, vect(0,0,0), damageType);
}
bHurtEntry = false;
}
function TakeDamage(int Damage, Pawn InstigatedBy, Vector hitlocation, Vector momentum, class<DamageType> damageType, optional int HitIndex){
if(damageType == class'SirenScreamDamage') Disintegrate(HitLocation, vect(0,0,1));
}
// Overridden to tweak the handling of the impact sound
simulated function HitWall(vector hitNormal, Actor wall){
local Vector vnorm;
local PlayerController player;
if(Pawn(wall) != none || GameObjective(wall) != none){ Explode(Location, HitNormal); return;
}
if(!bTimerSet){ SetTimer(ExplodeTimer, false); bTimerSet = true;
}
// Reflect off Wall w/damping
vnorm = (velocity dot hitNormal) * hitNormal;
Velocity = -vnorm * DampenFactor + (Velocity - vnorm) * dampenFactorParallel;
RandSpin(100000);
desiredRotation.roll = 0;
RotationRate.roll = 0;
speed = VSize(velocity);
if(speed < 20){ bBounce = False; PrePivot.Z = -1.5; SetPhysics(PHYS_None); Timer(); SetTimer(0.0,False); desiredRotation = Rotation; desiredRotation.Roll = 0; desiredRotation.Pitch = 0; SetRotation(desiredRotation); if(trail != none) trail.mRegen = false; return;
}
if(level.NetMode != NM_DedicatedServer && Speed > 50) PlaySound(ImpactSound, SLOT_Misc );
else{ bFixedRotationDir = false; bRotateToDesired = true; DesiredRotation.Pitch = 0; RotationRate.Pitch = 50000;
}
if(level.bDropDetail || level.DetailMode == DM_Low) return;
if( (level.TimeSeconds - lastSparkTime > 0.5) && EffectIsRelevant(location, false)){ player = level.GetLocalPlayerController(); if( player.viewTarget != none && VSize(player.viewTarget.location - location) < 6000) Spawn(HitEffectClass,,, Location, Rotator(HitNormal)); LastSparkTime = Level.TimeSeconds;
}
}
function Tick(float deltaTime){
if( totalFreezes > 0 && nextFreezeTime > 0 && nextFreezeTime < level.timeSeconds){ totalFreezes--; DoFreeze(damage, damageRadius, myDamageType, momentumTransfer, location); if(totalFreezes == 0) ambientSound = none;
}
}
defaultproperties
{ totalFreezes=100 freezeRate=0.030000 ExplosionSound=SoundGroup'KF_GrenadeSnd.NadeBase.MedicNade_Explode' Damage=0.000000 DamageRadius=175.000000 MyDamageType=Class'NicePack.NiceDamTypeCryoNade' ExplosionDecal=Class'NicePack.NiceNitroDecal' StaticMesh=StaticMesh'KF_pickups5_Trip.nades.MedicNade_Pickup' LifeSpan=8.000000 DrawScale=1.000000 SoundVolume=150 SoundRadius=100.000000 TransientSoundVolume=2.000000 TransientSoundRadius=200.000000
}

View file

@ -0,0 +1,23 @@
// ScrN copy
class NiceCryoNadeCloud extends Emitter;
var bool bFlashed;
simulated function PostBeginPlay(){
super.PostBeginPlay();
NadeLight();
}
simulated function NadeLight(){
if(instigator == none) return;
if(Level.bDropDetail) return;
if( (Level.TimeSeconds - LastRenderTime < 0.2) || (PlayerController(instigator.controller) != none)){
bDynamicLight = true;
SetTimer(0.25, false);
}
else Timer();
}
simulated function Timer(){
bDynamicLight = false;
}
defaultproperties
{ Begin Object Class=SpriteEmitter Name=SpriteEmitter0 UseColorScale=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True AutomaticInitialSpawning=False BlendBetweenSubdivisions=True ColorScale(0)=(Color=(B=255,G=235,R=215,A=255)) ColorScale(1)=(RelativeTime=1.000000,Color=(B=245,G=225,R=205,A=255)) FadeOutFactor=(W=0.000000,X=0.000000,Y=0.000000,Z=0.000000) FadeOutStartTime=5.000000 SpinsPerSecondRange=(Y=(Min=0.050000,Max=0.100000),Z=(Min=0.050000,Max=0.100000)) StartSpinRange=(X=(Min=-0.500000,Max=0.500000),Y=(Max=1.000000),Z=(Max=1.000000)) SizeScale(0)=(RelativeSize=1.000000) SizeScale(1)=(RelativeTime=1.000000,RelativeSize=5.000000) StartSizeRange=(X=(Min=40.000000,Max=40.000000),Y=(Min=40.000000,Max=40.000000),Z=(Min=40.000000,Max=40.000000)) InitialParticlesPerSecond=5000.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'kf_fx_trip_t.Misc.smoke_animated' TextureUSubdivisions=8 TextureVSubdivisions=8 LifetimeRange=(Min=3.000000,Max=3.000000) StartVelocityRange=(X=(Min=-750.000000,Max=750.000000),Y=(Min=-750.000000,Max=750.000000)) VelocityLossRange=(X=(Min=10.000000,Max=10.000000),Y=(Min=10.000000,Max=10.000000),Z=(Min=10.000000,Max=10.000000)) End Object Emitters(0)=SpriteEmitter'NicePack.NiceCryoNadeCloud.SpriteEmitter0'
AutoDestroy=True bNoDelete=False RemoteRole=ROLE_SimulatedProxy bNotOnDedServer=False
}

View file

@ -0,0 +1,5 @@
class NiceDamTypeCryoNade extends NiceWeaponDamageType
abstract;
defaultproperties
{ freezePower=200.000000
}

View file

@ -0,0 +1,28 @@
class NiceDamTypeEnforcerNade extends NiceDamageTypeVetEnforcer
abstract;
static function GetHitEffects(out class<xEmitter> HitEffects[4], int VictimHealth){
HitEffects[0] = class'HitSmoke';
if(VictimHealth <= 0)
HitEffects[1] = class'KFHitFlame';
else if(FRand() < 0.8)
HitEffects[1] = class'KFHitFlame';
}
defaultproperties
{
bIsExplosive=True
bCheckForHeadShots=False
//WeaponClass=Class'NicePack.NiceShotgun'//meantodo
DeathString="%o filled %k's body with shrapnel."
FemaleSuicide="%o blew up."
MaleSuicide="%o blew up."
bLocationalHit=False
bThrowRagdoll=True
bExtraMomentumZ=True
DamageThreshold=1
DeathOverlayMaterial=Combiner'Effects_Tex.GoreDecals.PlayerDeathOverlay'
DeathOverlayTime=999.000000
KDamageImpulse=2500.000000
KDeathVel=300.000000
KDeathUpKick=200.000000
HumanObliterationThreshhold=150
}

View file

@ -0,0 +1,5 @@
class NiceDamTypeFlameNade extends NiceDamTypeFire
abstract;
defaultproperties
{ WeaponClass=None DeathString="%k incinerated %o (flame grenade)." FemaleSuicide="%o roasted herself alive (flame grenade)." MaleSuicide="%o roasted himself alive (flame grenade)."
}

View file

@ -0,0 +1,166 @@
//=============================================================================
// MedicNade
//=============================================================================
// Medic grenade that heals friends and hurts enemies
//=============================================================================
// Killing Floor Source
// Copyright (C) 2012 Tripwire Interactive
// Author - John "Ramm-Jaeger" Gibson
//=============================================================================
class NiceMedicNade extends Nade;
#exec OBJ LOAD FILE=KF_GrenadeSnd.uax
#exec OBJ LOAD FILE=Inf_WeaponsTwo.uax
#exec OBJ LOAD FILE=KF_LAWSnd.uax
var() int HealBoostAmount;// How much we heal a player by default with the medic nade
var int TotalHeals; // The total number of times this nade has healed (or hurt enemies)
var() int MaxHeals; // The total number of times this nade will heal (or hurt enemies) until its done healing
var float NextHealTime; // The next time that this nade will heal friendlies or hurt enemies
var() float HealInterval; // How often to do healing
var() sound ExplosionSound; // The sound of the rocket exploding
var localized string SuccessfulHealMessage;
var int MaxNumberOfPlayers;
var bool bNeedToPlayEffects; // Whether or not effects have been played yet
replication
{
reliable if (Role==ROLE_Authority) bNeedToPlayEffects;
}
simulated function PostNetReceive()
{
super.PostNetReceive();
if( !bHasExploded && bNeedToPlayEffects )
{ bNeedToPlayEffects = false; Explode(Location, vect(0,0,1));
}
}
simulated function Explode(vector HitLocation, vector HitNormal)
{
bHasExploded = True;
BlowUp(HitLocation);
PlaySound(ExplosionSound,,TransientSoundVolume);
if( Role == ROLE_Authority )
{ bNeedToPlayEffects = true; AmbientSound=Sound'Inf_WeaponsTwo.smoke_loop';
}
if ( EffectIsRelevant(Location,false) )
{ Spawn(Class'NicePack.NiceNadeHealing',,, HitLocation, rotator(vect(0,0,1)));
}
}
function Timer()
{
if( !bHidden )
{ if( !bHasExploded ) { Explode(Location, vect(0,0,1)); }
}
else if( bDisintegrated )
{ AmbientSound=none; Destroy();
}
}
simulated function BlowUp(vector HitLocation)
{
HealOrHurt(Damage,DamageRadius, MyDamageType, MomentumTransfer, HitLocation);
if ( Role == ROLE_Authority ) MakeNoise(1.0);
}
function HealOrHurt(float DamageAmount, float DamageRadius, class<DamageType> DamageType, float Momentum, vector HitLocation)
{
local actor Victims;
local float damageScale;
local vector dir;
local int NumKilled;
local KFMonster KFMonsterVictim;
local Pawn P;
local KFPawn KFP;
local array<Pawn> CheckedPawns;
local int i;
local bool bAlreadyChecked;
// Healing
local KFPlayerReplicationInfo PRI;
local int MedicReward;
local float HealSum; // for modifying based on perks
local int PlayersHealed;
if ( bHurtEntry ) return;
NextHealTime = Level.TimeSeconds + HealInterval;
bHurtEntry = true;
if( Fear != none )
{ Fear.StartleBots();
}
foreach CollidingActors (class 'Actor', Victims, DamageRadius, HitLocation)
{ // 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;
damageScale = 1.0;
if ( Instigator == none || Instigator.Controller == none ) { Victims.SetDelayedDamageInstigatorController( InstigatorController ); }
P = Pawn(Victims);
if( P != none ) { for (i = 0; i < CheckedPawns.Length; i++) { if (CheckedPawns[i] == P) { bAlreadyChecked = true; break; } }
if( bAlreadyChecked ) { bAlreadyChecked = false; P = none; continue; }
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)); } else if( KFP != none ) { damageScale *= KFP.GetExposureTo(Location + 15 * -Normal(PhysicsVolume.Gravity)); }
CheckedPawns[CheckedPawns.Length] = P;
if ( damageScale <= 0) { P = none; continue; } else { //Victims = P; P = none; } } else { continue; }
if( KFP == none ) { //log(Level.TimeSeconds@"Hurting "$Victims$" for "$(damageScale * DamageAmount)$" damage");
if( Pawn(Victims) != none && Pawn(Victims).Health > 0 ) { Victims.TakeDamage(damageScale * DamageAmount,Instigator,Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dir,(damageScale * Momentum * dir),DamageType);
if( Role == ROLE_Authority && KFMonsterVictim != none && KFMonsterVictim.Health <= 0 ) { NumKilled++; } } } else { if(Instigator != none && KFP.Health > 0) { if ( KFP.bCanBeHealed ) { PlayersHealed += 1; MedicReward = HealBoostAmount;
PRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo);
if ( PRI != none && PRI.ClientVeteranSkill != none ) { MedicReward *= PRI.ClientVeteranSkill.Static.GetHealPotency(PRI); }
HealSum = MedicReward;
if ( (KFP.Health + KFP.healthToGive + MedicReward) > KFP.HealthMax ) { MedicReward = KFP.HealthMax - (KFP.Health + KFP.healthToGive); if ( MedicReward < 0 ) { MedicReward = 0; } }
//log(Level.TimeSeconds@"Healing "$KFP$" for "$HealSum$" base healamount "$HealBoostAmount$" health"); KFP.GiveHealth(HealSum, KFP.HealthMax); KFP.ShieldStrength += HealSum * 0.25; if(KFP.ShieldStrength > KFP.ShieldStrengthMax) KFP.ShieldStrength = KFP.ShieldStrengthMax;
if ( PRI != none ) { if ( MedicReward > 0 && KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements) != none ) { KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements).AddDamageHealed(MedicReward, false, true); }
// Give the medic reward money as a percentage of how much of the person's health they healed MedicReward = int((FMin(float(MedicReward),KFP.HealthMax)/KFP.HealthMax) * 60);
PRI.ReceiveRewardForHealing( MedicReward, KFP );
if ( KFHumanPawn(Instigator) != none ) { KFHumanPawn(Instigator).AlphaAmount = 255; }
if( PlayerController(Instigator.Controller) != none ) { PlayerController(Instigator.Controller).ClientMessage(SuccessfulHealMessage$KFP.GetPlayerName(), 'CriticalEvent'); } } } } }
KFP = none; }
if (PlayersHealed >= MaxNumberOfPlayers) { if (PRI != none) { KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements).HealedTeamWithMedicGrenade(); } }
}
bHurtEntry = false;
}
// Shoot nades in mid-air
// Alex
function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
{
if ( Monster(instigatedBy) != none || instigatedBy == Instigator )
{ if( damageType == class'SirenScreamDamage') { Disintegrate(HitLocation, vect(0,0,1)); }
}
}
// Overridden to tweak the handling of the impact sound
simulated function HitWall( vector HitNormal, actor Wall )
{
local Vector VNorm;
local PlayerController PC;
if ( (Pawn(Wall) != none) || (GameObjective(Wall) != none) )
{ Explode(Location, HitNormal); return;
}
if (!bTimerSet)
{ SetTimer(ExplodeTimer, false); bTimerSet = true;
}
// Reflect off Wall w/damping
VNorm = (Velocity dot HitNormal) * HitNormal;
Velocity = -VNorm * DampenFactor + (Velocity - VNorm) * DampenFactorParallel;
RandSpin(100000);
DesiredRotation.Roll = 0;
RotationRate.Roll = 0;
Speed = VSize(Velocity);
if ( Speed < 20 )
{ bBounce = False; PrePivot.Z = -1.5; SetPhysics(PHYS_none); Timer(); SetTimer(0.0,False); DesiredRotation = Rotation; DesiredRotation.Roll = 0; DesiredRotation.Pitch = 0; SetRotation(DesiredRotation);
if( Fear == none ) { //(jc) Changed to use MedicNade-specific grenade that's overridden to not make the ringmaster fear it Fear = Spawn(class'AvoidMarker_MedicNade'); Fear.SetCollisionSize(DamageRadius,DamageRadius); Fear.StartleBots(); }
if ( Trail != none ) Trail.mRegen = false; // stop the emitter from regenerating
}
else
{ if ( (Level.NetMode != NM_DedicatedServer) && (Speed > 50) ) PlaySound(ImpactSound, SLOT_Misc ); else { bFixedRotationDir = false; bRotateToDesired = true; DesiredRotation.Pitch = 0; RotationRate.Pitch = 50000; } if ( !Level.bDropDetail && (Level.DetailMode != DM_Low) && (Level.TimeSeconds - LastSparkTime > 0.5) && EffectIsRelevant(Location,false) ) { PC = Level.GetLocalPlayerController(); if ( (PC.ViewTarget != none) && VSize(PC.ViewTarget.Location - Location) < 6000 ) Spawn(HitEffectClass,,, Location, Rotator(HitNormal)); LastSparkTime = Level.TimeSeconds; }
}
}
function Tick( float DeltaTime )
{
if( Role < ROLE_Authority )
{ return;
}
// if( class'ROEngine.ROLevelInfo'.static.RODebugMode() )
// {
// DrawDebugSphere( Location, DamageRadius, 12, 255, 0, 0);
// }
if( TotalHeals < MaxHeals && NextHealTime > 0 && NextHealTime < Level.TimeSeconds )
{ TotalHeals += 1;
HealOrHurt(Damage,DamageRadius, MyDamageType, MomentumTransfer, Location);
if( TotalHeals >= MaxHeals ) { AmbientSound=none; }
}
}
defaultproperties
{ HealBoostAmount=10 MaxHeals=8 HealInterval=1.000000 ExplosionSound=SoundGroup'KF_GrenadeSnd.NadeBase.MedicNade_Explode' SuccessfulHealMessage="You healed " MaxNumberOfPlayers=6 Damage=50.000000 DamageRadius=175.000000 MyDamageType=Class'KFMod.DamTypeMedicNade' StaticMesh=StaticMesh'KF_pickups5_Trip.nades.MedicNade_Pickup' DrawScale=1.000000 SoundVolume=150 SoundRadius=100.000000 TransientSoundVolume=2.000000 TransientSoundRadius=200.000000
}

View file

@ -0,0 +1,158 @@
class NiceMedicNadePoison extends Nade;
#exec OBJ LOAD FILE=KF_GrenadeSnd.uax
#exec OBJ LOAD FILE=Inf_WeaponsTwo.uax
#exec OBJ LOAD FILE=KF_LAWSnd.uax
var() int HealBoostAmount;// How much we heal a player by default with the medic nade
var int TotalHeals; // The total number of times this nade has healed (or hurt enemies)
var() int MaxHeals; // The total number of times this nade will heal (or hurt enemies) until its done healing
var float NextHealTime; // The next time that this nade will heal friendlies or hurt enemies
var() float HealInterval; // How often to do healing
var() sound ExplosionSound; // The sound of the rocket exploding
var localized string SuccessfulHealMessage;
var int MaxNumberOfPlayers;
var bool bNeedToPlayEffects; // Whether or not effects have been played yet
replication
{
reliable if (Role==ROLE_Authority) bNeedToPlayEffects;
}
simulated function PostNetReceive()
{
super.PostNetReceive();
if( !bHasExploded && bNeedToPlayEffects )
{ bNeedToPlayEffects = false; Explode(Location, vect(0,0,1));
}
}
simulated function Explode(vector HitLocation, vector HitNormal)
{
bHasExploded = True;
BlowUp(HitLocation);
PlaySound(ExplosionSound,,TransientSoundVolume);
if( Role == ROLE_Authority )
{ bNeedToPlayEffects = true; AmbientSound=Sound'Inf_WeaponsTwo.smoke_loop';
}
if ( EffectIsRelevant(Location,false) )
{ Spawn(Class'NicePack.NiceNadeHealingFast',,, HitLocation, rotator(vect(0,0,1)));
}
}
function Timer()
{
if( !bHidden )
{ if( !bHasExploded ) { Explode(Location, vect(0,0,1)); }
}
else if( bDisintegrated )
{ AmbientSound=none; Destroy();
}
}
simulated function BlowUp(vector HitLocation)
{
HealOrHurt(Damage,DamageRadius, MyDamageType, MomentumTransfer, HitLocation);
if ( Role == ROLE_Authority ) MakeNoise(1.0);
}
function HealOrHurt(float DamageAmount, float DamageRadius, class<DamageType> DamageType, float Momentum, vector HitLocation)
{
local actor Victims;
local float damageScale;
local vector dir;
local int NumKilled;
local KFMonster KFMonsterVictim;
local Pawn P;
local KFPawn KFP;
local array<Pawn> CheckedPawns;
local int i;
local bool bAlreadyChecked;
// Healing
local KFPlayerReplicationInfo PRI;
local int MedicReward;
local float HealSum; // for modifying based on perks
local int PlayersHealed;
local NiceMonster niceZed;
if ( bHurtEntry ) return;
NextHealTime = Level.TimeSeconds + HealInterval;
bHurtEntry = true;
if( Fear != none )
{ Fear.StartleBots();
}
foreach CollidingActors (class 'Actor', Victims, DamageRadius, HitLocation)
{ // 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;
damageScale = 1.0;
if ( Instigator == none || Instigator.Controller == none ) { Victims.SetDelayedDamageInstigatorController( InstigatorController ); }
P = Pawn(Victims);
if( P != none ) { for (i = 0; i < CheckedPawns.Length; i++) { if (CheckedPawns[i] == P) { bAlreadyChecked = true; break; } }
if( bAlreadyChecked ) { bAlreadyChecked = false; P = none; continue; }
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)); } else if( KFP != none ) { damageScale *= KFP.GetExposureTo(Location + 15 * -Normal(PhysicsVolume.Gravity)); }
CheckedPawns[CheckedPawns.Length] = P;
if ( damageScale <= 0) { P = none; continue; } else { //Victims = P; P = none; } } else { continue; }
if( KFP == none ) { //log(Level.TimeSeconds@"Hurting "$Victims$" for "$(damageScale * DamageAmount)$" damage");
if(Pawn(Victims) != none && Pawn(Victims).Health > 0){ niceZed = NiceMonster(Victims); if(niceZed != none && niceZed.default.Health <= 500){ niceZed.madnessCountDown = FMax(5.0, niceZed.madnessCountDown); KFMonsterController(niceZed.Controller).FindNewEnemy(); } Victims.TakeDamage(damageScale * DamageAmount,Instigator,Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dir,(damageScale * Momentum * dir),DamageType);
if(Role == ROLE_Authority && KFMonsterVictim != none && KFMonsterVictim.Health <= 0) NumKilled ++; } } else { if( Instigator != none && KFP.Health > 0 && KFP.Health < KFP.HealthMax ) { if ( KFP.bCanBeHealed ) { PlayersHealed += 1; MedicReward = HealBoostAmount;
PRI = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo);
if ( PRI != none && PRI.ClientVeteranSkill != none ) { MedicReward *= PRI.ClientVeteranSkill.Static.GetHealPotency(PRI); }
HealSum = MedicReward;
if ( (KFP.Health + KFP.healthToGive + MedicReward) > KFP.HealthMax ) { MedicReward = KFP.HealthMax - (KFP.Health + KFP.healthToGive); if ( MedicReward < 0 ) { MedicReward = 0; } }
//log(Level.TimeSeconds@"Healing "$KFP$" for "$HealSum$" base healamount "$HealBoostAmount$" health"); KFP.GiveHealth(HealSum, KFP.HealthMax);
if ( PRI != none ) { if ( MedicReward > 0 && KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements) != none ) { KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements).AddDamageHealed(MedicReward, false, true); }
// Give the medic reward money as a percentage of how much of the person's health they healed MedicReward = int((FMin(float(MedicReward),KFP.HealthMax)/KFP.HealthMax) * 60);
PRI.ReceiveRewardForHealing( MedicReward, KFP );
if ( KFHumanPawn(Instigator) != none ) { KFHumanPawn(Instigator).AlphaAmount = 255; }
if( PlayerController(Instigator.Controller) != none ) { PlayerController(Instigator.Controller).ClientMessage(SuccessfulHealMessage$KFP.GetPlayerName(), 'CriticalEvent'); } } } } }
KFP = none; }
if (PlayersHealed >= MaxNumberOfPlayers) { if (PRI != none) { KFSteamStatsAndAchievements(PRI.SteamStatsAndAchievements).HealedTeamWithMedicGrenade(); } }
}
bHurtEntry = false;
}
// Shoot nades in mid-air
// Alex
function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
{
if ( Monster(instigatedBy) != none || instigatedBy == Instigator )
{ if( damageType == class'SirenScreamDamage') { Disintegrate(HitLocation, vect(0,0,1)); }
}
}
// Overridden to tweak the handling of the impact sound
simulated function HitWall( vector HitNormal, actor Wall )
{
local Vector VNorm;
local PlayerController PC;
if ( (Pawn(Wall) != none) || (GameObjective(Wall) != none) )
{ Explode(Location, HitNormal); return;
}
if (!bTimerSet)
{ SetTimer(ExplodeTimer, false); bTimerSet = true;
}
// Reflect off Wall w/damping
VNorm = (Velocity dot HitNormal) * HitNormal;
Velocity = -VNorm * DampenFactor + (Velocity - VNorm) * DampenFactorParallel;
RandSpin(100000);
DesiredRotation.Roll = 0;
RotationRate.Roll = 0;
Speed = VSize(Velocity);
if ( Speed < 20 )
{ bBounce = False; PrePivot.Z = -1.5; SetPhysics(PHYS_none); Timer(); SetTimer(0.0,False); DesiredRotation = Rotation; DesiredRotation.Roll = 0; DesiredRotation.Pitch = 0; SetRotation(DesiredRotation);
if( Fear == none ) { //(jc) Changed to use MedicNade-specific grenade that's overridden to not make the ringmaster fear it Fear = Spawn(class'AvoidMarker_MedicNade'); Fear.SetCollisionSize(DamageRadius,DamageRadius); Fear.StartleBots(); }
if ( Trail != none ) Trail.mRegen = false; // stop the emitter from regenerating
}
else
{ if ( (Level.NetMode != NM_DedicatedServer) && (Speed > 50) ) PlaySound(ImpactSound, SLOT_Misc ); else { bFixedRotationDir = false; bRotateToDesired = true; DesiredRotation.Pitch = 0; RotationRate.Pitch = 50000; } if ( !Level.bDropDetail && (Level.DetailMode != DM_Low) && (Level.TimeSeconds - LastSparkTime > 0.5) && EffectIsRelevant(Location,false) ) { PC = Level.GetLocalPlayerController(); if ( (PC.ViewTarget != none) && VSize(PC.ViewTarget.Location - Location) < 6000 ) Spawn(HitEffectClass,,, Location, Rotator(HitNormal)); LastSparkTime = Level.TimeSeconds; }
}
}
function Tick( float DeltaTime )
{
if( Role < ROLE_Authority )
{ return;
}
// if( class'ROEngine.ROLevelInfo'.static.RODebugMode() )
// {
// DrawDebugSphere( Location, DamageRadius, 12, 255, 0, 0);
// }
if( TotalHeals < MaxHeals && NextHealTime > 0 && NextHealTime < Level.TimeSeconds )
{ TotalHeals += 1;
HealOrHurt(Damage,DamageRadius, MyDamageType, MomentumTransfer, Location);
if( TotalHeals >= MaxHeals ) { AmbientSound=none; }
}
}
defaultproperties
{ HealBoostAmount=10 MaxHeals=4 HealInterval=1.000000 ExplosionSound=SoundGroup'KF_GrenadeSnd.NadeBase.MedicNade_Explode' SuccessfulHealMessage="You healed " MaxNumberOfPlayers=6 Damage=50.000000 DamageRadius=175.000000 MyDamageType=Class'KFMod.DamTypeMedicNade' StaticMesh=StaticMesh'KF_pickups5_Trip.nades.MedicNade_Pickup' LifeSpan=8.000000 DrawScale=1.000000 SoundVolume=150 SoundRadius=100.000000 TransientSoundVolume=2.000000 TransientSoundRadius=200.000000
}

View file

@ -0,0 +1,91 @@
class NiceNade extends ScrnNade;
var class<NiceAvoidMarker> AvoidMarkerClass;
var class<NiceWeaponDamageType> niceExplosiveDamage;
// Overloaded to implement nade skills
simulated function Explode(vector HitLocation, vector HitNormal){
local PlayerController LocalPlayer;
local Projectile P;
local byte i;
bHasExploded = true;
BlowUp(HitLocation);
// null reference fix
if(ExplodeSounds.length > 0) PlaySound(ExplodeSounds[rand(ExplodeSounds.length)],,2.0);
for(i = Rand(6);i < 10;i ++){ P = Spawn(ShrapnelClass,,,,RotRand(True)); if(P != none) P.RemoteRole = ROLE_None;
}
for(i = Rand(6);i < 10;i ++){ P = Spawn(ShrapnelClass,,,,RotRand(True)); if(P != none) P.RemoteRole = ROLE_none;
}
if(EffectIsRelevant(Location,false)){ Spawn(Class'KFmod.KFNadeExplosion',,, HitLocation, rotator(vect(0,0,1))); Spawn(ExplosionDecal, self,, HitLocation, rotator(-HitNormal));
}
// Shake nearby players screens
LocalPlayer = Level.GetLocalPlayerController();
if((LocalPlayer != none) && (VSize(Location - LocalPlayer.ViewTarget.Location) < (DamageRadius * 1.5))) LocalPlayer.ShakeView(RotMag, RotRate, RotTime, OffsetMag, OffsetRate, OffsetTime);
Destroy();
}
function TakeDamage(int Damage, Pawn InstigatedBy, Vector HitLocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex){
if(Monster(instigatedBy) != none || instigatedBy == Instigator){ if(DamageType == class'SirenScreamDamage') Disintegrate(HitLocation, vect(0,0,1)); else Explode(HitLocation, vect(0,0,1));
}
}
simulated function HurtRadius( float DamageAmount, float DamageRadius, class<DamageType> 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<Pawn> 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;
// 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 || Instigator.Controller == None ) { Victims.SetDelayedDamageInstigatorController( InstigatorController ); }
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;
// Scrake Nader ach if ( Role == ROLE_Authority && KFMonsterVictim != none && ZombieScrake(KFMonsterVictim) != none ) { // need to check Scrake's stun before dealing damage, because he can unstun by himself from damage received ScrakeNader(damageScale * DamageAmount, ZombieScrake(KFMonsterVictim), Stats); } } 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'ScrnBalanceSrv.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;
}
// Overridden to spawn different AvoidMarker
simulated function HitWall( vector HitNormal, actor Wall ){
local Vector VNorm;
local PlayerController PC;
if((Pawn(Wall) != none) || (GameObjective(Wall) != none)){ Explode(Location, HitNormal); return;
}
if(!bTimerSet){ SetTimer(ExplodeTimer, false); bTimerSet = true;
}
// Reflect off Wall w/damping
VNorm = (Velocity dot HitNormal) * HitNormal;
Velocity = -VNorm * DampenFactor + (Velocity - VNorm) * DampenFactorParallel;
RandSpin(100000);
DesiredRotation.Roll = 0;
RotationRate.Roll = 0;
Speed = VSize(Velocity);
if(Speed < 20){ bBounce = false; PrePivot.Z = -1.5; SetPhysics(PHYS_none); DesiredRotation = Rotation; DesiredRotation.Roll = 0; DesiredRotation.Pitch = 0; SetRotation(DesiredRotation);
if(Fear == none){ Fear = Spawn(AvoidMarkerClass); Fear.SetCollisionSize(DamageRadius, DamageRadius); Fear.StartleBots(); }
if(Trail != none) Trail.mRegen = false; // stop the emitter from regenerating
}
else{ if((Level.NetMode != NM_DedicatedServer) && (Speed > 50)) PlaySound(ImpactSound, SLOT_Misc ); else{ bFixedRotationDir = false; bRotateToDesired = true; DesiredRotation.Pitch = 0; RotationRate.Pitch = 50000; } if(!Level.bDropDetail && (Level.DetailMode != DM_Low) && (Level.TimeSeconds - LastSparkTime > 0.5) && EffectIsRelevant(Location,false)){ PC = Level.GetLocalPlayerController(); if ( (PC.ViewTarget != none) && VSize(PC.ViewTarget.Location - Location) < 6000 ) Spawn(HitEffectClass,,, Location, Rotator(HitNormal)); LastSparkTime = Level.TimeSeconds; }
}
}
defaultproperties
{ AvoidMarkerClass=Class'NicePack.NiceAvoidMarkerExplosive' niceExplosiveDamage=Class'NicePack.NiceDamTypeDemoExplosion'
}

View file

@ -0,0 +1,22 @@
class NiceNadeHealing extends Emitter;
var bool bFlashed;
simulated function PostBeginPlay()
{
Super.Postbeginplay();
NadeLight();
}
simulated function NadeLight()
{
if ( !Level.bDropDetail && (Instigator != none) && ((Level.TimeSeconds - LastRenderTime < 0.2) || (PlayerController(Instigator.Controller) != none)) )
{ bDynamicLight = true; SetTimer(0.25, false);
}
else Timer();
}
simulated function Timer()
{
bDynamicLight = false;
}
defaultproperties
{ Begin Object Class=SpriteEmitter Name=SpriteEmitter0 UseColorScale=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True AutomaticInitialSpawning=False BlendBetweenSubdivisions=True ColorScale(0)=(Color=(B=255,G=128,A=255)) ColorScale(1)=(RelativeTime=1.000000,Color=(B=161,G=61,R=61,A=255)) FadeOutFactor=(W=0.000000,X=0.000000,Y=0.000000,Z=0.000000) FadeOutStartTime=5.000000 SpinsPerSecondRange=(Y=(Min=0.050000,Max=0.100000),Z=(Min=0.050000,Max=0.100000)) StartSpinRange=(X=(Min=-0.500000,Max=0.500000),Y=(Max=1.000000),Z=(Max=1.000000)) SizeScale(0)=(RelativeSize=1.000000) SizeScale(1)=(RelativeTime=1.000000,RelativeSize=5.000000) StartSizeRange=(X=(Min=40.000000,Max=40.000000),Y=(Min=40.000000,Max=40.000000),Z=(Min=40.000000,Max=40.000000)) InitialParticlesPerSecond=5000.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'kf_fx_trip_t.Misc.smoke_animated' TextureUSubdivisions=8 TextureVSubdivisions=8 LifetimeRange=(Min=7.000000,Max=7.000000) StartVelocityRange=(X=(Min=-750.000000,Max=750.000000),Y=(Min=-750.000000,Max=750.000000)) VelocityLossRange=(X=(Min=10.000000,Max=10.000000),Y=(Min=10.000000,Max=10.000000),Z=(Min=10.000000,Max=10.000000)) End Object Emitters(0)=SpriteEmitter'NicePack.NiceNadeHealing.SpriteEmitter0'
AutoDestroy=True bNoDelete=False RemoteRole=ROLE_SimulatedProxy bNotOnDedServer=False
}

View file

@ -0,0 +1,22 @@
class NiceNadeHealingFast extends Emitter;
var bool bFlashed;
simulated function PostBeginPlay()
{
Super.Postbeginplay();
NadeLight();
}
simulated function NadeLight()
{
if ( !Level.bDropDetail && (Instigator != none) && ((Level.TimeSeconds - LastRenderTime < 0.2) || (PlayerController(Instigator.Controller) != none)) )
{ bDynamicLight = true; SetTimer(0.25, false);
}
else Timer();
}
simulated function Timer()
{
bDynamicLight = false;
}
defaultproperties
{ Begin Object Class=SpriteEmitter Name=SpriteEmitter0 UseColorScale=True RespawnDeadParticles=False SpinParticles=True UseSizeScale=True UseRegularSizeScale=False UniformSize=True AutomaticInitialSpawning=False BlendBetweenSubdivisions=True ColorScale(0)=(Color=(G=255,R=200,A=255)) ColorScale(1)=(RelativeTime=1.000000,Color=(B=61,G=105,R=105,A=255)) FadeOutFactor=(W=0.000000,X=0.000000,Y=0.000000,Z=0.000000) FadeOutStartTime=5.000000 SpinsPerSecondRange=(Y=(Min=0.050000,Max=0.100000),Z=(Min=0.050000,Max=0.100000)) StartSpinRange=(X=(Min=-0.500000,Max=0.500000),Y=(Max=1.000000),Z=(Max=1.000000)) SizeScale(0)=(RelativeSize=1.000000) SizeScale(1)=(RelativeTime=1.000000,RelativeSize=5.000000) StartSizeRange=(X=(Min=40.000000,Max=40.000000),Y=(Min=40.000000,Max=40.000000),Z=(Min=40.000000,Max=40.000000)) InitialParticlesPerSecond=5000.000000 DrawStyle=PTDS_AlphaBlend Texture=Texture'kf_fx_trip_t.Misc.smoke_animated' TextureUSubdivisions=8 TextureVSubdivisions=8 LifetimeRange=(Min=3.000000,Max=3.000000) StartVelocityRange=(X=(Min=-750.000000,Max=750.000000),Y=(Min=-750.000000,Max=750.000000)) VelocityLossRange=(X=(Min=10.000000,Max=10.000000),Y=(Min=10.000000,Max=10.000000),Z=(Min=10.000000,Max=10.000000)) End Object Emitters(0)=SpriteEmitter'NicePack.NiceNadeHealingFast.SpriteEmitter0'
AutoDestroy=True bNoDelete=False RemoteRole=ROLE_SimulatedProxy bNotOnDedServer=False
}

View file

@ -0,0 +1,24 @@
class NiceDamTypeWinGun extends NiceDamageTypeVetSharpshooter
abstract;
defaultproperties
{
stunMultiplier=1.500000
bIsProjectile=True
HeadShotDamageMult=200.000000
bSniperWeapon=True
WeaponClass=Class'NicePack.NiceWinchester'
DeathString="%k killed %o (Winchester)."
FemaleSuicide="%o shot herself in the foot."
MaleSuicide="%o shot himself in the foot."
bRagdollBullet=True
bBulletHit=True
PawnDamageEmitter=Class'ROEffects.ROBloodPuff'
LowGoreDamageEmitter=Class'ROEffects.ROBloodPuffNoGore'
LowDetailEmitter=Class'ROEffects.ROBloodPuffSmall'
FlashFog=(X=600.000000)
KDamageImpulse=2250.000000
KDeathVel=115.000000
KDeathUpKick=5.000000
VehicleDamageScaling=0.700000
}

View file

@ -0,0 +1,24 @@
class NiceDamTypeWinchester extends NiceDamageTypeVetSharpshooter
abstract;
defaultproperties
{
stunMultiplier=1.500000
bIsProjectile=True
HeadShotDamageMult=2.000000
bSniperWeapon=True
WeaponClass=Class'NicePack.NiceWinchester'
DeathString="%k killed %o (Winchester)."
FemaleSuicide="%o shot herself in the foot."
MaleSuicide="%o shot himself in the foot."
bRagdollBullet=True
bBulletHit=True
PawnDamageEmitter=Class'ROEffects.ROBloodPuff'
LowGoreDamageEmitter=Class'ROEffects.ROBloodPuffNoGore'
LowDetailEmitter=Class'ROEffects.ROBloodPuffSmall'
FlashFog=(X=600.000000)
KDamageImpulse=2250.000000
KDeathVel=115.000000
KDeathUpKick=5.000000
VehicleDamageScaling=0.700000
}

View file

@ -0,0 +1,91 @@
class NiceWinchester extends NiceWeapon;
simulated function fillSubReloadStages(){
// Loading 10 shells during 256 frames tops, with first shell loaded at frame 18, with 23 frames between load moments
generateReloadStages(10, 256, 18, 23);
}
static function FillInAppearance(){
local WeaponVariant variant;
local WeaponModel model;
local WeaponSkin skin, fancySkin;
local WeaponSoundSet soundSet;
local WeaponAnimationSet anims;
local NiceAmmoType ammoType;
local NiceAmmoEffects ammoEffects;
soundSet.selectSoundRef = "KF_RifleSnd.Rifle_Select";
soundSet.fireSoundRefs[0] = "KF_RifleSnd.Rifle_Fire";
soundSet.stereoFireSoundRefs[0] = "KF_RifleSnd.Rifle_FireST";
soundSet.noAmmoSoundRefs[0] = "KF_RifleSnd.Rifle_DryFire";
skin.ID = "Lever Action Rifle";
skin.paintRefs[0] = "KF_Weapons_Trip_T.Rifles.winchester_cmb";
fancySkin.ID = "Winchester";
fancySkin.paintRefs[0] = "NicePackT.Skins1st.OldLAR_cmb";
model.ID = "Winchester";
model.firstMeshRef = "KF_Weapons_Trip.Winchester_Trip";
model.hudImageRef = "KillingFloorHUD.WeaponSelect.winchester_unselected";
model.selectedHudImageRef = "KillingFloorHUD.WeaponSelect.Winchester";
model.skins[0] = skin;
model.skins[1] = fancySkin;
model.soundSet = soundSet;
anims.idleAnim = 'Idle';
anims.idleAimedAnim = 'AimIdle';
anims.selectAnim = 'Select';
anims.putDownAnim = 'PutDown';
anims.reloadAnim = 'Reload';
anims.fireAnimSets[0].justFire.anim = 'Fire';
anims.fireAnimSets[0].justFire.rate = 1.6;
anims.fireAnimSets[0].aimed.anim = 'AimFire';
anims.fireAnimSets[0].aimed.rate = 1.6;
model.animations = anims;
model.playerViewOffset = Vect(8.0, 14.0, -8.0);
model.effectOffset = Vect(100.0, 25.0, -10.0);
variant.models[0] = model;
ammoEffects.ammoID = "regular";
ammoEffects.fireTypeID = "crude";
variant.ammoEffects[0] = ammoEffects;
ammoEffects.ammoID = "irregular";
ammoEffects.fireTypeID = "fine";
variant.ammoEffects[1] = ammoEffects;
default.variants[0] = variant;
// Ammo
ammoType.ID = "regular";
ammoType.spaceMult = 1.0;
ammoType.amount = 20;
default.availableAmmoTypes[0] = ammoType;
ammoType.ID = "irregular";
ammoType.spaceMult = 1.0;
ammoType.amount = 20;
default.availableAmmoTypes[1] = ammoType;
}
defaultproperties
{
bChangeClipIcon=true
hudClipTexture=Texture'KillingFloorHUD.HUD.Hud_Single_Bullet'
reloadType=RTYPE_SINGLE
MagCapacity=10
ReloadRate=0.416667
ReloadAnimRate=1.600000
bHoldToReload=True
Weight=6.000000
bHasAimingMode=True
StandardDisplayFOV=70.000000
DisplayFOV=70.000000
PlayerIronSightFOV=70.000000
ZoomedDisplayFOV=50.000000
SleeveNum=2
TraderInfoTexture=Texture'KillingFloorHUD.Trader_Weapon_Images.Trader_Winchester'
FireModeClass(0)=Class'NicePack.NiceWinchesterFire'
FireModeClass(1)=Class'KFMod.NoFire'
bShowChargingBar=True
Description="A rugged and reliable single-shot rifle."
Priority=85
InventoryGroup=3
GroupOffset=3
PickupClass=Class'NicePack.NiceWinchesterPickup'
AttachmentClass=Class'NicePack.NiceWinchesterAttachment'
ItemName="Winchester"
TransientSoundVolume=50.000000
BobDamping=6.000000
}

View file

@ -0,0 +1,15 @@
class NiceWinchesterAmmo extends NiceAmmo;
#EXEC OBJ LOAD FILE=InterfaceContent.utx
defaultproperties
{
WeaponPickupClass=Class'NicePack.NiceWinchesterPickup'
AmmoPickupAmount=10
MaxAmmo=80
InitialAmount=20
PickupClass=Class'NicePack.NiceWinchesterAmmoPickup'
IconMaterial=Texture'KillingFloorHUD.Generic.HUD'
IconCoords=(X1=338,Y1=40,X2=393,Y2=79)
ItemName="Winchester bullets"
}

View file

@ -0,0 +1,9 @@
class NiceWinchesterAmmoPickup extends NiceAmmoPickup;
defaultproperties
{
AmmoAmount=10
InventoryType=Class'NicePack.NiceWinchesterAmmo'
PickupMessage=".44 rounds"
StaticMesh=None
}

View file

@ -0,0 +1,55 @@
class NiceWinchesterAttachment extends NiceAttachment;
defaultproperties
{
mMuzFlashClass=Class'ROEffects.MuzzleFlash3rdSTG'
mTracerClass=Class'KFMod.KFLargeTracer'
MovementAnims(0)="JogF_Winchester"
MovementAnims(1)="JogB_Winchester"
MovementAnims(2)="JogL_Winchester"
MovementAnims(3)="JogR_Winchester"
TurnLeftAnim="TurnL_Winchester"
TurnRightAnim="TurnR_Winchester"
CrouchAnims(0)="CHwalkF_Winchester"
CrouchAnims(1)="CHwalkB_Winchester"
CrouchAnims(2)="CHwalkL_Winchester"
CrouchAnims(3)="CHwalkR_Winchester"
WalkAnims(0)="WalkF_Winchester"
WalkAnims(1)="WalkB_Winchester"
WalkAnims(2)="WalkL_Winchester"
WalkAnims(3)="WalkR_Winchester"
CrouchTurnRightAnim="CH_TurnR_Winchester"
CrouchTurnLeftAnim="CH_TurnL_Winchester"
IdleCrouchAnim="CHIdle_Winchester"
IdleWeaponAnim="Idle_Winchester"
IdleRestAnim="Idle_Winchester"
IdleChatAnim="Idle_Winchester"
IdleHeavyAnim="Idle_Winchester"
IdleRifleAnim="Idle_Winchester"
FireAnims(0)="Fire_Winchester"
FireAnims(1)="Fire_Winchester"
FireAnims(2)="Fire_Winchester"
FireAnims(3)="Fire_Winchester"
FireAltAnims(0)="Fire_Winchester"
FireAltAnims(1)="Fire_Winchester"
FireAltAnims(2)="Fire_Winchester"
FireAltAnims(3)="Fire_Winchester"
FireCrouchAnims(0)="CHFire_Winchester"
FireCrouchAnims(1)="CHFire_Winchester"
FireCrouchAnims(2)="CHFire_Winchester"
FireCrouchAnims(3)="CHFire_Winchester"
FireCrouchAltAnims(0)="CHFire_Winchester"
FireCrouchAltAnims(1)="CHFire_Winchester"
FireCrouchAltAnims(2)="CHFire_Winchester"
FireCrouchAltAnims(3)="CHFire_Winchester"
HitAnims(0)="HitF_Winchester"
HitAnims(1)="HitB_Winchester"
HitAnims(2)="HitL_Winchester"
HitAnims(3)="HitR_Winchester"
PostFireBlendStandAnim="Blend_Winchester"
PostFireBlendCrouchAnim="CHBlend_Winchester"
MeshRef="KF_Weapons3rd_Trip.Winchester_3rd"
bHeavy=True
SplashEffect=Class'ROEffects.BulletSplashEmitter'
CullDistance=5000.000000
}

View file

@ -0,0 +1,40 @@
class NiceWinchesterFire extends NiceFire;
simulated function FillFireType(){
local NWFireType fireType;
fireType.fireTypeName = "crude";
fireType.weapon.bulletsAmount = 1;
fireType.weapon.ammoPerFire = 1;
fireType.weapon.bCanFireIncomplete = false;
fireType.weapon.fireRate = 0.562500;
fireType.movement.bulletClass = class'NiceBullet';
fireType.movement.speed = 37950.0;
fireType.rebound.recoilVertical = 150;
fireType.rebound.recoilHorizontal = 64;
fireType.bullet.damage = 136;
fireType.bullet.momentum = 18000;
fireType.bullet.shotDamageType = class'NicePack.NiceDamTypeWinchester';
fireTypes[0] = fireType;
fireType.fireTypeName = "fine";
fireType.bullet.damage = 10;
fireType.bullet.shotDamageType = class'NicePack.NiceDamTypeWinGun';
fireTypes[1] = fireType;
}
defaultproperties
{
DamageType=Class'NicePack.NiceDamTypeWinchester'
bPawnRapidFireAnim=true
bWaitForRelease=false
bModeExclusive=False
bAttachSmokeEmitter=True
TransientSoundVolume=1.800000
AmmoClass=Class'NicePack.NiceWinchesterAmmo'
ShakeRotMag=(X=100.000000,Y=100.000000,Z=500.000000)
ShakeRotRate=(X=10000.000000,Y=10000.000000,Z=10000.000000)
ShakeRotTime=2.000000
ShakeOffsetMag=(X=10.000000,Y=3.000000,Z=12.000000)
ShakeOffsetRate=(X=1000.000000,Y=1000.000000,Z=1000.000000)
ShakeOffsetTime=2.000000
FlashEmitterClass=Class'ROEffects.MuzzleFlash1stKar'
}

View file

@ -0,0 +1,24 @@
class NiceWinchesterPickup extends NiceWeaponPickup;
defaultproperties
{
Weight=6.000000
cost=200
BuyClipSize=10
PowerValue=50
SpeedValue=35
RangeValue=90
Description="A rugged and reliable single-shot rifle."
ItemName="Winchester"
ItemShortName="Winchester"
AmmoItemName="Winchester bullets"
CorrespondingPerkIndex=2
EquipmentCategoryID=2
InventoryType=Class'NicePack.NiceWinchester'
PickupMessage="You got Winchester"
PickupSound=Sound'KF_RifleSnd.RifleBase.Rifle_Pickup'
PickupForce="AssaultRiflePickup"
StaticMesh=StaticMesh'KF_pickups_Trip.Rifle.LeverAction_pickup'
CollisionRadius=30.000000
CollisionHeight=5.000000
}