aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/ai_blended_movement.h
blob: dab62be68649e6126afaa9ea3e240ba55c3e701f (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
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//

#ifndef AI_BLENDED_MOVEMENT_H
#define AI_BLENDED_MOVEMENT_H

#include "ai_basenpc.h"
#include "ai_motor.h"
#include "ai_navigator.h"

struct AI_Waypoint_t;

//-----------------------------------------------------------------------------
// CLASS: CAI_BlendedMotor
//
// Purpose: Home of fancy human animation transition code
//
//-----------------------------------------------------------------------------

class CAI_BlendedMotor : public CAI_Motor
{
	typedef CAI_Motor BaseClass;
public:
	CAI_BlendedMotor( CAI_BaseNPC *pOuter )
	 :	BaseClass( pOuter )
	{
		m_iPrimaryLayer = -1;
		m_nPrimarySequence = ACT_INVALID;

		m_iSecondaryLayer = -1;
		m_nSecondarySequence =  ACT_INVALID;
		m_flSecondaryWeight = 0.0f;

		m_nSavedGoalActivity = ACT_INVALID;
		m_nSavedTranslatedGoalActivity = ACT_INVALID;
		m_nGoalSequence = ACT_INVALID;

		m_nPrevMovementSequence = ACT_INVALID;
		m_nInteriorSequence = ACT_INVALID;

		m_bDeceleratingToGoal = false;

		m_flStartCycle = 0.0f;

		m_flPredictiveSpeedAdjust = 1.0f;
		m_flReactiveSpeedAdjust = 1.0f;
		m_vecPrevOrigin1.Init();
		m_vecPrevOrigin2.Init();

		m_prevYaw = 0.0f;
		m_doTurn = 0.0f;
		m_doLeft = 0.0f;
		m_doRight = 0.0f;
		m_flNextTurnAct = 0.0f;
	}

	void 	MoveClimbStart( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw );
	void 	MoveJumpStart( const Vector &velocity );

	void	ResetMoveCalculations();
	void	MoveStart();
	void	ResetGoalSequence();
	void	MoveStop();
	void	MovePaused();
	void	MoveContinue();

	float	OverrideMaxYawSpeed( Activity activity );
	void	UpdateYaw( int speed );
	void	RecalculateYawSpeed(); 

	bool	IsDeceleratingToGoal() const	{ return m_bDeceleratingToGoal; }
	float	GetMoveScriptTotalTime();

	void	MaintainTurnActivity( void );
	bool	AddTurnGesture( float flYD );


private:
	AIMotorMoveResult_t MoveGroundExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult );
	AIMotorMoveResult_t MoveFlyExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult );


	// --------------------------------

	void	BuildMoveScript(  const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult );

	void	BuildVelocityScript( const AILocalMoveGoal_t &move );
	void	InsertSlowdown( float distToObstruction, float idealAccel, bool bAlwaysSlowdown );

	int		BuildTurnScript( int i, int j );
	void	BuildTurnScript( const AILocalMoveGoal_t &move );
	int 	BuildInsertNode( int i, float flTime );

	Activity GetTransitionActivity( void );
	
	// --------------------------------

	// helpers to simplify code
	float	GetCycle()														{ return GetOuter()->GetCycle();								}
	int		AddLayeredSequence( int sequence, int iPriority )				{ return GetOuter()->AddLayeredSequence( sequence, iPriority ); }
	void	SetLayerWeight( int iLayer, float flWeight )					{ GetOuter()->SetLayerWeight( iLayer, flWeight );				}
	void	SetLayerPlaybackRate( int iLayer, float flPlaybackRate )		{ GetOuter()->SetLayerPlaybackRate( iLayer, flPlaybackRate );	}
	void	SetLayerNoRestore( int iLayer, bool bNoRestore )				{ GetOuter()->SetLayerNoRestore( iLayer, bNoRestore );			}
	void	SetLayerCycle( int iLayer, float flCycle )						{ GetOuter()->SetLayerCycle( iLayer, flCycle );					}
	void	SetLayerCycle( int iLayer, float flCycle, float flPrevCycle )	{ GetOuter()->SetLayerCycle( iLayer, flCycle, flPrevCycle );	}
	void	RemoveLayer( int iLayer, float flKillRate, float flKillDelay )	{ GetOuter()->RemoveLayer( iLayer, flKillRate, flKillDelay );	}

	// --------------------------------

	struct AI_Movementscript_t
	{
	public:
		AI_Movementscript_t( )
		{
			Init( );
		};

		void Init( void )
		{
			memset( this, 0, sizeof(*this) );
		};

		float	flTime;			// time till next entry
		float	flElapsedTime;	// time since first entry

		float	flDist;			// distance to next entry

		float	flMaxVelocity;

		// float	flVelocity;

		float	flYaw;
		float	flAngularVelocity;

		bool	bLooping;
		int		nFlags;

		AI_Waypoint_t *pWaypoint;

	public:
		AI_Movementscript_t *pNext;
		AI_Movementscript_t *pPrev;

		Vector	vecLocation;

	};
	
	//---------------------------------

	CUtlVector<AI_Movementscript_t>	m_scriptMove;
	CUtlVector<AI_Movementscript_t>	m_scriptTurn;

	//---------------------------------

	bool			m_bDeceleratingToGoal;

	int				m_iPrimaryLayer;
	int				m_iSecondaryLayer;

	int				m_nPrimarySequence;
	int				m_nSecondarySequence;
	float			m_flSecondaryWeight;

	Activity		m_nSavedGoalActivity;
	Activity		m_nSavedTranslatedGoalActivity;
	int				m_nGoalSequence;

	int				m_nPrevMovementSequence;
	int				m_nInteriorSequence;

	float			m_flStartCycle;

	float			m_flCurrRate;

	float			m_flPredictiveSpeedAdjust;		// predictive speed adjust from probing slope 
	float			m_flReactiveSpeedAdjust;		// reactive speed adjust when slope movement detected
	Vector			m_vecPrevOrigin1;
	Vector			m_vecPrevOrigin2;

	//---------------------------------

	float			m_flNextTurnGesture;	// next time for large turn gesture

	//---------------------------------
	float			m_prevYaw;
	float			m_doTurn;
	float			m_doLeft;
	float			m_doRight;
	float			m_flNextTurnAct;		// next time for small turn gesture

	
	float	GetMoveScriptDist( float &flNewSpeed );
	float	GetMoveScriptYaw( void );
	void	SetMoveScriptAnim( float flNewSpeed );

	int		GetInteriorSequence( int fromSequence );

	DECLARE_SIMPLE_DATADESC();
};

