1 /*
2 ===========================================================================
3 Copyright (C) 2000-2006 Tim Angus
4 
5 This file is part of Tremulous.
6 
7 Tremulous is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Tremulous is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Tremulous; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 
23 // cg_attachment.c -- an abstract attachment system
24 
25 #include "cg_local.h"
26 
27 /*
28 ===============
29 CG_AttachmentPoint
30 
31 Return the attachment point
32 ===============
33 */
CG_AttachmentPoint(attachment_t * a,vec3_t v)34 qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v )
35 {
36   centity_t   *cent;
37 
38   if( !a )
39     return qfalse;
40 
41   // if it all breaks, then use the last point we know was correct
42   VectorCopy( a->lastValidAttachmentPoint, v );
43 
44   switch( a->type )
45   {
46     case AT_STATIC:
47       if( !a->staticValid )
48         return qfalse;
49 
50       VectorCopy( a->origin, v );
51       break;
52 
53     case AT_TAG:
54       if( !a->tagValid )
55         return qfalse;
56 
57       AxisCopy( axisDefault, a->re.axis );
58       CG_PositionRotatedEntityOnTag( &a->re, &a->parent,
59                                      a->model, a->tagName );
60       VectorCopy( a->re.origin, v );
61       break;
62 
63     case AT_CENT:
64       if( !a->centValid )
65         return qfalse;
66 
67       if( a->centNum == cg.predictedPlayerState.clientNum )
68       {
69         // this is smoother if it's the local client
70         VectorCopy( cg.predictedPlayerState.origin, v );
71       }
72       else
73       {
74         cent = &cg_entities[ a->centNum ];
75         VectorCopy( cent->lerpOrigin, v );
76       }
77       break;
78 
79     case AT_PARTICLE:
80       if( !a->particleValid )
81         return qfalse;
82 
83       if( !a->particle->valid )
84       {
85         a->particleValid = qfalse;
86         return qfalse;
87       }
88       else
89         VectorCopy( a->particle->origin, v );
90       break;
91 
92     default:
93       CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
94       break;
95   }
96 
97   if( a->hasOffset )
98     VectorAdd( v, a->offset, v );
99 
100   VectorCopy( v, a->lastValidAttachmentPoint );
101 
102   return qtrue;
103 }
104 
105 /*
106 ===============
107 CG_AttachmentDir
108 
109 Return the attachment direction
110 ===============
111 */
CG_AttachmentDir(attachment_t * a,vec3_t v)112 qboolean CG_AttachmentDir( attachment_t *a, vec3_t v )
113 {
114   vec3_t      forward;
115   centity_t   *cent;
116 
117   if( !a )
118     return qfalse;
119 
120   switch( a->type )
121   {
122     case AT_STATIC:
123       return qfalse;
124       break;
125 
126     case AT_TAG:
127       if( !a->tagValid )
128         return qfalse;
129 
130       VectorCopy( a->re.axis[ 0 ], v );
131       break;
132 
133     case AT_CENT:
134       if( !a->centValid )
135         return qfalse;
136 
137       cent = &cg_entities[ a->centNum ];
138       AngleVectors( cent->lerpAngles, forward, NULL, NULL );
139       VectorCopy( forward, v );
140       break;
141 
142     case AT_PARTICLE:
143       if( !a->particleValid )
144         return qfalse;
145 
146       if( !a->particle->valid )
147       {
148         a->particleValid = qfalse;
149         return qfalse;
150       }
151       else
152         VectorCopy( a->particle->velocity, v );
153       break;
154 
155     default:
156       CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
157       break;
158   }
159 
160   VectorNormalize( v );
161   return qtrue;
162 }
163 
164 /*
165 ===============
166 CG_AttachmentAxis
167 
168 Return the attachment axis
169 ===============
170 */
CG_AttachmentAxis(attachment_t * a,vec3_t axis[3])171 qboolean CG_AttachmentAxis( attachment_t *a, vec3_t axis[ 3 ] )
172 {
173   centity_t   *cent;
174 
175   if( !a )
176     return qfalse;
177 
178   switch( a->type )
179   {
180     case AT_STATIC:
181       return qfalse;
182       break;
183 
184     case AT_TAG:
185       if( !a->tagValid )
186         return qfalse;
187 
188       AxisCopy( a->re.axis, axis );
189       break;
190 
191     case AT_CENT:
192       if( !a->centValid )
193         return qfalse;
194 
195       cent = &cg_entities[ a->centNum ];
196       AnglesToAxis( cent->lerpAngles, axis );
197       break;
198 
199     case AT_PARTICLE:
200       return qfalse;
201       break;
202 
203     default:
204       CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" );
205       break;
206   }
207 
208   return qtrue;
209 }
210 
211 /*
212 ===============
213 CG_AttachmentVelocity
214 
215 If the attachment can have velocity, return it
216 ===============
217 */
CG_AttachmentVelocity(attachment_t * a,vec3_t v)218 qboolean CG_AttachmentVelocity( attachment_t *a, vec3_t v )
219 {
220   if( !a )
221     return qfalse;
222 
223   if( a->particleValid && a->particle->valid )
224   {
225     VectorCopy( a->particle->velocity, v );
226     return qtrue;
227   }
228   else if( a->centValid )
229   {
230     centity_t *cent = &cg_entities[ a->centNum ];
231 
232     VectorCopy( cent->currentState.pos.trDelta, v );
233     return qtrue;
234   }
235 
236   return qfalse;
237 }
238 
239 /*
240 ===============
241 CG_AttachmentCentNum
242 
243 If the attachment has a centNum, return it
244 ===============
245 */
CG_AttachmentCentNum(attachment_t * a)246 int CG_AttachmentCentNum( attachment_t *a )
247 {
248   if( !a || !a->centValid )
249     return -1;
250 
251   return a->centNum;
252 }
253 
254 /*
255 ===============
256 CG_Attached
257 
258 If the attachment is valid, return qtrue
259 ===============
260 */
CG_Attached(attachment_t * a)261 qboolean CG_Attached( attachment_t *a )
262 {
263   if( !a )
264     return qfalse;
265 
266   return a->attached;
267 }
268 
269 /*
270 ===============
271 CG_AttachToPoint
272 
273 Attach to a point in space
274 ===============
275 */
CG_AttachToPoint(attachment_t * a)276 void CG_AttachToPoint( attachment_t *a )
277 {
278   if( !a || !a->staticValid )
279     return;
280 
281   a->type = AT_STATIC;
282   a->attached = qtrue;
283 }
284 
285 /*
286 ===============
287 CG_AttachToCent
288 
289 Attach to a centity_t
290 ===============
291 */
CG_AttachToCent(attachment_t * a)292 void CG_AttachToCent( attachment_t *a )
293 {
294   if( !a || !a->centValid )
295     return;
296 
297   a->type = AT_CENT;
298   a->attached = qtrue;
299 }
300 
301 /*
302 ===============
303 CG_AttachToTag
304 
305 Attach to a model tag
306 ===============
307 */
CG_AttachToTag(attachment_t * a)308 void CG_AttachToTag( attachment_t *a )
309 {
310   if( !a || !a->tagValid )
311     return;
312 
313   a->type = AT_TAG;
314   a->attached = qtrue;
315 }
316 
317 /*
318 ===============
319 CG_AttachToParticle
320 
321 Attach to a particle
322 ===============
323 */
CG_AttachToParticle(attachment_t * a)324 void CG_AttachToParticle( attachment_t *a )
325 {
326   if( !a || !a->particleValid )
327     return;
328 
329   a->type = AT_PARTICLE;
330   a->attached = qtrue;
331 }
332 
333 /*
334 ===============
335 CG_SetAttachmentPoint
336 ===============
337 */
CG_SetAttachmentPoint(attachment_t * a,vec3_t v)338 void CG_SetAttachmentPoint( attachment_t *a, vec3_t v )
339 {
340   if( !a )
341     return;
342 
343   VectorCopy( v, a->origin );
344   a->staticValid = qtrue;
345 }
346 
347 /*
348 ===============
349 CG_SetAttachmentCent
350 ===============
351 */
CG_SetAttachmentCent(attachment_t * a,centity_t * cent)352 void CG_SetAttachmentCent( attachment_t *a, centity_t *cent )
353 {
354   if( !a || !cent )
355     return;
356 
357   a->centNum = cent->currentState.number;
358   a->centValid = qtrue;
359 }
360 
361 /*
362 ===============
363 CG_SetAttachmentTag
364 ===============
365 */
CG_SetAttachmentTag(attachment_t * a,refEntity_t parent,qhandle_t model,char * tagName)366 void CG_SetAttachmentTag( attachment_t *a, refEntity_t parent,
367     qhandle_t model, char *tagName )
368 {
369   if( !a )
370     return;
371 
372   a->parent = parent;
373   a->model = model;
374   strncpy( a->tagName, tagName, MAX_STRING_CHARS );
375   a->tagValid = qtrue;
376 }
377 
378 /*
379 ===============
380 CG_SetAttachmentParticle
381 ===============
382 */
CG_SetAttachmentParticle(attachment_t * a,particle_t * p)383 void CG_SetAttachmentParticle( attachment_t *a, particle_t *p )
384 {
385   if( !a )
386     return;
387 
388   a->particle = p;
389   a->particleValid = qtrue;
390 }
391 
392 /*
393 ===============
394 CG_SetAttachmentOffset
395 ===============
396 */
CG_SetAttachmentOffset(attachment_t * a,vec3_t v)397 void CG_SetAttachmentOffset( attachment_t *a, vec3_t v )
398 {
399   if( !a )
400     return;
401 
402   VectorCopy( v, a->offset );
403   a->hasOffset = qtrue;
404 }
405