class Weapon extends Inventory abstract native nativereplication HideDropDown CacheExempt; #exec Texture Import File=Textures\Weapon.tga Name=S_Weapon Mips=Off Alpha=1 replication { // Things the server should send to the client. reliable if( Role==ROLE_Authority ) Ammo, AmmoCharge; //if _RO_ // Things the server should send to the client. reliable if( bNetDirty && Role==ROLE_Authority ) bBayonetMounted, bUsingSights; // end _RO_ // Functions called by server on client reliable if( Role==ROLE_Authority ) ClientWeaponSet, ClientWeaponThrown, ClientForceAmmoUpdate, ClientWriteStats, ClientWriteFire; // functions called by client on server reliable if( Role FireModeClass[NUM_FIRE_MODES]; var() protected WeaponFire FireMode[NUM_FIRE_MODES]; var() protected Ammunition Ammo[NUM_FIRE_MODES]; // animation // var() Name IdleAnim; var() Name RestAnim; var() Name AimAnim; var() Name RunAnim; var() Name SelectAnim; var() Name PutDownAnim; var() float IdleAnimRate; var() float RestAnimRate; var() float AimAnimRate; var() float RunAnimRate; var() float SelectAnimRate; var() float PutDownAnimRate; var float PutDownTime; var float BringUpTime; var() Sound SelectSound; var() String SelectForce; // jdf // AI // var() int BotMode; // the fire Mode currently being used for bots var() float AIRating; var float CurrentRating; // rating result from most recent RateSelf() var() bool bMeleeWeapon; var() bool bSniping; // other useful stuff // var bool bShowChargingBar; var bool bMatchWeapons; // OBSOLETE - see WeaponAttachment var() bool bCanThrow; var() bool bForceSwitch; // if true, this weapon will prevent any other weapon from delaying the switch to it (bomb launcher) var() deprecated bool bNotInPriorityList; // Should be displayed in a GUI weapon list - refer to 'Description' documentation var bool bNotInDemo; var bool bNoVoluntarySwitch; var bool bSpectated; var bool bDebugging; var bool bNoInstagibReplace; var bool bInitOldMesh; var config bool bUseOldWeaponMesh; var bool bEndOfRound; // don't allow firing var bool bNoAmmoInstances; // if true, replicated ammocount using the Weapons AmmoCharge property - true by default, included to allow mod authors to fallback to old style var bool bBerserk; // properties needed if no instantiated ammunition var int AmmoCharge[2]; var class AmmoClass[2]; var Mesh OldMesh; var string OldPickup; var(OldFirstPerson) float OldDrawScale, OldCenteredOffsetY; var(OldFirstPerson) vector OldPlayerViewOffset, OldSmallViewOffset; var(OldFirstPerson) rotator OldPlayerViewPivot; var(OldFirstPerson) int OldCenteredRoll, OldCenteredYaw; /* A note about weapons & the caching system: You must now perform two commands on your mod's final package file: 'ucc dumpint ' - this exports the localized text to a localization file, which is used by the caching system to load the ItemName and Description 'ucc exportcache ' - this exports the information that will be used to load the weapon into the caching system. Type 'ucc help exportcache' at the command-line for more info. Ex: (ACoolWeaponMod.u) ucc dumpint ACoolWeaponMod.u - creates 'ACoolWeaponMod.int' file, (file extension will vary if a different language is specified in the UT2004.ini file) ucc exportcache ACoolWeaponMod.u - creates an entry in the 'CacheRecords.ucl' file, containing caching information for your package Weapons must have values for both ItemName & Description in order to appear in the game. The caching system will not recognize inherited values for these properties. If creating a custom crosshair for your weapon, it will FIXME -- rjp */ var() localized cache string Description; var class DemoReplacement; var transient bool bPendingSwitch; var(FirstPerson) vector EffectOffset; // where muzzle flashes and smoke appear. replace by bone reference eventually var() Localized string MessageNoAmmo; var(FirstPerson) float DisplayFOV; var() enum EWeaponClientState { WS_None, WS_Hidden, WS_BringUp, WS_PutDown, WS_ReadyToFire } ClientState; // this will always be None on the server var() config byte ExchangeFireModes; var() config byte Priority; var() deprecated byte DefaultPriority; var float Hand; var float RenderedHand; var Color HudColor; var Weapon OldWeapon; var(FirstPerson) vector SmallViewOffset; // Offset from view center with small weapons option. var(FirstPerson) vector SmallEffectOffset; var(FirstPerson) float CenteredOffsetY; var(FirstPerson) int CenteredRoll, CenteredYaw; var config int CustomCrosshair; var config color CustomCrossHairColor; var config float CustomCrossHairScale; var config string CustomCrossHairTextureName; var texture CustomCrossHairTexture; var float DownDelay, MinReloadPct; // Used to delay putting down weapons which have jsut been fired // ROVariables - put here to avoid casting // if _RO_ var bool bBayonetMounted; // If true this weapon has a bayonet mounted var bool bCanAttachOnBack;// True if this weapon can be placed on the pawns back var bool bCanRestDeploy;// True if this weapon can be deployed by resting it on something var bool bCanBipodDeploy;// True if this weapon can be deployed using a bipod var bool bBipodDeployed; // True if the weapon is deployed on its bipod var float LastStartCrawlingTime; // Used in smoothing out transitions to/from crawling forward/back var bool bUsingSights; // True if the weapon is zoomed in using the sights var bool bUsesFreeAim; // Whether or not this weapon uses free-aim var bool bCanSway; // This weapon can sway in ironsights (false for binocs) // end _RO_ native final function InitWeaponFires(); simulated function float ChargeBar(); // ROFunctions - put here to avoid casting // if _RO_ simulated function bool WeaponCanSwitch() {return true;} simulated function bool WeaponCanBusySwitch() {return false;} simulated function bool WeaponAllowSprint() {return true;} simulated function bool WeaponAllowProneChange() {return true;} simulated function bool WeaponAllowCrouchChange() {return true;} simulated function bool IsMounted() {return false;} simulated function bool IsCrawling() {return false;} simulated function ROIronSights(); simulated function int GetHudAmmoCount(); simulated function NotifyOwnerJumped(); function SetServerOrientation(rotator NewRotation); function coords GetMuzzleCoords(); simulated function bool ShouldUseFreeAim() {return false;} simulated function PostFire(); // end _RO_ // Called by physics when the player is crawling simulated event NotifyCrawlMoving(); simulated event NotifyStopCrawlMoving(); //========================================================================= // Ammunition Interface (to remove the need for instantiated ammunition) simulated function class GetAmmoClass(int mode) { return AmmoClass[mode]; } simulated function MaxOutAmmo() { if ( bNoAmmoInstances ) { if ( AmmoClass[0] != None ) AmmoCharge[0] = MaxAmmo(0); if ( (AmmoClass[1] != None) && (AmmoClass[0] != AmmoClass[1]) ) AmmoCharge[1] = MaxAmmo(1); return; } if ( Ammo[0] != None ) Ammo[0].AmmoAmount = Ammo[0].MaxAmmo; if ( Ammo[1] != None ) Ammo[1].AmmoAmount = Ammo[1].MaxAmmo; } simulated function SuperMaxOutAmmo() { if ( bNoAmmoInstances ) { if ( AmmoClass[0] != None ) AmmoCharge[0] = 999; if ( (AmmoClass[1] != None) && (AmmoClass[0] != AmmoClass[1]) ) AmmoCharge[1] = 999; return; } if ( Ammo[0] != None ) Ammo[0].AmmoAmount = 999; if ( Ammo[1] != None ) Ammo[1].AmmoAmount = 999; } simulated function int MaxAmmo(int mode) { if ( AmmoClass[mode] != None ) return AmmoClass[mode].Default.MaxAmmo; return 0; } simulated function FillToInitialAmmo() { if ( bNoAmmoInstances ) { if ( AmmoClass[0] != None ) AmmoCharge[0] = Max(AmmoCharge[0], AmmoClass[0].Default.InitialAmount); if ( (AmmoClass[1] != None) && (AmmoClass[0] != AmmoClass[1]) ) AmmoCharge[1] = Max(AmmoCharge[1], AmmoClass[1].Default.InitialAmount); return; } if ( Ammo[0] != None ) Ammo[0].AmmoAmount = Max(Ammo[0].AmmoAmount,Ammo[0].InitialAmount); if ( Ammo[1] != None ) Ammo[1].AmmoAmount = Max(Ammo[1].AmmoAmount,Ammo[1].InitialAmount); } simulated function int AmmoAmount(int mode) { if ( bNoAmmoInstances ) { if ( AmmoClass[0] == AmmoClass[mode] ) return AmmoCharge[0]; return AmmoCharge[mode]; } if ( Ammo[mode] != None ) return Ammo[mode].AmmoAmount; return 0; } simulated function class AmmoPickupClass(int mode) { if ( AmmoClass[mode] != None ) return FireMode[mode].AmmoClass.Default.PickupClass; return None; } simulated function bool AmmoMaxed(int mode) { if ( AmmoClass[mode] == None ) return false; if ( bNoAmmoInstances ) { if ( AmmoClass[0] == AmmoClass[mode] ) mode = 0; return AmmoCharge[mode] >= MaxAmmo(mode); } if ( Ammo[mode] == None ) return false; return (Ammo[mode].AmmoAmount >= MaxAmmo(mode)); } simulated function GetAmmoCount(out float MaxAmmoPrimary, out float CurAmmoPrimary) { if ( AmmoClass[0] == None ) return; if ( bNoAmmoInstances ) { MaxAmmoPrimary = MaxAmmo(0); CurAmmoPrimary = AmmoCharge[0]; return; } if ( Ammo[0] == None ) return; MaxAmmoPrimary = Ammo[0].MaxAmmo; CurAmmoPrimary = Ammo[0].AmmoAmount; } simulated function float AmmoStatus(optional int Mode) // returns float value for ammo amount { if ( bNoAmmoInstances ) { if ( AmmoClass[Mode] == None ) return 0; if ( AmmoClass[0] == AmmoClass[mode] ) mode = 0; return float(AmmoCharge[Mode])/float(MaxAmmo(Mode)); } if (Ammo[Mode] == None) return 0.0; else return float(Ammo[Mode].AmmoAmount) / float(Ammo[Mode].MaxAmmo); } simulated function bool ConsumeAmmo(int Mode, float load, optional bool bAmountNeededIsMax) { local int AmountNeeded; if ( bNoAmmoInstances ) { if ( AmmoClass[0] == AmmoClass[mode] ) mode = 0; AmountNeeded = int(load); if (bAmountNeededIsMax && AmmoCharge[mode] < AmountNeeded) AmountNeeded = AmmoCharge[mode]; if (AmmoCharge[mode] < AmountNeeded) { CheckOutOfAmmo(); return false; // Can't do it } AmmoCharge[mode] -= AmountNeeded; NetUpdateTime = Level.TimeSeconds - 1; if (Level.NetMode == NM_StandAlone || Level.NetMode == NM_ListenServer) CheckOutOfAmmo(); return true; } if (Ammo[Mode] != None) return Ammo[Mode].UseAmmo(int(load), bAmountNeededIsMax); return true; } function bool AddAmmo(int AmmoToAdd, int Mode) { if ( bNoAmmoInstances ) { if ( AmmoClass[0] == AmmoClass[mode] ) mode = 0; if ( Level.GRI.WeaponBerserk > 1.0 ) AmmoCharge[mode] = MaxAmmo(Mode); else if ( AmmoCharge[mode] < MaxAmmo(mode) ) AmmoCharge[mode] = Min(MaxAmmo(mode), AmmoCharge[mode]+AmmoToAdd); NetUpdateTime = Level.TimeSeconds - 1; return true; } if (Ammo[Mode] != None) return Ammo[Mode].AddAmmo(AmmoToAdd); } simulated function bool HasAmmo() { if ( bNoAmmoInstances ) { if ( AmmoClass[0] == AmmoClass[1] ) return ( (AmmoClass[0] != None && FireMode[0] != None && AmmoCharge[0] >= FireMode[0].AmmoPerFire) ); return ( (AmmoClass[0] != None && FireMode[0] != None && AmmoCharge[0] >= FireMode[0].AmmoPerFire) || (AmmoClass[1] != None && FireMode[1] != None && AmmoCharge[1] >= FireMode[1].AmmoPerFire) ); } return ( (Ammo[0] != None && FireMode[0] != None && Ammo[0].AmmoAmount >= FireMode[0].AmmoPerFire) || (Ammo[1] != None && FireMode[1] != None && Ammo[1].AmmoAmount >= FireMode[1].AmmoPerFire) ); } // for AI simulated function bool NeedAmmo(int mode) { if ( bNoAmmoInstances ) { if ( AmmoClass[0] == AmmoClass[mode] ) mode = 0; if ( AmmoClass[mode] == None ) return false; return ( AmmoCharge[Mode] < AmmoClass[mode].default.InitialAmount ); } if ( Ammo[mode] != None ) return (Ammo[mode].AmmoAmount < Ammo[mode].InitialAmount); return false; } simulated function float DesireAmmo(class NewAmmoClass, bool bDetour) { local int i; local float curr, max; for ( i=0; i<2; i++ ) if ( NewAmmoClass == AmmoClass[i] ) { if ( AmmoMaxed(i) ) return -100; curr = AmmoAmount(i); if ( curr == 0 ) return 1; max = MaxAmmo(i); return ( FMin(0.5*(max-curr),AmmoClass[i].Default.AmmoAmount)/max ); } return 0; } simulated function CheckOutOfAmmo() { if (Instigator != None && Instigator.Weapon == self) { if ( bNoAmmoInstances ) { if ( (AmmoCharge[0] <= 0) && (AmmoCharge[1] <= 0) ) OutOfAmmo(); return; } if ( Ammo[0] != None ) Ammo[0].CheckOutOfAmmo(); if ( Ammo[1] != None ) Ammo[1].CheckOutOfAmmo(); } } simulated function PostNetReceive() { CheckOutOfAmmo(); } //========================================================================= simulated function DrawWeaponInfo(Canvas C); simulated function NewDrawWeaponInfo(Canvas C, float YPos); function StartDebugging() { } simulated function ClientWriteStats(byte Mode, bool bMatch, bool bAllowFire, bool bDelay, bool bAlt, float wait) { log(self$" Same weapon "$bMatch$" Mode "$Mode$" Allow fire "$bAllowFire$" delay start fire "$bDelay$" alt firing "$bAlt$" next fire wait "$wait); } function class GetDamageType(); function HackPlayFireSound() { if ( (FireMode[0] != None) && (FireMode[0].FireSound != None) ) PlaySound(FireMode[0].FireSound, SLOT_None, 1.0); } //================================================================= // AI functions function float RangedAttackTime() { return 0; } function bool RecommendRangedAttack() { return false; } function bool RecommendLongRangedAttack() { return false; } function bool FocusOnLeader(bool bLeaderFiring) { return false; } function FireHack(byte Mode); // return true if weapon effect has splash damage (if significant) // use by bot to avoid hurting self // should be based on current firing Mode if active function bool SplashDamage() { return FireMode[BotMode].bSplashDamage; } // return true if weapon should be fired to take advantage of splash damage // For example, rockets should be fired at enemy feet function bool RecommendSplashDamage() { return FireMode[BotMode].bRecommendSplashDamage; } function float GetDamageRadius() { if (FireMode[BotMode].ProjectileClass == None) return 0; else return FireMode[BotMode].ProjectileClass.default.DamageRadius; } // Repeater weapons like minigun should be 0.99, other weapons based on likelihood // of firing again right away function float RefireRate() { return FireMode[BotMode].BotRefireRate; } // tells AI that it needs to release the fire button for this weapon to do anything function bool FireOnRelease() { return FireMode[BotMode].bFireOnRelease; } simulated function Loaded(); simulated function DisplayDebug(Canvas Canvas, out float YL, out float YPos) { local int i; local string T; local name Anim; local float frame,rate; Canvas.SetDrawColor(0,255,0); if ( (Pawn(Owner) != None) && (Pawn(Owner).PlayerReplicationInfo != None) ) Canvas.DrawText("WEAPON "$GetItemName(string(self))$" Owner "$Pawn(Owner).PlayerReplicationInfo.PlayerName); else Canvas.DrawText("WEAPON "$GetItemName(string(self))$" Owner "$Owner); YPos += YL; Canvas.SetPos(4,YPos); T = " STATE: "$GetStateName()$" Timer: "$TimerCounter$" Client State "; Switch( ClientState ) { case WS_None: T=T$"None"; break; case WS_Hidden: T=T$"Hidden"; break; case WS_BringUp: T=T$"BringUp"; break; case WS_PutDown: T=T$"PutDown"; break; case WS_ReadyToFire: T=T$"ReadyToFire"; break; } Canvas.DrawText(T, false); YPos += YL; Canvas.SetPos(4,YPos); if ( DrawType == DT_StaticMesh ) Canvas.DrawText(" StaticMesh "$GetItemName(string(StaticMesh))$" AmbientSound "$AmbientSound, false); else Canvas.DrawText(" Mesh "$GetItemName(string(Mesh))$" AmbientSound "$AmbientSound, false); YPos += YL; Canvas.SetPos(4,YPos); if ( Mesh != None ) { // mesh animation GetAnimParams(0,Anim,frame,rate); T = " AnimSequence "$Anim$" Frame "$frame$" Rate "$rate; if ( bAnimByOwner ) T= T$" Anim by Owner"; Canvas.DrawText(T, false); YPos += YL; Canvas.SetPos(4,YPos); T = "Eyeheight "$Instigator.EyeHeight$" base "$Instigator.BaseEyeheight$" landbob "$Instigator.Landbob$" just landed "$Instigator.bJustLanded$" land recover "$Instigator.bLandRecovery; Canvas.DrawText(T, false); YPos += YL; Canvas.SetPos(4,YPos); } for ( i=0; i rating) ) { rating = oldRating; return Recommended; } } return self; } function SetAITarget(Actor T); /* BestMode() choose between regular or alt-fire */ function byte BestMode() { if ( Instigator.Controller.bFire != 0 ) return 0; else if ( Instigator.Controller.bAltFire != 0 ) return 1; if ( FRand() < 0.5 ) return 1; return 0; } /* BotFire() called by NPC firing weapon. Weapon chooses appropriate firing Mode to use (typically no change) bFinished should only be true if called from the Finished() function FiringMode can be passed in to specify a firing Mode (used by scripted sequences) */ function bool BotFire(bool bFinished, optional name FiringMode) { local int newmode; local Controller C; C = Instigator.Controller; newMode = BestMode(); if ( newMode == 0 ) { C.bFire = 1; C.bAltFire = 0; } else { C.bFire = 0; C.bAltFire = 1; } if ( bFinished ) return true; if ( FireMode[BotMode].IsFiring() ) { if (BotMode == newMode) return true; else StopFire(BotMode); } if ( !ReadyToFire(newMode) || ClientState != WS_ReadyToFire ) return false; BotMode = NewMode; StartFire(NewMode); return true; } // this returns the actual projectile spawn location or trace start simulated function vector GetFireStart(vector X, vector Y, vector Z) { return FireMode[BotMode].GetFireStart(X,Y,Z); } // 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); return CurrentRating; } function float GetAIRating() { return AIRating; } // tells bot whether to charge or back off while using this weapon function float SuggestAttackStyle() { return 0.0; } // tells bot whether to charge or back off while defending against this weapon function float SuggestDefenseStyle() { return 0.0; } // return true if recommend jumping while firing to improve splash damage (by shooting at feet) // true for R.L., for example function bool SplashJump() { return FireMode[BotMode].bSplashJump; } // 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; local bool bShouldAttack; // if _RO_ // Extra friendly fire checking local pawn Victims; local vector dir, lookdir; local float DiffAngle, FriendlyDist, MinAngle; // end _RO_ if ( (Instigator == None) || (Instigator.Controller == None) ) return false; // check that target is within range Dist = VSize(Instigator.Location - Other.Location); if ( (Dist > FireMode[0].MaxRange()) && (Dist > FireMode[1].MaxRange()) ) return false; // check that can see target if ( !Instigator.Controller.LineOfSightTo(Other) ) return false; for (m = 0; m < NUM_FIRE_MODES; m++) { 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(Instigator.Controller.Rotation, X,Y,Z); projStart = GetFireStart(X,Y,Z); if ( bInstantHit ) HitActor = Instigator.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 = Instigator.Trace(HitLocation, HitNormal, projStart + CheckDist * Normal(Other.Location + Other.CollisionHeight * vect(0,0,0.8) - Location), projStart, true); } // if( (HitActor != None) && HitActor.IsA('ROCollisionAttachment')) // { // log(self$"'s trace hit "$HitActor.Base$" Collision attachment"); // } // if _RO_ // Extra friendly fire checking if (!Instigator.IsHumanControlled() ) { foreach VisibleCollidingActors( class 'Pawn', Victims, 3000 ) //, RadiusHitLocation { if( Victims != Instigator && Instigator.Controller.SameTeamAs(Victims.Controller)) { FriendlyDist = VSizeSquared(Instigator.Location - Victims.Location); if( FriendlyDist < 22500 ) //2.5 meters { MinAngle = 0.85; } else if( FriendlyDist < 90000 ) //5.0 meters { MinAngle = 0.95; } else if( FriendlyDist < 360000 ) //10.0 meters { MinAngle = 0.98; } else { MinAngle = 0.99; } lookdir = Normal((Other.Location + Other.CollisionHeight * vect(0,0,0.8))-projStart); dir = Normal(Victims.Location - Instigator.Location); DiffAngle = lookdir dot dir; if( DiffAngle > MinAngle ) { //log("Not firing because we might hit a friendly with a DiffAngle of "$DiffAngle); return false; } } } } if ( (HitActor == None) || (HitActor == Other) ) bShouldAttack = true;//return true; else if ( Pawn(HitActor) == None ) bShouldAttack = !HitActor.BlocksShotAt(Other);//return !HitActor.BlocksShotAt(Other); else if ( (Pawn(HitActor).Controller == None) || !Instigator.Controller.SameTeamAs(Pawn(HitActor).Controller) ) bShouldAttack = true;//return true; // if( Pawn(HitActor) != none && Instigator.Controller.SameTeamAs(Pawn(HitActor).Controller)) // { // log("Weapon "$Instigator$"'s shot would hit "$Other$" who is on the same team and should attack is "$bShouldAttack); // } return bShouldAttack;//false; } //================================================================= simulated function PostBeginPlay() { local int m; Super.PostBeginPlay(); for (m = 0; m < NUM_FIRE_MODES; m++) { if (FireModeClass[m] != None) { FireMode[m] = new(self) FireModeClass[m]; if ( FireMode[m] != None ) AmmoClass[m] = FireMode[m].AmmoClass; } } InitWeaponFires(); for (m = 0; m < NUM_FIRE_MODES; m++) { if (FireMode[m] != None) { FireMode[m].ThisModeNum = m; FireMode[m].Weapon = self; FireMode[m].Instigator = Instigator; FireMode[m].Level = Level; FireMode[m].Owner = self; FireMode[m].PreBeginPlay(); FireMode[m].BeginPlay(); FireMode[m].PostBeginPlay(); FireMode[m].SetInitialState(); FireMode[m].PostNetBeginPlay(); } } if ( Level.bDropDetail || (Level.DetailMode == DM_Low) ) MaxLights = Min(4,MaxLights); if ( SmallViewOffset == vect(0,0,0) ) SmallViewOffset = Default.PlayerviewOffset; if ( SmallEffectOffset == vect(0,0,0) ) SmallEffectOffset = EffectOffset + Default.PlayerViewOffset - SmallViewOffset; if ( bUseOldWeaponMesh && (OldMesh != None) ) { bInitOldMesh = true; LinkMesh(OldMesh); } if ( Level.GRI != None ) CheckSuperBerserk(); } simulated function SetGRI(GameReplicationInfo G) { CheckSuperBerserk(); } simulated function Destroyed() { local int m; AmbientSound = None; for (m = 0; m < NUM_FIRE_MODES; m++) { if ( FireMode[m] != None ) FireMode[m].DestroyEffects(); if (Ammo[m] != None) { Ammo[m].Destroy(); Ammo[m] = None; } } Super.Destroyed(); } simulated function Reselect() { } simulated function bool WeaponCentered() { return ( bSpectated || (Hand > 1) ); } simulated event RenderOverlays( Canvas Canvas ) { local int m; local vector NewScale3D; local rotator CenteredRotation; local name AnimSeq; local float frame,rate; if (Instigator == None) return; if ( Instigator.Controller != None ) Hand = Instigator.Controller.Handedness; if ((Hand < -1.0) || (Hand > 1.0)) return; // draw muzzleflashes/smoke for all fire modes so idle state won't // cause emitters to just disappear for (m = 0; m < NUM_FIRE_MODES; m++) { if (FireMode[m] != None) { FireMode[m].DrawMuzzleFlash(Canvas); } } if ( (OldMesh != None) && (bUseOldWeaponMesh != (OldMesh == Mesh)) ) { GetAnimParams(0,AnimSeq,frame,rate); bInitOldMesh = true; if ( bUseOldWeaponMesh ) LinkMesh(OldMesh); else LinkMesh(Default.Mesh); PlayAnim(AnimSeq,rate,0.0); } if ( (Hand != RenderedHand) || bInitOldMesh ) { newScale3D = Default.DrawScale3D; if ( Hand != 0 ) newScale3D.Y *= Hand; SetDrawScale3D(newScale3D); SetDrawScale(Default.DrawScale); CenteredRoll = Default.CenteredRoll; CenteredYaw = Default.CenteredYaw; CenteredOffsetY = Default.CenteredOffsetY; PlayerViewPivot = Default.PlayerViewPivot; SmallViewOffset = Default.SmallViewOffset; if ( SmallViewOffset == vect(0,0,0) ) SmallViewOffset = Default.PlayerviewOffset; bInitOldMesh = false; if ( Default.SmallEffectOffset == vect(0,0,0) ) SmallEffectOffset = EffectOffset + Default.PlayerViewOffset - SmallViewOffset; else SmallEffectOffset = Default.SmallEffectOffset; if ( Mesh == OldMesh ) { SmallEffectOffset = EffectOffset + OldPlayerViewOffset - OldSmallViewOffset; PlayerViewPivot = OldPlayerViewPivot; SmallViewOffset = OldSmallViewOffset; if ( Hand != 0 ) { PlayerViewPivot.Roll *= Hand; PlayerViewPivot.Yaw *= Hand; } CenteredRoll = OldCenteredRoll; CenteredYaw = OldCenteredYaw; CenteredOffsetY = OldCenteredOffsetY; SetDrawScale(OldDrawScale); } else if ( Hand == 0 ) { PlayerViewPivot.Roll = Default.PlayerViewPivot.Roll; PlayerViewPivot.Yaw = Default.PlayerViewPivot.Yaw; } else { PlayerViewPivot.Roll = Default.PlayerViewPivot.Roll * Hand; PlayerViewPivot.Yaw = Default.PlayerViewPivot.Yaw * Hand; } RenderedHand = Hand; } if ( class'PlayerController'.Default.bSmallWeapons ) PlayerViewOffset = SmallViewOffset; else if ( Mesh == OldMesh ) PlayerViewOffset = OldPlayerViewOffset; else PlayerViewOffset = Default.PlayerViewOffset; if ( Hand == 0 ) PlayerViewOffset.Y = CenteredOffsetY; else PlayerViewOffset.Y *= Hand; SetLocation( Instigator.Location + Instigator.CalcDrawOffset(self) ); if ( Hand == 0 ) { CenteredRotation = Instigator.GetViewRotation(); CenteredRotation.Yaw += CenteredYaw; CenteredRotation.Roll = CenteredRoll; SetRotation(CenteredRotation); } else SetRotation( Instigator.GetViewRotation() ); PreDrawFPWeapon(); // Laurent -- Hook to override things before render (like rotation if using a staticmesh) bDrawingFirstPerson = true; Canvas.DrawActor(self, false, false, DisplayFOV); bDrawingFirstPerson = false; if ( Hand == 0 ) PlayerViewOffset.Y = 0; } simulated function PreDrawFPWeapon(); simulated function SetHand(float InHand) { Hand = InHand; } simulated function GetViewAxes( out vector xaxis, out vector yaxis, out vector zaxis ) { if ( Instigator.Controller == None ) GetAxes( Instigator.Rotation, xaxis, yaxis, zaxis ); else GetAxes( Instigator.Controller.Rotation, xaxis, yaxis, zaxis ); } simulated function vector CenteredEffectStart() { return Instigator.Location; } simulated function vector GetEffectStart() { local Vector X,Y,Z; // jjs - this function should actually never be called in third person views // any effect that needs a 3rdp weapon offset should figure it out itself // 1st person if (Instigator.IsFirstPerson()) { if ( WeaponCentered() ) return CenteredEffectStart(); GetViewAxes(X, Y, Z); if ( class'PlayerController'.Default.bSmallWeapons ) return (Instigator.Location + Instigator.CalcDrawOffset(self) + SmallEffectOffset.X * X + SmallEffectOffset.Y * Y * Hand + SmallEffectOffset.Z * Z); else return (Instigator.Location + Instigator.CalcDrawOffset(self) + EffectOffset.X * X + EffectOffset.Y * Y * Hand + EffectOffset.Z * Z); } // 3rd person else { return (Instigator.Location + Instigator.EyeHeight*Vect(0,0,0.5) + Vector(Instigator.Rotation) * 40.0); } } simulated function IncrementFlashCount(int Mode) { if ( WeaponAttachment(ThirdPersonActor) != None ) { if (Mode == 0) WeaponAttachment(ThirdPersonActor).FiringMode = 0; else WeaponAttachment(ThirdPersonActor).FiringMode = 1; ThirdPersonActor.NetUpdateTime = Level.TimeSeconds - 1; WeaponAttachment(ThirdPersonActor).FlashCount++; WeaponAttachment(ThirdPersonActor).ThirdPersonEffects(); } } simulated function ZeroFlashCount(int Mode) { if ( WeaponAttachment(ThirdPersonActor) != None ) { if (Mode == 0) WeaponAttachment(ThirdPersonActor).FiringMode = 0; else WeaponAttachment(ThirdPersonActor).FiringMode = 1; ThirdPersonActor.NetUpdateTime = Level.TimeSeconds - 1; WeaponAttachment(ThirdPersonActor).FlashCount = 0; WeaponAttachment(ThirdPersonActor).ThirdPersonEffects(); } } simulated function Weapon WeaponChange( byte F, bool bSilent ) { local Weapon newWeapon; if ( InventoryGroup == F ) { if ( !HasAmmo() ) { if ( Inventory == None ) newWeapon = None; else newWeapon = Inventory.WeaponChange(F,bSilent); if ( !bSilent && (newWeapon == None) && Instigator.IsHumanControlled() ) Instigator.ClientMessage( ItemName$MessageNoAmmo ); return newWeapon; } else return self; } else if ( Inventory == None ) return None; else return Inventory.WeaponChange(F,bSilent); } simulated function Weapon PrevWeapon(Weapon CurrentChoice, Weapon CurrentWeapon) { if ( HasAmmo() ) { if ( (CurrentChoice == None) ) { if ( CurrentWeapon != self ) CurrentChoice = self; } else if ( InventoryGroup == CurrentWeapon.InventoryGroup ) { if ( (GroupOffset < CurrentWeapon.GroupOffset) && ((CurrentChoice.InventoryGroup != InventoryGroup) || (GroupOffset > CurrentChoice.GroupOffset)) ) CurrentChoice = self; } else if ( InventoryGroup == CurrentChoice.InventoryGroup ) { if ( GroupOffset > CurrentChoice.GroupOffset ) CurrentChoice = self; } else if ( InventoryGroup > CurrentChoice.InventoryGroup ) { if ( (InventoryGroup < CurrentWeapon.InventoryGroup) || (CurrentChoice.InventoryGroup > CurrentWeapon.InventoryGroup) ) CurrentChoice = self; } else if ( (CurrentChoice.InventoryGroup > CurrentWeapon.InventoryGroup) && (InventoryGroup < CurrentWeapon.InventoryGroup) ) CurrentChoice = self; } if ( Inventory == None ) return CurrentChoice; else return Inventory.PrevWeapon(CurrentChoice,CurrentWeapon); } simulated function Weapon NextWeapon(Weapon CurrentChoice, Weapon CurrentWeapon) { if ( HasAmmo() ) { if ( (CurrentChoice == None) ) { if ( CurrentWeapon != self ) CurrentChoice = self; } else if ( InventoryGroup == CurrentWeapon.InventoryGroup ) { if ( (GroupOffset > CurrentWeapon.GroupOffset) && ((CurrentChoice.InventoryGroup != InventoryGroup) || (GroupOffset < CurrentChoice.GroupOffset)) ) CurrentChoice = self; } else if ( InventoryGroup == CurrentChoice.InventoryGroup ) { if ( GroupOffset < CurrentChoice.GroupOffset ) CurrentChoice = self; } else if ( InventoryGroup < CurrentChoice.InventoryGroup ) { if ( (InventoryGroup > CurrentWeapon.InventoryGroup) || (CurrentChoice.InventoryGroup < CurrentWeapon.InventoryGroup) ) CurrentChoice = self; } else if ( (CurrentChoice.InventoryGroup < CurrentWeapon.InventoryGroup) && (InventoryGroup > CurrentWeapon.InventoryGroup) ) CurrentChoice = self; } if ( Inventory == None ) return CurrentChoice; else return Inventory.NextWeapon(CurrentChoice,CurrentWeapon); } function HolderDied() { local int m; for (m = 0; m < NUM_FIRE_MODES; m++) { // if _RO_ if( FireMode[m] == none ) continue; // End _RO_ if (FireMode[m].bIsFiring) { StopFire(m); if (FireMode[m].bFireOnRelease) FireMode[m].ModeDoFire(); } } } simulated function bool CanThrow() { local int Mode; for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { // if _RO_ if( FireMode[Mode] == none ) continue; // End _RO_ if ( FireMode[Mode].bFireOnRelease && FireMode[Mode].bIsFiring ) return false; if ( FireMode[Mode].NextFireTime > Level.TimeSeconds) return false; } return (bCanThrow && (ClientState == WS_ReadyToFire || (Level.NetMode == NM_DedicatedServer) || (Level.NetMode == NM_ListenServer)) && HasAmmo() ); } function DropFrom(vector StartLocation) { local int m; local Pickup Pickup; if (!bCanThrow || !HasAmmo()) return; ClientWeaponThrown(); for (m = 0; m < NUM_FIRE_MODES; m++) { // if _RO_ if( FireMode[m] == none ) continue; // End _RO_ if (FireMode[m].bIsFiring) StopFire(m); } if ( Instigator != None ) { DetachFromPawn(Instigator); } Pickup = Spawn(PickupClass,,, StartLocation); if ( Pickup != None ) { Pickup.InitDroppedPickupFor(self); Pickup.Velocity = Velocity; if (Instigator.Health > 0) WeaponPickup(Pickup).bThrown = true; } Destroy(); } simulated function DetachFromPawn(Pawn P) { Super.DetachFromPawn(P); P.AmbientSound = None; } simulated function ClientWeaponThrown() { local int m; AmbientSound = None; Instigator.AmbientSound = None; if( Level.NetMode != NM_Client ) return; Instigator.DeleteInventory(self); for (m = 0; m < NUM_FIRE_MODES; m++) { if (Ammo[m] != None) Instigator.DeleteInventory(Ammo[m]); } } function GiveTo(Pawn Other, optional Pickup Pickup) { local int m; local weapon w; local bool bPossiblySwitch, bJustSpawned; Instigator = Other; W = Weapon(Instigator.FindInventoryType(class)); if ( W == None || W.Class != Class ) // added class check because somebody made FindInventoryType() return subclasses for some reason { bJustSpawned = true; Super.GiveTo(Other); bPossiblySwitch = true; W = self; } else if ( !W.HasAmmo() ) bPossiblySwitch = true; if ( Pickup == None ) bPossiblySwitch = true; for (m = 0; m < NUM_FIRE_MODES; m++) { if ( FireMode[m] != None ) { FireMode[m].Instigator = Instigator; W.GiveAmmo(m,WeaponPickup(Pickup),bJustSpawned); } } if ( Instigator.Weapon != W ) W.ClientWeaponSet(bPossiblySwitch); if ( !bJustSpawned ) { for (m = 0; m < NUM_FIRE_MODES; m++) Ammo[m] = None; Destroy(); } } function GiveAmmo(int m, WeaponPickup WP, bool bJustSpawned) { local bool bJustSpawnedAmmo; local int addAmount, InitialAmount; 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.AmmoAmount[0] > 0) || (WP.AmmoAmount[1] > 0)) ) { InitialAmount = WP.AmmoAmount[m]; } 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) ); if ( (WP != None) && ((WP.AmmoAmount[0] > 0) || (WP.AmmoAmount[1] > 0)) ) { addAmount = WP.AmmoAmount[m]; } else if ( bJustSpawnedAmmo ) { addAmount = Ammo[m].InitialAmount; } Ammo[m].AddAmmo(addAmount); Ammo[m].GotoState(''); } } } simulated function ClientWeaponSet(bool bPossiblySwitch) { local int Mode; Instigator = Pawn(Owner); bPendingSwitch = bPossiblySwitch; if( Instigator == None ) { GotoState('PendingClientWeaponSet'); return; } for( Mode = 0; Mode < NUM_FIRE_MODES; Mode++ ) { if( FireModeClass[Mode] != None ) { // laurent -- added check for vehicles (ammo not replicated but unlimited) if( ( FireMode[Mode] == None ) || ( FireMode[Mode].AmmoClass != None ) && !bNoAmmoInstances && Ammo[Mode] == None && FireMode[Mode].AmmoPerFire > 0 ) { GotoState('PendingClientWeaponSet'); return; } } FireMode[Mode].Instigator = Instigator; FireMode[Mode].Level = Level; } ClientState = WS_Hidden; GotoState('Hidden'); if( Level.NetMode == NM_DedicatedServer || !Instigator.IsHumanControlled() ) return; if( Instigator.Weapon == self || Instigator.PendingWeapon == self ) // this weapon was switched to while waiting for replication, switch to it now { if (Instigator.PendingWeapon != None) Instigator.ChangedWeapon(); else BringUp(); return; } if( Instigator.PendingWeapon != None && Instigator.PendingWeapon.bForceSwitch ) return; if( Instigator.Weapon == None ) { Instigator.PendingWeapon = self; Instigator.ChangedWeapon(); } else if ( bPossiblySwitch && !Instigator.Weapon.IsFiring() ) { if ( PlayerController(Instigator.Controller) != None && PlayerController(Instigator.Controller).bNeverSwitchOnPickup ) return; if ( Instigator.PendingWeapon != None ) { if ( RateSelf() > Instigator.PendingWeapon.RateSelf() ) { Instigator.PendingWeapon = self; Instigator.Weapon.PutDown(); } } else if ( RateSelf() > Instigator.Weapon.RateSelf() ) { Instigator.PendingWeapon = self; Instigator.Weapon.PutDown(); } } } // jdf --- simulated function ClientPlayForceFeedback( String EffectName ) { local PlayerController PC; PC = PlayerController(Instigator.Controller); if ( PC != None && PC.bEnableWeaponForceFeedback ) { PC.ClientPlayForceFeedback( EffectName ); } } simulated function StopForceFeedback( String EffectName ) { local PlayerController PC; PC = PlayerController(Instigator.Controller); if ( PC != None && PC.bEnableWeaponForceFeedback ) { PC.StopForceFeedback( EffectName ); } } // --- jdf simulated function BringUp(optional Weapon PrevWeapon) { local int Mode; if ( ClientState == WS_Hidden ) { PlayOwnedSound(SelectSound, SLOT_Interact,,,,, false); ClientPlayForceFeedback(SelectForce); // jdf if ( Instigator.IsLocallyControlled() ) { if ( (Mesh!=None) && HasAnim(SelectAnim) ) PlayAnim(SelectAnim, SelectAnimRate, 0.0); } ClientState = WS_BringUp; SetTimer(BringUpTime, false); } for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { 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 (ClientState == WS_BringUp || ClientState == WS_ReadyToFire) { if ( (Instigator.PendingWeapon != None) && !Instigator.PendingWeapon.bForceSwitch ) { for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { // if _RO_ if( FireMode[Mode] == none ) continue; // End _RO_ if ( FireMode[Mode].bFireOnRelease && FireMode[Mode].bIsFiring ) return false; if ( FireMode[Mode].NextFireTime > Level.TimeSeconds + FireMode[Mode].FireRate*(1.f - MinReloadPct)) DownDelay = FMax(DownDelay, FireMode[Mode].NextFireTime - Level.TimeSeconds - FireMode[Mode].FireRate*(1.f - MinReloadPct)); } } if (Instigator.IsLocallyControlled()) { for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { // if _RO_ if( FireMode[Mode] == none ) continue; // End _RO_ if ( FireMode[Mode].bIsFiring ) ClientStopFire(Mode); } if ( DownDelay <= 0 ) { if ( ClientState == WS_BringUp ) TweenAnim(SelectAnim,PutDownTime); else if ( HasAnim(PutDownAnim) ) PlayAnim(PutDownAnim, PutDownAnimRate, 0.0); } } ClientState = WS_PutDown; if ( Level.GRI.bFastWeaponSwitching ) DownDelay = 0; if ( DownDelay > 0 ) SetTimer(DownDelay, false); else SetTimer(PutDownTime, false); } for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) { // if _RO_ if( FireMode[Mode] == none ) continue; // End _RO_ FireMode[Mode].bServerDelayStartFire = false; FireMode[Mode].bServerDelayStopFire = false; } Instigator.AmbientSound = None; OldWeapon = None; return true; // return false if preventing weapon switch } simulated function Fire(float F) { } simulated function AltFire(float F) { } simulated event WeaponTick(float dt); // only called on currently held weapon simulated function OutOfAmmo() { if ( Instigator == None || !Instigator.IsLocallyControlled() || HasAmmo() ) return; DoAutoSwitch(); } simulated function DoAutoSwitch() { Instigator.Controller.SwitchToBestWeapon(); } //// client only //// simulated event ClientStartFire(int Mode) { if ( Pawn(Owner).Controller.IsInState('GameEnded') || Pawn(Owner).Controller.IsInState('RoundEnded') ) return; if (Role < ROLE_Authority) { if (StartFire(Mode)) { ServerStartFire(Mode); } } else { StartFire(Mode); } } simulated event ClientStopFire(int Mode) { if (Role < ROLE_Authority) { //Log("ClientStopFire"@Level.TimeSeconds); StopFire(Mode); } ServerStopFire(Mode); } simulated function ClientWriteFire(string Result) { log(self$" ServerStartFire! "$Result); } //// server only //// event ServerStartFire(byte Mode) { if ( (Instigator != None) && (Instigator.Weapon != self) ) { if ( Instigator.Weapon == None ) Instigator.ServerChangedWeapon(None,self); else Instigator.Weapon.SynchronizeWeapon(self); return; } if ( (FireMode[Mode].NextFireTime <= Level.TimeSeconds + FireMode[Mode].PreFireTime) && StartFire(Mode) ) { FireMode[Mode].ServerStartFireTime = Level.TimeSeconds; FireMode[Mode].bServerDelayStartFire = false; } else if ( FireMode[Mode].AllowFire() ) { FireMode[Mode].bServerDelayStartFire = true; } else ClientForceAmmoUpdate(Mode, AmmoAmount(Mode)); } simulated function ClientForceAmmoUpdate(int Mode, int NewAmount) { //log(self$" ClientForceAmmoUpdate mode "$Mode$" newamount "$NewAmount); if ( bNoAmmoInstances ) AmmoCharge[Mode] = NewAmount; else if ( Ammo[mode] != None ) Ammo[mode].AmmoAmount = NewAmount; } function SynchronizeWeapon(Weapon ClientWeapon) { Instigator.ServerChangedWeapon(self,ClientWeapon); } function ServerStopFire(byte Mode) { // if a stop was received on the same frame as a start then we need to delay the stop for one frame if (FireMode[Mode].bServerDelayStartFire || FireMode[Mode].ServerStartFireTime == Level.TimeSeconds) { //log("Stop Delayed"); FireMode[Mode].bServerDelayStopFire = true; } else { //Log("ServerStopFire"@Level.TimeSeconds); StopFire(Mode); } } simulated function bool ReadyToFire(int Mode) { local int alt; if ( Mode == 0 ) alt = 1; else alt = 0; if ( ((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; } //// client & server //// 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].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; } simulated event StopFire(int Mode) { if ( FireMode[Mode].bIsFiring ) FireMode[Mode].bInstantStop = true; if (Instigator.IsLocallyControlled() && !FireMode[Mode].bFireOnRelease) FireMode[Mode].PlayFireEnd(); FireMode[Mode].bIsFiring = false; FireMode[Mode].StopFiring(); if (!FireMode[Mode].bFireOnRelease) ZeroFlashCount(Mode); } //hack to stop all firing and release any charging firemodes RIGHT THIS INSTANT //used when getting into vehicles simulated function ImmediateStopFire() { local int i; for (i = 0; i < NUM_FIRE_MODES; i++) { ClientStopFire(i); if (FireMode[i].bFireOnRelease) { if (Level.TimeSeconds > FireMode[i].NextFireTime && (FireMode[i].bInstantStop || !FireMode[i].bNowWaiting)) FireMode[i].ModeDoFire(); if (FireMode[i].bWaitForRelease) FireMode[i].bNowWaiting = true; } } } simulated function Timer() { local int Mode; local float OldDownDelay; OldDownDelay = DownDelay; DownDelay = 0; if (ClientState == WS_BringUp) { for( Mode = 0; Mode < NUM_FIRE_MODES; Mode++ ) FireMode[Mode].InitEffects(); PlayIdle(); ClientState = WS_ReadyToFire; } else if (ClientState == WS_PutDown) { if ( OldDownDelay > 0 ) { if ( HasAnim(PutDownAnim) ) PlayAnim(PutDownAnim, PutDownAnimRate, 0.0); SetTimer(PutDownTime, false); return; } if ( Instigator.PendingWeapon == None ) { PlayIdle(); ClientState = WS_ReadyToFire; } else { ClientState = WS_Hidden; Instigator.ChangedWeapon(); if ( Instigator.Weapon == self ) { PlayIdle(); ClientState = WS_ReadyToFire; } else { for( Mode = 0; Mode < NUM_FIRE_MODES; Mode++ ) FireMode[Mode].DestroyEffects(); } } } } simulated function bool IsFiring() // called by pawn animation, mostly { if (Level.NetMode == NM_DedicatedServer || Level.NetMode == NM_ListenServer) return (FireMode[0].IsFiring() || FireMode[1].IsFiring()); return ( ClientState == WS_ReadyToFire && (FireMode[0].IsFiring() || FireMode[1].IsFiring()) ); } function bool IsRapidFire() // called by pawn animation { if (FireMode[1] != None && FireMode[1].bIsFiring) return FireMode[1].bPawnRapidFireAnim; else if (FireMode[0] != None) return FireMode[0].bPawnRapidFireAnim; else return false; } // called every time owner takes damage while holding this weapon - used by shield gun function AdjustPlayerDamage( out int Damage, Pawn InstigatedBy, Vector HitLocation, out Vector Momentum, class DamageType) { } simulated function CheckSuperBerserk() { if ( Level.GRI.WeaponBerserk > 1.0 ) { if (FireMode[0] != None) FireMode[0].StartSuperBerserk(); if (FireMode[1] != None) FireMode[1].StartSuperBerserk(); } } simulated function StartBerserk() { if ( (Level.GRI != None) && Level.GRI.WeaponBerserk > 1.0 ) return; bBerserk = true; if (FireMode[0] != None) FireMode[0].StartBerserk(); if (FireMode[1] != None) FireMode[1].StartBerserk(); } simulated function StopBerserk() { bBerserk = false; if ( (Level.GRI != None) && Level.GRI.WeaponBerserk > 1.0 ) return; if (FireMode[0] != None) FireMode[0].StopBerserk(); if (FireMode[1] != None) FireMode[1].StopBerserk(); } simulated function AnimEnd(int channel) { local name anim; local float frame, rate; GetAnimParams(0, anim, frame, rate); if (ClientState == WS_ReadyToFire) { if (anim == FireMode[0].FireAnim && HasAnim(FireMode[0].FireEndAnim)) // rocket hack { PlayAnim(FireMode[0].FireEndAnim, FireMode[0].FireEndAnimRate, 0.0); } else if (anim== FireMode[1].FireAnim && HasAnim(FireMode[1].FireEndAnim)) { PlayAnim(FireMode[1].FireEndAnim, FireMode[1].FireEndAnimRate, 0.0); } else if ((FireMode[0] == None || !FireMode[0].bIsFiring) && (FireMode[1] == None || !FireMode[1].bIsFiring)) { PlayIdle(); } } } simulated function PlayIdle() { LoopAnim(IdleAnim, IdleAnimRate, 0.2); } state PendingClientWeaponSet { simulated function Timer() { if ( Pawn(Owner) != None ) ClientWeaponSet(bPendingSwitch); if ( IsInState('PendingClientWeaponSet') ) SetTimer(0.05, false); } simulated function BeginState() { SetTimer(0.05, false); } simulated function EndState() { } } state Hidden { } function bool CheckReflect( Vector HitLocation, out Vector RefNormal, int AmmoDrain ) { return false; } function DoReflectEffect(int Drain) { } function bool HandlePickupQuery( pickup Item ) { local WeaponPickup wpu; local int i; if ( bNoAmmoInstances ) { // handle ammo pickups for ( i=0; i<2; i++ ) { if ( (item.inventorytype == AmmoClass[i]) && (AmmoClass[i] != None) ) { if ( AmmoCharge[i] >= MaxAmmo(i) ) return true; item.AnnouncePickup(Pawn(Owner)); AddAmmo(Ammo(item).AmmoAmount, i); item.SetRespawn(); return true; } } } if (class == Item.InventoryType) { wpu = WeaponPickup(Item); if (wpu != None) return !wpu.AllowRepeatPickup(); else return false; } if ( Inventory == None ) return false; return Inventory.HandlePickupQuery(Item); } simulated function bool WantsZoomFade() { return false; } /* CanHeal() used by bot AI should return true if this weapon is able to heal Other */ function bool CanHeal(Actor Other) { return false; } //called by AI when camping/defending //return true if it is useful to fire this weapon even though bot doesn't have a target //for example, a weapon that launches turrets or mines function bool ShouldFireWithoutTarget() { return false; } // ugly hack for tutorial function bool ShootHoop(Controller B, Vector ShootLoc) { return false; } simulated function PawnUnpossessed(); // FIXME - hack to get classes building again after fixing the bug that was allowing all protected variables to // be referenced in other classes - maybe there's already an accessor that does this and I just don't know about it // ...in that case, just remove this function -- rjp simulated function WeaponFire GetFireMode( byte Mode ) { if ( Mode < NUM_FIRE_MODES ) return FireMode[Mode]; return None; } defaultproperties { DrawType=DT_Mesh Style=STY_Normal PlayerViewOffset=(X=0,Y=0,Z=0) InventoryGroup=1 FireModeClass(0)=None FireModeClass(1)=None // animation // IdleAnim=Idle RestAnim=Rest AimAnim=Aim RunAnim=Run SelectAnim=Select PutDownAnim=Down IdleAnimRate=1.0 RestAnimRate=1.0 AimAnimRate=1.0 RunAnimRate=1.0 // other useful stuff // MessageNoAmmo=" has no ammo" DisplayFOV=90.0 bCanThrow=true AIRating=0.5 CurrentRating=0.5 AttachmentClass=class'WeaponAttachment' NetPriority=3.0 ScaleGlow=1.5 AmbientGlow=20 MaxLights=6 SoundVolume=255 HudColor=(r=255,g=255,b=0,a=255) CenteredOffsetY=-10.0 CenteredRoll=2000 CenteredYaw=0 bUseOldWeaponMesh=False ExchangeFireModes=0 CustomCrosshair=0 CustomCrossHairColor=(R=255,G=255,B=255,A=255) CustomCrossHairScale=+1.0 CustomCrossHairTexture=None // if _RO_ CustomCrossHairTextureName="InterfaceArt_tex.Cursors.Crosshair_Cross2" // else // CustomCrossHairTextureName="Crosshairs.Hud.Crosshair_Cross1" // end if _RO_ OldCenteredOffsetY=-10.0 OldCenteredRoll=2000 OldCenteredYaw=0 OldDrawScale=+1.0 SelectAnimRate=1.3636 PutDownAnimRate=1.3636 BringUpTime=+0.33 PutDownTime=+0.33 MinReloadPct=+0.5 NetUpdateFrequency=2 bNoAmmoInstances=true bNetNotify=true }