First commit
This commit is contained in:
commit
5b48414900
263 changed files with 24830 additions and 0 deletions
10
sources/Weapons/BaseWeaponClasses/NiceAmmo.uc
Normal file
10
sources/Weapons/BaseWeaponClasses/NiceAmmo.uc
Normal 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
|
||||
{
|
||||
}
|
||||
15
sources/Weapons/BaseWeaponClasses/NiceAmmoPickup.uc
Normal file
15
sources/Weapons/BaseWeaponClasses/NiceAmmoPickup.uc
Normal 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
|
||||
{
|
||||
}
|
||||
63
sources/Weapons/BaseWeaponClasses/NiceAttachment.uc
Normal file
63
sources/Weapons/BaseWeaponClasses/NiceAttachment.uc
Normal 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
|
||||
}
|
||||
16
sources/Weapons/BaseWeaponClasses/NiceDamTypeFire.uc
Normal file
16
sources/Weapons/BaseWeaponClasses/NiceDamTypeFire.uc
Normal 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."
|
||||
}
|
||||
5
sources/Weapons/BaseWeaponClasses/NiceDamTypeSPAM.uc
Normal file
5
sources/Weapons/BaseWeaponClasses/NiceDamTypeSPAM.uc
Normal 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
|
||||
}
|
||||
96
sources/Weapons/BaseWeaponClasses/NiceWeaponDamageType.uc
Normal file
96
sources/Weapons/BaseWeaponClasses/NiceWeaponDamageType.uc
Normal 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
|
||||
}
|
||||
944
sources/Weapons/NiceBullet.uc
Normal file
944
sources/Weapons/NiceBullet.uc
Normal 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
|
||||
}
|
||||
225
sources/Weapons/NiceBulletAdapter.uc
Normal file
225
sources/Weapons/NiceBulletAdapter.uc
Normal 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
|
||||
}
|
||||
218
sources/Weapons/NiceBulletSpawner.uc
Normal file
218
sources/Weapons/NiceBulletSpawner.uc
Normal 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);
|
||||
}
|
||||
69
sources/Weapons/NiceCollisionManager.uc
Normal file
69
sources/Weapons/NiceCollisionManager.uc
Normal 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
1003
sources/Weapons/NiceFire.uc
Normal file
File diff suppressed because it is too large
Load diff
236
sources/Weapons/NiceScopedWeapon.uc
Normal file
236
sources/Weapons/NiceScopedWeapon.uc
Normal 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
|
||||
}
|
||||
2427
sources/Weapons/NiceWeapon.uc
Normal file
2427
sources/Weapons/NiceWeapon.uc
Normal file
File diff suppressed because it is too large
Load diff
29
sources/Weapons/NiceWeaponPickup.uc
Normal file
29
sources/Weapons/NiceWeaponPickup.uc
Normal 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
|
||||
}
|
||||
14
sources/Weapons/Playable/Grenades/NiceBallisticNade.uc
Normal file
14
sources/Weapons/Playable/Grenades/NiceBallisticNade.uc
Normal 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
|
||||
}
|
||||
88
sources/Weapons/Playable/Grenades/NiceCryoNade.uc
Normal file
88
sources/Weapons/Playable/Grenades/NiceCryoNade.uc
Normal 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
|
||||
}
|
||||
23
sources/Weapons/Playable/Grenades/NiceCryoNadeCloud.uc
Normal file
23
sources/Weapons/Playable/Grenades/NiceCryoNadeCloud.uc
Normal 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
|
||||
}
|
||||
5
sources/Weapons/Playable/Grenades/NiceDamTypeCryoNade.uc
Normal file
5
sources/Weapons/Playable/Grenades/NiceDamTypeCryoNade.uc
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class NiceDamTypeCryoNade extends NiceWeaponDamageType
|
||||
abstract;
|
||||
defaultproperties
|
||||
{
freezePower=200.000000
|
||||
}
|
||||
28
sources/Weapons/Playable/Grenades/NiceDamTypeEnforcerNade.uc
Normal file
28
sources/Weapons/Playable/Grenades/NiceDamTypeEnforcerNade.uc
Normal 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
|
||||
}
|
||||
|
|
@ -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)."
|
||||
}
|
||||
166
sources/Weapons/Playable/Grenades/NiceMedicNade.uc
Normal file
166
sources/Weapons/Playable/Grenades/NiceMedicNade.uc
Normal 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
|
||||
}
|
||||
158
sources/Weapons/Playable/Grenades/NiceMedicNadePoison.uc
Normal file
158
sources/Weapons/Playable/Grenades/NiceMedicNadePoison.uc
Normal 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
|
||||
}
|
||||
91
sources/Weapons/Playable/Grenades/NiceNade.uc
Normal file
91
sources/Weapons/Playable/Grenades/NiceNade.uc
Normal 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'
|
||||
}
|
||||
22
sources/Weapons/Playable/Grenades/NiceNadeHealing.uc
Normal file
22
sources/Weapons/Playable/Grenades/NiceNadeHealing.uc
Normal 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
|
||||
}
|
||||
22
sources/Weapons/Playable/Grenades/NiceNadeHealingFast.uc
Normal file
22
sources/Weapons/Playable/Grenades/NiceNadeHealingFast.uc
Normal 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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
class NiceWinchesterAmmoPickup extends NiceAmmoPickup;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
AmmoAmount=10
|
||||
InventoryType=Class'NicePack.NiceWinchesterAmmo'
|
||||
PickupMessage=".44 rounds"
|
||||
StaticMesh=None
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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'
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue