Ballistic weapon for KF

Тема в разделе "Мутаторы", создана пользователем AnRouge, 6 мар 2013.

Метки:
  1. STaJIKeR

    STaJIKeR Капо

    Что из выше сказаного не понятно? Мут утерян... Какой спринт?
     
  2. denfil777

    denfil777 Капо

    Утеряна scrn версия.
     
  3. kok-s

    kok-s Консильери

    Да не может быть чтоб не у кого не осталась на компе scrn версия. По любому много кто качал.
     
  4. Titanishu

    Titanishu Бандит

    Ссылка на Beta2 страницей ранее работает, а спринт там есть. Потому и спросил, вот.
     
  5. ЛОХМАТЫЙ

    ЛОХМАТЫЙ •*´¨`*•.,¸¸,.•*´¨`*•.,¸¸,.•*´¨`*•

    А поиск репостов не помогает ?
    Ведь полезные вещи нередко скачивают и выкладывают уже со своего ресурса.
    Не всегда ограничиваются ссылкой на первоисточник.
     
  6. Flame

    Flame -Заслуженый кодер форума-

    Рассказали бы что за спринт. Может мутатор делать то минут 5.
     
    ЛОХМАТЫЙ нравится это.
  7. kok-s

    kok-s Консильери

    Не могу найти, а Beta2 брать как то не хочется.
     
  8. Titanishu

    Titanishu Бандит

    Там есть отображение выносливости, которая тратится на этот спринт. Вызывается, судя по всему, нажатием какой-то кнопки, при этом скорость увеличивается на 35%, каждый тик тратится выносливость. Это я исходя из кода говорю, на деле там может, несколько иначе, но суть именно в том, чтобы по нажатии кнопки увеличивать скорость. В исходниках как минимум Beta2 поиск по слову "sprint" говорит, что оно содержится в трех файлах из пакета KFBCoreV25 - BallisticWeapon, BCReplicationInfo, и BCSprintControl.

    BallisticWeapon:
    Код:
    //=============================================================================
    // BallisticWeapon.
    //
    // A special sub-class of Engine.Weapon, this is to add support for new Ballistic
    // weapon features. These features include:
    //
    // An improved ammo system allowing the use of magazines, reloading, etc.
    //
    // Various fire modes including Semi-Auto, Burst, Full Auto and more that alter
    // how many bullets and how quickly a weapon can refire.
    //
    // A crosshair system allowing the crosshair to change as the weapon is fired.
    //
    // A comprehensive aiming system which alteres accuracy and weapon stability
    // according to player movements and many other factors. Aim is also
    // predictable so that a laser sight could show the exact aim of the weapon.
    // Firing recoil is also included and used interpolation curves and randomness
    // to rotate the aim.
    //
    // Sights or Scopes which can be used to aim precisely. Scopes also have a
    // variable zoom level which can be controlled in several ways.
    //
    // Red and Blue team variants for the weapon skins.
    //
    // by Nolan "Dark Carnivour" Richert.
    // Copyright(c) 2005 RuneStorm. All Rights Reserved.
    //=============================================================================
    class BallisticWeapon extends KFWeapon
        abstract
        config(KFBallisticV25)
        DependsOn(BUtil)
        HideDropDown
        CacheExempt;
    
    // These settings below may look intimidating, but just remember, many of them are
    // internal things that you don't need to worry about and for many others, the defaults
    // will be ok. There are lots of settings just available in case you need to change
    // some behavior.
    
    //General vars ---------------------------------------------------------------------------------------------------------
    struct WeaponSkin
    {
        var() Material  RedTex;     // Texture to use when red
        var() Material  BlueTex;    // Texture to use when blue
        var() int       SkinNum;    // Index in Skins array
    };
    var() float             PlayerSpeedFactor;      // Instigator movement speed is multiplied by this when this weapon is in use
    var   bool              PlayerSpeedUp;          // Player speed has been altered by this weapon
    var() float             PlayerJumpFactor;       // Player JumpZ multiplied by this when holding this weapon
    var() array<WeaponSkin> TeamSkins;              // A list of which skins change to show team colors
    var() Sound             UsedAmbientSound;       // Use this instead of AmbientSound to have gun hum when in use
    var() float             AIReloadTime;           // How long it's likely to take to reload. Used by bots to tell if they should reload
    var   float             BotTryReloadTime;       // Time when bot should try reload again
    var   Vehicle           OwnerLastVehicle;       // Vehicle being driven last tick...
    var   Controller        InstigatorController;   // Controller of the instigator
    var   BallisticFire   BFireMode[NUM_FIRE_MODES];// BallisticFire FireModes. So you don't have to write: BallisticFire(FireMode[m])
    var() Material          BigIconMaterial;        // A big icon for this weapon. Used in outfitting screens
    var() byte              BallisticInventoryGroup;// Normal InventoryGroup is set to this when Ballistic style groupings are used
    var   BCSprintControl   SprintControl;          // A low, poor sort of hack to draw Sprint info on the HUD
    var() float             IdleTweenTime;          // Just a general tween time used by anims like idle
    var   Actor             SightFX;                // SightFX actor
    var() class<Actor>      SightFXClass;           // Effect to attach as an iron sight effect or could be used for anything
    var() name              SightFXBone;            // Bone to attach SightFX to
    var() class<BCReplicationInfo>  BCRepClass;     // BCReplication info class to use for server side variables that are sent to clients
    //----------------------------------------------------------------------------------------------------------------------
    
    //Global configurable settings -----------------------------------------------------------------------------------------
    var() globalconfig bool     bOldCrosshairs;         // Use UT2004 crosshairs instead of BW's
    var() globalconfig bool     bBallisticInvGroups;        // Use ballistic Style Inventory Groups instead of UT2004 similar ones
    var() globalconfig bool     bUseScopeViewAim;       // ViewAimFactor and VViewRecoilFactor are set to 1.0 when in scope view
    var() globalconfig float        ViewAimScale;               // Option for scaling view aim. View aim is applied using this * ViewAimFactor
    var() globalconfig float        ViewRecoilScale;            // Option for scaling view recoil. View aim is applied using this * ViewRecoilFactor
    var() globalconfig float    CrosshairScaleFactor;   // Adjusts how much crosshair is scaled up by recoil and chaos
    var() globalconfig bool     bGlobalCrosshair;           // All Ballistic Weapons use the universal crosshair instead of weapon specific ones
    var() globalconfig bool     bEvenBodyDamage;        // Will weapon limb hits cause as much damage as any non-head body region?...
    var() globalconfig bool     bRandomDamage;          // Allow random weapon damage?, each hit causes a random damage between a min and max range...
    var() globalconfig bool     bUseModifiers;              // Uses configurable modifiers in BallisticInstantFire / BallisticProjectile to handle locational damage
    var()   globalconfig float      AimKnockScale;          // Scale the weapon displacement caused by taking damage
    var() globalconfig bool     bViewDecline;               // Shift view when recoil is declining?
    var() globalconfig bool     bDrawSimpleCrosshair; //Draw descriptive crosshairs?
    var()   globalconfig bool       bDrawCrosshairDot;      //Dot in middle of simple crosshairs
    var() globalconfig bool     bManualReload;      //ScrnBalance Compat setting
    //----------------------------------------------------------------------------------------------------------------------
    
    //Special weapon info vars ---------------------------------------------------------------------------------------------
    var() config float      WeaponPrice;                    // Cash cost to buy the weapon
    var() config float      PrimaryAmmoPrice;           // Cost to fill primary fm ammo
    var() config float      SecondaryAmmoPrice;     // Cost to fill secondary fm ammo
    var() int               InventorySize;                      // How much space this weapon should occupy in an inventory. 0-100. Used by mutators, games, etc...
    
    // Flags to try and describe the weapons or its capabilities. Use for mutators, AI, anything that needs to try just types of weapons
    var() bool      bWT_Bullet;                         // Some kind of bullets
    var() bool      bWT_Shotgun;                            // Its a shotgun
    var() bool      bWT_Hazardous;                      // It is dangerous to the user (if not used carefully)
    var() bool      bWT_Splash;                         // Has large radius damage attacks
    var() bool      bWT_Sidearm;                            // A small light sidearm type weapon
    var() bool      bWT_Machinegun;                 // A fairly automatic non-proj pistol, smg, ar, mg, minigun, etc
    var() bool      bWT_RapidProj;                      // A fairly automatic projectile weapon
    var() bool      bWT_Projectile;                     // Has non-instant non-rapid projectile attack
    var() bool      bWT_Grenade;                            // Has non-instant bouncing grenade type projectiles
    var() bool      bWT_Energy;                         // Energy attack
    var() bool      bWT_Super;                          // Is considered a 'super weapon' or more powerful than normal weapons. Ballistic Freon won't resupply weapons with this bool set.
    var() bool      bWT_Trap;                               // Some kind of wierd or deployable weapon. eg. mine, bomb, beartrap, etc
    
    // Special weapon info that could be set from anywhere if needed
    struct SpecialInfoEntry
    {
        var() name      ID;
        var() string    Info;
    };
    var() config array<SpecialInfoEntry>    SpecialInfo; // A list of special info strings and their IDs
    //----------------------------------------------------------------------------------------------------------------------
    
    //Ammo/Reloading Stuff -------------------------------------------------------------------------------------------------
    enum EReloadState
    {
        RS_None,            //Not reloading or cocking. Used as default as well as after reload finishes
        RS_PreClipOut,      //Reload just started. Clip still in gun
        RS_PreClipIn,       //Clip pulled. New clip coming up
        RS_PostClipIn,      //New clip in. From here it either goes to ready or cocking
        RS_StartShovel,     //Pre shovel loop
        RS_Shovel,          //Busy shovelling shells. Either pushing shell toward gun or retracting hand to get another one
        RS_PostShellIn,     //Shell just gone in. Decide to either go for another one or stop reloading and go to EndShovel
        RS_EndShovel,       //Shovel loop finished. Hand moving back to handle or whatever
        RS_Cocking          //Gun being cocked. Ready after this
    };
    var() BUtil.FullSound   BringUpSound;       //Sound to play when weapon is brough out
    var() BUtil.FullSound   PutDownSound;       //Sound to play when weapon is put away
    var() bool              bNoMag;             //Does not use reloading. Takes ammo straight from inventory
    var() Name              CockAnim;           //Animation to use for cocking
    var() Name              CockAnimPostReload; //Anim to use for cocking at end of reload
    var() float             CockAnimRate;       //Rate to play cock anim at
    var() BUtil.FullSound   CockSound;          //Sound to play for cocking
    var() BUtil.FullSound   ClipHitSound;       //Sound to play when clip gets hit
    var() BUtil.FullSound   ClipOutSound;       //Sound to play when clip is pulled out
    var() BUtil.FullSound   ClipInSound;        //Sound to play when clip is put in
    var() float             ClipInFrame;        //RED! Frame at which clip is put in. Also frame of shovel loop when shell is placed in
    var() bool              bCockAfterReload;   //Always cock the gun after reload
    var() bool              bCockOnEmpty;       //Gun will cock when reload ends if mag was empty before reload
    var   bool              bNeedReload;        //Gun needs to be reloaded. When on, pressing fire will start a reload
    var   bool              bNeedCock;          //Gun needs to be cocked. Will be cocked when reload ends
    var   bool              bPreventReload;     //Reload will not start. Used to prevent reloading while fire anim plays
    var() bool              bNonCocking;        //Gun doesn't, can't or shouldn't get cocked...
    var() bool              bCanSkipReload;     //Can press fire to exit reloading from shovel loop or PreClipIn
    var() bool              bAltTriggerReload;  //Pressing alt fire triggers reload/skip/cock just like primary.
    var() bool              bShovelLoad;        //Ammo is loaded into gun repeatedly, e.g. the loading of a winchester or pump-action shotgun
    var() Name              StartShovelAnim;    //Played before shoveling loop starts
    var() float             StartShovelAnimRate;//Rate for start anim
    var() Name              EndShovelAnim;      //Anim to play after shovel loop ends
    var() float             EndShovelAnimRate;  //Rate for end anim
    var() int                   ShovelIncrement;    //Amount of ammo to stick in gun each time
    var   EReloadState  ReloadState;        //State of the gun during reloading or cocking. Set seperately on client and server
    var   bool              bServerReloading;   //Used to let clients know that server side is still reloading
    struct WeaponModeType   //All the settings for a weapon firing mode
    {
        var() localized string ModeName;//Display name for this mode
        var() bool bUnavailable;        //Is it disabled and hidden(not in use)
        var() string ModeID;            //A non localized ID to easily identify this mode. Format: WM_????????, e.g. WM_FullAuto or WM_Burst
        var() float Value;              //Just a useful extra numerical value. Could be max count for burst mode or whatever...
    };
    var() Array<WeaponModeType> WeaponModes;    //A list of the available weapon firing modes and their info for this weapon
    var() byte              CurrentWeaponMode;  //The index of the firing mode currently active
    var   int               FireCount;          //How many shots have been fired since trigger was pulled
    //----------------------------------------------------------------------------------------------------------------------
    
    // Scope and Sights stuff ----------------------------------------------------------------------------------------------
    var() bool              bUseSights;         // This weapon has sights or a scope that can be used
    var() globalconfig bool bPlayScopeUp;           //Do scope up after cocking, long gun and reloading - Azarael
    var() bool              bNoTweenToScope;            //Don't tween to the first idle frame to fix the animation jump (M75 fix)
    var() config float      ScopeXScale;            //Manual scaling for scopes
    var() globalconfig bool bInvertScope;       // Inverts Prev/Next weap relation to Zoom In/Out
    var() name              ZoomInAnim;         // Anim to play for raising weapon to view through Scope or sights
    var() name              ZoomOutAnim;        // Anim to play when lowering weapon after viewing through scope or sights
    var() Texture           ScopeViewTex;       // Texture displayed in Scope View. Fills the screen
    var() BUtil.FullSound   ZoomInSound;        // Sound when zooming in
    var() BUtil.FullSound   ZoomOutSound;       // Sound when zooming out
    var() float             FullZoomFOV;        // The FOV that can be reached when fully zoomed in
    var() bool              bNoMeshInScope;     // Weapon mesh is hidden when in scope/sight view
    var() bool              bSmoothZoom;        // Use smooth zooming (Hold scope key to zoom in, release to stop zooming)
    var() bool              bNoCrosshairInScope;// Crosshair will be hiden when in scope or sights
    var() int               SightZoomFactor; // (90 - this) gives the FOV of ironsight zoom
    var() name              SightBone;          // Bone at which camera should be to view through sights. Uses origin if none
    var() Rotator           SightPivot;         // Rotate the weapon by this when in sight view
    var() Vector            SightOffset;        // Offset of actual sight view position from SightBone or mesh origin.
    var() float             SightDisplayFOV;    // DisplayFOV for drawing gun in scope/sight view
    var() float             SightingTime;       // Time it takes to move weapon to and from sight view
    var() globalconfig float SightingTimeScale; // Scales the SightingTime for each weapon by this amount.
    var   float             OldZoomFOV;         // FOV saved for temporary scope down
    var   float             SightingPhase;      // Current level of progress moving weapon into place for sight view
    var   bool              bPendingSightUp;    // Currently out of sight view for something. Will go back when done
    var   bool              bScopeView;         // Currently viewing through scope or sights
    var   bool              bScopeHeld;         // Scope key has not been released(Its being held down)
    var   float             NextCheckScopeTime; // Used to prevent CheckScope() from exiting scope view for a period of time (eg. Prevent RG recoil from cutting scope view)
    
    enum ESightingState
    {
        SS_None,            //Not viewing through sights or moving gun into sight postions
        SS_Lowering,        //Finished sight view, lowering un
        SS_Raising,         //Lifting gun and getting to sight view
        SS_Active           //Looking through sights
    };
    var   ESightingState    SightingState;      // State of non anim, sight related gun movement
    //----------------------------------------------------------------------------------------------------------------------
    
    // Crosshair Info ------------------------------------------------------------------------------------------------------
    struct BWCrosshairCfg   // Configurable crosshair settings
    {
        var() Material  Pic1, Pic2;             // Crosshair Materials
        var() int       USize1, VSize1;         // Sizes of crosshair materials
        var() int       USize2, VSize2;         // Sizes of crosshair materials
        var() Color     Color1, Color2;         // Color of each crosshair part
        var() int       StartSize1, StartSize2; // Minimum / Starting size of crosshairs
    };
    struct BWCrosshairInfo  // Settings for crosshair behavior
    {
        var()    FloatBox   SpreadRatios;   // How much CurrentScale is applied to crosshairs in each dimension
        var()    FloatBox   SizeFactors;    // X and Y Size factors for the crosshairs
        var()    float      MaxScale;       // Maximum Scale
        var      float      CurrentScale;   // Current Scale (changes to show chaos and recoil)
    };
    var()   config  BWCrosshairCfg   CrosshairCfg;  // Configurable crosshair settings
    var()   config  BWCrosshairInfo CrosshairInfo;  // Weapon specific Crosshair settings
    var   float         CrosshairScale;                 // HUD scales crosshair by this
    var() float         CrosshairChaosFactor;           //How much crosshair size is affected by chaos. 0=none, 1=full chaos is max crosshairsize
    //----------------------------------------------------------------------------------------------------------------------
    
    // Aim Stuff -----------------------------------------------------------------------------------------------------------
    // This is the eccessivly complicated aiming system.
    // Basically, a Rotator(Aim) and rotator generated from the recoil are used to offset the gun from the player's view.
    // Aim is the base aim of the gun. Aim is interpolated randomly, within the ranges set by AimSpread. AimAdjustTime is
    // used to set how long it takes to shift. Aim only changes when the player turns of moves.
    //
    // Chaos is applied when the player moves, jumps, turns, etc and greatly ruins a players ability to aim accurately. The
    // faster and more wildly the player moves, the more chaos is aplied to the weapon. When no chaos is applied the Aim will be
    // randomly interpolated whithin the ranges set by AimSpread. When full chaos is applied, the Aim uses the ranges set
    // by ChaosAimSpread. AimSpread ranges can be used as a minimum spread and ChaosAimSpread as the maximum spread. Aim
    // spread is adjusted smoothly between AimSpread and ChaosAimSpread depedning on chaos level.
    //
    // Recoil is added each shot and declines each tick(). Recoil is seperate from the base aim and makes the weapon inaccurate
    // from firing. Crouching reduces the rate of increase of recoil. How recoil affects the weapon depends on 3 factors:
    // Recoil Path Curves:
    //      Yaw and Pitch are applied to the gun through two curves that give the Yaw and Pitch value depending
    //      the amount of recoil. These curves can be altered to steer the gun along winding, curved paths when recoil is applied.
    //      At (In=0,Out=0),(In=1,Out=1) these will do nothing and the Scaling Factors will set a straight recoil path.
    // Recoil Scaling:
    //      RecoilYawFactor and RecoilPitchFactor * Recoil add Yaw and Pitch to the gun. At 1.0, these do nothing and the curves
    //      set how the gun moves with recoil. These can be set to give general scaling to the curves.
    // Recoil Randomness:
    //      RecoilRand(X and Y) * Recoil add Yaw and Pitch randomness to the gun.
    //
    // FireModes have an aditional spread to make bullets vear away from the gun's actual aim. This can be used to make guns
    // seem crap or to make shotgun pellets spread properly.
    //
    struct XYRange
    {
        var() config Range X;
        var() config Range Y;
    };
    // Gun length
    var(BAim) float     GunLength;          // How far weapon extends from player. Used by long-gun check
    var       float     LongGunFactor;      // Current percent of long-gun factors applied. Will be interpolated to NewLongGunFactor
    var       float     NewLongGunFactor;   // What LongGunFactor should be. Set instantly when bumping into obstacles
    var(BAim) rotator   LongGunPivot;       // How to rotate aim and gun at full LongGunFactor
    var(BAim) vector    LongGunOffset;      // How much to offset weapon position at full LongGunFactor
    // General
    var(BAim) bool      bAimDisabled;       // Disables the entire aiming system. Bullets go exactly where crosshair is aimed.
    var(BAim) bool      bUseNetAim;         // Aim info is replicated to clients. Otherwise client and server aim will be seperate
    var(BAim) bool      bAlwaysUseNetAim;   // Always use replicated aim info (used for high-recoil accurately hipfiring weapons)
    var(BAim) bool      bUseSpecialAim;     // Firemodes will use GetPlayerAim instead of normal AdjustAim. Used for autotracking and other special aiming functions
    var(BAim) float     CrouchAimFactor;    // Aim recoil and wildness will be mutiplied by this when crouched
    var(BAim) float     SightAimFactor;     // Recoil and aim is multiplied by this when in sights or scope
    var(BAim) Rotator   SprintOffSet;       // Rotation applied to AimOffset when sprinting
    var(BAim) Rotator   JumpOffSet;         // Temporarily offset aim by this when jumping
    var(BAim) float     JumpChaos;          // Chaos applied for jump event
    var(BAim) float     FallingChaos;       // Chaos applied when falling
    var(BAim) float     SprintChaos;        // Chaos applied for sprint event
    var       bool      bForceReaim;        // Another Reaim event will be forced after current one completes
    var    bool     bForceRecoilUpdate; // Forces ApplyAimToView to calculate recoil (set after ReceiveNetRecoil)
    //Base aiming.
    var(BAim) float     AimAdjustTime;      // Time it should take to move aim pointer to new random aim when view moves
    var(BAim) XYRange   AimSpread;          // How far aim can be from crosshair(rotator units)
    var(BAim) float     ViewAimFactor;      // How much of the Aim is applied to the player's view rotation. 0.0 - 1.0
    var(BAim) float     ViewRecoilFactor;   // How much of the recoil is applied to the player's view rotation. 0.0 - 1.0
    var       float     ReaimTime;          // Time it should take to move aim pointer to new position
    var    Rotator  ViewAim;            // Aim saved between ApplyAimToView calls, used to find delta aim
    var    Rotator   ViewRecoil;            // Recoil saved between ApplyAimToView calls, used to find delta recoil
    var       Rotator   Aim;                // How far aim pointer is from crosshair
    var       Rotator   NewAim;             // New destination for aim pointer
    var       Rotator   OldAim;             // Where aim poitner was before it started moving
    var       float     ReaimPhase;         // How far along pointer is in its movement from old to new
    var       bool      bReaiming;          // Is the pointer being reaimed?
    var       Rotator   AimOffset;          // Extra Aim offset. Set NewAimOffset and AimOffsetTime to have this move smoothly
    var       Rotator   NewAimOffset;       // This is what AimOffset should be and is adjusted for sprinting and so on
    var       Rotator   OldAimOffset;       // AimOffset before it started shifting. Used for interpolationg AimOffset
    var       float     AimOffsetTime;      // Time when AimOffset should reach NewAimOffset. Used for interpolating AimOffset
    var(BAim) float     AimDamageThreshold; // Damage done to player is divided by this to calculate chaos added from being damaged
    // Chaos, Wildness
    var(BAim) float     ChaosDeclineTime;   // Time it take for chaos to decline from 1 to 0
    var(BAim) float     ChaosTurnThreshold; // Speed(Rotator units per second) of view rotation required to reach full chaos.
    var(BAim) float     ChaosSpeedThreshold;// Player speed divided by this to set chaos. <100=Very High Spread, 500=Average, >500 Good Spread.
    var(BAim) XYRange   ChaosAimSpread;     // How far aim can be from crosshair when full chaos is applied(rotator units)
    var       float     Chaos;              // The amount of chaos to be applied to aiming. 0=No Chaos, best aim.1=Full Chaos, Worst aim
    var       float     NewChaos;           // The Chaos when reaim started. Used for crosshair interpolation.
    var       float     OldChaos;           // The NewChaos from the previous reaim
    var       Rotator   OldLookDir;         // Where player was looking last tick. Used to check if player view changed
    // Recoil
    var(BAim) InterpCurve RecoilXCurve;     // Curve used to apply Yaw according to recoil amount.
    var(BAim) InterpCurve RecoilYCurve;     // Curve used to apply Pitch according to recoil amount.
    var(BAim) float     RecoilPitchFactor;  // Recoil is multiplied by this and added to Aim Pitch.
    var(BAim) float     RecoilYawFactor;    // Recoil is multiplied by this and added to Aim Yaw.
    var(BAim) float     RecoilXFactor;      // Recoil multiplied by this for recoil Yaw randomness
    var(BAim) float     RecoilYFactor;      // Recoil multiplied by this for recoil Pitch randomness
    var(BAim) float     RecoilMax;          // The maximum recoil amount
    var(BAim) float     RecoilDeclineTime;  // Time it takes for Recoil to decline maximum to zero
    var       float     RecoilXRand;        // Random between 0 and 1. Recorded random number for recoil Yaw randomness
    var       float     RecoilYRand;        // Random between 0 and 1. Recorded random number for recoil Pitch randomness
    var       float     Recoil;             // The current recoil amount. Increases each shot, decreases when not firing
    var(BAim) float     RecoilDeclineDelay; // The time between firing and when recoil should start decaying
    var       float     LastFireTime;       // Time of last fire
    var       float     NextZeroAimTime;    //For zeroing aim when scoping
    var       bool      bPendingBringupTimer;
    //----------------------------------------------------------------------------------------------------------------------
    
    // Preloading Stuff -----------------------------------------------------------------------------------------------------------
    struct WeaponSkinRef
    {
        var() string 	RedTex;     // Texture to use when red
        var() string  	BlueTex;    // Texture to use when blue
        var() int       SkinNum;    // Index in Skins array
    };
    var() 	array<WeaponSkinRef> TeamSkinRefs;
    var()	string			  BringUpSoundRef;
    var()	string			  PutDownSoundRef;
    var()	string			  CockSoundRef;
    var()	string			  ClipHitSoundRef;
    var()	string			  ClipOutSoundRef;
    var()	string			  ClipInSoundRef;
    var()	string			  ZoomInSoundRef;
    var()	string			  ZoomOutSoundRef;
    var()	string			  UsedAmbientSoundRef;
    var()	string			  BigIconMaterialRef;
    var()	string			  ScopeViewTexRef;
    //----------------------------------------------------------------------------------------------------------------------
    
    replication
    {
        // Things the server should send to the client.
        unreliable if( bNetOwner && bNetDirty && (Role==ROLE_Authority) )
            CurrentWeaponMode;
    
        // Things the server should send to the client.
        reliable if( bNetOwner && bNetDirty && (Role==ROLE_Authority) )
            bServerReloading;
    
        // Things the server should send to the client.
    //  reliable if (bNetInitial && Role==ROLE_Authority)
    //      AccuracyScale, RecoilScale, bNoJumpOffset, bNoLongGun, bNoReloading;
    
        // functions on server, called by client
        reliable if( Role<ROLE_Authority )
            ServerReloadRelease, ServerStartReload, ServerSwitchWeaponMode, ServerSkipReload, ServerWeaponSpecial,
            ServerWeaponSpecialRelease, ServerCockGun, ServerSetScopeView, ServerSetViewAimScale, ServerStopReload;
    
        // functions on client, called by server
        reliable if( Role==ROLE_Authority )
            Reload, ClientReloadRelease, ClientStartReload, ReceiveNewAim, ClientWeaponSpecial, ClientWeaponSpecialRelease,
            ReceiveNetRecoil, ClientJumped, ClientPlayerDamaged, ClientScopeDown, ClientJamMode, ClientCockGun, ClientInitWeaponFromTurret;
    }
    
    //Preloading -------------------------------------------------------------------------------------------------------------
    
    //Thank you Epic for making UE2 have wierd memory limits
    static function PreloadAssets(Inventory Inv, optional bool bSkipRefCount)
    {
    	local byte i;
    
    	for ( i = 0; i < default.TeamSkinRefs.Length; i++ )
    	{
    		default.TeamSkins[i].RedTex = Texture(DynamicLoadObject(default.TeamSkinRefs[i].RedTex, class'Texture', true));
    		default.TeamSkins[i].BlueTex = Texture(DynamicLoadObject(default.TeamSkinRefs[i].BlueTex, class'Texture', true));
    		default.TeamSkins[i].SkinNum = default.TeamSkinRefs[i].SkinNum;
    	}
    	
    	default.BringUpSound.Sound = Sound(DynamicLoadObject(default.BringUpSoundRef, class'Sound', true));
    	default.PutDownSound.Sound = Sound(DynamicLoadObject(default.PutDownSoundRef, class'Sound', true));
    	default.CockSound.Sound = Sound(DynamicLoadObject(default.CockSoundRef, class'Sound', true));
    	default.ClipHitSound.Sound = Sound(DynamicLoadObject(default.ClipHitSoundRef, class'Sound', true));
    	default.ClipOutSound.Sound = Sound(DynamicLoadObject(default.ClipOutSoundRef, class'Sound', true));
    	default.ClipInSound.Sound = Sound(DynamicLoadObject(default.ClipInSoundRef, class'Sound', true));
    	default.ZoomInSound.Sound = Sound(DynamicLoadObject(default.ZoomInSoundRef, class'Sound', true));
    	default.ZoomOutSound.Sound = Sound(DynamicLoadObject(default.ZoomOutSoundRef, class'Sound', true));
    	default.UsedAmbientSound = Sound(DynamicLoadObject(default.UsedAmbientSoundRef, class'Sound', true));
    	
    	default.BigIconMaterial = Texture(DynamicLoadObject(default.BigIconMaterialRef, class'Texture', true));
    	default.ScopeViewTex = Texture(DynamicLoadObject(default.ScopeViewTexRef, class'Texture', true));
    	
    	if ( BallisticWeapon(Inv) != none )
    	{
    		BallisticWeapon(Inv).BringUpSound.Sound = default.BringUpSound.Sound;
    		BallisticWeapon(Inv).PutDownSound.Sound = default.PutDownSound.Sound;
    		BallisticWeapon(Inv).CockSound.Sound = default.CockSound.Sound;
    		BallisticWeapon(Inv).ClipHitSound.Sound = default.ClipHitSound.Sound;
    		BallisticWeapon(Inv).ClipOutSound.Sound = default.ClipOutSound.Sound;
    		BallisticWeapon(Inv).ClipInSound.Sound = default.ClipInSound.Sound;
    		BallisticWeapon(Inv).ZoomInSound.Sound = default.ZoomInSound.Sound;
    		BallisticWeapon(Inv).ZoomOutSound.Sound = default.ZoomOutSound.Sound;
    		BallisticWeapon(Inv).UsedAmbientSound = default.UsedAmbientSound;
    		BallisticWeapon(Inv).BigIconMaterial = default.BigIconMaterial;
    		BallisticWeapon(Inv).ScopeViewTex = default.ScopeViewTex;
    		
    		for ( i = 0; i < default.TeamSkinRefs.Length; i++ )
    		{
    			BallisticWeapon(Inv).TeamSkins[i].RedTex = default.TeamSkins[i].RedTex;
    			BallisticWeapon(Inv).TeamSkins[i].BlueTex = default.TeamSkins[i].BlueTex;
    			BallisticWeapon(Inv).TeamSkins[i].SkinNum = default.TeamSkins[i].SkinNum;
    		}
    	}
    	
    	Super.PreloadAssets(Inv, bSkipRefCount);
    }
    
    static function bool UnloadAssets()
    {
    	local byte i;
    
    	for ( i = 0; i < default.TeamSkinRefs.Length; i++ )
    	{
    		default.TeamSkins[i].RedTex = None;
    		default.TeamSkins[i].BlueTex = None;
    	}
    	
    	default.BringUpSound.Sound = None;
    	default.PutDownSound.Sound = None;
    	default.CockSound.Sound = None;
    	default.ClipHitSound.Sound = None;
    	default.ClipOutSound.Sound = None;
    	default.ClipInSound.Sound = None;
    	default.ZoomInSound.Sound = None;
    	default.ZoomOutSound.Sound = None;
    	default.UsedAmbientSound = None;
    	
    	default.BigIconMaterial = None;
    	default.ScopeViewTex = None;
    	
    	return Super.UnloadAssets();
    }
    
    //The Core -------------------------------------------------------------------------------------------------------------
    
    // These functions can be used to safely play anims and avoid disrupting anims that are essential to timing or reload state
    simulated function bool SafePlayAnim (name Sequence, optional float Rate, optional float TweenTime, optional int Channel, optional string AnimID)
    { if (!CanPlayAnim(Sequence, Channel, AnimID)) return false; return PlayAnim (Sequence, Rate, TweenTime, Channel); }
    simulated function bool SafeLoopAnim (name Sequence, optional float Rate, optional float TweenTime, optional int Channel, optional string AnimID)
    { if (!CanPlayAnim(Sequence, Channel, AnimID)) return false; return LoopAnim (Sequence, Rate, TweenTime, Channel); }
    simulated function bool SafeTweenAnim (name Sequence, float Time, optional int Channel, optional string AnimID)
    { if (!CanPlayAnim(Sequence, Channel, AnimID)) return false; return TweenAnim (Sequence, Time, Channel); }
    
    // This should be expanded in subclasses if needed
    simulated function bool CanPlayAnim (name Sequence, optional int Channel, optional string AnimID)
    {
        if (ReloadState != RS_None && AnimID != "RELOAD")
            return false;
        return true;
    }
    
    // Quick shortcut...
    final simulated function vector ViewAlignedOffset (vector Offset) { return class'BUtil'.static.ViewAlignedOffset(self, Offset); }
    
    // Set a few things...
    simulated function PostBeginPlay()
    {
        local int m;
    
        Super(Weapon).PostBeginPlay();
    
        SightingTime = Default.SightingTime*Default.SightingTimeScale;
        if (bBallisticInvGroups && BallisticInventoryGroup != 254)
            InventoryGroup = BallisticInventoryGroup;
        for (m = 0; m < NUM_FIRE_MODES; m++)
            if (FireMode[m] != None && BallisticFire(FireMode[m]) != None)
                BFireMode[m] = BallisticFire(FireMode[m]);
                
        InitFOV();
    }
    static final operator(34) Range *= (out Range A, float B)
    {
        A.Min *= B;
        A.Max *= B;
        return A;
    }
    static final operator(34) XYRange *= (out XYRange A, float B)
    {
        A.X *= B;
        A.Y *= B;
        return A;
    }
    static final operator(34) Range /= (out Range A, float B)
    {
        A.Min /= B;
        A.Max /= B;
        return A;
    }
    static final operator(34) XYRange /= (out XYRange A, float B)
    {
        A.X /= B;
        A.Y /= B;
        return A;
    }
    
    // Apply accuracy scale and send client's view aim info to server
    // Disable first cock if necessary
    // Increase reloading speed if set
    // Bots don't use the aim system
    simulated function PostNetBeginPlay()
    {
        Super(Weapon).PostNetBeginPlay();
    
        if (BCRepClass.default.bNoReloading)
            bNoMag = true;
        if (BCRepClass.default.bNoFirstCock)
            bNeedCock = False;
        if (BCRepClass.default.bLockRecoil)
        {
            ViewRecoilFactor = 1;
            default.ViewRecoilFactor = 1;
        }
        
        if (BCRepClass.default.ReloadSpeedScale != 1)
        {
            CockAnimRate *= BCRepClass.default.ReloadSpeedScale;
            ReloadAnimRate *= BCRepClass.default.ReloadSpeedScale;
            StartShovelAnimRate *= BCRepClass.default.ReloadSpeedScale;
            EndShovelAnimRate *= BCRepClass.default.ReloadSpeedScale;
        }
        
        if (BCRepClass.default.AccuracyScale != 1)
        {
            ChaosAimSpread *= BCRepClass.default.AccuracyScale;
            AimSpread *= BCRepClass.default.AccuracyScale;
            default.AimSpread = AimSpread;
        }
        
        if(Pawn(Owner) != None && AIController(Pawn(Owner).Controller) != None)
            bAimDisabled=True;
        
        if (RecoilDeclineDelay < 0.1)
            RecoilDeclineDelay=0.1;
    
        if (level.NetMode == NM_Client)
            ServerSetViewAimScale(ViewAimScale*255, ViewRecoilScale*255, bUseScopeViewAim);
    }
    function ServerSetViewAimScale(byte NewAimScale, byte NewRecoilScale, bool NewScopeViewAim) {   ViewAimScale = float(NewAimScale)/255;  ViewRecoilScale = float(NewRecoilScale)/255;    bUseScopeViewAim = NewScopeViewAim; }
    
    simulated function AnimEnded (int Channel, name anim, float frame, float rate)
    {
        if (Anim == ZoomInAnim)
        {
            ScopeUpAnimEnd();
            return;
        }
        else if (Anim == ZoomOutAnim)
        {
            ScopeDownAnimEnd();
            return;
        }
    
        if (anim == FireMode[0].FireAnim || (FireMode[1] != None && anim == FireMode[1].FireAnim))
            bPreventReload=false;
    
        // Modified stuff from Engine.Weapon
        if (ClientState == WS_ReadyToFire && ReloadState == RS_None)
        {
            if (anim == FireMode[0].FireAnim && HasAnim(FireMode[0].FireEndAnim)) // rocket hack
                SafePlayAnim(FireMode[0].FireEndAnim, FireMode[0].FireEndAnimRate, 0.0);
            else if (FireMode[1]!=None && anim== FireMode[1].FireAnim && HasAnim(FireMode[1].FireEndAnim))
                SafePlayAnim(FireMode[1].FireEndAnim, FireMode[1].FireEndAnimRate, 0.0);
            else if ((FireMode[0] == None || !FireMode[0].bIsFiring) && (FireMode[1] == None || !FireMode[1].bIsFiring))
            {
                bPreventReload=false;
                PlayIdle();
            }
        }
        // End stuff from Engine.Weapon
    
        // Start Shovel ended, move on to Shovel loop
        if (ReloadState == RS_StartShovel)
        {
            ReloadState = RS_Shovel;
            PlayShovelLoop();
            return;
        }
        // Shovel loop ended, start it again
        if (ReloadState == RS_PostShellIn)
        {
            if (MagAmmoRemaining >= MagCapacity || Ammo[0].AmmoAmount < 1)
            {
                PlayShovelEnd();
                ReloadState = RS_EndShovel;
                return;
            }
            ReloadState = RS_Shovel;
            PlayShovelLoop();
            return;
        }
        // End of reloading, either cock the gun or go to idle
        if (ReloadState == RS_PostClipIn || ReloadState == RS_EndShovel)
        {		
            if (bNeedCock && MagAmmoRemaining > 0)
                CommonCockGun();
            else
            {
                bNeedCock=false;
                ReloadState = RS_None;
                ReloadFinished();
                PlayIdle();
                ReAim(0.05);
            }
            return;
        }
        //Cock anim ended, goto idle
        if (ReloadState == RS_Cocking)
        {
            ReloadState = RS_None;
            ReloadFinished();
            PlayIdle();
            ReAim(0.05);
        }
    
    }
    // On the server, this adjusts anims, ammo and such. On clients it only adjusts anims.
    simulated event AnimEnd (int Channel)
    {
        local name anim;
        local float frame, rate;
    
        GetAnimParams(Channel, anim, frame, rate);
    
        AnimEnded(Channel, anim, frame, rate);
    }
    
    simulated function float GetModifiedJumpZ(Pawn P)
    {
        return P.JumpZ * PlayerJumpFactor;
    }
    
    simulated function PlayerEnteredVehicle(Vehicle V)
    {
        if (Role == ROLE_Authority)
            bServerReloading=false;
        ReloadState = RS_None;
        PlayIdle();
    
        if (bOldCrosshairs)
            return;
        if (PlayerController(InstigatorController)!=None && PlayerController(InstigatorController).MyHud != None)
            PlayerController(InstigatorController).MyHud.bCrosshairShow = PlayerController(InstigatorController).MyHud.default.bCrosshairShow;
    }
    simulated function PlayerLeftVehicle(Vehicle V)
    {
        if (bOldCrosshairs)
            return;
        if (PlayerController(InstigatorController)!=None && PlayerController(InstigatorController).MyHud != None/* && (CrosshairPic1 != None || CrosshairPic2 != None)*/)
            PlayerController(InstigatorController).MyHud.bCrosshairShow = false;
    }
    
    simulated event Tick(float DT)
    {
        Super(Weapon).Tick(DT);
        
        if ( !bScopeView )
        {
            if( KFHumanPawn(Instigator)!=None )
                KFHumanPawn(Instigator).SetAiming(False);
        }
    
        if (Instigator!= None && Instigator.Weapon == self && OwnerLastVehicle != Instigator.DrivenVehicle )
        {
            if (Instigator.DrivenVehicle != None)
                PlayerEnteredVehicle(Instigator.DrivenVehicle);
            else
                PlayerLeftVehicle(OwnerLastVehicle);
            OwnerLastVehicle = Instigator.DrivenVehicle;
        }
    }
    
    // Check a few things and run the aiming tick
    simulated event WeaponTick(float DT)
    {
        Super(Weapon).WeaponTick(DT);
    
        TickAim(DT);
    
        TickSighting(DT);
    
        if (!BCRepClass.default.bNoLongGun && GunLength > 0)
            TickLongGun(DT);
    
        TickFireCounter(DT);
    
        if (bPreventReload && (!IsFiring()))
            bPreventReload = false;
    
        if (!bNoMag && level.TimeSeconds > BotTryReloadTime && AIController(Instigator.Controller) != None && (!Instigator.Controller.LineOfSightTo(AIController(Instigator.Controller).Enemy)) && BotShouldReload() )
        {
            BotTryReloadTime = level.TimeSeconds + 1.0;
            BotReload();
        }
    }
    
    simulated function TickFireCounter (float DT)
    {
        if (!IsFiring() && FireCount > 0)
            FireCount = 0;
    }
    
    // Notify functions ---------------------------------
    // These are used to time lots of reloading stuff
    
    // Animation notify for when a shell is loaded in
    simulated function Notify_ShellIn()
    {
        local float BotSafety;
        local int AmmoNeeded;
    
        if (ReloadState == RS_Shovel)
        {
            ReloadState = RS_PostShellIn;
            AddReloadedAmmo();
            if( Level.NetMode!=NM_Client ){
                Instigator.SetAnimAction(WeaponReloadAnim);
            }
            PlayOwnedSound(ClipInSound.Sound,ClipInSound.Slot,ClipInSound.Volume,ClipInSound.bNoOverride,ClipInSound.Radius,ClipInSound.Pitch,ClipInSound.bAtten);
            // A bot will stop reloading if they feel unsafe. Dumb ones will do this less
            if (AIController(Instigator.Controller) != None && MagAmmoRemaining > 0 && AIController(Instigator.Controller).Enemy != None)
            {
                BotSafety = FMin( Level.TimeSeconds - Instigator.LastPainTime, VSize(Instigator.Location - AIController(Instigator.Controller).Enemy.Location)/200 );
                if (AIController(Instigator.Controller).Skill + FRand()*2 > BotSafety)
                    SkipReload();
            }
        }
    }
    // Animation notify for when the clip is stuck in
    simulated function Notify_ClipIn()
    {
        local int AmmoNeeded;
    
        if (ReloadState == RS_None)
            return;
        ReloadState = RS_PostClipIn;
        AddReloadedAmmo();
    	PlayOwnedSound(ClipInSound.Sound,ClipInSound.Slot,ClipInSound.Volume,ClipInSound.bNoOverride,ClipInSound.Radius,ClipInSound.Pitch,ClipInSound.bAtten);
    }
    // Animation notify for when the clip is pulled out
    simulated function Notify_ClipOut()
    {
        if (ReloadState == RS_None)
            return;
        ReloadState = RS_PreClipIn;
        PlayOwnedSound(ClipOutSound.Sound,ClipOutSound.Slot,ClipOutSound.Volume,ClipOutSound.bNoOverride,ClipOutSound.Radius,ClipOutSound.Pitch,ClipOutSound.bAtten);
    }
    // Animation notify for when cocking action starts. Used to time sounds
    simulated function Notify_CockStart()
    {
        if (ReloadState == RS_None) return;
        PlayOwnedSound(CockSound.Sound,CockSound.Slot,CockSound.Volume,CockSound.bNoOverride,CockSound.Radius,CockSound.Pitch,CockSound.bAtten);
    }
    // Animation notify for ejecting a cartridge
    simulated function Notify_BrassOut()
    {
        BFireMode[0].EjectBrass();
    }
    // Animation notify to make gun cock after fired
    simulated function Notify_CockAfterFire()
    {
        bPreventReload=false;
        if (bNeedCock && MagAmmoRemaining > 0)
            CommonCockGun(1);
    }
    // Animation notify to make gun cock after reload
    simulated function Notify_CockAfterReload()
    {
        if (bNeedCock && MagAmmoRemaining > 0)
            CommonCockGun(2);
    }
    // Animation notify for when the clip is hit
    simulated function Notify_ClipHit()
    {
        PlayOwnedSound(ClipHitSound.Sound,ClipHitSound.Slot,ClipHitSound.Volume,ClipHitSound.bNoOverride,ClipHitSound.Radius,ClipHitSound.Pitch,ClipHitSound.bAtten);
    }
    // End notify stuff ---------------------------------
    
    // Anim Play functions ------------------------------
    // These are called to play anims and can be overridden in subclasses.
    simulated function PlayIdle()
    {
        if (IsFiring())
            return;
        if (bPendingSightUp && bPlayScopeUp)
            ScopeBackUp();
        else if (SightingState != SS_None)
        {
            if (SafePlayAnim(IdleAnim, 1.0))
                FreezeAnimAt(0.0);
        }
        else if (bScopeView)
        {
            if(SafePlayAnim(ZoomOutAnim, 1.0))
                FreezeAnimAt(0.0);
        }
        else
            SafeLoopAnim(IdleAnim, IdleAnimRate, IdleTweenTime, ,"IDLE");
    }
    simulated function PlayReload()
    {
        if (bShovelLoad)
            SafePlayAnim(StartShovelAnim, StartShovelAnimRate, , 0, "RELOAD");
        else
            SafePlayAnim(ReloadAnim, ReloadAnimRate, , 0, "RELOAD");
    }
    simulated function PlayShovelEnd()
    {
        SafePlayAnim(EndShovelAnim, EndShovelAnimRate, 0.1, ,"RELOAD");
    }
    simulated function PlayShovelLoop()
    {
        SafePlayAnim(ReloadAnim, ReloadAnimRate, 0.0, , "RELOAD");
    }
    simulated function PlayCocking(optional byte Type)
    {
        if (Type == 2 && HasAnim(CockAnimPostReload))
            SafePlayAnim(CockAnimPostReload, CockAnimRate, 0.2, , "RELOAD");
        else
            SafePlayAnim(CockAnim, CockAnimRate, 0.2, , "RELOAD");
    
    //  if ((SightingState != SS_None || bScopeView) && Instigator.IsLocallyControlled())
        if (SightingState != SS_None)
            TemporaryScopeDown(Default.SightingTime*Default.SightingTimeScale);
    }
    // End Play funcs -----------------------------------
    
    simulated function ClientJamMode(byte Mode)
    {
        if (level.NetMode == NM_Client)
            BFireMode[Mode].DoJam();
    }
    
    // Called when reloading sequence ends. (sequence includes cocking)
    simulated function ReloadFinished()
    {
        if (Role == ROLE_Authority)
            bServerReloading=false;
        if (BFireMode[0] != None)
            BFireMode[0].WeaponReloaded();
        if (BFireMode[1] != None)
            BFireMode[1].WeaponReloaded();
    }
    
    // Returns true if gun will need reloading after a certain amount of ammo is consumed. Subclass for special stuff
    simulated function bool MayNeedReload(byte Mode, float Load)
    {
        if (!bNoMag && BFireMode[Mode]!= None && BFireMode[Mode].bUseWeaponMag && (MagAmmoRemaining < 1))
            return true;
        return bNeedReload;
    }
    
    simulated function EmptyFire (byte Mode)
    {
        if (bNeedReload && ClientState == WS_ReadyToFire && FireCount < 1 && Instigator.IsLocallyControlled() && !bManualReload)
            ServerStartReload();
    }
    
    // Fire pressed. Change weapon if out of ammo, reload if empty mag or skip reloading if possible
    simulated function FirePressed(float F)
    {
        if (!HasAmmo())
            OutOfAmmo();
        else if (bNeedReload && ClientState == WS_ReadyToFire)
        {
            // Removed and replaced by EmptyFire()
    //      ServerStartReload();
        }
        else if (bCanSkipReload && ((ReloadState == RS_Shovel) || (ReloadState == RS_PostShellIn) || (ReloadState == RS_PreClipOut)))
        {
            ServerSkipReload();
            if (Level.NetMode == NM_Client)
                SkipReload();
        }
        else if (reloadState == RS_None && bNeedCock && MagAmmoRemaining > 0 && !IsFiring() && level.TimeSeconds > FireMode[0].NextfireTime)
        {
            CommonCockGun();
            if (Level.NetMode == NM_Client)
                ServerCockGun();
        }
    }
    
    simulated function Fire(float F)    {   FirePressed(F); }
    simulated function AltFire(float F) {   if (bAltTriggerReload)FirePressed(F);   }
    
    //Skip reloading if fire is pressed in time
    simulated function SkipReload()
    {
        if (ReloadState == RS_Shovel || ReloadState == RS_PostShellIn)
        {//Leave shovel loop and go to EndShovel
            PlayShovelEnd();
            ReloadState = RS_EndShovel;
        }
        else if (ReloadState == RS_PreClipOut)
        {//skip reload if clip has not yet been pulled out
            ReloadState = RS_PostClipIn;
            SetAnimFrame(ClipInFrame);
        }
    }
    function ServerSkipReload() {   SkipReload();   }
    
    function ServerStopReload() {   ReloadState = RS_None;  }
    
    // Scope / Sights view stuff below...
    
    // Scope up anim has ended. Now view through the scope or sights
    simulated function StartScopeView()
    {
        if (bSmoothZoom)
        {
            if (bPendingSightUp)
                PlayerController(Instigator.Controller).DesiredFOV = OldZoomFOV;
            else if (Instigator.Controller.IsA( 'PlayerController' ))
                PlayerController(Instigator.Controller).StartZoomWithMax((PlayerController(Instigator.Controller).DefaultFOV-FullZoomFOV)/88);
        }
        else
            PlayerController(Instigator.Controller).DesiredFOV = FullZoomFOV;
        SetScopeView(true);
        if (ZoomInSound.Sound != None)  class'BUtil'.static.PlayFullSound(self, ZoomInSound);
        if (bPendingSightUp)
            bPendingSightUp=false;
        if (!bNeedCock)
            PlayIdle();
    }
    //Stop viewing through the scope or sights and play scope down anim
    //Azarael - improved ironsights
    simulated function StopScopeView(optional bool bNoAnim)
    {
        OldZoomFOV = PlayerController(Instigator.Controller).FovAngle;
        if (bSmoothZoom || FullZoomFOV <= 50)
        {
            if (Instigator.Controller.IsA( 'PlayerController' ))
                PlayerController(Instigator.Controller).EndZoom();
        }
        SetScopeView(false);
        bAimingRifle=false;
        if( KFHumanPawn(Instigator)!=None )
            KFHumanPawn(Instigator).SetAiming(False);
        if (ZoomOutSound.Sound != None) class'BUtil'.static.PlayFullSound(self, ZoomOutSound);
        PlayScopeDown(bNoAnim);
        Instigator.Controller.bRun = 0;
    }
    // Scope up anim just ended. Either go into scope view or move the scope back down again
    simulated function ScopeUpAnimEnd()
    {
        if (!bUseSights || Instigator.Physics == PHYS_Falling || (SprintControl != None && SprintControl.bSprinting))
        {
            PlayScopeDown();
            return;
        }
        if (bPendingSightUp)
        {
            StartScopeView();
            bPendingSightUp=false;
        }
        else if (bScopeHeld)
        {
            StartScopeView();
            bScopeHeld=false;
        }
        else
            PlayScopeDown();
    }
    // Scope down anim has just ended. Play idle anims like normal
    simulated function ScopeDownAnimEnd()
    {
        if (!bPendingSightUp)
            PlayIdle();
    }
    // Play the scope down anim or start the 'sighting' repositioning of gun
    simulated function PlayScopeDown(optional bool bNoAnim)
    {
        if (!bNoAnim && HasAnim(ZoomOutAnim))
            SafePlayAnim(ZoomOutAnim, 1.0);
        else if (SightingState == SS_Active || SightingState == SS_Raising)
            SightingState = SS_Lowering;
    }
    // Play the scope up anim or start the 'sighting' repositioning of gun
    // Azarael - Anti TCC compatible zoom
    simulated function PlayScopeUp()
    {
        if (HasAnim(ZoomInAnim))
            SafePlayAnim(ZoomInAnim, 1.0);
        else
            SightingState = SS_Raising;
            
        if(!bSmoothZoom && FullZoomFOV > 50)
            PlayerController(Instigator.Controller).bZooming = True;
    
        Instigator.Controller.bRun = 1;
    }
    
    // Tell the weapon lower and wait until anims are over to go back to scope/sight view
    simulated function TemporaryScopeDown(optional float NewSightingTime, optional float StartPhase)
    {
        if (!bScopeView && SightingState == SS_None)
            return;
        bPendingSightUp = true;
        StopScopeView();
        if (NewSightingTime > 0.0)
            SightingTime = NewSightingTime;
        if (StartPhase != 0.0/* && StartPhase < SightingPhase*/)
            SightingPhase = StartPhase;
        if( KFHumanPawn(Instigator)!=None )
            KFHumanPawn(Instigator).SetAiming(False);
    }
    // anim has ended and we're still pending sight up so tell it to go back up
    simulated function ScopeBackUp(optional float NewSightingTime, optional float StartPhase)
    {
        if (!bPlayScopeUp)
        {
            bPendingSightUp=False;
            return;
        }
        if (NewSightingTime > 0.0)
            SightingTime = NewSightingTime;
        if (StartPhase != 0.0)
            SightingPhase = StartPhase;
        if( KFHumanPawn(Instigator)!=None )
            KFHumanPawn(Instigator).SetAiming(True);
        PlayScopeUp();
    }
    
    // Set the new bScopeView
    function ServerSetScopeView(bool bNewValue)     {   SetScopeView(bNewValue);    }
    simulated function SetScopeView(bool bNewValue)
    {
        if (Level.NetMode == NM_Client)
            ServerSetScopeView(bNewValue);
        bScopeView = bNewValue;
        SetScopeBehavior();
    }
    // Azarael - improved ironsights
    simulated function SetScopeBehavior()
    {
        bUseNetAim = default.bUseNetAim || bScopeView;
            
        if (bScopeView)
        {
            if (bUseScopeViewAim)       {
                ViewAimScale = 1.0;
                ViewRecoilScale = 1.0;  }
            ViewAimFactor = 1.0;
            ViewRecoilFactor = 1.0;
            AimAdjustTime *= 2;
            AimSpread *= SightAimFactor;
            ChaosAimSpread *= SightAimFactor;
            ChaosDeclineTime *= 2.0;
            ChaosSpeedThreshold *= 0.7;
        }
        else
        {
            //PositionSights will handle this for clients
            if(Level.NetMode == NM_DedicatedServer)
            {
                ViewAimFactor = default.ViewAimFactor;
                ViewAimScale = default.ViewAimScale;
                ViewRecoilScale = default.ViewRecoilScale;
                ViewRecoilFactor = default.ViewRecoilFactor;
            }
    
            AimAdjustTime = default.AimAdjustTime;
            AimSpread = default.AimSpread;
            AimSpread *= BCRepClass.default.AccuracyScale;
            ChaosAimSpread = default.ChaosAimSpread;
            ChaosAimSpread *= BCRepClass.default.AccuracyScale;
            ChaosDeclineTime = default.ChaosDeclineTime;
            ChaosSpeedThreshold = default.ChaosSpeedThreshold;
        }
    }
    
    simulated function RenderSightFX(Canvas Canvas)
    {
        local coords C;
    
        if (SightFX != None)
        {
            C = GetBoneCoords(SightFXBone);
            SightFX.SetLocation(C.Origin);
            if (RenderedHand < 0)
                SightFX.SetRotation( OrthoRotation(C.XAxis, -C.YAxis, C.ZAxis) );
            else
                SightFX.SetRotation( OrthoRotation(C.XAxis, C.YAxis, C.ZAxis) );
            Canvas.DrawActor(SightFX, false, false, DisplayFOV);
        }
    }
    
    // Draw the scope view
    simulated event RenderOverlays (Canvas C)
    {
        local float ImageScaleRatio;
    
        if (!bScopeView)
        {
            Super(Weapon).RenderOverlays(C);
            if (SightFX != None)
                RenderSightFX(C);
            return;
        }
        if (!bNoMeshInScope)
        {
            Super(Weapon).RenderOverlays(C);
            if (SightFX != None)
                RenderSightFX(C);
        }
        else
        {
            SetLocation(Instigator.Location + Instigator.CalcDrawOffset(self));
            SetRotation(Instigator.GetViewRotation());
        }
    
        // Draw Scope View
        if (ScopeViewTex != None)
        {
            C.SetDrawColor(255,255,255,255);
            C.SetPos(C.OrgX, C.OrgY);
            // This is the ratio the images in the package were saved at, we took a 1280x1024 image and scaled it down to a 1024x1024 image.
            // Thus if we draw them as a perfect square, they will be squashed looking.
            ImageScaleRatio = 1.3333333;
            C.DrawTile(ScopeViewTex, (C.SizeX - (C.SizeY*ImageScaleRatio))/2, C.SizeY, 0, 0, 1, 1);
    
            C.SetPos((C.SizeX - (C.SizeY*ImageScaleRatio))/2, C.OrgY);
            C.DrawTile(ScopeViewTex, (C.SizeY*ImageScaleRatio), C.SizeY, 0, 0, 1024, 1024);
    
            C.SetPos(C.SizeX - (C.SizeX - (C.SizeY*ImageScaleRatio))/2, C.OrgY);
            C.DrawTile(ScopeViewTex, (C.SizeX - (C.SizeY*ImageScaleRatio))/2, C.SizeY, 0, 0, 1, 1);
        }
    }
    // Cut in before the gun is rendered and move it around if we're trying to use sight view...
    simulated function PreDrawFPWeapon()
    {
        if (SightingState != SS_None)
            PositionSights();
        if (LongGunFactor != 0)
            SetLocation(Location + ViewAlignedOffset(LongGunOffset)*LongGunFactor);
    }
    
    // Relocate the weapon according to sight view.
    // Azarael - improved ironsights
    simulated function PositionSights ()
    {
        local Vector SightPos, Offset, NewLoc, OldLoc;//, X,Y,Z;
        local PlayerController PC;
    
        //bots can't use sights
        PC=PlayerController(Instigator.Controller);
    
        if (SightBone != '')
            SightPos = GetBoneCoords(SightBone).Origin - Location;
    
        OldLoc = Instigator.Location + Instigator.CalcDrawOffset(self);
        Offset = SightOffset; Offset.X += float(Normalize(Instigator.GetViewRotation()).Pitch) / 4096;
        NewLoc = (PC.CalcViewLocation-(Instigator.WalkBob * (1-SightingPhase))) - (SightPos + ViewAlignedOffset(Offset));
        
        if (SightingPhase >= 1.0 )
        {   // Weapon locked in sight view
            SetLocation(NewLoc);
            SetRotation(Instigator.GetViewRotation() + SightPivot);
            DisplayFOV = SightDisplayFOV;
            ViewAimFactor=1.0;
            ViewAimScale= 1.0;
            ViewRecoilFactor=1.0;
            if (!bSmoothZoom && FullZoomFOV > 50)
            {
                PC.DesiredFOV = PC.DefaultFOV - (90 - FullZoomFOV);
            }
        }
        
        else if (SightingPhase <= 0.0)
        {   // Weapon completely lowered
            SetLocation(OldLoc);
            SetRotation(Instigator.GetViewRotation());
            DisplayFOv = default.DisplayFOV;
            PlayerController(Instigator.Controller).bZooming = False;
            ViewAimFactor=default.ViewAimFactor;
            ViewAimScale=default.ViewAimScale;
            ViewRecoilFactor=default.ViewRecoilFactor;
            if(!bSmoothZoom && FullZoomFOV > 50)
                PC.DesiredFOV = PC.DefaultFOV;
    
        }
        else
        {   // Gun is on the move...
            SetLocation(class'BUtil'.static.VSmerp(SightingPhase, OldLoc, NewLoc));
            SetRotation(Instigator.GetViewRotation() + SightPivot * SightingPhase);
            DisplayFOV = Smerp(SightingPhase, default.DisplayFOV, SightDisplayFOV);
            ViewAimFactor=Smerp(SightingPhase, default.ViewAimFactor, 1);
            ViewAimScale=Smerp(SightingPhase, default.ViewAimScale, 1);
            ViewRecoilFactor = Smerp(SightingPhase, default.ViewRecoilFactor, 1);
            //Don't do this for scoped weapons
            if (!bSmoothZoom && FullZoomFOV > 50)
            {
                PC.DesiredFOV = Lerp(SightingPhase, PC.DefaultFOV, (PC.DefaultFOV - (90 - FullZoomFOV)));
            }
        }
    }
    
    simulated function bool CanUseSights()
    {
        if (Instigator.Physics == PHYS_Falling || (SprintControl != None && SprintControl.bSprinting))
            return false;
    /*
        if (Instigator.base != None)
        {
            if (VSize(Instigator.velocity - Instigator.base.velocity) > 220)
                return false;
        }
        else if (VSize(Instigator.velocity) > 220)
            return false;
    */
        return true;
    }
    
    // Interpolate our generated 'sighting anims' (the gun's movement to and from the sight view position)
    simulated function TickSighting (float DT)
    {
        if (SightingState == SS_None || SightingState == SS_Active)
            return;
            
        if(NewLongGunFactor >= 0 && bScopeView ){
            if( KFHumanPawn(Instigator)!=None )
                KFHumanPawn(Instigator).SetAiming(False);
        }
    
        if (SightingState == SS_Raising)
        {   // Raising gun to sight position
            if (SightingPhase < 1.0)
            {
                if ((bScopeHeld || bPendingSightUp) && CanUseSights())
                    SightingPhase += DT/SightingTime;
                else
                {
                    SightingState = SS_Lowering;
    
                    Instigator.Controller.bRun = 0;
                }
            }
            else
            {   // Got all the way up. Now go to scope/sight view
                SightingPhase = 1.0;
                SightingState = SS_Active;
                ScopeUpAnimEnd();
            }
        }
        else if (SightingState == SS_Lowering)
        {   // Lowering gun from sight pos
            if (SightingPhase > 0.0)
            {
                if (bScopeHeld && CanUseSights())
                    SightingState = SS_Raising;
                else
                    SightingPhase -= DT/SightingTime;
            }
            else
            {   // Got all the way down. Tell the system our anim has ended...
                SightingPhase = 0.0;
                SightingState = SS_None;
                ScopeDownAnimEnd();
                DisplayFOv = default.DisplayFOV;
            }
        }
    }
    // Adjust the zoom level
    simulated function ChangeZoom (float Value)
    {
        local PlayerController PC;
        local float OldZoomLevel;
    
        PC = PlayerController(Instigator.Controller);
        if (PC == None)
            return;
        if (bInvertScope)
            Value*=-1;
        OldZoomLevel = PC.ZoomLevel;
        PC.ZoomLevel = FClamp(PC.ZoomLevel+Value, 0.05, 1.0);
        if (PC.ZoomLevel > OldZoomLevel)
            if (ZoomInSound.Sound != None)  class'BUtil'.static.PlayFullSound(self, ZoomInSound);
        else if (PC.ZoomLevel < OldZoomLevel)
            if (ZoomOutSound.Sound != None) class'BUtil'.static.PlayFullSound(self, ZoomOutSound);
        PC.DesiredFOV = FClamp(PC.DefaultFOV - (PC.ZoomLevel * (PC.DefaultFOV-FullZoomFOV)), 1, 170);
    }
    // Tell the client to exit scope view
    simulated function ClientScopeDown()    {   if (level.NetMode != NM_Client) return;     StopScopeView();    }
    
    simulated function bool WeaponCentered()
    {
        return ( bSpectated || bScopeView || (Hand > 1) );
    }
    
    // Swap sighted offset and pivot for left handers
    simulated function SetHand(float InHand)
    {
        Super(Weapon).SetHand(InHand);
        if (Hand < 0)
        {
            SightOffset.Y = default.SightOffset.Y * -1;
            SightPivot.Roll = default.SightPivot.Roll * -1;
            SightPivot.Yaw = default.SightPivot.Yaw * -1;
        }
        else
        {
            SightOffset.Y = default.SightOffset.Y;
            SightPivot.Roll = default.SightPivot.Roll;
            SightPivot.Yaw = default.SightPivot.Yaw;
        }
    }
    
    // Key Events and associated core stuff -------------
    
    // This is the standard form of a key event pipeline. There are 8 functions covering all events and behavior related to
    // a key on both client and server side.
    // First the exec function is called on local machine. It would normally be used to call the server function. It could
    // be used in subclasses to implement client side only features that need not interact with the server. The server
    // function runs only on the server and should be used to do server side only stuff. The client function can be called
    // from the server and is a handy way to get back to the client after the server has done its stuff. The Common function
    // is not replcated and is useful for stuff that is common to both client and server. The Release functions mirror
    // normal four, but should be used when a key is released.
    // E.g. for reloading functions:
    // Exec called when key pressed and calls Server. Server verifys that reloading is ok and runs some server reload stuff,
    // the Client function and the Common function. Client function does some client reload stuff and calls Common function.
    // Common function does commons stuff like set up timing, etc...
    
    // Weapon Special stuff >>>>>>>>>>>>>>>>>>>>>
    // Weapon Special key event. Client side before server has any say. Override for client only WS functions. Calls ServerWeaponSpecial.
    exec simulated function WeaponSpecial(optional byte i){ ServerWeaponSpecial(i); }
    // Server side WS event. Override for server side WS funcs. ClientWeaponSpecial can be called from here.
    function ServerWeaponSpecial(optional byte i);
    // Client WS. This is the call back from server. Not called by default...
    simulated function ClientWeaponSpecial(optional byte i);
    // Actual implementation of WeaponSpecial. Stuff common to client and server here. Should be called from any of these. Not Called by default.
    simulated function CommonWeaponSpecial(optional byte i);
    
    // WeaponSpecial Key Released Event... Works the same as the press stuff...
    exec simulated function WeaponSpecialRelease(optional byte i){ ServerWeaponSpecialRelease(i); }
    function ServerWeaponSpecialRelease(optional byte i);
    simulated function ClientWeaponSpecialRelease(optional byte i);
    simulated function CommonWeaponSpecialRelease(optional byte i);
    // End Weapon Special <<<<<<<<<<<<<<<<<<<<<<<
    
    // Gun cocking stuff >>>>>>>>>>>>>>>>>>>>>>>>
    // This can be used to cock a gun manually during the game...
    exec simulated function CockGun(optional byte Type)     {if (bNonCocking || ReloadState != RS_None) return; ServerCockGun(Type);    CommonCockGun(Type);    }
    function ServerCockGun(optional byte Type)              {   CommonCockGun(Type);                            }
    simulated function ClientCockGun (optional byte Type)   {   CommonCockGun(Type);                            }
    //This is run by AnimEnd() when reload or fire sequence finishes
    //or by Timer() when BringUp time is finished
    simulated function CommonCockGun(optional byte Type)
    {
        local int m;
        if (bNonCocking)
            return;
        if (Role == ROLE_Authority)
            bServerReloading=true;
        ReloadState = RS_Cocking;
        PlayCocking(Type);
        bNeedCock=false;
        for (m=0; m < NUM_FIRE_MODES; m++)
            if (BFireMode[m] != None)
                BFireMode[m].CockingGun(Type);
    }
    // End gun cocking <<<<<<<<<<<<<<<<<<<<<<<<<<
    
    // Reloading Stuff >>>>>>>>>>>>>>>>>>>>>>>>>>
    //KF reload key, overridden to enable the use of the BallisticWeapons reload
    exec function ReloadMeNow(){ Reload(); }
    // Run on client, send call to server. It will send it back if reload is valid
    simulated function Reload (optional byte i)
    {	
        if (ClientState == WS_ReadyToFire && ReloadState == RS_None) 
            ServerStartReload(i);   
    }
    //First this is run on the server
    function ServerStartReload (optional byte i)
    {
        local int m;
        local float ReloadMulti;
    
        if(!AllowReload())
            return;
        if (bPreventReload)
            return;
        if (ReloadState != RS_None)
            return;
        if (MagAmmoRemaining >= MagCapacity)
            return;
        if (Ammo[0].AmmoAmount < 1)
            return; 
        
        if ( KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo) != none && KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill != none )
        {
            ReloadMulti = KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo).ClientVeteranSkill.Static.GetReloadSpeedModifier(KFPlayerReplicationInfo(Instigator.PlayerReplicationInfo), self);
        }
        else
        {
            ReloadMulti = 1.0;
        }
    
        for (m=0; m < NUM_FIRE_MODES; m++)
            if (FireMode[m] != None && FireMode[m].bIsFiring)
                StopFire(m);
    
        ReloadTimer = Level.TimeSeconds;
        ReloadRate = Default.ReloadRate / ReloadMulti;
        bServerReloading = true;
        
        if( bShovelLoad )
        {
            NumLoadedThisReload = 0;
        }
        
        CommonStartReload(i);   //Server animation
        ClientStartReload(i);   //Client animation
        if(!bShovelLoad){
            Instigator.SetAnimAction(WeaponReloadAnim);
        }
    
        // Reload message commented out for now - Ramm
        if ( Level.Game.NumPlayers > 1 && KFGameType(Level.Game).bWaveInProgress && KFPlayerController(Instigator.Controller) != none &&
             Level.TimeSeconds - KFPlayerController(Instigator.Controller).LastReloadMessageTime > KFPlayerController(Instigator.Controller).ReloadMessageDelay )
        {
            KFPlayerController(Instigator.Controller).Speech('AUTO', 2, "");
            KFPlayerController(Instigator.Controller).LastReloadMessageTime = Level.TimeSeconds;
        }
    }
    //This is called by the server once it has decided that the reload is possible
    //This is run on client by server
    simulated function ClientStartReload(optional byte i)
    {
        if (Level.NetMode == NM_Client)
            CommonStartReload(i);
    }
    // Prepare to reload, set reload state, start anims. Called on client and server
    simulated function CommonStartReload (optional byte i)
    {
        local int m;
        if (ClientState == WS_BringUp)
            ClientState = WS_ReadyToFire;
        if (bShovelLoad)
            ReloadState = RS_StartShovel;
        else
            ReloadState = RS_PreClipOut;
        PlayReload();
    
        if (bScopeView && Instigator.IsLocallyControlled())
            TemporaryScopeDown(Default.SightingTime*Default.SightingTimeScale);
        for (m=0; m < NUM_FIRE_MODES; m++)
            if (BFireMode[m] != None)
                BFireMode[m].ReloadingGun(i);
    
        if (bCockAfterReload)
            bNeedCock=true;
        if (bCockOnEmpty && MagAmmoRemaining < 1)
            bNeedCock=true;
        bNeedReload=false;
    }
    exec simulated function ReloadRelease(optional byte i);
    function ServerReloadRelease(optional byte i);
    simulated function ClientReloadRelease(optional byte i);
    simulated function CommonReloadRelease(optional byte i);
    
    //Lets override this to replace bServerReloading
    simulated function bool AllowReload()
    {
    	UpdateMagCapacity(Instigator.PlayerReplicationInfo);
    
    	if(KFInvasionBot(Instigator.Controller) != none && !bServerReloading &&
    		MagAmmoRemaining < MagCapacity && AmmoAmount(0) > MagAmmoRemaining)
    		return true;
    
    	if(KFFriendlyAI(Instigator.Controller) != none && !bServerReloading &&
    		MagAmmoRemaining < MagCapacity && AmmoAmount(0) > MagAmmoRemaining)
    		return true;
    
    
    	if(FireMode[0].IsFiring() || FireMode[1].IsFiring() ||
    		   bServerReloading || MagAmmoRemaining >= MagCapacity ||
    		   ClientState == WS_BringUp ||
    		   AmmoAmount(0) <= MagAmmoRemaining ||
    				   (FireMode[0].NextFireTime - Level.TimeSeconds) > 0.1 )
    		return false;
    	return true;
    }
    // End Reloading Stuff <<<<<<<<<<<<<<<<<<<<<<
    
    // Weapon Firing Mode Stuff >>>>>>>>>>>>>>>>>
    // WeapMode key pressed. Server will do the switching and the WM var will be replicated.
    exec simulated function SwitchWeaponMode () {   ServerSwitchWeaponMode();   }
    // Cycle through the various weapon modes
    function ServerSwitchWeaponMode ()
    {
        local PlayerController Player;
        local int NewMode;
    
        Player = PlayerController(Instigator.Controller);
        NewMode = CurrentWeaponMode + 1;
        while (NewMode != CurrentWeaponMode && (NewMode >= WeaponModes.length || WeaponModes[NewMode].bUnavailable) )
        {
            if (NewMode >= WeaponModes.length)
                NewMode = 0;
            else
                NewMode++;
        }
        if (!WeaponModes[NewMode].bUnavailable)
            CurrentWeaponMode = NewMode;
        if (WeaponModes[CurrentWeaponMode].ModeID ~= "WM_SemiAuto")
        {
            Player.ReceiveLocalizedMessage(class'KFBCoreV25.BallisticSwitchMessage',1); 
        }
        if (WeaponModes[CurrentWeaponMode].ModeID ~= "WM_FullAuto")
        {
            Player.ReceiveLocalizedMessage(class'KFBCoreV25.BallisticSwitchMessage',2); 
        }
        if (WeaponModes[CurrentWeaponMode].ModeID ~= "WM_Burst")
        {
            Player.ReceiveLocalizedMessage(class'KFBCoreV25.BallisticSwitchMessage',0); 
        }
    }
    // See if firing modes will let us fire another round or not
    simulated function bool CheckWeaponMode (int Mode)
    {
        if (WeaponModes[CurrentWeaponMode].ModeID ~= "WM_FullAuto" || WeaponModes[CurrentWeaponMode].ModeID ~= "WM_None")
            return true;
        if (FireCount >= WeaponModes[CurrentWeaponMode].Value)
            return false;
        return true;
    }
    // End Firing Mode Stuff <<<<<<<<<<<<<<<<<<<<
    
    // Sight View Stuff >>>>>>>>>>>>>>>>>>>>>>>>>
    // Scopes can be activated with the sight key. Holding the key will zoom in until released. Further adjustments can
    // be made with the Prev/Next weapon select keys.
    
    //KF ironsight key, overridden to enable the use of BallisticWeapons ironsight system
    simulated exec function ToggleIronSights(){ local byte i; Super.ToggleIronSights(); ScopeView(); if(!bUseSights){ WeaponSpecial(i); }}
    // Sight key pressed. Bring the scope/sights up to eye level or lower gun if already in scope view.
    // Azarael - Improved ironsights
    exec simulated function ScopeView()
    {
        local float F;
    
        bScopeHeld=true;
        bPendingSightUp=false;
        
        if (!bUseSights)
            return;
            
        if (bServerReloading)
            return;
            
        if ( LongGunFactor > 0 )
            return;
            
        if (bScopeView)
        {
            bScopeHeld=false;
            StopScopeView();
            return;
        }
        
        if( KFHumanPawn(Instigator)!=None )
            KFHumanPawn(Instigator).SetAiming(True);
    
        if (!CanUseSights())
            return;
            
        ZeroAim(SightingTime); //Level out sights over aim adjust time to stop the "shunt" effect
        
        if (!IsFiring() && !bNoTweenToScope)
            TweenAnim(IdleAnim, SightingTime);
    
        bForceReaim=true;
        
        if (NewLongGunFactor == 0)
            PlayScopeUp();
    }
    // Sight key released. Stop zooming in
    exec simulated function ScopeViewRelease()
    {
        bScopeHeld=false;
        if (!bUseSights)
            return;
        if( Instigator.Controller.IsA( 'PlayerController' ) )
            PlayerController(Instigator.Controller).StopZoom();
    }
    // End Sight View <<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    // Base dual select >>>>>>>>>>>>>>>>>>>>>>>>>
    // Base function for dual select key is to 'quick draw' the last dual wielded weapons.
    // If there was no last pair, pick two handguns.
    // If there is only one, pick it
    
    // Go through chain and find the last handgun used. Make it pull the last slave or the best slave
    // If there is no last, find the best handgun. Make it pull out the best slave
    // If there are no handguns, don't do anything.
    
    simulated function DoQuickDraw();
    
    simulated function BallisticWeapon FindQuickDraw(BallisticWeapon CurrentChoice, float ChoiceRank)
    {
        local Inventory Inv;
        local BallisticWeapon Best;
    
        for ( Inv=Inventory; Inv!=None; Inv=Inv.Inventory )
            if (BallisticWeapon(Inv) != None)
            {   Best = BallisticWeapon(Inv).FindQuickDraw(CurrentChoice, ChoiceRank);   break;  }
    
        if (Best == None)
            return CurrentChoice;
        else
            return Best;
    }
    
    exec simulated function DualSelect (optional class<Weapon> NewWeaponClass )
    {
        local BallisticWeapon Best;
        local Inventory Inv;
    
        for ( Inv=Instigator.Inventory; Inv!=None; Inv=Inv.Inventory )
        {
            if (BallisticWeapon(Inv) != None)
            {
                Best = BallisticWeapon(Inv).FindQuickDraw(None, 0);
                break;
            }
        }
        if (Best != None)
            Best.DoQuickDraw();
    }
    // End dual stuff <<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    // End Key event stuff ------------------------------
    
    // Big powerful cheat to give you all the ballistic weapons and some ammo of course
    exec function Reloaded()
    {
        local class<Weapon> Weap;
        local Inventory Inv;
        local int i;
        local array<CacheManager.WeaponRecord> Recs;
    
        if (Level.Netmode != NM_Standalone || Instigator == None || Vehicle(Instigator) != None)
            return;
    
        class'CacheManager'.static.GetWeaponList(Recs);
        for (i=0;i<Recs.Length;i++)
        {
            if (!class'BC_WeaponInfoCache'.static.AutoWeaponInfo(Recs[i].ClassName).bIsBW)
                continue;
            Weap = class<Weapon>(DynamicLoadObject(Recs[i].ClassName, class'Class'));
            if (Weap != None && ClassIsChildOf(Weap, class'BallisticWeapon'))
                Instigator.GiveWeapon(Recs[i].ClassName);
        }
        class'BC_WeaponInfoCache'.static.EndSession();
    
        for(Inv=Instigator.Inventory; Inv!=None; Inv=Inv.Inventory)
            if (Weapon(Inv)!=None)
                Weapon(Inv).SuperMaxOutAmmo();
    }
    
    simulated function bool HasMagAmmo(byte Mode)
    {
        return HasAmmo();
    }
    
    simulated function bool HasNonMagAmmo(byte Mode)
    {
        return HasAmmo();
    }
    simulated function bool HasAmmoLoaded(byte Mode)
    {
        return HasAmmo();
    }
    
    // End Main Core functions ---------------------------------------------------------------------------------------------
    
    // Misc and Barely changed old functions -------------------------------------------------------------------------------
    // FIXME: Clean up this section!
    
    function string GetSpecialInfo (name InfoID)
    {
        local int i;
    
        for(i=0;i<SpecialInfo.length;i++)
        {
            if (Specialinfo[i].ID == InfoID)
                return Specialinfo[i].Info;
        }
        return "";
    }
    
    static function string StaticGetSpecialInfo (name InfoID)
    {
        local int i;
    
        for(i=0;i<default.SpecialInfo.length;i++)
        {
            if (default.Specialinfo[i].ID == InfoID)
                return default.Specialinfo[i].Info;
        }
        return "";
    }
    
    // Initialize and reset a lot of thing on bringup
    simulated function BringUp(optional Weapon PrevWeapon)
    {
    	local int mode, i;
    	local Inventory Inv;
    	local float NewSpeed;
        local KFPlayerController Player;
    	
        HandleSleeveSwapping();
        
        // Hint check
        Player = KFPlayerController(Instigator.Controller);
    
        if ( Player != none && ClientGrenadeState != GN_BringUp )
        {
            if ( class == class'Single' )
            {
                Player.CheckForHint(10);
            }
            else if ( class == class'Dualies' )
            {
                Player.CheckForHint(11);
            }
            else if ( class == class'Deagle' )
            {
                Player.CheckForHint(12);
            }
            else if ( class == class'Bullpup' )
            {
                Player.CheckForHint(13);
            }
            else if ( class == class'Shotgun' )
            {
                Player.CheckForHint(14);
            }
            else if ( class == class'Winchester' )
            {
                Player.CheckForHint(15);
            }
            else if ( class == class'Crossbow' )
            {
                Player.CheckForHint(16);
            }
            else if ( class == class'BoomStick' )
            {
                Player.CheckForHint(17);
                Player.WeaponPulloutRemark(21);
            }
            else if ( class == class'FlameThrower' )
            {
                Player.CheckForHint(18);
            }
            else if ( class == class'LAW' )
            {
                Player.CheckForHint(19);
                Player.WeaponPulloutRemark(23);
            }
            else if ( class == class'Knife' && bShowPullOutHint )
            {
                Player.CheckForHint(20);
            }
            else if ( class == class'Machete' )
            {
                Player.CheckForHint(21);
            }
            else if ( class == class'Axe' )
            {
                Player.CheckForHint(22);
                Player.WeaponPulloutRemark(24);
            }
            else if ( class == class'DualDeagle' || class == class'GoldenDualDeagle' )
            {
                Player.WeaponPulloutRemark(22);
            }
    
            bShowPullOutHint = true;
        }
    	
    	// Set ambient sound when gun is held
    	if (UsedAmbientSound != None)
    		AmbientSound = UsedAmbientSound;
    
        if (SightFXClass!=None && Instigator.IsLocallyControlled() && Instigator.IsHumanControlled() && level.DetailMode == DM_SuperHigh && SightFX == None && class'BallisticMod'.default.EffectsDetailMode >= 2)
        {
    		SightFX = Spawn(SightFXClass);
    		if (SightFX != None)
    			class'BallisticEmitter'.static.ScaleEmitter(Emitter(SightFX), DrawScale);
    	}
    	
        if ( KFHumanPawn(Instigator) != none )
            KFHumanPawn(Instigator).SetAiming(false);
    
    	InstigatorController = Instigator.Controller;
    	OldLookDir = GetPlayerAim();
    	Instigator.bCountJumps = true;
    	// Reset Reloading
    	if (Role == ROLE_Authority)
    		bServerReloading=false;
    	ReloadState = RS_None;
    	// Link up with sprint control
    	if (SprintControl == None)	{
    		for (Inv=Instigator.Inventory;Inv!=None;Inv=Inv.Inventory)
    			if (BCSprintControl(Inv) != None)	{
    				SprintControl = BCSprintControl(Inv);		break;	}
    	}
    	// Reset aim offset
    	AimOffset = CalcNewAimOffset();
    	NewAimOffset = AimOffset;
    	OldAimOffset = AimOffset;
    	
    	if (Role == ROLE_Authority)
    	{
    		// If factor differs from previous wep, or no previous wep, set groundspeed anew
    		if (BallisticWeapon(PrevWeapon) == None || BallisticWeapon(PrevWeapon).PlayerSpeedFactor != PlayerSpeedFactor)
    		{
    				NewSpeed = Instigator.default.GroundSpeed * PlayerSpeedFactor;
    				if (Instigator.GroundSpeed != NewSpeed)
    					Instigator.GroundSpeed = NewSpeed;
    		}
    		
    		//Transfer over SpeedUp responsibility if we can
    		if (BallisticWeapon(PrevWeapon) != None)
    			BallisticWeapon(PrevWeapon).PlayerSpeedUp = False;
    		PlayerSpeedUp = True;
    	}	
    	
    	// Dumber bots take longer to change weapons
    	if (AIController(InstigatorController) != None && AIController(InstigatorController).Skill <= 4)
    		BringUpTime = default.BringUpTime*(2-(AIController(InstigatorController).Skill/4));
    
    	// Change certain skins to show team colors
    	if (Instigator.PlayerReplicationInfo != None && Instigator.PlayerReplicationInfo.Team != None)
    	{
    		for (i=0;i<TeamSkins.Length;i++)
    		{
    			if (Instigator.PlayerReplicationInfo.Team.TeamIndex == 0)
    			{
    				if (TeamSkins[i].RedTex != None)
    					Skins[TeamSkins[i].SkinNum]=TeamSkins[i].RedTex;
    			}
    			else if (TeamSkins[i].BlueTex != None)
    				Skins[TeamSkins[i].SkinNum]=TeamSkins[i].BlueTex;
    		}
    	}
    	if (PlayerController(Instigator.Controller) != None && PlayerController(Instigator.Controller).MyHud != None)
    	{
    		if (bOldCrosshairs)
    			PlayerController(Instigator.Controller).MyHud.bCrosshairShow = PlayerController(Instigator.Controller).MyHud.default.bCrosshairShow;
    		else
    			PlayerController(Instigator.Controller).MyHud.bCrosshairShow = false;
    	}
    
    	// Old Stuff from weapon.uc
        if (ClientState == WS_Hidden)
        {
    		if (BringUpSound.Sound != None)
    			class'BUtil'.static.PlayFullSound(self, BringUpSound);
    		ClientPlayForceFeedback(SelectForce);  // jdf
    
            if (Instigator.IsLocallyControlled())
            {
                if (HasAnim(SelectAnim))
                    PlayAnim(SelectAnim, SelectAnimRate, 0.0);
    		}
            ClientState = WS_BringUp;
    	}
    	
        if (!IsInState('PendingClientWeaponSet'))
        	SetTimer(BringUpTime, false);
        else bPendingBringupTimer = True;
    		
        for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++)
    	{
    		if (FireMode[Mode] == None)
    			continue;
    		FireMode[Mode].bIsFiring = false;
    		FireMode[Mode].HoldTime = 0.0;
    		FireMode[Mode].bServerDelayStartFire = false;
    		FireMode[Mode].bServerDelayStopFire = false;
    		FireMode[Mode].bInstantStop = false;
    	}
    	   if ( (PrevWeapon != None) && PrevWeapon.HasAmmo() && !PrevWeapon.bNoVoluntarySwitch )
    		OldWeapon = PrevWeapon;
    	else
    		OldWeapon = None;
    }
    
    simulated function bool PutDown()
    {
        local int Mode;
        
        if ( bServerReloading )
            return false;
    
        if( bAimingRifle || bScopeView)
        {
            ZoomOut(False);
            bScopeHeld=false;
            StopScopeView();
        }
    
        if (ClientState == WS_BringUp || ClientState == WS_ReadyToFire)
        {
            if (Instigator.PendingWeapon != None && !Instigator.PendingWeapon.bForceSwitch)
            {
                for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++)
                {
                    if (FireMode[Mode]!=None && FireMode[Mode].bFireOnRelease && FireMode[Mode].bIsFiring)
                        return false;
                }
            }
    
            if (Instigator.IsLocallyControlled())
            {
                for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++)
                {
                    if (FireMode[Mode]!=None && FireMode[Mode].bIsFiring)
                        ClientStopFire(Mode);
                }
    
                if (ClientState != WS_BringUp && HasAnim(PutDownAnim))
                    PlayAnim(PutDownAnim, PutDownAnimRate, 0.0);
            }
            ClientState = WS_PutDown;
    
            if (bScopeView)
                StopScopeView(true);
    
            if (ReloadState != RS_None)
            {
                if (level.NetMode == NM_Client)
                    ServerStopReload();
                ReloadState = RS_None;
            }
            bPendingSightUp=false;
    //      if (PlayerController(Instigator.Controller) != None && PlayerController(Instigator.Controller).MyHud != None)
            if (!bOldCrosshairs && (Instigator.PendingWeapon == None || BallisticWeapon(Instigator.PendingWeapon) == None) && PlayerController(Instigator.Controller) != None && PlayerController(Instigator.Controller).MyHud != None)
                PlayerController(Instigator.Controller).MyHud.bCrosshairShow = PlayerController(Instigator.Controller).MyHud.default.bCrosshairShow;
            if (PutDownSound.Sound != None)
                class'BUtil'.static.PlayFullSound(self, PutDownSound);
            SetTimer(PutDownTime, false);
        }
        for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++)
        {
            if (FireMode[Mode]==None)
                continue;
            FireMode[Mode].bServerDelayStartFire = false;
            FireMode[Mode].bServerDelayStopFire = false;
        }
        Instigator.AmbientSound = None;
        AmbientSound = None;
        OldWeapon = None;
        return true; // return false if preventing weapon switch
    }
    
    simulated function Weapon WeaponChange( byte F, bool bSilent )
    {
        local Weapon newWeapon;
    
        if ( InventoryGroup == F )
        {
            if ( !HasAmmo() )
            {
                if (Inventory != None)
                {
                    newWeapon = Inventory.WeaponChange(F,bSilent);
                    if (newWeapon != None && newWeapon != Instigator.Weapon && newWeapon.HasAmmo())
                        return newWeapon;
                }
                if ( !bSilent && (newWeapon == None) && Instigator.IsHumanControlled() )
                    Instigator.ClientMessage( ItemName$MessageNoAmmo );
            }
            return self;
        }
        else if ( Inventory == None )
            return None;
        else
            return Inventory.WeaponChange(F,bSilent);
    }
    
    // need to figure out modified rating based on enemy/tactical situation
    simulated function float RateSelf()
    {
        if ( !HasAmmo() )
            CurrentRating = -2;
        else if ( Instigator.Controller == None )
            return 0;
        else
        {
            CurrentRating = Instigator.Controller.RateWeapon(self);
            if (!bNoMag){
                if(!HasNonMagAmmo(255) && MagAmmoRemaining < MagCapacity / 4)
                    CurrentRating /= (1+AIReloadTime);
    //              CurrentRating = CurrentRating * 0.25;
                else if (MagAmmoRemaining <= 0)
                    CurrentRating /= (2+AIReloadTime);
    //              CurrentRating = FClamp(CurrentRating / (1+AIReloadTime), 2, CurrentRating);
            }
        }
        return CurrentRating;
    }
    
    function float GetAIRating()
    {
        if (bNoMag)
            return AIRating;
        if (MagAmmoRemaining < 1 && AIController(Instigator.Controller).Enemy != None && (Level.TimeSeconds - AIController(Instigator.Controller).LastSeenTime < AIReloadTime || AmmoAmount(0) < 1))
            return AIRating * 0.25;
        return AIRating;
    }
    
    // Makes a bot reload if they have the skill or its forced
    // Allows clever bots to reload when they get the chance and dumb ones only when they have to
    function bool BotReload(optional bool bForced)
    {
        if (bForced || AIController(Instigator.Controller).Skill > Rand(5))
        {
            ServerStartReload();
            return true;
        }
        return false;
    }
    
    // Is reloading a good idea???
    function bool BotShouldReload ()
    {
        if ( (Level.TimeSeconds - AIController(Instigator.Controller).LastSeenTime > AIReloadTime + AIReloadTime * (MagAmmoRemaining/MagCapacity)) &&
             (Level.TimeSeconds - Instigator.LastPainTime > AIReloadTime) )
            return true;
        return false;
    }
    
    // return false if out of range, can't see target, etc.
    function bool CanAttack(Actor Other)
    {
        local float Dist, CheckDist;
        local vector HitLocation, HitNormal,X,Y,Z, projStart;
        local actor HitActor;
        local int m;
        local bool bInstantHit;
        
        Super.CanAttack(Other);
    
        if ( (Instigator == None) || (Instigator.Controller == None) )
            return false;
    
        if (ReloadState != RS_None)
            return false;
        if (!bNoMag && (bNeedReload || MagAmmoRemaining < 1))
        {
            BotReload(true);
            return false;
        }
        if (!bNonCocking && bNeedCock && !bNeedReload && MagAmmoRemaining > 0)
        {
            CommonCockGun();
            return false;
        }
    
        // check that target is within range
        Dist = VSize(Instigator.Location - Other.Location);
    
        if (Dist > FireMode[0].MaxRange() && Dist > FireMode[1].MaxRange())
        {
            if (!bNoMag && BotShouldReload())
                BotReload();
            return false;
        }
    
        // check that can see target
        if (!Instigator.Controller.LineOfSightTo(Other))
        {
            if (!bNoMag && BotShouldReload())
                BotReload();
            return false;
        }
    
    //  if ((Rand(6) < AIController(Instigator.Controller).Skill) && ( (NewChaos*ChaosAimSpread.X.Max > 150 * (1+4000/Dist)) || (NewChaos*ChaosAimSpread.Y.Max > 150 * (1+4000/Dist)) ))
    //      return false;
        // Skilled bots can conserve ammo by not firing when the spread is too high
        if ((Rand(6) < AIController(Instigator.Controller).Skill) && ( (Recoil*RecoilYawFactor > 100 * (1+4000/Dist)) || (Recoil*RecoilPitchFactor > 100 * (1+4000/Dist))) )
            return false;
    
        for (m = 0; m < NUM_FIRE_MODES; m++)
        {
            if (FireMode[m] == None)
                continue;
            if ( FireMode[m].bInstantHit )
                bInstantHit = true;
            else
            {
                CheckDist = FMax(CheckDist, 0.5 * FireMode[m].ProjectileClass.Default.Speed);
                CheckDist = FMax(CheckDist, 300);
                CheckDist = FMin(CheckDist, VSize(Other.Location - Location));
            }
        }
        // check that would hit target, and not a friendly
        GetAxes(GetPlayerAim(), X,Y,Z);
        projStart = GetFireStart(X,Y,Z);
        if ( bInstantHit )
            HitActor = Trace(HitLocation, HitNormal, Other.Location + Other.CollisionHeight * vect(0,0,0.8), projStart, true);
        else
        {
            // for non-instant hit, only check partial path (since others may move out of the way)
            HitActor = Trace(HitLocation, HitNormal,
                    projStart + CheckDist * Normal(Other.Location + Other.CollisionHeight * vect(0,0,0.8) - Location),
                    projStart, true);
        }
    
        if ( (HitActor == None) || (HitActor == Other) || (Pawn(HitActor) == None)
            || (Pawn(HitActor).Controller == None) || !Instigator.Controller.SameTeamAs(Pawn(HitActor).Controller) )
            return true;
    
        return false;
    }
    
    simulated function bool IsFiring() // called by pawn animation, mostly
    {
        if (Level.NetMode == NM_DedicatedServer || Level.NetMode == NM_ListenServer)
            return (FireMode[0].IsFiring() || (FireMode[1] != None && FireMode[1].IsFiring()));
    
        return  ( ClientState == WS_ReadyToFire && (FireMode[0].IsFiring() || (FireMode[1] != None && FireMode[1].IsFiring()) ) );
    }
    
    simulated function bool ReadyToFire(int Mode)
    {
        local int alt;
    
        if ( Mode == 0 )
            alt = 1;
        else
            alt = 0;
    
        if (FireMode[Mode] == None)
            return false;
    
        if ( ((FireMode[alt] != None && FireMode[alt] != FireMode[Mode]) && FireMode[alt].bModeExclusive && FireMode[alt].bIsFiring)
            || !FireMode[Mode].AllowFire()
            || (FireMode[Mode].NextFireTime > Level.TimeSeconds + FireMode[Mode].PreFireTime) )
        {
            return false;
        }
    
        return true;
    }
    
    function bool BotFire(bool bFinished, optional name FiringMode)
    {
        if (ReloadState != RS_None)
            return false;
    
        if (!bNoMag && (bNeedReload || MagAmmoRemaining < 1))
            BotReload(true);
        else
            Super.BotFire(bFinished, FiringMode);
    }
    
    simulated function bool StartFire(int Mode)
    {
        local int alt;
    
        if (!ReadyToFire(Mode))
            return false;
    
        if (Mode == 0)
            alt = 1;
        else
            alt = 0;
    
        FireMode[Mode].bIsFiring = true;
        FireMode[Mode].NextFireTime = Level.TimeSeconds + FireMode[Mode].PreFireTime;
    
        if (FireMode[alt] != None && FireMode[alt].bModeExclusive)
        {
            // prevents rapidly alternating fire modes
            FireMode[Mode].NextFireTime = FMax(FireMode[Mode].NextFireTime, FireMode[alt].NextFireTime);
        }
    
        if (Instigator.IsLocallyControlled())
        {
            if (FireMode[Mode].PreFireTime > 0.0 || FireMode[Mode].bFireOnRelease)
            {
                FireMode[Mode].PlayPreFire();
            }
            FireMode[Mode].FireCount = 0;
        }
    
        return true;
    }
    
    // complete cut n' paste job needed, so that it can be modified
    // to stop this function giving ammo to empty guns that have been
    // thrown out
    function GiveAmmo(int m, WeaponPickup WP, bool bJustSpawned)
    {
        local bool bJustSpawnedAmmo;
        local int addAmount, InitialAmount;
    
        UpdateMagCapacity(Instigator.PlayerReplicationInfo);
    
        if ( FireMode[m] != None && FireMode[m].AmmoClass != None )
        {
            Ammo[m] = Ammunition(Instigator.FindInventoryType(FireMode[m].AmmoClass));
            bJustSpawnedAmmo = false;
    
            if ( bNoAmmoInstances )
            {
                if ( (FireMode[m].AmmoClass == None) || ((m != 0) && (FireMode[m].AmmoClass == FireMode[0].AmmoClass)) )
                    return;
    
                InitialAmount = FireMode[m].AmmoClass.Default.InitialAmount;
    
                if(WP!=none && WP.bThrown==true)
                    InitialAmount = WP.AmmoAmount[m];
                else
                {
                    // Other change - if not thrown, give the gun a full clip
                    MagAmmoRemaining = MagCapacity;
                }
    
                if ( Ammo[m] != None )
                {
                    addamount = InitialAmount + Ammo[m].AmmoAmount;
                    Ammo[m].Destroy();
                }
                else
                    addAmount = InitialAmount;
    
                AddAmmo(addAmount,m);
            }
            else
            {
                if ( (Ammo[m] == None) && (FireMode[m].AmmoClass != None) )
                {
                    Ammo[m] = Spawn(FireMode[m].AmmoClass, Instigator);
                    Instigator.AddInventory(Ammo[m]);
                    bJustSpawnedAmmo = true;
                }
                else if ( (m == 0) || (FireMode[m].AmmoClass != FireMode[0].AmmoClass) )
                    bJustSpawnedAmmo = ( bJustSpawned || ((WP != None) && !WP.bWeaponStay) );
    
                  // and here is the modification for instanced ammo actors
    
                if(WP!=none && WP.bThrown==true)
                {
                    addAmount = WP.AmmoAmount[m];
                }
                else if ( bJustSpawnedAmmo )
                {
                    if (default.MagCapacity == 0)
                        addAmount = 0;  // prevent division by zero.
                    else
                        addAmount = Ammo[m].InitialAmount * (float(MagCapacity) / float(default.MagCapacity));
                }
    
                // Don't double add ammo if primary and secondary fire modes share the same ammo class
                if ( WP != none && m > 0 && (FireMode[m].AmmoClass == FireMode[0].AmmoClass) )
                {
                    return;
                }
    
                Ammo[m].AddAmmo(addAmount);
                Ammo[m].GotoState('');
            }
        }
    }
    
    //Azarael - used in BallisticTurrets
    function SetAmmoTo(int Amount, int m)
    {
        if (Amount > Ammo[m].MaxAmmo || Amount < 0)
            return;
            
        Ammo[m].AmmoAmount = Amount;
    }
    
    function HolderDied()
    {
        local int m;
    
        if (AmbientSound != None)
            AmbientSound = None;
        for (m = 0; m < NUM_FIRE_MODES; m++)
        {
            if (FireMode[m] == None)
                continue;
            if (FireMode[m].bIsFiring)
            {
                StopFire(m);
                if (FireMode[m].bFireOnRelease && (BFireMode[m] == None || BFireMode[m].bReleaseFireOnDie))
                    FireMode[m].ModeDoFire();
            }
        }
    }
    
    // Modded to allow for throwing even when out of ammo.  (also added : You cannot throw while reloading)
    simulated function bool CanThrow()
    {
        local int Mode;
    
        if(bKFNeverThrow)
          return false;
    
        for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++)
        {
            if ( FireMode[Mode].bFireOnRelease && FireMode[Mode].bIsFiring )
                return false;
            if ( FireMode[Mode].NextFireTime > Level.TimeSeconds)
                return false;
        }
        return (bCanThrow && (!bServerReloading || !bServerReloading) && (ClientState == WS_ReadyToFire || (Level.NetMode == NM_DedicatedServer) || (Level.NetMode == NM_ListenServer)));
    }
    
    function DropFrom(vector StartLocation)
    {
        local int m;
        local Pickup Pickup;
        local vector Direction;
    
        if (!bCanThrow)
            return;
    
        ClientWeaponThrown();
    
        for (m = 0; m < NUM_FIRE_MODES; m++)
        {
            if (FireMode[m].bIsFiring)
                StopFire(m);
        }
    
        if ( Instigator != None )
        {
            DetachFromPawn(Instigator);
            Direction = vector(Instigator.Rotation);
        }
        else if ( Owner != none )
        {
            Direction = vector(Owner.Rotation);
        }
    
        Pickup = Spawn(PickupClass,,, StartLocation);
        if ( Pickup != None )
        {
            Pickup.InitDroppedPickupFor(self);
            Pickup.Velocity = Velocity + (Direction * 100);
            if (Instigator.Health > 0)
                WeaponPickup(Pickup).bThrown = true;
        }
    
        Destroyed();
    
        Destroy();
    }
    
    //Azarael - auto melee fire
    simulated function RClientStopFire(int Mode)
    {
        if (Role < ROLE_Authority)
        {
            StopFire(Mode);
        }
    }
    
    simulated event Timer()
    {
        local int Mode;
    
        ReAim(0.1);
    
        if (ClientState == WS_BringUp)
        {
            for( Mode = 0; Mode < NUM_FIRE_MODES; Mode++ )
                if (FireMode[Mode] != None)
                    FireMode[Mode].InitEffects();
            PlayIdle();
            ClientState = WS_ReadyToFire;
            if (!bOldCrosshairs && PlayerController(Instigator.Controller) != None && PlayerController(Instigator.Controller).MyHud != None)
                PlayerController(Instigator.Controller).MyHud.bCrosshairShow = false;
    
            if (bNeedCock)
            {
                if (MagAmmoRemaining > 0)
                    CommonCockGun();
            }
        }
        else if (ClientState == WS_PutDown)
        {
            if (SightFX != None)
            {
                SightFX.Destroy();
                SightFX=None;
            }
    
            if ( Instigator.PendingWeapon == None )
            {
                if( ClientGrenadeState == GN_TempDown )
                {
                    if(KFPawn(Instigator)!=none)
                    {
                        KFPawn(Instigator).WeaponDown();
                    }
                }
                else
                    PlayIdle();
                ClientState = WS_ReadyToFire;
            }
            else
            {
                ClientState = WS_Hidden;
                Instigator.ChangedWeapon();
                for( Mode = 0; Mode < NUM_FIRE_MODES; Mode++ )
                    if (FireMode[Mode] != None)
                        FireMode[Mode].DestroyEffects();
                if (PlayerSpeedFactor != 0 && PlayerSpeedUp)
                {
                    Instigator.GroundSpeed *= (1/PlayerSpeedFactor);
                    PlayerSpeedUp = false;
                }
            }
        }
        else if (Clientstate == WS_None && Instigator.PendingWeapon == none && bNeedCock)
        {
            if (MagAmmoRemaining > 0)
                CommonCockGun();
        }
    }
    
    simulated function bool AllowWeapPrevUI()
    {
        if (bScopeView && bSmoothZoom)
            return false;
        return true;
    }
    simulated function bool AllowWeapNextUI()
    {
        if (bScopeView && bSmoothZoom)
            return false;
        return true;
    }
    
    simulated function Weapon PrevWeapon(Weapon CurrentChoice, Weapon CurrentWeapon)
    {
        // Adjust zoom level when in scope...
        if (bScopeView && CurrentWeapon == self && bSmoothZoom)
        {
            ChangeZoom(0.1);
            return None;
        }
        
        Super.PrevWeapon(CurrentChoice, CurrentWeapon);
    }
    
    simulated function Weapon NextWeapon(Weapon CurrentChoice, Weapon CurrentWeapon)
    {
        // Adjust zoom level when in scope...
        if (bScopeView && CurrentWeapon == self && bSmoothZoom)
        {
            ChangeZoom(-0.1);
            return None;
        }
        
        Super.NextWeapon(CurrentChoice, CurrentWeapon);
    }
    
    // Obsolete since new attachement system
    simulated function IncrementFlashCount(int Mode){}
    simulated function ZeroFlashCount(int Mode) {}
    
    // End of misc stuff ---------------------------------------------------------------------------------------------------
    
    // The Aiming system ---------------------------------------------------------------------------------------------------
    // Net Stuff for aiming >>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // Send aim info to client
    /*
    function SendNewAim()
    {
        local float Yaw, Pitch, Time;
        Yaw = ((NewAim.Yaw+8192)/16384)*255;
        Pitch = ((NewAim.Pitch+8192)/16384)*255;
        Time = (ReaimTime/15)*255;
        ReceiveNewAim(Yaw, Pitch, Time);
    }
    // Receive aim info from server
    simulated function ReceiveNewAim(byte Yaw, byte Pitch, byte Time)
    {
        local float f;
        if (!bUseNetAim || Role == ROLE_Authority)
            return;
        bReaiming=true;
        OldAim = Aim;
        ReaimPhase = 0;
        f = 0.058823 * Time;
        ReaimTime = f;
        f = Yaw * 64.250980 - 8192;
        NewAim.Yaw = f;
        f = Pitch * 64.250980 - 8192;
        NewAim.Pitch = f;
    }
    */
    function SendNewAim()
    {
        local float Yaw, Pitch, Time;
        Yaw = NewAim.Yaw;
        Pitch = NewAim.Pitch;
        Time = ReaimTime;
        ReceiveNewAim(Yaw, Pitch, Time);
    }
    // Receive aim info from server
    simulated function ReceiveNewAim(float Yaw, float Pitch, float Time)
    {
        if (!bUseNetAim || Role == ROLE_Authority)
            return;
        bReaiming=true;
        OldAim = Aim;
        ReaimPhase = 0;
        ReaimTime = Time;
        NewAim.Yaw = Yaw;
        NewAim.Pitch = Pitch;
    }
    // Send the random values used for recoil to the client so he'll have the same recoil effect
    function SendNetRecoil()
    {
        //DC 110313
    //  ReceiveNetRecoil(RecoilXRand*255, RecoilYRand*255);
    //  ReceiveNetRecoil(RecoilXRand*255, RecoilYRand*255, (Recoil/RecoilMax)*255.0 );
        ReceiveNetRecoil(RecoilXRand*255, RecoilYRand*255, Recoil );
    //  log( "SendNetRecoil() Recoil: "$Recoil );
    }
    // Receive random values for recoil from the server
    //DC 110313
    //simulated function ReceiveNetRecoil(byte XRand, byte YRand)
    //simulated function ReceiveNetRecoil(byte XRand, byte YRand, byte Amp)
    simulated function ReceiveNetRecoil(byte XRand, byte YRand, float RecAmp)
    {
        if (!bUseNetAim || Role == ROLE_Authority)
            return;
        RecoilXRand = float(XRand)/255;
        RecoilYRand = float(YRand)/255;
        //DC 110313
    //  Recoil = (float(Amp)/255) * RecoilMax;
        Recoil = RecAmp;
    //  log( "ReceiveNetRecoil() Amp: "$Amp$", Recoil: "$Recoil$" RecoilMax: "$RecoilMax );
    //  log( "ReceiveNetRecoil() RecAmp: "$RecAmp$", Recoil: "$Recoil$" RecoilMax: "$RecoilMax );
    }
    
    // End Net Stuff <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    // Core functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    
    simulated function TickLongGun (float DT)
    {
        local Actor     T;
        local Vector    HitLoc, HitNorm, Start;
        local float     Dist;
        
        Start = Instigator.Location + Instigator.EyePosition();
        LongGunFactor += FClamp(NewLongGunFactor - LongGunFactor, -DT/AimAdjustTime, DT/AimAdjustTime);
        
        foreach Instigator.TraceActors(class'Actor', T, HitLoc, HitNorm, Start + vector(Instigator.GetViewRotation()) * (GunLength+Instigator.CollisionRadius), Start)
        {
            if( (!T.bBlockActors && T!=Level && TerrainInfo(T)==None) || KFMonster(T)!=None || KFHumanPawn(T)!=None )
                continue;
            break;
        }
        
        if (T == None || T.Base == Instigator)
        {
            if (bPendingSightUp && SightingState < SS_Raising && NewLongGunFactor > 0)
                ScopeBackUp(0.5);
            NewLongGunFactor = 0;
        }
        else
        {
            Dist = FMax(0, VSize(HitLoc - Start)-Instigator.CollisionRadius);
            if (Dist < GunLength)
            {
                if (bScopeView)
                    TemporaryScopeDown(Default.SightingTime*Default.SightingTimeScale);
                NewLongGunFactor = Acos(Dist / GunLength)/1.570796;
            }
        }
    }
    
    simulated function bool CheckScope()
    {
        if (level.TimeSeconds < NextCheckScopeTime)
            return true;
    
        NextCheckScopeTime = level.TimeSeconds + 0.25;
        if (Instigator.base != None)
        {
            if (VSize(Instigator.velocity - Instigator.base.velocity) > 220)
            {
                StopScopeView();
                return false;
            }
        }
        else if (VSize(Instigator.velocity) > 220)
        {
            StopScopeView();
            return false;
        }
        return true;
    }
    
    // This a major part of of the aiming system. It checks on things and interpolates Aim, AimOffset, Chaos,  Recoil, and
    // CrosshairScale. Calls Reaim if it detects view change or movement and constantly sets the gun pivot and view rotation.
    // Azarael - fixed recoil bug here
    simulated function TickAim (float DT)
    {
        if (bAimDisabled)
        {
            Aim = Rot(0,0,0);
            Recoil = 0;
            return;
        }
        
        // Interpolate aim
        if (bReaiming)
        {   
            ReaimPhase += DT;
            if (ReaimPhase >= ReaimTime)
                StopAim();
            else
                Aim = class'BUtil'.static.RSmerp(ReaimPhase/ReaimTime, OldAim, NewAim);
        }
        
        // Falling - reaim 
        else if (Instigator.Physics == PHYS_Falling)    
        {
            if (bScopeView && Instigator.Velocity.Z > 150)  // hold scope briefly if fall isn't too bad
                StopScopeView();
            Reaim(DT, , FallingChaos);  
        }
        
        // Moved, Reaim
        else if (bForceReaim || GetPlayerAim() != OldLookDir || (Instigator.Physics != PHYS_None && VSize(Instigator.Velocity) > 100))
            Reaim(DT);
    
        // Check if scope view can continue
        if (bScopeView)
            CheckScope();
    
        // Interpolate the AimOffset
        if (AimOffset != NewAimOffset)
            AimOffset = class'BUtil'.static.RSmerp(FMax(0.0,(AimOffsetTime-level.TimeSeconds)/AimAdjustTime), NewAimOffset, OldAimOffset);
    
        // Align the gun mesh and player view
        if (LastFireTime + RecoilDeclineDelay >= Level.TimeSeconds)
        {
            ApplyAimRotation();
            OldLookDir = GetPlayerAim();
            return;
        }
        
        // Chaos decline
        if (Chaos > 0)
        {
            if (Instigator.bIsCrouched)
                Chaos -= FMin(Chaos, DT / (ChaosDeclineTime*CrouchAimFactor));
            else
                Chaos -= FMin(Chaos, DT / ChaosDeclineTime);
        }
        // Recoil Decline
        if (Recoil > 0 && LastFireTime + RecoilDeclineDelay < Level.TimeSeconds)
            Recoil -= FMin(Recoil, RecoilMax * (DT / RecoilDeclineTime));
        // Set crosshair size
        if (bReaiming)
            CrosshairInfo.CurrentScale = FMin(1, Lerp(ReaimPhase/ReaimTime, OldChaos, NewChaos)*CrosshairChaosFactor*BCRepClass.default.AccuracyScale + (Recoil/RecoilMax)*BCRepClass.default.RecoilScale) * CrosshairInfo.MaxScale * CrosshairScaleFactor;
        else
            CrosshairInfo.CurrentScale = FMin(1, NewChaos*CrosshairChaosFactor*BCRepClass.default.AccuracyScale + (Recoil/RecoilMax)*BCRepClass.default.RecoilScale) * CrosshairInfo.MaxScale * CrosshairScaleFactor;
    
        // Align the gun mesh and player view
        ApplyAimRotation();
    
        // Remember the player's view rotation for this tick
        OldLookDir = GetPlayerAim();
    }
    // Sets NewAim, OldAim, interpolation time and adds chaos. Another key part of the aiming system. Entry point for aim system...
    // DT           Should be time since last tick,
    // TimeMod      Set this to use custom time instead of AimAdjustTime,
    // ExtraChaos   Extra amount added to chaos
    // XMod         Extra Yaw Added to new aim,
    // YMod         Extra Pitch Added to new aim,
    // BaseChaos    Minimum chaos for new aim. (Player turn chaos and ExtraChaos are still added after this)
    simulated function Reaim (float DT, optional float TimeMod, optional float ExtraChaos, optional float XMod, optional float YMod, optional float BaseChaos)
    {
        local int RDist;
        local float VResult, CAF, X, Y, T, XValue, YValue;
        local Rotator ViewOff, R;
        local Vector V;//, Forward, Right, up;
    
        if (bAimDisabled)
            return;
        if (bUseNetAim && Role < ROLE_Authority)
            return;
    
        bForceReaim=false;
    
        // Figure out how much the view changed
        ViewOff = GetPlayerAim() - OldLookDir;
        R.Yaw = Abs(ViewOff.Yaw);       R.Pitch = Abs(ViewOff.Pitch);
        RDist = int(Sqrt((R.Yaw*R.Yaw) + (R.Pitch*R.Pitch)));
    
        // Calculate chaos caused by movement
        if (Instigator.Physics != PHYS_None)
        {
            V = Instigator.Velocity;
            if (Instigator.Base != None)
    
                V -= Instigator.Base.Velocity;
            VResult = VSize(V) / ChaosSpeedThreshold;
        }
        // CAF is CrouchAimFactor if we're actually crouched
        if (Instigator.bIsCrouched) CAF = CrouchAimFactor;  else CAF = 1;
    
        OldChaos = NewChaos;
        // Add some wildness depending on how much view changed and player movement speed.
        // Chaos is calculated as (BaseChaos + Move Speed Chaos) unleass current chaos is already higher,
        // then it adds (View Change Chaos * CrouchAimFactor) + ExtraChaos.
        Chaos = FClamp(FMax(BaseChaos+VResult, Chaos) + ExtraChaos + CAF*((RDist/DT)/ChaosTurnThreshold), 0, 1 );
    //  Chaos = FMin( 1, FMax(BaseChaos+VResult, Chaos) + ExtraChaos + CAF*((RDist/DT)/ChaosTurnThreshold) );
        NewChaos = Chaos;
    
        if (PlayerController(Instigator.Controller) != None && RDist > 0)
        {   // Bias new aim according to direction player was turning
            XValue = 0.5 + FRand() * 0.5 * (( (ViewOff.Yaw/R.Yaw)*2 + (FRand()*2 - 1) )/3);
            YValue = 0.5 + FRand() * 0.5 * (( (ViewOff.Pitch/R.Pitch)*2 + (FRand()*2 - 1) )/3);
        }
    /*  else if (PlayerController(Instigator.Controller) != None && VResult > 0)
        {   // Bias new aim direction according to player movement
            GetViewAxes(Forward, Right, Up);
            XValue = 0.5 + (FRand()-0.5) * (( abs(Normal(V) Dot Right) + (FRand()*2 - 1) )/2);
            YValue = 0.5 + (FRand()-0.5) * (( abs(Normal(V) Dot Forward) + (FRand()*2 - 1) )/2);
        }
    */  else
        {   // Random direction
            XValue = FRand();
            YValue = FRand();
        }
        // Calculate new aim
        X = XMod + Lerp( XValue/*FRand()*/, Lerp(Chaos, AimSpread.X.Min, ChaosAimSpread.X.Min), Lerp(Chaos, AimSpread.X.Max, ChaosAimSpread.X.Max) );
        Y = YMod + Lerp( YValue/*FRand()*/, Lerp(Chaos, AimSpread.Y.Min, ChaosAimSpread.Y.Min), Lerp(Chaos, AimSpread.Y.Max, ChaosAimSpread.Y.Max) );
        if (TimeMod!=0)
            T = TimeMod;
        else
            T = AimAdjustTime;
        StartAim(T, X, Y);
    
        if (bUseNetAim)
            SendNewAim();
    }
    //Azarael - Zeros aim over TimeMod
    simulated function ZeroAim (float TimeMod)
    {
        if (bAimDisabled || Level.TimeSeconds < NextZeroAimTime)
            return;
            
        if (!bUseNetAim)
            StartAim(TimeMod, 0,0);
    
        ServerZeroAim(TimeMod);
        NextZeroAimTime = Level.TimeSeconds + 0.2;
    }
    function ServerZeroAim (float TimeMod)
    {
        StartAim(TimeMod, 0, 0);
        
        if (bUseNetAim)
            SendNewAim();
    }
    // Start aim interpolation
    simulated function StartAim(float Time, float Yaw, float Pitch)
    {
        bReaiming = true;
        OldAim = Aim;
        ReaimTime = Time;
        ReaimPhase = 0;
        NewAim.Yaw = Yaw;
        NewAim.Pitch = Pitch;
    }
    // Stop interpolating the aim and set it to the end point
    simulated function StopAim()
    {
        bReaiming = false;
        Aim = NewAim;
        ReaimPhase = 0;
    //  ViewAim = GetRecoilPivot(true) * ViewRecoilFactor;
    }
    // Rotate weapon and view according to aim
    simulated function ApplyAimRotation()
    {
        ApplyAimToView();
        PlayerViewPivot = default.PlayerViewPivot + (GetAimPivot() + GetRecoilPivot()) * (DisplayFOV / Instigator.Controller.FovAngle);
    }
    // Rotates the player's view according to Aim
    simulated function ApplyAimToView()
    {
        local Rotator BaseAim, RecoilAim;
    
        //DC 110313
    //  if (!Instigator.IsFirstPerson() || Instigator.Controller == None || AIController(Instigator.Controller) != None/* || !Instigator.IsLocallyControlled()*/)
        if (!Instigator.IsFirstPerson() || Instigator.Controller == None || AIController(Instigator.Controller) != None || !Instigator.IsLocallyControlled())
            return;
    
        RecoilAim = GetRecoilPivot(true) * ViewRecoilFactor*ViewRecoilScale;
        BaseAim = Aim * ViewAimFactor * ViewAimScale + RecoilAim;
    //  BaseAim = class'BUtil'.static.RLerp(ReaimPhase/ReaimTime, RecoilAim, NewAim * ViewAimFactor*ViewAimScale + RecoilAim);
        Instigator.SetViewRotation(Instigator.Controller.Rotation + (BaseAim - ViewAim));
        ViewAim = BaseAim;
    }
    
    // Sets new aimoffset and gets AimOffset to interpolate to it over a period set by ShiftTime
    simulated function SetNewAimOffset(Rotator NewOffset, float ShiftTime)
    {
        OldAimOffset = AimOffset;
        NewAimOffset = NewOffset;
        AimOffsetTime = level.timeseconds + ShiftTime;
    }
    // End Core <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    // Quick Access to aiming aystem output >>>>>>>>>>>>
    
    // Returns the interpolated base aim with its offset, chaos, etc and view aim removed in the form of a single rotator
    simulated function Rotator GetAimPivot(optional bool bIgnoreViewAim)
    {
        if (bIgnoreViewAim || Instigator.Controller == None || PlayerController(Instigator.Controller) == None || PlayerController(Instigator.Controller).bBehindView)
            return AimOffset + Aim + LongGunPivot * LongGunFactor;
        return AimOffset + Aim * (1-ViewAimFactor*ViewAimScale) + LongGunPivot * LongGunFactor;
    //      return AimOffset + Aim * (1-ViewAimFactor*ViewAimScale);
    }
    
    // Returns all the effects of recoil in the form of a single rotator
    simulated function Rotator GetRecoilPivot(optional bool bIgnoreViewAim)
    {
        local Rotator R;
    
        if (!bIgnoreViewAim && ViewRecoilFactor==1 && ViewRecoilScale==1)
            return R;
        // Randomness
        R.Yaw = -Recoil*RecoilXFactor + Recoil*RecoilXFactor*2*RecoilXRand;
        R.Pitch = -Recoil*RecoilYFactor + Recoil*RecoilYFactor*2*RecoilYRand;
        // Pitching/Yawing
        R.Yaw += RecoilMax * InterpCurveEval(RecoilXCurve, Recoil/RecoilMax) * RecoilYawFactor;
        R.Pitch += RecoilMax * InterpCurveEval(RecoilYCurve, Recoil/RecoilMax) * RecoilPitchFactor;
        if (bIgnoreViewAim || Instigator.Controller == None || PlayerController(Instigator.Controller) == None || PlayerController(Instigator.Controller).bBehindView)
            return R;
        return R*(1-ViewRecoilFactor*ViewRecoilScale);
    }
    // Checks up on things and returns what our AimOffset should be
    simulated function Rotator CalcNewAimOffset()
    {
        local Rotator R;
    
        R = default.AimOffset;
        if (!BCRepClass.default.bNoJumpOffset && SprintControl != None && SprintControl.bSprinting)
            R += SprintOffset;
        return R;
    }
    // Should return where the player is aiming this gun. Override this to point the gun in a wierd direction (e.g: Auto Tracking)
    // To make WeaponFire code skip normal AdjustAim and use this, set bUseSpecialAim to true
    simulated function Rotator GetPlayerAim(optional bool bFire)
    {
        if (Instigator != None)
            return Instigator.GetViewRotation();
        else if (Owner != None)
            return Owner.Rotation;
        else
            return Rotation;
    }
    // End Access functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    // Some input events and similar >>>>>>>>>>>>>>>>>>>
    
    // Aim goes bad when player takes damage
    function AdjustPlayerDamage( out int Damage, Pawn InstigatedBy, Vector HitLocation, out Vector Momentum, class<DamageType> DamageType)
    {
        local float DF;
    
        DF = FMin(1, float(Damage)/AimDamageThreshold);
    //  Reaim(0.1, 0.3*AimAdjustTime, DF, DF*(-3500 + 7000 * FRand()), DF*(-3000 + 6000 * FRand()));
        ApplyDamageFactor(DF);
        ClientPlayerDamaged(255*DF);
        bForceReaim=true;
    }
    simulated function ClientPlayerDamaged(byte DamageFactor)
    {
        local float DF;
        if (level.NetMode != NM_Client)
            return;
        DF = float(DamageFactor)/255;
    //  Reaim(0.1, 0.3*AimAdjustTime, DF, DF*(-3500 + 7000 * FRand()), DF*(-3000 + 6000 * FRand()));
        ApplyDamageFactor(DF);
        bForceReaim=true;
    }
    simulated function ApplyDamageFactor (float DF)
    {
        Reaim(0.1, 0.3*AimAdjustTime, DF*2, DF*2*(-3500 + 7000 * FRand()), DF*2*(-3000 + 6000 * FRand()));
    }
    // Do stuff when player sprints or jumps
    // Azarael - workaround for Reloaded cheat
    // Skips all Ammo and inactive Weapons
    function OwnerEvent(name EventName)
    {
        local Inventory Inv;
        
        if (Instigator.Weapon == Self)
        {
            if ((EventName == 'Jumped' || EventName == 'Dodged') && !BCRepClass.default.bNoJumpOffset && !bForceReaim)
            {
                ClientJumped();
                Reaim(0.05, AimAdjustTime, JumpChaos, JumpOffSet.Yaw, JumpOffSet.Pitch);
                bForceReaim=true;
            }
        }
            
        for (Inv = Inventory; Inv != None; Inv = Inv.Inventory)
        {
            if (Ammunition(Inv) != None)
                continue;
            if (Weapon(Inv) != None && Inv != Instigator.Weapon)
                continue;
    
            break;
        }
        
        if (Inv != None)
            Inv.OwnerEvent(EventName);
    }
    
    simulated function PlayerSprint (bool bSprinting)
    {
        if (BCRepClass.default.bNoJumpOffset)
            return;
        if (bScopeView && Instigator.IsLocallyControlled())
            StopScopeView();
        if (bAimDisabled)
            return;
        SetNewAimOffset(CalcNewAimOffset(), AimAdjustTime);
        Reaim(0.05, AimAdjustTime, SprintChaos);
    }
    
    simulated function ClientJumped()
    {
        if (bScopeView)
            StopScopeView();
        if (level.NetMode != NM_Client)
            return;
        Reaim(0.05, AimAdjustTime, JumpChaos, JumpOffSet.Yaw, JumpOffSet.Pitch);
        bForceReaim=true;
    }
    // Add recoil effect
    simulated function AddRecoil (float Amount, optional byte Mode)
    {
        LastFireTime = Level.TimeSeconds;
    
        if (bAimDisabled || Amount == 0)
            return;
        Amount *= BCRepClass.default.RecoilScale;
        if (Instigator.bIsCrouched)
            Amount *= CrouchAimFactor;
        if (bScopeView)
            Amount *= SightAimFactor;
        //DC 110313
    //  Recoil = FMin(RecoilMax, Recoil + Amount);
        if (!BUseNetAim || Role == ROLE_Authority)
        {
            //DC 110313
            Recoil = FMin(RecoilMax, Recoil + Amount);
            RecoilXRand = FRand();
            RecoilYRand = FRand();
            if (BUseNetAim)
                SendNetRecoil();
        }
        // Set crosshair size
        if (bReaiming)
            CrosshairInfo.CurrentScale = FMin(1, Lerp(ReaimPhase/ReaimTime, OldChaos, NewChaos)*CrosshairChaosFactor*BCRepClass.default.AccuracyScale + (Recoil/RecoilMax)*BCRepClass.default.RecoilScale) * CrosshairInfo.MaxScale * CrosshairScaleFactor;
        else
            CrosshairInfo.CurrentScale = FMin(1, NewChaos*CrosshairChaosFactor*BCRepClass.default.AccuracyScale + (Recoil/RecoilMax)*BCRepClass.default.RecoilScale) * CrosshairInfo.MaxScale * CrosshairScaleFactor;
    //  if (bReaiming)
    //      CrosshairInfo.CurrentScale = FMin(1, Lerp(ReaimPhase/ReaimTime, OldChaos, NewChaos)*CrosshairChaosFactor + (Recoil/RecoilMax)) * CrosshairInfo.MaxScale * CrosshairScaleFactor;
    //  else
    //      CrosshairInfo.CurrentScale = FMin(1, NewChaos*CrosshairChaosFactor + (Recoil/RecoilMax)) * CrosshairInfo.MaxScale * CrosshairScaleFactor;
    }
    
    
    // These can be called when a turret undeploys and gives this weapon. Override in sub-classes to add some funtionality
    function InitWeaponFromTurret(BallisticTurret Turret);
    simulated function ClientInitWeaponFromTurret(BallisticTurret Turret);
    function InitTurretWeapon(BallisticTurret Turret);
    
    // End input functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    
    // Rendering and HUD functions -----------------------------------------------------------------------------------------
    
    simulated static function Font GetFontSizeIndex(Canvas C, int FontSize)
    {
        if ( C.ClipX >= 512 )
            FontSize++;
        if ( C.ClipX >= 640 )
            FontSize++;
        if ( C.ClipX >= 800 )
            FontSize++;
        if ( C.ClipX >= 1024 )
            FontSize++;
        if ( C.ClipX >= 1280 )
            FontSize++;
        if ( C.ClipX >= 1600 )
            FontSize++;
    
        return class'HudBase'.static.LoadFontStatic(Clamp( 8-FontSize, 0, 8));
    }
    
    simulated function string GetHUDAmmoText(int Mode)
    {
        if (Ammo[Mode] != None)
            return string(Ammo[Mode].AmmoAmount);
        return "";
    }
    
    //Draw special weapon info on the hud
    simulated function DrawWeaponInfo(Canvas C)
    {
        local float     ScaleFactor, XL, YL, YL2, SprintFactor;
        local string    Temp;
    
        ScaleFactor = C.ClipX / 1600;
        C.Font = GetFontSizeIndex(C, -2 + int(2 * class'HUDKillingFloor'.default.HudScale));
        C.SetDrawColor(128, 190, 255);
    
        if (CurrentWeaponMode < WeaponModes.length && !WeaponModes[CurrentWeaponMode].bUnavailable && WeaponModes[CurrentWeaponMode].ModeName != "")
        {
            C.Font = GetFontSizeIndex(C, -3 + int(2 * class'HUDKillingFloor'.default.HudScale));
            C.TextSize(WeaponModes[CurrentWeaponMode].ModeName, XL, YL2);
            C.CurX = C.ClipX - 100 * ScaleFactor * class'HUDKillingFloor'.default.HudScale - XL;
            C.CurY = C.ClipY - 145 * ScaleFactor * class'HUDKillingFloor'.default.HudScale - YL2 - YL;
            C.DrawText(WeaponModes[CurrentWeaponMode].ModeName, false);
        }
    
        // This is pretty damn disgusting, but the weapon seems to be the only way we can draw extra info on the HUD
        // Would be nice if someone could have a HUD function called along the inventory chain
        if (SprintControl != None && SprintControl.Stamina < SprintControl.MaxStamina)
        {
            SprintFactor = SprintControl.Stamina / SprintControl.MaxStamina;
            C.CurX = C.OrgX  + 5    * ScaleFactor * class'HUDKillingFloor'.default.HudScale;
            C.CurY = C.ClipY - 330  * ScaleFactor * class'HUDKillingFloor'.default.HudScale;
            if (SprintFactor < 0.2)
                C.SetDrawColor(255, 0, 0);
            else if (SprintFactor < 0.5)
                C.SetDrawColor(64, 128, 255);
            else
                C.SetDrawColor(0, 0, 255);
            C.DrawTile(Texture'Engine.MenuWhite', 200 * ScaleFactor * class'HUDKillingFloor'.default.HudScale * SprintFactor, 30 * ScaleFactor * class'HUDKillingFloor'.default.HudScale, 0, 0, 1, 1);
        }
    }
    
    simulated function DrawCrosshairs(canvas C)
    {
        local IntBox    Size;
        local float     ScaleFactor;
        local BWCrosshairCfg CHCfg;
    
        ScaleFactor = C.ClipX / 1600;
    
        // Draw weapon specific Crosshairs
        if (bOldCrosshairs || (bScopeView && bNoCrosshairInScope))
            return;
    
        if (bGlobalCrosshair)
            CHCfg = class'BallisticWeapon'.default.CrosshairCfg;
        else
            CHCfg = CrosshairCfg;
    
        //Work out the exact size of the crosshair
        Size.X1 = CHCfg.StartSize1 * CrosshairInfo.SizeFactors.X1 * (1 + (CrosshairInfo.CurrentScale * CrosshairInfo.SpreadRatios.X1)) * ScaleFactor * class'HUDKillingFloor'.default.CrosshairScale;
        Size.Y1 = CHCfg.StartSize1 * CrosshairInfo.SizeFactors.Y1 * (1 + (CrosshairInfo.CurrentScale * CrosshairInfo.SpreadRatios.Y1)) * ScaleFactor * class'HUDKillingFloor'.default.CrosshairScale;
        Size.X2 = CHCfg.StartSize2 * CrosshairInfo.SizeFactors.X2 * (1 + (CrosshairInfo.CurrentScale * CrosshairInfo.SpreadRatios.X2)) * ScaleFactor * class'HUDKillingFloor'.default.CrosshairScale;
        Size.Y2 = CHCfg.StartSize2 * CrosshairInfo.SizeFactors.Y2 * (1 + (CrosshairInfo.CurrentScale * CrosshairInfo.SpreadRatios.Y2)) * ScaleFactor * class'HUDKillingFloor'.default.CrosshairScale;
    
        // Draw primary
        if (CHCfg.Pic1 != None)
        {
            C.DrawColor = CHCfg.Color1;
            if (bScopeView) C.DrawColor.A = float(C.DrawColor.A) / 1.3;
            C.SetPos((C.ClipX / 2) - (Size.X1/2), (C.ClipY / 2) - (Size.Y1/2));
            C.DrawTile (CHCfg.Pic1, Size.X1, Size.Y1, 0, 0, CHCfg.USize1, CHCfg.VSize1);
        }
        // Draw secondary
        if (CHCfg.Pic2 != None)
        {
            C.DrawColor = CHCfg.Color2;
            if (bScopeView) C.DrawColor.A = float(C.DrawColor.A) / 1.5;
            C.SetPos((C.ClipX / 2) - (Size.X2/2), (C.ClipY / 2) - (Size.Y2/2));
            C.DrawTile (CHCfg.Pic2, Size.X2, Size.Y2, 0, 0, CHCfg.USize2, CHCfg.VSize2);
        }
    }
    // End render stuff ----------------------------------------------------------------------------------------------------
    
    // End Aiming ----------------------------------------------------------------------------------------------------------
    
    // Debug stuff ---------------------------------------------------------------------------------------------------------
    // These ca be used to align the BrassOffset during the game
    exec function BrassOffX (float V)   {   BFireMode[0].BrassOffset.X = V;     BrassMessage(); }
    exec function BrassOffY (float V)   {   BFireMode[0].BrassOffset.Y = V;     BrassMessage(); }
    exec function BrassOffZ (float V)   {   BFireMode[0].BrassOffset.Z = V;     BrassMessage(); }
    function BrassMessage ()    {   Instigator.ClientMessage("BrassOffset is "$BFireMode[0].BrassOffset);   }
    
    // These are to align the 1st person weapon itself
    exec function RVC (float f) {   CenteredOffsetY = f;    default.CenteredOffsetY = f;    Instigator.ClientMessage("CenteredOffset: Y"$CenteredOffsetY);  }
    exec function RVX (float f) {   PlayerViewOffset.X = f; default.PlayerViewOffset.X = f; RVMessage();    }
    exec function RVY (float f) {   PlayerViewOffset.Y = f; default.PlayerViewOffset.Y = f; RVMessage();    }
    exec function RVZ (float f) {   PlayerViewOffset.Z = f; default.PlayerViewOffset.Z = f; RVMessage();    }
    exec function RVF (float f) {   DisplayFov = f;         default.DisplayFov = f;         RVMessage();    }
    exec function RVS (float f) {   SetDrawScale (F);                                       RVMessage();    }
    function RVMessage (){  Instigator.ClientMessage("X: "$PlayerViewOffset.X$", Y: "$PlayerViewOffset.Y$", Z: "$PlayerViewOffset.Z$", Scale: "$DrawScale$", FOV: "$DisplayFov);    }
    
    delegate DumpHead(array<CacheManager.WeaponRecord> Recs);
    delegate DumpLine(class<BallisticWeapon> Weap, int Line);
    delegate DumpTail(array<CacheManager.WeaponRecord> Recs);
    function DumpClassWeapInfo ()
    {
        local class<BallisticWeapon> Weap;
        local int i, j;
        local array<CacheManager.WeaponRecord> Recs;
    
        if (level.NetMode != NM_Standalone)
            return;
        class'CacheManager'.static.GetWeaponList(Recs);
        DumpHead(Recs);
        for (i=0;i<Recs.Length;i++)
        {
            if (!class'BC_WeaponInfoCache'.static.AutoWeaponInfo(Recs[i].ClassName).bIsBW)
                continue;
            Weap = class<BallisticWeapon>(DynamicLoadObject(Recs[i].ClassName, class'Class'));
            if (Weap != None)
            {
                DumpLine(Weap, j);
                j++;
            }
        }
        class'BC_WeaponInfoCache'.static.EndSession();
        DumpTail(Recs);
    }
    
    delegate DumpIHead();
    delegate DumpILine(BallisticWeapon Weap, int Line);
    delegate DumpITail(int Count);
    function DumpInvWeapInfo ()
    {
        local Inventory Inv;
        local int i;
    
        if (level.NetMode != NM_Standalone)
            return;
    
        DumpIHead();
        for (Inv=Instigator.Inventory; Inv!=None; Inv=Inv.Inventory)
            if (BallisticWeapon(Inv) != None)
            {
                DumpILine(BallisticWeapon(Inv), i);
                i++;
            }
        DumpITail(i);
    }
    // This dumps to the log all the playerviewpivot and other stuff that can be changed with the RV# commands
    exec function DumpRVInfo () {
        DumpIHead = DumpRVHead; DumpILine = DumpRVLine; DumpITail = DumpRVTail; DumpInvWeapInfo (); }
    function DumpRVHead()   {
        local string s; s = "Dumping Review stuff for equiped weapons:"; log(s);    Instigator.ClientMessage(s);    }
    function DumpRVLine(BallisticWeapon Weap, int Line) {
        log(Line$" "$Weap.ItemName$"::PlayerViewOffset "$Weap.PlayerViewOffset$", DisplayFov "$Weap.DisplayFov$", DrawScale "$Weap.DrawScale$", CenteredOffsetY "$Weap.CenteredOffsetY);    }
    function DumpRVTail(int Count)  {
        local string s; s = "Review stuff for "$Count$" weapons:"; log(s);  Instigator.ClientMessage(s);    }
    /*
    exec function DumpRVInfo () {
        DumpHead = DumpRVHead; DumpLine = DumpRVLine;   DumpTail = None; DumpClassWeapInfo ();  }
    function DumpRVHead(array<CacheManager.WeaponRecord> Recs)  {
        local string s; s = "Dumping Review stuff: "$Recs.length$" Weapons found."; log(s); Instigator.ClientMessage(s);    }
    function DumpRVLine(class<BallisticWeapon> Weap, int Line)  {
        log(Line$" "$Weap.default.ItemName$"::PlayerViewOffset "$Weap.default.PlayerViewOffset$", DisplayFov "$Weap.default.DisplayFov$", DrawScale "$Weap.default.DrawScale$", CenteredOffsetY "$Weap.default.CenteredOffsetY);    }
    */
    // This dumps to the log all the Sight alignments stuff. Use 'Set' in the consol to change things, then dump with this.
    exec function DumpSightInfo ()  {
        DumpHead = DumpSightHead; DumpLine = DumpSightLine; DumpTail = None; DumpClassWeapInfo ();  }
    function DumpSightHead(array<CacheManager.WeaponRecord> Recs)   {
        local string s; s = "Dumping Sight stuff: "$Recs.length$" Weapons found."; log(s);  Instigator.ClientMessage(s);    }
    function DumpSightLine(class<BallisticWeapon> Weap, int Line)   {
        log(Line$" "$Weap.default.ItemName$"::SightOffset "$Weap.default.SightOffset$", SightPivot "$Weap.default.SightPivot$", SightDisplayFOV "$Weap.default.SightDisplayFOV$", SightBone "$Weap.default.SightBone$", FullZoomFOV "$Weap.default.FullZoomFOV$", SightAimFactor "$Weap.default.SightAimFactor);    }
    
    // Add extra Ballistic info to the debug readout
    simulated function DisplayDebug(Canvas Canvas, out float YL, out float YPos)
    {
        local string s;
    
        super.DisplayDebug(Canvas, YL, YPos);
    
        Canvas.SetDrawColor(255,128,0);
        s = "Ballistic Weapon: ReloadeState: ";
        Switch( ReloadState )
        {
            case RS_None: s=s$"None"; break;
            case RS_PreClipOut: s=s$"PreClipOut"; break;
            case RS_PreClipIn: s=s$"PreClipIn"; break;
            case RS_PostClipIn: s=s$"PostClipIn"; break;
            case RS_StartShovel: s=s$"StartShovel"; break;
            case RS_Shovel: s=s$"Shovel"; break;
            case RS_PostShellIn: s=s$"PostShellIn"; break;
            case RS_EndShovel: s=s$"EndShovel"; break;
            case RS_Cocking: s=s$"Cocking"; break;
        }
        s = s $ ", MagCapacity: "$MagCapacity $ ", WeaponMode: "$WeaponModes[CurrentWeaponMode].ModeName $ ", FireCount: "$FireCount;
        Canvas.DrawText(s);
        YPos += YL;
        Canvas.SetPos(4,YPos);
    
        Canvas.DrawText("Chaos: "$Chaos$", Recoil: "$Recoil$", ReaimPhase: "$ReaimPhase$", Aim: "$Aim.Yaw$","$Aim.Pitch);
        YPos += YL;
        Canvas.SetPos(4,YPos);
    }
    // End debug -----------------------------------------------------------------------------------------------------------
    
    // Start KF System -----------------------------------------------------------------------------------------------------------
    // Check if we have ammo for the secondary fire
    simulated function bool CheckSecondaryAmmo()
    {
        if(Ammo[1].AmmoAmount <= 0){
            return false;
        }
        return true;
    }
    //Change up the sleeve swapping that way we can swap the hand texture of more then just 1 skin per-weapon
    simulated function HandleSleeveSwapping()
    {
        local XPawn XP;
        local int i;
        local Material SleeveTexture;
    
        // don't bother with AI players
        if( !Instigator.IsHumanControlled() || !Instigator.IsLocallyControlled() )
            return;
    
        XP = XPawn(Instigator);
    
        if( XP == none )
        {
            return;
        }
    
        SleeveTexture = Class<KFSpeciesType>(XP.Species).static.GetSleeveTexture();
    
        if( SleeveTexture != none )
        {
            for (i=0;i<TeamSkins.Length;i++)
            {
                TeamSkins[i].RedTex = SleeveTexture;
                TeamSkins[i].BlueTex = SleeveTexture;
            }
        }
    }
    // End KF System -----------------------------------------------------------------------------------------------------------
    
    defaultproperties
    {
         PlayerJumpFactor=1.000000
         TeamSkins(0)=(RedTex=Texture'KF_Weapons_Trip_T.hands.hands_1stP_military_diff',BlueTex=Texture'KF_Weapons_Trip_T.hands.hands_1stP_military_diff')
         AIReloadTime=2.000000
         BallisticInventoryGroup=254
         IdleTweenTime=0.200000
         SightFXBone="tip"
         BCRepClass=Class'KFBCoreV25.BCReplicationInfo'
         bBallisticInvGroups=True
         bUseScopeViewAim=True
         ViewAimScale=1.000000
         ViewRecoilScale=1.000000
         CrosshairScaleFactor=1.000000
         InventorySize=35
         SpecialInfo(0)=(id="EvoDefs",Info="0.0;10.0;0.5;50.0;0.2;0.2;0.1")
         BringUpSound=(Volume=0.500000,Radius=32.000000,Slot=SLOT_Interact,Pitch=1.000000,bAtten=True)
         PutDownSound=(Volume=0.500000,Radius=32.000000,Slot=SLOT_Interact,Pitch=1.000000,bAtten=True)
         CockAnim="Cock"
         CockAnimRate=1.000000
         CockSound=(Volume=0.500000,Radius=32.000000,Pitch=1.000000,bAtten=True)
         ClipHitSound=(Volume=0.500000,Radius=32.000000,Pitch=1.000000,bAtten=True)
         ClipOutSound=(Volume=0.500000,Radius=32.000000,Slot=SLOT_Interact,Pitch=1.000000,bAtten=True)
         ClipInSound=(Volume=0.500000,Radius=32.000000,Slot=SLOT_Interact,Pitch=1.000000,bAtten=True)
         ClipInFrame=0.900000
         StartShovelAnimRate=1.000000
         EndShovelAnimRate=1.000000
         ShovelIncrement=1
         WeaponModes(0)=(ModeName="Semi-Auto",ModeID="WM_SemiAuto",Value=1.000000)
         WeaponModes(1)=(ModeName="Burst Fire",ModeID="WM_Burst",Value=3.000000)
         WeaponModes(2)=(ModeName="Full Auto",ModeID="WM_FullAuto")
         CurrentWeaponMode=2
         bUseSights=True
         bPlayScopeUp=True
         FullZoomFOV=80.000000
         SightOffset=(Z=2.500000)
         SightDisplayFOV=30.000000
         SightingTime=0.350000
         SightingTimeScale=1.000000
         CrosshairCfg=(USize1=128,VSize1=128,USize2=128,VSize2=128,Color1=(R=255,A=255),Color2=(G=255,R=255,A=255),StartSize1=96,StartSize2=96)
         CrosshairInfo=(SpreadRatios=(X1=0.500000,Y1=0.500000,X2=0.500000,Y2=0.750000),SizeFactors=(X1=1.000000,Y1=1.000000,X2=1.000000,Y2=1.000000),MaxScale=4.000000)
         CrosshairChaosFactor=0.400000
         GunLength=64.000000
         LongGunPivot=(Pitch=4000,Yaw=-12000)
         LongGunOffset=(X=5.000000,Y=10.000000,Z=-11.000000)
         CrouchAimFactor=0.700000
         SightAimFactor=0.700000
         JumpOffSet=(Pitch=-5000,Yaw=-1000)
         JumpChaos=0.400000
         FallingChaos=0.400000
         SprintChaos=0.400000
         AimAdjustTime=0.500000
         AimSpread=(X=(Min=-16.000000,Max=16.000000),Y=(Min=-16.000000,Max=16.000000))
         ViewAimFactor=0.500000
         ViewRecoilFactor=0.500000
         AimDamageThreshold=100.000000
         ChaosDeclineTime=2.000000
         ChaosTurnThreshold=131072.000000
         ChaosSpeedThreshold=500.000000
         ChaosAimSpread=(X=(Min=-2560.000000,Max=2560.000000),Y=(Min=-2560.000000,Max=2560.000000))
         RecoilXCurve=(Points=(,(InVal=1.000000,OutVal=1.000000)))
         RecoilYCurve=(Points=(,(InVal=1.000000,OutVal=1.000000)))
         RecoilPitchFactor=1.000000
         RecoilYawFactor=1.000000
         RecoilXFactor=0.500000
         RecoilYFactor=0.500000
         RecoilMax=2048.000000
         RecoilDeclineTime=2.000000
         RecoilDeclineDelay=0.300000
         MagCapacity=30
         ReloadAnim="Reload"
         ReloadAnimRate=1.000000
         WeaponReloadAnim="Reload_BullPup"
         StandardDisplayFOV=50.000000
         SleeveNum=0
         SelectAnim="Pullout"
         PutDownAnim="Putaway"
         SelectAnimRate=1.000000
         PutDownAnimRate=1.000000
         PutDownTime=0.300000
         BringUpTime=0.300000
         DisplayFOV=60.000000
         Priority=2
         CenteredOffsetY=0.000000
         CenteredRoll=500
         CustomCrosshair=7
         ItemName="BallisticWeapon"
         TransientSoundVolume=0.500000
    }
    
    

    BCReplicationInfo
    Код:
    //=============================================================================
    // BCReplicationInfo.
    //
    // Special global replication actor for transmitting server-side globals to all
    // clients.
    // This is spawned at the beginning of the match by mutator, then it is
    // replicated to all clients. Client then copies the values of all the varibles
    // to its defaults. After that, all actors client side can see what the server
    // has set by reading the defaults of this class.
    //
    // by Nolan "Dark Carnivour" Richert.
    // Copyright(c) 2007 RuneStorm. All Rights Reserved.
    //=============================================================================
    class BCReplicationInfo extends LinkedReplicationInfo config(BallisticV25);
    
    var() string		ModString;
    
    // Server Variables -----------------------------------------------------------
    // Weapon
    var() config float		AccuracyScale;		// Used for scaling general weapon accuracy.
    var() config float		RecoilScale;		// Used for scaling general weapon recoil.
    var() config float		ReloadSpeedScale;	// Buff reload speeds
    var() config bool		bNoJumpOffset;		// Prevents weapons shifting and being offset when jumping or sprinting
    var() config bool		bNoLongGun;			// Disable 'long gun' features
    var() config bool		bNoReloading;		// Disables reloading and weapons use boring old style ammo handling...
    var() config bool		bNoFirstCock; 	// Disables standard weapons cocking when brought out
    var() config bool		bLockRecoil; 	// Forcibly locks recoil to crosshairs
    
    // ----------------------------------------------------------------------------
    var struct RepInfo_BCore
    {
    	var float		AccuracyScale;
    	var float		RecoilScale;
    	var float		ReloadSpeedScale;
    	var bool		bNoJumpOffset;
    	var bool		bNoLongGun;
    	var bool		bNoReloading;
    	var bool		bNoFirstCock;
    	var bool		bLockRecoil;
    }BCoreRep;
    
    replication
    {
    	reliable if (Role == ROLE_Authority && bNetInitial)
    		BCoreRep;
    }
    
    // Set all defaults to match server vars here
    simulated function InitClientVars()
    {
    	AccuracyScale	= BCoreRep.AccuracyScale;
    	RecoilScale		= BCoreRep.RecoilScale;
    	ReloadSpeedScale = BCoreRep.ReloadSpeedScale;
    	bNoJumpOffset	= BCoreRep.bNoJumpOffset;
    	bNoLongGun		= BCoreRep.bNoLongGun;
    	bNoReloading	= BCoreRep.bNoReloading;
    	bNoFirstCock = BCoreRep.bNoFirstCock;
    	bLockRecoil = BCoreRep.bLockRecoil;
    
    	class.default.AccuracyScale	= AccuracyScale;
    	class.default.RecoilScale	= RecoilScale;
    	class.default.ReloadSpeedScale = ReloadSpeedScale;
    	class.default.bNoJumpOffset	= bNoJumpOffset;
    	class.default.bNoLongGun	= bNoLongGun;
    	class.default.bNoReloading	= bNoReloading;
    	class.default.bNoFirstCock = bNoFirstCock;
    	class.default.bLockRecoil = bLockRecoil;
    	Log("InitClientVars: "$ModString);
    
    	Log("AccuracyScale: "$AccuracyScale);
    	Log("RecoilScale: "$RecoilScale);
    	Log("ReloadSpeedScale: "$ReloadSpeedScale);
    	Log("bNoJumpOffset: "$bNoJumpOffset);
    	Log("bNoLongGun: "$bNoLongGun);
    	Log("bNoReloading: "$bNoReloading);
    	Log("bNoFirstCock: "$bNoFirstCock);
    	Log("bLockRecoil: "$bLockRecoil);
    }
    
    function ServerInitialize()
    {
    	BCoreRep.AccuracyScale	= AccuracyScale;
    	BCoreRep.RecoilScale	= RecoilScale;
    	BCoreRep.ReloadSpeedScale = ReloadSpeedScale;
    	BCoreRep.bNoJumpOffset	= bNoJumpOffset;
    	BCoreRep.bNoLongGun		= bNoLongGun;
    	BCoreRep.bNoReloading	= bNoReloading;
    	BCoreRep.bNoFirstCock = bNoFirstCock;
    	BCoreRep.bLockRecoil = bLockRecoil;
    
    	Log("ServerInitialize: "$ModString);
    }
    
    simulated event PostNetBeginPlay()
    {
    	if (Role < ROLE_Authority)
    		InitClientVars();
    }
    
    static function BCReplicationInfo HitMe(actor A)
    {
    	local BCReplicationInfo BRI;
    
    	BRI = GetBRep(A);
    
    	if (BRI == None)
    	{
    		BRI = A.Spawn(default.class);
    		BRI.ServerInitialize();
    	}
    	return BRI;
    }
    
    static function BCReplicationInfo GetBRep(actor A)
    {
    	local BCReplicationInfo BRI;
    
    	foreach A.DynamicActors(class'BCReplicationInfo', BRI)
    	{
    		if (A != None)
    			return BRI;
    	}
    	return None;
    }
    
    defaultproperties
    {
         ModString="Ballistic Core v2.5 Fix"
         AccuracyScale=1.000000
         RecoilScale=1.000000
         ReloadSpeedScale=1.000000
         bOnlyDirtyReplication=False
    }
    
    

    И самое интересное: BCSprintControl
    Код:
    //=============================================================================
    // BCSprintControl.
    //
    // A special inventory actor used to control player sprinting. Key events must
    // be sent from somewhere like a mutator.
    //
    // by Nolan "Dark Carnivour" Richert.
    // Copyright(c) 2005 RuneStorm. All Rights Reserved.
    //=============================================================================
    class BCSprintControl extends Inventory;
    
    var() float		Stamina;			// Stamina level of player. Players can't sprint when this is out
    var() float		MaxStamina;			// Max level of stamina
    var() float		StaminaDrainRate;	// Amount of stamina lost each second when sprinting
    var() float		StaminaChargeRate;	// Amount  of stamina gained each second when not sprinting
    var   bool		bSprinting;			// Currently sprinting
    var   bool		bSprintHeld;		// Sprint key is held down
    var() float		SpeedFactor;		// Player speed multiplied by this when sprinting
    
    var float		SprintRechargeDelay; // Retrigger delay
    
    replication
    {
    	reliable if (Role == ROLE_Authority)
    		ClientStartSprint, ClientStopSprint, ClientJumped;
    }
    
    // Key press sent from server
    simulated function ClientStartSprint()
    {
    	if (level.netMode == NM_Client)
    		StartSprint();
    }
    // Called from mutator or whatever when key is pressed
    function ServerStartSprint()
    {
    	ClientStartSprint();
    	StartSprint();
    }
    // Sprint Key pressed. Used on Client and Server
    simulated function StartSprint()
    {
    	local float NewSpeed;
    	if (Stamina <= 0 || bSprintHeld || (xPawn(Instigator)!=None && xPawn(Instigator).CurrentCombo!=None))
    		return;
    	bSprintHeld=true;
    	
    	if (Instigator != None)
    	{
    		NewSpeed = Instigator.default.GroundSpeed * SpeedFactor;
    		if (BallisticWeapon(Instigator.Weapon) != None)
    			NewSpeed *=  BallisticWeapon(Instigator.Weapon).PlayerSpeedFactor;
    		Instigator.GroundSpeed = NewSpeed;
    	}
    }
    
    // Key release sent from server
    simulated function ClientStopSprint()
    {
    	if (level.netMode == NM_Client)
    		StopSprint();
    }
    // Called from mutator or whatever when key is released
    function ServerStopSprint()
    {
    	ClientStopSprint();
    	StopSprint();
    }
    // Sprint Key released. Used on Client and Server
    simulated function StopSprint()
    {
    	local float NewSpeed;
    	
    	if (!bSprintHeld)
    		return;
    	bSprintHeld=false;
    	if (Instigator != None)
    	{
    		NewSpeed = Instigator.default.GroundSpeed;
    		if (BallisticWeapon(Instigator.Weapon) != None)
    			NewSpeed *=  BallisticWeapon(Instigator.Weapon).PlayerSpeedFactor;
    		Instigator.GroundSpeed = NewSpeed;
    	}
    	SprintRechargeDelay = Level.TimeSeconds + 1.5;
    }
    simulated function OwnerEvent(name EventName)
    {
    	super.OwnerEvent(EventName);
    	if (EventName == 'Jumped' || EventName == 'Dodged')
    	{
    		ClientJumped();
    		Stamina = FMax(0, Stamina - StaminaDrainRate * 2);
    		SprintRechargeDelay = Level.TimeSeconds + 1.5;
    	}
    }
    simulated function ClientJumped()
    {
    	if (level.NetMode != NM_Client)
    		return;
    	Stamina = FMax(0, Stamina - StaminaDrainRate * 2);
    	SprintRechargeDelay = Level.TimeSeconds + 1.5;
    }
    
    simulated event Tick(float DT)
    {
    	// Drain stamin while sprinting
    	if (bSprintHeld && Instigator.Physics != PHYS_Falling && VSize(Instigator.Acceleration) > 100 && VSize(Instigator.Velocity) > 50 && (xPawn(Instigator) == None || xPawn(Instigator).CurrentCombo==None))
    	{
    		if (!bSprinting)
    		{
    			bSprinting=true;
    			if (BallisticWeapon(Instigator.Weapon) != None)
    				BallisticWeapon(Instigator.Weapon).PlayerSprint(true);
    			if (Instigator != None && Instigator.Inventory != None)
    				Instigator.Inventory.OwnerEvent('StartSprint');
    		}
    		Stamina -= StaminaDrainRate * DT;
    		if (Stamina <= 0)
    			StopSprint();
    	}
    	// Stamina charges when not sprinting
    	else// if (VSize(RV) < Instigator.default.GroundSpeed * 0.8)
    	{
    		if (bSprinting)
    		{
    			bSprinting=False;
    			if (BallisticWeapon(Instigator.Weapon) != None)
    				BallisticWeapon(Instigator.Weapon).PlayerSprint(false);
    			if (Instigator != None && Instigator.Inventory != None)
    				Instigator.Inventory.OwnerEvent('StopSprint');
    		}
    		if (Stamina < MaxStamina && Level.TimeSeconds > SprintRechargeDelay)
    			Stamina += StaminaChargeRate * DT;
    	}
    	Stamina = FClamp(Stamina, 0, MaxStamina);
    }
    
    function GiveTo(Pawn Other, optional Pickup Pickup)
    {
    	Super.GiveTo(Other);
    
    	if (Instigator != None && Instigator.Weapon != None && BallisticWeapon(Instigator.Weapon) != None && BallisticWeapon(Instigator.Weapon).SprintControl == None)
    		BallisticWeapon(Instigator.Weapon).SprintControl = self;
    }
    
    defaultproperties
    {
         Stamina=100.000000
         MaxStamina=100.000000
         StaminaDrainRate=10.000000
         StaminaChargeRate=15.000000
         SpeedFactor=1.350000
         bReplicateInstigator=True
    }
    
    
     
  9. Flame

    Flame -Заслуженый кодер форума-

    Ну ускорение у меня есть по шприцу
    Полосочка усталости есть у берса
    А реагирование на кнопочку тоже есть
    В принципе объединить это всё недолго

    Впрочем, гляну код баллистика тоже
     
  10. kok-s

    kok-s Консильери

    А может кто написать автору ТУТ что бы он обновил ссылки. Я там не зареган, да и регаться из за 1 поста глупо.
     
  11. w.a.l

    w.a.l Консильери

    Кушайте не обляпайтесь :dry: :
    killingfloorgame.net

    Чё будет не хватать, скажете.
     
    Последнее редактирование: 29 окт 2018
    Человек нравится это.
  12. WipeMaster

    WipeMaster Бандит

    Beta 2 и есть последняя стабильная версия с поддержкой scrn. Forrestmark9 дал ту же ссылку в ЛС.

    KFBallisticCompat.ini

    [ScrnBalanceCompat CompatSettings]
    bEnabled=False
    bUseServerPerks=False
    bUseScrnBalance=True
    PlayerControllerClass="KFBallisticV25_Scrn.BallisticPlayer"
    HUDClass="KFBallisticV25_Scrn.BWHUDKillingFloor"
    ScrnBalanceMut="ScrnBalanceSrv.ScrnBalance"
    ServerPackage="KFBallisticV25_Scrn"
     
    kok-s нравится это.
  13. Titanishu

    Titanishu Бандит

    Ну шо, как оно там?
     
  14. drummer36

    drummer36 Солдат

    Я думаю как говорит Флейм - "пинайте меня" :teehee:
     
  15. Titanishu

    Titanishu Бандит

    Я бы и пнул осторожненько, дык личка заполнена
     
  16. Stein

    Stein Солдат

    Всем добра... кто подскажет, в этом огромном объёме кода, где фиксить перезарядку оружий :sad: хотябы в каком классе
     
  17. Flame

    Flame -Заслуженый кодер форума-

    Я часто сталкиваюсь, что по многим крупным модам часто битые ссылки и авторы не шевелятся это как-то править.
    Пусть хоть у нас будут нормальные.
    Перенёс данную тему из подфорума Оружие, так как исторически такие крупные моды, затрагивающие весь игровой процесс, у нас хранятся вне категорий
    Тему восстанавливаю из архивов у себя на диске - вроде там нормальная версия для SP

    Перекомпилировал и поправил, чтобы было адекватно текущим патчам
    Scrn версии у меня нет, либо выкладывайте у кого есть, либо пните Пуша, либо и фиг бы с ней )
    Ссылка 1 или Ссылка 2

    В продолжении темы:
    Я особо не разбирался в представленных в этом пакете мутаторах.
    Mut_Regeneration - видимо вампиризм/регенерация от катаны и других факторов
    Mut_Sprinter - бег
    Mut_Loadout, Mut_LoadoutConfig - мутаторы выбора оружия перед 1 волной и начала игры без оружия. Не разбирался пока что

    У большинства оружия есть спец атака/возможность. Надо биндить WeaponSpecial и
    WeaponSpecialRelease. Для спринта биндить mutate BStartSprint и mutate BStopSprint (ну и мутатор спринта не забыть подключить)
    Позже я аккуратно распишу нюансы этого мода

    Кроме ссылок на кф версию - вот ссылка на версию для ut2004
    Возможно мододелам интересен будет некоторый код или ресурсы
    Ссылка

    Ещё там есть папка Help, а в ней информация по моду
    Выделил её в отдельный архив. Например, Ballisticv25-Manual_Weapons.html, достаточно полное руководство по представленному в моде оружию. В идеале бы на форум бы всё это описание аккуратно поместить, чтобы можно было заранее ознакомиться с оружием. Но мне лень, например
    Ссылка

    Насчёт PowerItem'а по ускорению тем, кто ждал этого в начале 2016, но так и не смог меня пнуть
    Поглядел я код в баллистике - а вы уверены, что это работало?
    Там скорость игрока меняется ровно так же как в ut2004, а в KF это происходит по-другому
    Да и при тесте вживую я не заметил разницы в скорости (ShowDebug выдавало одну и ту же скорость)
    Может Пуш правил это для Scrn?
    В общем сделаю тогда работающий вариант на основе этого кода (ибо сделано вполне терпимо) и выложу отдельным мутатором
     
    Последнее редактирование: 17 авг 2017
    RaideN- и w.a.l нравится это.
  18. RaideN-

    RaideN- Игровая Администрация

    всё круто! Флейм, сможешь выпилить этот спринт в виде отдельного мутатора?
    Штука то очень занятная
     
  19. Flame

    Flame -Заслуженый кодер форума-

    Ну накидал какую-то базовую версию
    Пришлось отображение полосочки своё делать - в баллистике там хитро сделано - доступ в HUD через оружие, чуть ли не через прицел
    Я взял стандартный подход - Interaction

    Вот совсем сейчас лень всё это расписывать, делать аккуратный код, выводить настройки в ини
    На днях сделаю и темку оформлю
    Пока всё что вам надо знать - это то, что скорость правится тут (посредством InventorySpeedModifier)
    Код:
    KFHumanPawn(Instigator).InventorySpeedModifier=300;
    
    А запускать возможность спринта надо командой mutate StartSprint

    Ссылка
     
    STaJIKeR и RaideN- нравится это.
  20. RaideN-

    RaideN- Игровая Администрация

    Круто получилось. Единственное нашел 2 бага:
    1. когда спринт заканчивается, иногда трясется/дергается оружие в руках.
    2. этот баг появился только 1 раз. Спринт залип и не отключался. Я минуту быстро бегал по карте.