/
c_npc_advisor.cpp
251 lines (198 loc) · 5.93 KB
/
c_npc_advisor.cpp
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
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Definition for client-side advisor.
//
//=====================================================================================//
#include "cbase.h"
// this file contains the definitions for the message ID constants (eg ADVISOR_MSG_START_BEAM etc)
#include "npc_advisor_shared.h"
#if NPC_ADVISOR_HAS_BEHAVIOR
#include "particles_simple.h"
#include "citadel_effects_shared.h"
#include "particles_attractor.h"
#include "clienteffectprecachesystem.h"
#include "c_te_effect_dispatch.h"
#include "c_ai_basenpc.h"
#include "dlight.h"
#include "iefx.h"
//-----------------------------------------------------------------------------
// Purpose: unpack a networked entity index into a basehandle.
//-----------------------------------------------------------------------------
inline C_BaseEntity *IndexToEntity( int eindex )
{
return ClientEntityList().GetBaseEntityFromHandle(ClientEntityList().EntIndexToHandle(eindex));
}
#define ADVISOR_ELIGHT_CVARS 1 // enable/disable tuning advisor elight with console variables
#if ADVISOR_ELIGHT_CVARS
ConVar advisor_elight_e("advisor_elight_e","3");
ConVar advisor_elight_rfeet("advisor_elight_rfeet","52");
#endif
/*! Client-side reflection of the advisor class.
*/
class C_NPC_Advisor : public C_AI_BaseNPC
{
DECLARE_CLASS( C_NPC_Advisor, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
public:
// Server to client message received
virtual void ReceiveMessage( int classID, bf_read &msg );
virtual void ClientThink( void );
private:
/*
// broken into its own function so I can move it if necesasry
void Initialize();
*/
// start/stop beam particle effect from me to a pelting object
void StartBeamFX( C_BaseEntity *pOnEntity );
void StopBeamFX( C_BaseEntity *pOnEntity );
void StartElight();
void StopElight();
int m_ElightKey; // test using an elight to make the escape sequence more visible. 0 is invalid.
};
IMPLEMENT_CLIENTCLASS_DT( C_NPC_Advisor, DT_NPC_Advisor, CNPC_Advisor )
END_RECV_TABLE()
// Server to client message received
void C_NPC_Advisor::ReceiveMessage( int classID, bf_read &msg )
{
if ( classID != GetClientClass()->m_ClassID )
{
// message is for subclass
BaseClass::ReceiveMessage( classID, msg );
return;
}
int messageType = msg.ReadByte();
switch( messageType )
{
case ADVISOR_MSG_START_BEAM:
{
int eindex = msg.ReadLong();
StartBeamFX(IndexToEntity(eindex));
}
break;
case ADVISOR_MSG_STOP_BEAM:
{
int eindex = msg.ReadLong();
StopBeamFX(IndexToEntity(eindex));
}
break;
case ADVISOR_MSG_STOP_ALL_BEAMS:
{
ParticleProp()->StopEmission();
}
break;
case ADVISOR_MSG_START_ELIGHT:
{
StartElight();
}
break;
case ADVISOR_MSG_STOP_ELIGHT:
{
StopElight();
}
break;
default:
AssertMsg1( false, "Received unknown message %d", messageType);
}
}
/// only use of the clientthink on the advisor is to update the elight
void C_NPC_Advisor::ClientThink( void )
{
// if the elight has gone away, bail out
if (m_ElightKey == 0)
{
SetNextClientThink( CLIENT_THINK_NEVER );
return;
}
// get the elight
dlight_t * el = effects->GetElightByKey(m_ElightKey);
if (!el)
{
// the elight has been invalidated. bail out.
m_ElightKey = 0;
SetNextClientThink( CLIENT_THINK_NEVER );
return;
}
else
{
el->origin = WorldSpaceCenter();
#if ADVISOR_ELIGHT_CVARS
el->color.exponent = advisor_elight_e.GetFloat();
el->radius = advisor_elight_rfeet.GetFloat() * 12.0f;
#endif
}
}
//-----------------------------------------------------------------------------
// Create a telekinetic beam effect from my head to an object
// TODO: use a point attachment.
//-----------------------------------------------------------------------------
void C_NPC_Advisor::StartBeamFX( C_BaseEntity *pOnEntity )
{
Assert(pOnEntity);
if (!pOnEntity)
return;
CNewParticleEffect *pEffect = ParticleProp()->Create( "Advisor_Psychic_Beam", PATTACH_ABSORIGIN_FOLLOW );
Assert(pEffect);
if (!pEffect) return;
ParticleProp()->AddControlPoint( pEffect, 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW );
}
//-----------------------------------------------------------------------------
// terminate a telekinetic beam effect from my head to an object
//-----------------------------------------------------------------------------
void C_NPC_Advisor::StopBeamFX( C_BaseEntity *pOnEntity )
{
Assert(pOnEntity);
if (!pOnEntity)
return;
ParticleProp()->StopParticlesInvolving( pOnEntity );
}
void C_NPC_Advisor::StartElight()
{
AssertMsg(m_ElightKey == 0 , "Advisor trying to create new elight on top of old one!");
if ( m_ElightKey != 0 )
{
Warning("Advisor tried to start his elight when it was already one.\n");
}
else
{
m_ElightKey = LIGHT_INDEX_TE_DYNAMIC + this->entindex();
dlight_t * el = effects->CL_AllocElight( m_ElightKey );
if ( el )
{
// create an elight on top of me
el->origin = this->WorldSpaceCenter();
el->color.r = 235;
el->color.g = 255;
el->color.b = 255;
el->color.exponent = 3;
el->radius = 52*12;
el->decay = 0.0f;
el->die = gpGlobals->curtime + 2000.0f; // 1000 just means " a long time "
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
else
{ // null out the light value
m_ElightKey = 0;
}
}
}
void C_NPC_Advisor::StopElight()
{
AssertMsg( m_ElightKey != 0, "Advisor tried to stop elight when none existed!");
dlight_t * el;
// note: the following conditional sets el if not short-circuited
if ( m_ElightKey == 0 || (el = effects->GetElightByKey(m_ElightKey)) == NULL )
{
Warning("Advisor tried to stop its elight when it had none.\n");
}
else
{
// kill the elight by setting the die value to now
el->die = gpGlobals->curtime;
}
}
#endif
/******************************************************
* Tenser, said the Tensor. *
* Tenser, said the Tensor. *
* Tension, apprehension and dissension have begun. *
******************************************************/