//-----------------------------------------------------------------------------
// CLASS: CAI_BlendingHost
//
// Purpose: Bridge to the home of fancy human animation transition code
//
//-----------------------------------------------------------------------------

template <class BASE_NPC>
class CAI_BlendingHost : public BASE_NPC
{
	DECLARE_CLASS_NOFRIEND( CAI_BlendingHost, BASE_NPC );
public:
	const CAI_BlendedMotor *GetBlendedMotor() const { return assert_cast<const CAI_BlendedMotor *>(this->GetMotor()); }
	CAI_BlendedMotor *		GetBlendedMotor()		{ return assert_cast<CAI_BlendedMotor *>(this->GetMotor()); }

	CAI_Motor *CreateMotor()
	{
		MEM_ALLOC_CREDIT();
		return new CAI_BlendedMotor( this );
	}

	CAI_Navigator *CreateNavigator()
	{
		CAI_Navigator *pNavigator = BaseClass::CreateNavigator();
		pNavigator->SetValidateActivitySpeed( false );
		return pNavigator;
	}

	float MaxYawSpeed( void )
	{
		float override = GetBlendedMotor()->OverrideMaxYawSpeed( this->GetActivity() );
		if ( override != -1 )
			return override;
		return BaseClass::MaxYawSpeed();
	}

	float GetTimeToNavGoal()
	{
		float result = GetBlendedMotor()->GetMoveScriptTotalTime();
		if ( result != -1 )
			return result;
		return BaseClass::GetTimeToNavGoal();
	}

};

//-------------------------------------
// to simplify basic usage:
class CAI_BlendedNPC : public CAI_BlendingHost<CAI_BaseNPC>
{
	DECLARE_CLASS( CAI_BlendedNPC, CAI_BlendingHost<CAI_BaseNPC> );
};

//-----------------------------------------------------------------------------	

#endif