//============================================================================= // Shield Gun //============================================================================= class ShieldGun extends Weapon config(user); #EXEC OBJ LOAD FILE=InterfaceContent.utx var Sound ShieldHitSound; var String ShieldHitForce; replication { reliable if (Role == ROLE_Authority) ClientTakeHit; } simulated function DoAutoSwitch() { } simulated event RenderOverlays( Canvas Canvas ) { local int m; if ((Hand < -1.0) || (Hand > 1.0)) { for (m = 0; m < NUM_FIRE_MODES; m++) { if (FireMode[m] != None) { FireMode[m].DrawMuzzleFlash(Canvas); } } } Super.RenderOverlays(Canvas); } // AI Interface function GiveTo(Pawn Other, optional Pickup Pickup) { Super.GiveTo(Other, Pickup); if ( Bot(Other.Controller) != None ) Bot(Other.Controller).bHasImpactHammer = true; } function bool CanAttack(Actor Other) { return true; } simulated function Timer() { local Bot B; if (ClientState == WS_BringUp) { // check if owner is bot waiting to do impact jump B = Bot(Instigator.Controller); if ( (B != None) && B.bPreparingMove && (B.ImpactTarget != None) ) { B.ImpactJump(); B = None; } } Super.Timer(); if ( (B != None) && (B.Enemy != None) ) BotFire(false); } function FireHack(byte Mode) { if ( Mode == 0 ) { FireMode[0].PlayFiring(); FireMode[0].FlashMuzzleFlash(); FireMode[0].StartMuzzleSmoke(); IncrementFlashCount(0); } } /* BestMode() choose between regular or alt-fire */ function byte BestMode() { local float EnemyDist; local bot B; B = Bot(Instigator.Controller); if ( (B == None) || (B.Enemy == None) ) return 1; EnemyDist = VSize(B.Enemy.Location - Instigator.Location); if ( EnemyDist > 2 * Instigator.GroundSpeed ) return 1; if ( (B.MoveTarget != B.Enemy) && ((EnemyDist > 0.5 * Instigator.GroundSpeed) || (((B.Enemy.Location - Instigator.Location) Dot vector(Instigator.Rotation)) <= 0)) ) return 1; return 0; } // super desireable for bot waiting to impact jump function float GetAIRating() { local Bot B; local float EnemyDist; B = Bot(Instigator.Controller); if ( B == None ) return AIRating; if ( B.bPreparingMove && (B.ImpactTarget != None) ) return 9; if ( B.PlayerReplicationInfo.HasFlag != None ) { if ( Instigator.Health < 50 ) return AIRating + 0.35; return AIRating + 0.25; } if ( B.Enemy == None ) return AIRating; EnemyDist = VSize(B.Enemy.Location - Instigator.Location); if ( B.Stopped() && (EnemyDist > 100) ) return 0.1; if ( (EnemyDist < 750) && (B.Skill <= 2) && !B.Enemy.IsA('Bot') && (ShieldGun(B.Enemy.Weapon) != None) ) return FClamp(300/(EnemyDist + 1), 0.6, 0.75); if ( EnemyDist > 400 ) return 0.1; if ( (Instigator.Weapon != self) && (EnemyDist < 120) ) return 0.25; return ( FMin(0.6, 90/(EnemyDist + 1)) ); } // End AI interface function AdjustPlayerDamage( out int Damage, Pawn InstigatedBy, Vector HitLocation, out Vector Momentum, class DamageType) { local int Drain; local vector Reflect; local vector HitNormal; local float DamageMax; DamageMax = 100.0; if ( DamageType == class'Fell' ) DamageMax = 20.0; else if( !DamageType.default.bArmorStops || (DamageType == class'DamTypeShieldImpact' && InstigatedBy == Instigator) ) return; if ( CheckReflect(HitLocation, HitNormal, 0) ) { Drain = Min( Ammo[1].AmmoAmount*2, Damage ); Drain = Min(Drain,DamageMax); Reflect = MirrorVectorByNormal( Normal(Location - HitLocation), Vector(Instigator.Rotation) ); Damage -= Drain; Momentum *= 1.25; Ammo[1].UseAmmo(Drain/2); DoReflectEffect(Drain/2); } } function DoReflectEffect(int Drain) { PlaySound(ShieldHitSound, SLOT_None); ShieldAltFire(FireMode[1]).TakeHit(Drain); ClientTakeHit(Drain); } simulated function ClientTakeHit(int Drain) { ClientPlayForceFeedback(ShieldHitForce); ShieldAltFire(FireMode[1]).TakeHit(Drain); } function bool CheckReflect( Vector HitLocation, out Vector RefNormal, int AmmoDrain ) { local Vector HitDir; local Vector FaceDir; if (!FireMode[1].bIsFiring || Ammo[0].AmmoAmount == 0) return false; FaceDir = Vector(Instigator.Controller.Rotation); HitDir = Normal(Instigator.Location - HitLocation + Vect(0,0,8)); //Log(self@"HitDir"@(FaceDir dot HitDir)); RefNormal = FaceDir; if ( FaceDir dot HitDir < -0.37 ) // 68 degree protection arc { if (AmmoDrain > 0) Ammo[0].UseAmmo(AmmoDrain); return true; } return false; } function AnimEnd(int channel) { if (FireMode[0].bIsFiring) { LoopAnim('Charged'); } else if (!FireMode[1].bIsFiring) { Super.AnimEnd(channel); } } function float SuggestAttackStyle() { return 0.8; } function float SuggestDefenseStyle() { return -0.8; } simulated function float ChargeBar() { return FMin(1,FireMode[0].HoldTime/ShieldFire(FireMode[0]).FullyChargedTime); } defaultproperties { ItemName="Shield Gun" IconMaterial=Material'InterfaceContent.Hud.SkinA' IconCoords=(X1=200,Y1=281,X2=321,Y2=371) bShowChargingBar=true bCanThrow=false FireModeClass(0)=ShieldFire FireModeClass(1)=ShieldAltFire InventoryGroup=1 Mesh=mesh'Weapons.ShieldGun_1st' BobDamping=2.2 PickupClass=class'ShieldGunPickup' EffectOffset=(X=15.0,Y=6.7,Z=1.2) bMeleeWeapon=true ShieldHitSound=Sound'WeaponSounds.ShieldGun.ShieldReflection' DrawScale=0.4 PutDownAnim=PutDown DisplayFOV=60 PlayerViewOffset=(X=2,Y=-0.7,Z=-2.7) PlayerViewPivot=(Pitch=500,Roll=0,Yaw=500) UV2Texture=Material'XGameShaders.WeaponEnvShader' AttachmentClass=class'ShieldAttachment' SelectSound=Sound'WeaponSounds.ShieldGun_change' SelectForce="ShieldGun_change" ShieldHitForce="ShieldReflection" AIRating=0.35 CurrentRating=0.35 DefaultPriority=2 }