1107 lines
22 KiB
Text
1107 lines
22 KiB
Text
/*
|
|
===============================================================================
|
|
|
|
weapon_clip
|
|
|
|
This is a base class for weapons that use ammo from clips with a finite number
|
|
of bullets
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
object weapon_clip : weapon_base {
|
|
|
|
void preinit();
|
|
void init();
|
|
void destroy();
|
|
void Raise();
|
|
void Lower();
|
|
|
|
//
|
|
// General stuff
|
|
//
|
|
void Idle();
|
|
void IdleInit();
|
|
void IdleClipWeapon();
|
|
|
|
boolean DisableSpread();
|
|
|
|
boolean hasIronSights;
|
|
boolean hasIronSightsLock;
|
|
boolean hasTargetLock;
|
|
boolean hasScope;
|
|
boolean hasScopeSway;
|
|
boolean hasScopeZoom;
|
|
boolean hasScopeLock;
|
|
boolean hasEndFireAnim;
|
|
boolean usesStroyent;
|
|
boolean hasHeat;
|
|
boolean infiniteAmmo;
|
|
|
|
boolean localScopeEffectsActive; // Effects should be active, if this is the local view
|
|
boolean localScopeEffectsEnabled; // Effects are actually active
|
|
|
|
float burstCount;
|
|
|
|
//
|
|
// Firing stuff
|
|
//
|
|
boolean CanFire() { return true; }
|
|
void DoFire();
|
|
void FireBurst( float maxBurst );
|
|
void FireCommon();
|
|
void FireAuto();
|
|
void FireSingle();
|
|
void EndFire();
|
|
void PlayBrassSound();
|
|
void StopBrassSound();
|
|
void PlayFireAnim();
|
|
|
|
boolean AllowSprint();
|
|
void PlayLeaveSprintAnim( string newState, float blend );
|
|
|
|
float refireTime;
|
|
float fireRateSingle;
|
|
float fireRateAuto;
|
|
boolean playingBrassSound;
|
|
boolean playingFireAnim;
|
|
|
|
//
|
|
// Reloading stuff
|
|
//
|
|
boolean CanReload();
|
|
boolean NeedsReload();
|
|
void Reload();
|
|
float DoReload( boolean wasScoped );
|
|
|
|
void BeginFireSingleReloadTime();
|
|
void EndFireSingleReloadTime();
|
|
|
|
boolean dryfireAttack;
|
|
|
|
//
|
|
// Heat
|
|
//
|
|
void Overheat();
|
|
|
|
//
|
|
// Callbacks
|
|
//
|
|
boolean IsScopeZoomed();
|
|
float OnActivate( entity p, float distance );
|
|
float OnActivateHeld( entity p, float distance );
|
|
float OnUsed( entity p, float distance );
|
|
boolean OnWeapNext();
|
|
boolean OnWeapPrev();
|
|
void Cleanup();
|
|
|
|
void OnIronSightsEnabled();
|
|
void OnIronSightsDisabled();
|
|
|
|
//
|
|
// Scope stuff
|
|
//
|
|
boolean CheckScope( boolean upOnly );
|
|
void CycleZoom();
|
|
void ScopeUp();
|
|
void ScopeDown( boolean allowBlocking );
|
|
void LoadScopeGUI();
|
|
void FreeScopeGUI();
|
|
void UpdateScopeScale();
|
|
void OnScopeZoomCycle();
|
|
void vSetScopeState( boolean up );
|
|
|
|
void RemoveLocalScopeEffects();
|
|
void AddLocalScopeEffects();
|
|
|
|
void OnBecomeViewWeapon();
|
|
void OnFinishViewWeapon();
|
|
|
|
void ToolTipThread_Raise();
|
|
void ToolTipThread_Scope();
|
|
|
|
boolean sniperScopeUp;
|
|
boolean zoomKeyDown;
|
|
boolean changingScopeStatus;
|
|
zoomWidget zoomer;
|
|
float scopeGUIHandle;
|
|
|
|
float maxScopeUpFrames;
|
|
float maxScopeDownFrames;
|
|
|
|
boolean scopeThreadDone;
|
|
|
|
boolean showSingleReloadTime;
|
|
boolean fireSingleReloadTimeActive;
|
|
}
|
|
|
|
void weapon_clip::preinit() {
|
|
showSingleReloadTime = getFloatKeyWithDefault( "show_single_reload_time", 0 ) != 0;
|
|
|
|
hasIronSights = true;
|
|
hasTargetLock = false;
|
|
hasScope = false;
|
|
hasScopeSway = true;
|
|
hasScopeZoom = false;
|
|
hasScopeLock = false;
|
|
hasEndFireAnim = false;
|
|
usesStroyent = false;
|
|
infiniteAmmo = false;
|
|
|
|
maxScopeUpFrames = 999999;
|
|
maxScopeDownFrames = 999999;
|
|
|
|
zoomer = new zoomWidget;
|
|
zoomer.Init( self );
|
|
|
|
scopeGUIHandle = -1;
|
|
|
|
fireRateAuto = getFloatKeyWithDefault( "fire_rate", 0.2f );
|
|
fireRateSingle = 0.15f;
|
|
|
|
refireTime = -1.0f;
|
|
}
|
|
|
|
boolean weapon_clip::DisableSpread() {
|
|
if ( hasScopeSway ) {
|
|
if ( myPlayer != $null_entity ) {
|
|
return myPlayer.IsSniperScopeUp();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void weapon_clip::init() {
|
|
myPlayer.SetSniperScopeUp( false );
|
|
setBlendFrames( ANIMCHANNEL_ALL, 4 );
|
|
|
|
if ( hasTargetLock ) {
|
|
enableTargetLock( 1.0f );
|
|
}
|
|
|
|
if ( myPlayer.isLocalPlayer() ) {
|
|
thread ToolTipThread_Raise();
|
|
}
|
|
|
|
weaponState( "Raise", 0 );
|
|
}
|
|
|
|
void weapon_clip::destroy() {
|
|
if ( hasScope ) {
|
|
ScopeDown( false );
|
|
}
|
|
|
|
RemoveLocalScopeEffects();
|
|
|
|
if ( ShouldRunGuis() ) {
|
|
KillUpdateHeat();
|
|
}
|
|
|
|
delete zoomer;
|
|
|
|
StopBrassSound();
|
|
}
|
|
|
|
void weapon_clip::Raise() {
|
|
if ( hasHeat && ShouldRunGuis() ) {
|
|
CreateUpdateHeat();
|
|
}
|
|
|
|
Base_Raise();
|
|
}
|
|
|
|
void weapon_clip::Lower() {
|
|
if ( ShouldRunGuis() ) {
|
|
KillUpdateHeat();
|
|
}
|
|
|
|
Cleanup();
|
|
Base_Lower();
|
|
}
|
|
|
|
/*
|
|
=====================================================================
|
|
|
|
General stuff
|
|
|
|
=====================================================================
|
|
*/
|
|
void weapon_clip::Idle() {
|
|
IdleInit();
|
|
while ( true ) {
|
|
IdleClipWeapon();
|
|
sys.waitFrame();
|
|
}
|
|
}
|
|
|
|
void weapon_clip::IdleInit() {
|
|
weaponReady();
|
|
|
|
PlayIdleAnim();
|
|
|
|
playingFireAnim = false;
|
|
altFireDown = WEAPON_ALTFIRE;
|
|
}
|
|
|
|
void weapon_clip::IdleClipWeapon() {
|
|
if ( !myPlayer.IsSniperScopeUp() ) {
|
|
// if its not already playing the idle effect it'll start playing it
|
|
StartIdleEffect();
|
|
}
|
|
|
|
float time = sys.getTime();
|
|
|
|
if ( hasIronSights ) {
|
|
CheckIronSights();
|
|
} else if ( hasScope ) {
|
|
CheckScope( false );
|
|
}
|
|
|
|
if ( WEAPON_LOWERWEAPON ) {
|
|
StopIdleEffect();
|
|
weaponState( "Lower", 4 );
|
|
}
|
|
if ( WEAPON_RELOAD && CanReload() ) {
|
|
StopIdleEffect();
|
|
weaponState( "Reload", 4 );
|
|
}
|
|
|
|
if ( WEAPON_ATTACK ) {
|
|
myPlayer.disableSprint( 1.f );
|
|
|
|
if ( CanFire() && !NeedsReload() ) {
|
|
dryfireAttack = false;
|
|
if ( time >= refireTime && !changingScopeStatus ) {
|
|
DoFire();
|
|
mainFireDown = true;
|
|
}
|
|
} else {
|
|
if ( !dryfireAttack ) {
|
|
startSound( "snd_dryfire", SND_WEAPON_DRYFIRE );
|
|
dryfireAttack = true;
|
|
}
|
|
if ( CanReload() ) {
|
|
StopIdleEffect();
|
|
weaponState( "Reload", 4 );
|
|
}
|
|
}
|
|
} else {
|
|
if ( myPlayer.getButton( PK_ATTACK ) ) {
|
|
if ( !dryfireAttack ) {
|
|
startSound( "snd_dryfire", SND_WEAPON_DRYFIRE );
|
|
dryfireAttack = true;
|
|
}
|
|
} else {
|
|
dryfireAttack = false;
|
|
}
|
|
burstCount = 0;
|
|
mainFireDown = false;
|
|
|
|
if ( AllowSprint() ) {
|
|
myPlayer.disableSprint( 0.f );
|
|
|
|
if ( myPlayer.AI_SPRINT ) {
|
|
if ( hasScope ) {
|
|
ScopeDown( true );
|
|
}
|
|
StopIdleEffect();
|
|
weaponState( "Sprint", 4 );
|
|
}
|
|
} else {
|
|
myPlayer.disableSprint( 1.f );
|
|
}
|
|
}
|
|
|
|
if ( hasScope && hasScopeZoom ) {
|
|
if ( myPlayer.getButton( PK_ACTIVATE ) ) {
|
|
if ( !zoomKeyDown ) {
|
|
zoomKeyDown = true;
|
|
CycleZoom();
|
|
}
|
|
} else {
|
|
zoomKeyDown = false;
|
|
}
|
|
}
|
|
|
|
if ( !sys.isClient() ) {
|
|
if ( IsOverheated() ) {
|
|
StopIdleEffect();
|
|
weaponState( "Overheat", 4 );
|
|
}
|
|
}
|
|
|
|
|
|
if ( time > refireTime && refireTime != -1.0f ) {
|
|
EndFire();
|
|
refireTime = -1.0f;
|
|
}
|
|
|
|
if ( playingFireAnim && refireTime == -1.0f ) {
|
|
if ( animDone( ANIMCHANNEL_ALL, 0 ) ) {
|
|
PlayIdleAnim();
|
|
playingFireAnim = false;
|
|
}
|
|
}
|
|
|
|
UpdateCharge();
|
|
}
|
|
|
|
/*
|
|
=====================================================================
|
|
|
|
Firing functions
|
|
|
|
=====================================================================
|
|
*/
|
|
|
|
void weapon_clip::DoFire() {
|
|
if ( myPlayer.IsSniperScopeUp() ) {
|
|
if ( !mainFireDown ) {
|
|
FireSingle();
|
|
}
|
|
} else {
|
|
FireAuto();
|
|
}
|
|
}
|
|
|
|
void weapon_clip::PlayFireAnim() {
|
|
if ( ironSightsEnabled || myPlayer.IsSniperScopeUp() ) {
|
|
playAnim( ANIMCHANNEL_ALL, "fire_zoom" );
|
|
} else {
|
|
playAnim( ANIMCHANNEL_ALL, "fire" );
|
|
}
|
|
}
|
|
|
|
void weapon_clip::FireBurst( float maxBurst ) {
|
|
if ( burstCount >= maxBurst ) {
|
|
return;
|
|
}
|
|
|
|
FireAuto();
|
|
}
|
|
|
|
void weapon_clip::FireCommon() {
|
|
PlayFireEffect();
|
|
PlayFireSound();
|
|
PlayBrassSound();
|
|
PlayFireAnim();
|
|
|
|
burstCount++;
|
|
playingFireAnim = true;
|
|
launchProjectiles( numProjectiles, 0, getCurrentSpread(), 0, 1, 1 );
|
|
increaseSpread();
|
|
|
|
if ( !infiniteAmmo ) {
|
|
if ( !usesStroyent ) {
|
|
UseAmmo( 0 );
|
|
AmmoCheckClip( 0 );
|
|
} else {
|
|
UseAmmo_Stroyent( 0 );
|
|
AmmoCheck( 0 );
|
|
}
|
|
}
|
|
|
|
if ( hasHeat ) {
|
|
AddHeat();
|
|
}
|
|
}
|
|
|
|
void weapon_clip::FireAuto() {
|
|
FireCommon();
|
|
|
|
refireTime = sys.getTime() + fireRateAuto;
|
|
}
|
|
|
|
void weapon_clip::FireSingle() {
|
|
FireCommon();
|
|
|
|
playEffect( "fx_tracer", "muzzle", 0 );
|
|
|
|
refireTime = sys.getTime() + fireRateSingle;
|
|
|
|
if ( showSingleReloadTime ) {
|
|
BeginFireSingleReloadTime();
|
|
}
|
|
}
|
|
|
|
void weapon_clip::EndFire() {
|
|
StopBrassSound();
|
|
resetTracerCounter();
|
|
|
|
if ( fireSingleReloadTimeActive ) {
|
|
EndFireSingleReloadTime();
|
|
}
|
|
|
|
if ( hasEndFireAnim ) {
|
|
if ( !ironSightsEnabled ) {
|
|
playAnim( ANIMCHANNEL_ALL, "fire_end" );
|
|
waitUntil( animDone( ANIMCHANNEL_ALL, 1 ) );
|
|
playingFireAnim = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void weapon_clip::PlayBrassSound() {
|
|
if ( !playingBrassSound ) {
|
|
if ( sys.getLocalPlayer() == myPlayer ) {
|
|
playingBrassSound = true;
|
|
startSound( "snd_brass_loop", SND_WEAPON_BRASS );
|
|
}
|
|
}
|
|
}
|
|
|
|
void weapon_clip::StopBrassSound() {
|
|
if ( playingBrassSound ) {
|
|
playingBrassSound = false;
|
|
startSound( "snd_brass_stop", SND_WEAPON_BRASS );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================================================================
|
|
|
|
Reloading functions
|
|
|
|
=====================================================================
|
|
*/
|
|
|
|
boolean weapon_clip::CanReload() {
|
|
if ( !usesStroyent && !infiniteAmmo ) {
|
|
if ( ( ammoAvailable( 0 ) > ammoInClip( 0 ) ) && ( ammoInClip( 0 ) < clipSize( 0 ) ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
boolean weapon_clip::NeedsReload() {
|
|
if ( !infiniteAmmo ) {
|
|
if ( !usesStroyent ) {
|
|
if ( ammoInClip( 0 ) <= 0 ) {
|
|
return true;
|
|
}
|
|
} else {
|
|
if ( ammoAvailable( 0 ) <= 0 ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void weapon_clip::Reload() {
|
|
myPlayer.disableSprint( 1.f );
|
|
|
|
StopBrassSound();
|
|
|
|
Base_BeginReload();
|
|
|
|
boolean wasEnabled = false;
|
|
float lastZoomState;
|
|
if ( hasIronSights ) {
|
|
wasEnabled = wantsIronSights;
|
|
if ( wasEnabled ) {
|
|
DisableIronSights();
|
|
waitUntil( !ironSightsThreadActive );
|
|
}
|
|
} else if ( hasScope ) {
|
|
wasEnabled = sniperScopeUp;
|
|
if ( wasEnabled ) {
|
|
lastZoomState = zoomer.GetZoomState();
|
|
ScopeDown( true );
|
|
}
|
|
}
|
|
|
|
float stayEnabled = DoReload( wasEnabled );
|
|
|
|
if ( stayEnabled != 0.0f ) {
|
|
if ( hasIronSights ) {
|
|
EnableIronSights();
|
|
waitUntil( !ironSightsThreadActive );
|
|
} else if ( hasScope ) {
|
|
ScopeUp();
|
|
zoomer.Zoom( lastZoomState );
|
|
UpdateScopeScale();
|
|
}
|
|
}
|
|
|
|
Base_EndReload();
|
|
weaponState( "Idle", 4 );
|
|
}
|
|
|
|
float weapon_clip::DoReload( boolean wasScoped ) {
|
|
weaponReloading();
|
|
playAnim( ANIMCHANNEL_ALL, "reload" );
|
|
|
|
wasScoped = false; // disabled for now
|
|
|
|
boolean altKeyDown;
|
|
float stayEnabled = wasScoped;
|
|
while ( !animDone( ANIMCHANNEL_ALL, 4 ) ) {
|
|
sys.waitFrame();
|
|
|
|
if ( WEAPON_HIDE ) {
|
|
Base_EndReload();
|
|
weaponState( "Idle", 4 );
|
|
}
|
|
|
|
if ( WEAPON_LOWERWEAPON ) {
|
|
Base_EndReload();
|
|
weaponState( "Lower", 4 );
|
|
}
|
|
|
|
if ( WEAPON_ALTFIRE ) {
|
|
if ( !altKeyDown ) {
|
|
altKeyDown = true;
|
|
stayEnabled = 1 - stayEnabled;
|
|
}
|
|
} else {
|
|
altKeyDown = false;
|
|
}
|
|
}
|
|
|
|
addToClip( 0, clipSize( 0 ) );
|
|
|
|
return stayEnabled;
|
|
}
|
|
|
|
void weapon_clip::BeginFireSingleReloadTime() {
|
|
if ( ShouldRunGuis() ) {
|
|
if ( fireSingleReloadTimeActive ) {
|
|
EndFireSingleReloadTime();
|
|
}
|
|
|
|
fireSingleReloadTimeActive = true;
|
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponReloadTime", fireRateSingle );
|
|
}
|
|
}
|
|
|
|
void weapon_clip::EndFireSingleReloadTime() {
|
|
if ( ShouldRunGuis() ) {
|
|
fireSingleReloadTimeActive = false;
|
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponReloadTime", 0 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================================================================
|
|
|
|
Heat
|
|
|
|
=====================================================================
|
|
*/
|
|
|
|
void weapon_clip::Overheat() {
|
|
resetTracerCounter();
|
|
|
|
boolean wasEnabled = false;
|
|
float lastZoomState;
|
|
if ( hasIronSights ) {
|
|
wasEnabled = wantsIronSights;
|
|
if ( wasEnabled ) {
|
|
DisableIronSights();
|
|
waitUntil( !ironSightsThreadActive );
|
|
}
|
|
} else if ( hasScope ) {
|
|
wasEnabled = sniperScopeUp;
|
|
if ( wasEnabled ) {
|
|
lastZoomState = zoomer.GetZoomState();
|
|
ScopeDown( true );
|
|
}
|
|
}
|
|
|
|
weaponReloading();
|
|
StartCooling();
|
|
|
|
if ( sys.getLocalViewPlayer() != myPlayer || pm_thirdperson.getBoolValue() ) {
|
|
entity worldModel = getWorldModel( 0 ); // FIXME
|
|
worldModel.playEffect( "fx_overheat_world", "muzzle", 0.0f );
|
|
}
|
|
|
|
playAnim( ANIMCHANNEL_ALL, "overheat" );
|
|
boolean altKeyDown;
|
|
float stayEnabled = false;//wasEnabled;
|
|
while ( !animDone( ANIMCHANNEL_ALL, 4 ) ) {
|
|
if ( WEAPON_ALTFIRE ) {
|
|
if ( !altKeyDown ) {
|
|
altKeyDown = true;
|
|
stayEnabled = 1 - stayEnabled;
|
|
}
|
|
} else {
|
|
altKeyDown = false;
|
|
}
|
|
|
|
sys.waitFrame();
|
|
}
|
|
|
|
FinishCooling();
|
|
|
|
if ( stayEnabled != 0.0f ) {
|
|
if ( hasIronSights ) {
|
|
EnableIronSights();
|
|
waitUntil( !ironSightsThreadActive );
|
|
} else if ( hasScope ) {
|
|
ScopeUp();
|
|
zoomer.Zoom( lastZoomState );
|
|
UpdateScopeScale();
|
|
}
|
|
}
|
|
|
|
weaponState( "Idle", 4 );
|
|
}
|
|
|
|
|
|
/*
|
|
=====================================================================
|
|
|
|
Callbacks
|
|
|
|
=====================================================================
|
|
*/
|
|
boolean weapon_clip::IsScopeZoomed() {
|
|
if ( hasScope && hasScopeZoom && ( myPlayer.IsSniperScopeUp() ) && zoomer.IsEnabled() ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
float weapon_clip::OnActivate( entity p, float distance ) {
|
|
return IsScopeZoomed();
|
|
}
|
|
|
|
float weapon_clip::OnActivateHeld( entity p, float distance ) {
|
|
return IsScopeZoomed();
|
|
}
|
|
|
|
float weapon_clip::OnUsed( entity p, float distance ) {
|
|
return IsScopeZoomed();
|
|
}
|
|
|
|
boolean weapon_clip::OnWeapNext() {
|
|
if ( IsScopeZoomed() ) {
|
|
if ( !zoomer.IsFullyZoomedOut() ) {
|
|
startSound( "snd_zoomout", SND_WEAPON_MODE );
|
|
}
|
|
|
|
zoomer.ZoomOut();
|
|
UpdateScopeScale();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
boolean weapon_clip::OnWeapPrev() {
|
|
if ( IsScopeZoomed() ) {
|
|
if ( !zoomer.IsFullyZoomedIn() ) {
|
|
startSound( "snd_zoomin", SND_WEAPON_MODE );
|
|
}
|
|
|
|
zoomer.ZoomIn();
|
|
UpdateScopeScale();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void weapon_clip::Cleanup() {
|
|
if ( hasIronSights ) {
|
|
if ( ironSightsThreadActive || ironSightsEnabled ) {
|
|
DisableIronSights_Private( false );
|
|
}
|
|
StopIronSightsThread();
|
|
ironSightsThreadActive = false;
|
|
} else if ( hasScope ) {
|
|
ScopeDown( false );
|
|
}
|
|
|
|
StopBrassSound();
|
|
}
|
|
|
|
|
|
/*
|
|
=====================================================================
|
|
|
|
Zoom functions
|
|
|
|
=====================================================================
|
|
*/
|
|
|
|
void weapon_clip::vSetScopeState( boolean up ) {
|
|
if ( up ) {
|
|
thread ScopeUp();
|
|
} else {
|
|
thread ScopeDown( true );
|
|
}
|
|
|
|
UpdateCrosshair();
|
|
}
|
|
|
|
boolean weapon_clip::CheckScope( boolean upOnly ) {
|
|
boolean comingup = false;
|
|
|
|
boolean isSprinting = false;
|
|
vector move = myPlayer.getMove();
|
|
if ( move_x > 0.01f ) {
|
|
if ( myPlayer.getButton( PK_SPRINT ) ) {
|
|
isSprinting = true;
|
|
}
|
|
}
|
|
|
|
if ( WEAPON_ALTFIRE ) {
|
|
if ( !altFireDown ) {
|
|
|
|
// toggle the scope
|
|
if ( !sys.isClient() ) {
|
|
if ( !upOnly && myPlayer.IsSniperScopeUp() && !isSprinting ) {
|
|
thread ScopeDown( true );
|
|
} else {
|
|
thread ScopeUp();
|
|
comingup = true;
|
|
}
|
|
}
|
|
|
|
altFireDown = true;
|
|
}
|
|
} else {
|
|
altFireDown = false;
|
|
}
|
|
|
|
// scope can be toggled off by sprinting
|
|
if ( !upOnly ) {
|
|
if ( isSprinting ) {
|
|
thread ScopeDown( true );
|
|
}
|
|
}
|
|
|
|
return comingup;
|
|
}
|
|
|
|
void weapon_clip::CycleZoom() {
|
|
if ( !myPlayer.IsSniperScopeUp() || !zoomer.IsEnabled() ) {
|
|
return;
|
|
}
|
|
|
|
sys.assert( zoomer.enabled );
|
|
|
|
startSound( "snd_zoomin", SND_WEAPON_MODE );
|
|
|
|
zoomer.Cycle();
|
|
|
|
UpdateScopeScale();
|
|
|
|
OnScopeZoomCycle();
|
|
}
|
|
|
|
void weapon_clip::LoadScopeGUI() {
|
|
FreeScopeGUI();
|
|
|
|
string key = getKey( "gui_sniper_scope" );
|
|
if( sys.strLength( key ) > 0 ) {
|
|
scopeGUIHandle = sys.allocHudModule( getKey( "gui_sniper_scope" ), getFloatKeyWithDefault( "hud_sort", 0 ), false );
|
|
}
|
|
}
|
|
|
|
void weapon_clip::FreeScopeGUI() {
|
|
if ( scopeGUIHandle != -1 ) {
|
|
sys.freeHudModule( scopeGUIHandle );
|
|
scopeGUIHandle = -1;
|
|
}
|
|
}
|
|
|
|
void weapon_clip::UpdateScopeScale() {
|
|
if ( scopeGUIHandle == -1 ) {
|
|
return;
|
|
}
|
|
|
|
float state = zoomer.GetZoomState();
|
|
|
|
sys.setGUIFloat( scopeGUIHandle, "zoomState", state );
|
|
|
|
if ( state == 0 ) {
|
|
sys.setGUIFloat( scopeGUIHandle, "zoomCycleTransition", -( zoomer.GetNumZoomStates() - 1 ) );
|
|
} else {
|
|
sys.setGUIFloat( scopeGUIHandle, "zoomCycleTransition", 1 );
|
|
}
|
|
}
|
|
|
|
void weapon_clip::OnScopeZoomCycle() {
|
|
if ( scopeGUIHandle == -1 ) {
|
|
return;
|
|
}
|
|
|
|
sys.guiPostNamedEvent( scopeGUIHandle, "", "onZoomCycle" );
|
|
}
|
|
|
|
void weapon_clip::OnBecomeViewWeapon() {
|
|
if ( localScopeEffectsActive ) {
|
|
AddLocalScopeEffects();
|
|
}
|
|
if ( localIronSightsEffectsActive ) {
|
|
AddLocalIronSightsEffects();
|
|
}
|
|
if ( hasHeat && ShouldRunGuis() ) {
|
|
CreateUpdateHeat();
|
|
}
|
|
UpdateCrosshair();
|
|
}
|
|
|
|
void weapon_clip::OnFinishViewWeapon() {
|
|
KillUpdateHeat();
|
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponReloadTime", 0 );
|
|
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.cooling", 0.f );
|
|
|
|
RemoveLocalScopeEffects();
|
|
RemoveLocalIronSightsEffects();
|
|
}
|
|
|
|
void weapon_clip::AddLocalScopeEffects() {
|
|
if ( localScopeEffectsEnabled ) {
|
|
return;
|
|
}
|
|
|
|
if ( myPlayer == $null_entity ) {
|
|
return;
|
|
}
|
|
|
|
if ( myPlayer == sys.getLocalViewPlayer() ) {
|
|
localScopeEffectsEnabled = true;
|
|
|
|
HideSights();
|
|
string modelKey = getKey( "def_scopemodel" );
|
|
if ( modelKey != "" ) {
|
|
myPlayer.enableClientModelSights( modelKey );
|
|
}
|
|
LoadScopeGUI();
|
|
}
|
|
}
|
|
|
|
void weapon_clip::ScopeUp() {
|
|
while ( changingScopeStatus ) {
|
|
sys.waitFrame();
|
|
}
|
|
|
|
if ( sniperScopeUp ) {
|
|
UpdateCrosshair();
|
|
UpdateSpreadModifiers();
|
|
return;
|
|
}
|
|
|
|
changingScopeStatus = true;
|
|
sniperScopeUp = true;
|
|
myPlayer.SetSniperScopeUp( true );
|
|
|
|
StopIdleEffect();
|
|
playAnim( ANIMCHANNEL_ALL, "zoomin" );
|
|
sys.waitFrame();
|
|
|
|
float scopeUpFrames = 0;
|
|
while ( !animDone( ANIMCHANNEL_ALL, 4 ) ) {
|
|
sys.waitFrame();
|
|
scopeUpFrames++;
|
|
if ( scopeUpFrames == maxScopeUpFrames - 1 ) {
|
|
break;
|
|
}
|
|
|
|
// there is an off chance that during this wait, a non-blocking ScopeDown gets called,
|
|
// which will have hijacked the purpose of this since it was called AFTER ScopeUp
|
|
// the end result desired is for the scope to be down anyway, so we might as well abort out of here
|
|
if ( !sniperScopeUp ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
setBlendFrames( ANIMCHANNEL_ALL, 4 );
|
|
playCycle( ANIMCHANNEL_ALL, "idle_zoom" );
|
|
myPlayer.setSpeedModifier( speedMod * fovSpeed );
|
|
|
|
hide();
|
|
|
|
localScopeEffectsActive = true;
|
|
AddLocalScopeEffects();
|
|
|
|
UpdateScopeScale();
|
|
|
|
zoomer.Enable();
|
|
startSound( "snd_scopeup", SND_WEAPON_SIG );
|
|
myPlayer.setSniperAOR( 1.f );
|
|
|
|
if ( hasScopeSway ) {
|
|
enableSway( 1.f );
|
|
}
|
|
|
|
UpdateSpreadModifiers();
|
|
|
|
changingScopeStatus = false;
|
|
|
|
if ( hasScopeLock ) {
|
|
enableTargetLock( 1 );
|
|
}
|
|
|
|
if ( myPlayer.isLocalPlayer() ) {
|
|
thread ToolTipThread_Scope();
|
|
}
|
|
|
|
UpdateCrosshair();
|
|
}
|
|
|
|
void weapon_clip::RemoveLocalScopeEffects() {
|
|
if ( !localScopeEffectsEnabled ) {
|
|
return;
|
|
}
|
|
localScopeEffectsEnabled = false;
|
|
|
|
ShowSights();
|
|
myPlayer.disableClientModelSights();
|
|
FreeScopeGUI();
|
|
}
|
|
|
|
void weapon_clip::ScopeDown( boolean allowBlocking ) {
|
|
if ( allowBlocking ) {
|
|
while ( changingScopeStatus ) {
|
|
sys.waitFrame();
|
|
}
|
|
}
|
|
|
|
if ( !sniperScopeUp ) {
|
|
UpdateCrosshair();
|
|
UpdateSpreadModifiers();
|
|
return;
|
|
}
|
|
|
|
if ( !hasTargetLock ) {
|
|
enableTargetLock( 0 );
|
|
}
|
|
|
|
changingScopeStatus = true;
|
|
|
|
sniperScopeUp = false;
|
|
if ( myPlayer != $null_entity ) {
|
|
myPlayer.SetSniperScopeUp( false );
|
|
myPlayer.setSpeedModifier( speedMod );
|
|
}
|
|
|
|
localScopeEffectsActive = false;
|
|
RemoveLocalScopeEffects();
|
|
|
|
show();
|
|
|
|
zoomer.Disable();
|
|
startSound( "snd_scopedown", SND_WEAPON_SIG );
|
|
|
|
if ( allowBlocking ) {
|
|
playAnim( ANIMCHANNEL_ALL, "zoomout" );
|
|
|
|
float scopeDownFrames = 0;
|
|
while ( !animDone( ANIMCHANNEL_ALL, 4 ) ) {
|
|
sys.waitFrame();
|
|
scopeDownFrames++;
|
|
if ( scopeDownFrames == maxScopeDownFrames - 1 ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
setBlendFrames( ANIMCHANNEL_ALL, 4 );
|
|
PlayIdleAnim();
|
|
|
|
if ( myPlayer != $null_entity ) {
|
|
myPlayer.setSniperAOR( 0.f );
|
|
}
|
|
|
|
if ( hasScopeSway ) {
|
|
enableSway( 0.f );
|
|
}
|
|
|
|
UpdateSpreadModifiers();
|
|
|
|
changingScopeStatus = false;
|
|
|
|
UpdateCrosshair();
|
|
}
|
|
|
|
void weapon_clip::OnIronSightsDisabled() {
|
|
if ( !hasTargetLock ) {
|
|
enableTargetLock( 0 );
|
|
}
|
|
UpdateCrosshair();
|
|
}
|
|
|
|
void weapon_clip::OnIronSightsEnabled() {
|
|
if ( hasIronSightsLock ) {
|
|
enableTargetLock( 1 );
|
|
}
|
|
UpdateCrosshair();
|
|
}
|
|
|
|
void weapon_clip::ToolTipThread_Raise() {
|
|
sys.wait( myPlayer.CalcTooltipWait() + 0.2f );
|
|
while ( myPlayer.isSinglePlayerToolTipPlaying() ) {
|
|
sys.wait( 0.5f );
|
|
}
|
|
myPlayer.cancelToolTips();
|
|
|
|
WAIT_FOR_TOOLTIP;
|
|
myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_1" ) ) );
|
|
|
|
WAIT_FOR_TOOLTIP;
|
|
myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_2" ) ) );
|
|
|
|
if ( hasIronSights ) {
|
|
WAIT_FOR_TOOLTIP;
|
|
myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_ironsights_1" ) ) );
|
|
|
|
WAIT_FOR_TOOLTIP;
|
|
myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_ironsights_2" ) ) );
|
|
}
|
|
|
|
if ( hasScope ) {
|
|
WAIT_FOR_TOOLTIP;
|
|
myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_scope" ) ) );
|
|
}
|
|
|
|
if ( hasHeat ) {
|
|
WAIT_FOR_TOOLTIP;
|
|
myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_heat" ) ) );
|
|
} else {
|
|
WAIT_FOR_TOOLTIP;
|
|
myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_reload" ) ) );
|
|
}
|
|
}
|
|
|
|
void weapon_clip::ToolTipThread_Scope() {
|
|
if ( scopeThreadDone ) {
|
|
return;
|
|
}
|
|
scopeThreadDone = true;
|
|
|
|
WAIT_FOR_TOOLTIP;
|
|
myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_scope_up_1" ) ) );
|
|
|
|
WAIT_FOR_TOOLTIP;
|
|
myPlayer.sendToolTip( GetToolTip( getKey( "tt_intro_scope_up_2" ) ) );
|
|
}
|
|
|
|
boolean weapon_clip::AllowSprint() {
|
|
return !myPlayer.IsSniperScopeUp() && sys.getTime() > refireTime;
|
|
}
|
|
|
|
void weapon_clip::PlayLeaveSprintAnim( string newState, float blend ) {
|
|
if ( hasWeaponAnim( "leave_sprint" ) ) {
|
|
playAnim( ANIMCHANNEL_ALL, "leave_sprint" );
|
|
while( !animDone( ANIMCHANNEL_ALL, 4 ) ) {
|
|
sys.waitFrame();
|
|
if ( hasScope ) {
|
|
if ( newState == "Idle" ) {
|
|
// scoped weapons may early exit the leave sprint animation by using scope
|
|
if ( CheckScope( true ) ) {
|
|
weaponState( newState, blend );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|