summaryrefslogtreecommitdiff
path: root/game/shared/tf/tf_weapon_invis.cpp
blob: 91f36742804408c2c70fe863b1b7f59006737eef (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================

#include "cbase.h"
#include "tf_weapon_invis.h"
#include "in_buttons.h"

#if !defined( CLIENT_DLL )
	#include "vguiscreen.h"
	#include "tf_player.h"
#else
	#include "c_tf_player.h"
#endif

extern ConVar tf_spy_invis_unstealth_time;
extern ConVar tf_spy_cloak_consume_rate;
extern ConVar tf_spy_cloak_regen_rate;

//=============================================================================
//
// TFWeaponBase Melee tables.
//
IMPLEMENT_NETWORKCLASS_ALIASED( TFWeaponInvis, DT_TFWeaponInvis )

BEGIN_NETWORK_TABLE( CTFWeaponInvis, DT_TFWeaponInvis )
END_NETWORK_TABLE()

BEGIN_PREDICTION_DATA( CTFWeaponInvis )
END_PREDICTION_DATA()

LINK_ENTITY_TO_CLASS( tf_weapon_invis, CTFWeaponInvis );
PRECACHE_WEAPON_REGISTER( tf_weapon_invis );

// Server specific.
#if !defined( CLIENT_DLL ) 
	BEGIN_DATADESC( CTFWeaponInvis )
	END_DATADESC()
#endif

//-----------------------------------------------------------------------------
// Purpose: Use the offhand view model
//-----------------------------------------------------------------------------
void CTFWeaponInvis::Spawn( void )
{
	BaseClass::Spawn();

	SetViewModelIndex( 1 );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFWeaponInvis::OnActiveStateChanged( int iOldState )
{
	BaseClass::OnActiveStateChanged( iOldState );

	// If we are being removed, we need to remove all stealth effects from our owner
	if ( m_iState == WEAPON_NOT_CARRIED && iOldState != WEAPON_NOT_CARRIED )
	{
		CleanupInvisibilityWatch();
	}
}

//-----------------------------------------------------------------------------
// Purpose: Clear out the view model when we hide
//-----------------------------------------------------------------------------
void CTFWeaponInvis::HideThink( void )
{ 
	SetWeaponVisible( false );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CTFWeaponInvis::GetViewModel( int viewmodelindex  ) const
{
	// Watch uses the player model as its viewmodel, because it's never seen being carried by the player
	const CEconItemView *pItem = GetAttributeContainer()->GetItem();
	if ( pItem->IsValid() )
	{
		int iClass = 0;
		int iTeam = 0;
		CTFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() );
		if ( pTFPlayer )
		{
			iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
			iTeam = pTFPlayer->GetTeamNumber();
		}

		return pItem->GetPlayerDisplayModel( iClass, iTeam );
	}

	return BaseClass::GetViewModel( viewmodelindex );
}

//-----------------------------------------------------------------------------
// Purpose: Show/hide weapon and corresponding view model if any
// Input  : visible - 
//-----------------------------------------------------------------------------
void CTFWeaponInvis::SetWeaponVisible( bool visible )
{
	CBaseViewModel *vm = NULL;

	CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
	if ( pOwner )
	{
		vm = pOwner->GetViewModel( m_nViewModelIndex );
	}

	if ( visible )
	{
		RemoveEffects( EF_NODRAW );
		if ( vm )
		{
			vm->RemoveEffects( EF_NODRAW );
		}
	}
	else
	{
		AddEffects( EF_NODRAW );
		if ( vm )
		{
			vm->AddEffects( EF_NODRAW );
		}
	}
}

//-----------------------------------------------------------------------------
bool CTFWeaponInvis::Deploy( void )
{
	bool b = BaseClass::Deploy();

	SetWeaponIdleTime( gpGlobals->curtime + 1.5 );

	return b;
}

//-----------------------------------------------------------------------------
bool CTFWeaponInvis::Holster( CBaseCombatWeapon *pSwitchingTo )
{ 
	bool bHolster = BaseClass::Holster( pSwitchingTo );

	// far in the future
	SetWeaponIdleTime( gpGlobals->curtime + 10 );

	return bHolster;
}

//-----------------------------------------------------------------------------
void CTFWeaponInvis::PrimaryAttack( void )
{
	// do nothing
}

//-----------------------------------------------------------------------------
void CTFWeaponInvis::SecondaryAttack( void )
{
	// do nothing
}

//-----------------------------------------------------------------------------
void CTFWeaponInvis::ItemBusyFrame( void )
{
	// do nothing
}

//-----------------------------------------------------------------------------
// Purpose: the player alt-fired or otherwise activated the functionality of
//			the invisibility watch
//-----------------------------------------------------------------------------
bool CTFWeaponInvis::ActivateInvisibilityWatch( void )
{
	CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
	if ( !pOwner )
		return false;

	SetCloakRates();

	bool bDoSkill = false;
	// If we're in TF_COND_STEALTHED - which means we gave it ourselves - always remove it
	// If we're in TF_COND_STEALTHED_USER_BUFF and we have Dead Ringer, allow it to be toggled
	// since we're allowed to fire from stealth
	if ( pOwner->m_Shared.InCond( TF_COND_STEALTHED ) )
	{
		// De-cloak.
		float flDecloakRate = 0.0f;
		CALL_ATTRIB_HOOK_FLOAT( flDecloakRate, mult_decloak_rate );
		if ( flDecloakRate <= 0.0f )
			flDecloakRate = 1.0f;

		pOwner->m_Shared.FadeInvis( 1.0f );
	}
	else
	{
		if ( HasFeignDeath() )
		{
			if ( pOwner->m_Shared.IsFeignDeathReady() )
			{
				// Turn it off...
				SetFeignDeathState( false );
			}
			else if ( pOwner->m_Shared.GetSpyCloakMeter() == 100.f )
			{
				// Turn it on...
				SetFeignDeathState( true );
			}
		}
		else if ( pOwner->CanGoInvisible() && ( pOwner->m_Shared.GetSpyCloakMeter() > 8.0f ) )	// must have over 10% cloak to start
		{
			// Do standard cloak.
			pOwner->m_Shared.AddCond( TF_COND_STEALTHED, -1.f, pOwner );

#ifdef STAGING_ONLY
			if ( pOwner->m_Shared.HasPhaseCloakAbility() )
			{
				pOwner->m_Shared.AddCond( TF_COND_STEALTHED_PHASE, -1.f, pOwner );
			}
#endif // STAGING_ONLY

			bDoSkill = true;
		}
	}

	if ( bDoSkill )
	{
		pOwner->m_Shared.SetNextStealthTime( gpGlobals->curtime + 0.5 );
	}
	else
	{
		pOwner->m_Shared.SetNextStealthTime( gpGlobals->curtime + 0.1 );
	}

	return bDoSkill;
}

//-----------------------------------------------------------------------------
// Purpose: the player has changed loadouts or done something else that causes
//			us to clean up any side effects of our watch
//-----------------------------------------------------------------------------
void CTFWeaponInvis::CleanupInvisibilityWatch( void )
{
	CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
	if ( !pOwner )
		return;

	pOwner->m_Shared.SetFeignDeathReady( false );

	if ( pOwner->m_Shared.IsStealthed() )
	{
		// De-cloak.
		pOwner->m_Shared.FadeInvis( 1.0f );
	}

	pOwner->HolsterOffHandWeapon();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFWeaponInvis::SetFeignDeathState( bool bEnabled )
{
	CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
	if ( !pOwner )
		return;

	if ( pOwner->m_Shared.InCond( TF_COND_GRAPPLINGHOOK ) )
		return;

	if ( bEnabled )
	{
		pOwner->m_Shared.SetFeignDeathReady( true );
		pOwner->SetOffHandWeapon( this );
		pOwner->m_Shared.SetNextStealthTime( gpGlobals->curtime + 0.5 );
	}
	else
	{
		pOwner->m_Shared.SetFeignDeathReady( false );
		if ( !pOwner->m_Shared.InCond( TF_COND_STEALTHED ) )
		{
			pOwner->HolsterOffHandWeapon();
			if ( pOwner->GetActiveWeapon() )
			{
				pOwner->GetActiveWeapon()->m_flNextPrimaryAttack = gpGlobals->curtime + 0.1f;
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Set the correct cloak consume & regen rates for this item.
//-----------------------------------------------------------------------------
void CTFWeaponInvis::SetCloakRates( void )
{
	CTFPlayer *pOwner = ToTFPlayer( GetOwner() );

	float fCloakConsumeRate = tf_spy_cloak_consume_rate.GetFloat();
	float fCloakConsumeFactor = 1.0f;
	CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pOwner, fCloakConsumeFactor, mult_cloak_meter_consume_rate );	// Ask the owner since this attr may come from another weapon
	
	// This value is a inverse scale and does not match expectations on description
	// so we subtract and invert to make it align
	// ie 25% (0.75% in schema) makes 10seconds go to 13.3 when we want 12.5
	// 2 - 0.75 = 1.25... 1 / 1.25 = 0.8.. Consume rate "8". 10s / 0.8 = 12.5s
	if ( fCloakConsumeFactor < 1.0f )
	{
		fCloakConsumeFactor = 1.0f / (2.0f - fCloakConsumeFactor);
	}
	
	pOwner->m_Shared.SetCloakConsumeRate( fCloakConsumeRate * fCloakConsumeFactor );

	float fCloakRegenRate = tf_spy_cloak_regen_rate.GetFloat();
	float fCloakRegenFactor = 1.0f;
	CALL_ATTRIB_HOOK_FLOAT( fCloakRegenFactor, mult_cloak_meter_regen_rate );
	pOwner->m_Shared.SetCloakRegenRate( fCloakRegenRate * fCloakRegenFactor );
}

#ifndef CLIENT_DLL

//-----------------------------------------------------------------------------
// Purpose: Return the right pda panel for the watch model we're using
//-----------------------------------------------------------------------------
void CTFWeaponInvis::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
{
	const char *pszViewModel = GetViewModel(0);
	if ( Q_stristr( pszViewModel, "pocket" ) )
	{
		pPanelName = "pda_panel_spy_invis_pocket";
	}
	else if ( Q_stristr( pszViewModel, "ttg_watch_spy" ) )
	{
		pPanelName = "pda_panel_spy_invis_pocket_ttg";
	}
	else if ( Q_stristr( pszViewModel, "hm_watch" ) )
	{
		pPanelName = "pda_panel_spy_invis_pocket_hm";
	}
	else
	{
		pPanelName = "pda_panel_spy_invis";
	}
}

#endif