~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/q3_ui/ui_players.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
===========================================================================
 
3
Copyright (C) 1999-2005 Id Software, Inc.
 
4
 
 
5
This file is part of Quake III Arena source code.
 
6
 
 
7
Quake III Arena source code 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
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
 
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
20
===========================================================================
 
21
*/
 
22
//
 
23
// ui_players.c
 
24
 
 
25
#include "ui_local.h"
 
26
 
 
27
 
 
28
#define UI_TIMER_GESTURE                2300
 
29
#define UI_TIMER_JUMP                   1000
 
30
#define UI_TIMER_LAND                   130
 
31
#define UI_TIMER_WEAPON_SWITCH  300
 
32
#define UI_TIMER_ATTACK                 500
 
33
#define UI_TIMER_MUZZLE_FLASH   20
 
34
#define UI_TIMER_WEAPON_DELAY   250
 
35
 
 
36
#define JUMP_HEIGHT                             56
 
37
 
 
38
#define SWINGSPEED                              0.3f
 
39
 
 
40
#define SPIN_SPEED                              0.9f
 
41
#define COAST_TIME                              1000
 
42
 
 
43
 
 
44
static int                      dp_realtime;
 
45
static float            jumpHeight;
 
46
 
 
47
 
 
48
/*
 
49
===============
 
50
UI_PlayerInfo_SetWeapon
 
51
===============
 
52
*/
 
53
static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) {
 
54
        gitem_t *       item;
 
55
        char            path[MAX_QPATH];
 
56
 
 
57
        pi->currentWeapon = weaponNum;
 
58
tryagain:
 
59
        pi->realWeapon = weaponNum;
 
60
        pi->weaponModel = 0;
 
61
        pi->barrelModel = 0;
 
62
        pi->flashModel = 0;
 
63
 
 
64
        if ( weaponNum == WP_NONE ) {
 
65
                return;
 
66
        }
 
67
 
 
68
        for ( item = bg_itemlist + 1; item->classname ; item++ ) {
 
69
                if ( item->giType != IT_WEAPON ) {
 
70
                        continue;
 
71
                }
 
72
                if ( item->giTag == weaponNum ) {
 
73
                        break;
 
74
                }
 
75
        }
 
76
 
 
77
        if ( item->classname ) {
 
78
                pi->weaponModel = trap_R_RegisterModel( item->world_model[0] );
 
79
        }
 
80
 
 
81
        if( pi->weaponModel == 0 ) {
 
82
                if( weaponNum == WP_MACHINEGUN ) {
 
83
                        weaponNum = WP_NONE;
 
84
                        goto tryagain;
 
85
                }
 
86
                weaponNum = WP_MACHINEGUN;
 
87
                goto tryagain;
 
88
        }
 
89
 
 
90
        if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) {
 
91
                strcpy( path, item->world_model[0] );
 
92
                COM_StripExtension( path, path, sizeof(path) );
 
93
                strcat( path, "_barrel.md3" );
 
94
                pi->barrelModel = trap_R_RegisterModel( path );
 
95
        }
 
96
 
 
97
        strcpy( path, item->world_model[0] );
 
98
        COM_StripExtension( path, path, sizeof(path) );
 
99
        strcat( path, "_flash.md3" );
 
100
        pi->flashModel = trap_R_RegisterModel( path );
 
101
 
 
102
        switch( weaponNum ) {
 
103
        case WP_GAUNTLET:
 
104
                MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
 
105
                break;
 
106
 
 
107
        case WP_MACHINEGUN:
 
108
                MAKERGB( pi->flashDlightColor, 1, 1, 0 );
 
109
                break;
 
110
 
 
111
        case WP_SHOTGUN:
 
112
                MAKERGB( pi->flashDlightColor, 1, 1, 0 );
 
113
                break;
 
114
 
 
115
        case WP_GRENADE_LAUNCHER:
 
116
                MAKERGB( pi->flashDlightColor, 1, 0.7f, 0.5f );
 
117
                break;
 
118
 
 
119
        case WP_ROCKET_LAUNCHER:
 
120
                MAKERGB( pi->flashDlightColor, 1, 0.75f, 0 );
 
121
                break;
 
122
 
 
123
        case WP_LIGHTNING:
 
124
                MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
 
125
                break;
 
126
 
 
127
        case WP_RAILGUN:
 
128
                MAKERGB( pi->flashDlightColor, 1, 0.5f, 0 );
 
129
                break;
 
130
 
 
131
        case WP_PLASMAGUN:
 
132
                MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
 
133
                break;
 
134
 
 
135
        case WP_BFG:
 
136
                MAKERGB( pi->flashDlightColor, 1, 0.7f, 1 );
 
137
                break;
 
138
 
 
139
        case WP_GRAPPLING_HOOK:
 
140
                MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 );
 
141
                break;
 
142
 
 
143
        default:
 
144
                MAKERGB( pi->flashDlightColor, 1, 1, 1 );
 
145
                break;
 
146
        }
 
147
}
 
148
 
 
149
 
 
150
/*
 
151
===============
 
152
UI_ForceLegsAnim
 
153
===============
 
154
*/
 
155
static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) {
 
156
        pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
 
157
 
 
158
        if ( anim == LEGS_JUMP ) {
 
159
                pi->legsAnimationTimer = UI_TIMER_JUMP;
 
160
        }
 
161
}
 
162
 
 
163
 
 
164
/*
 
165
===============
 
166
UI_SetLegsAnim
 
167
===============
 
168
*/
 
169
static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) {
 
170
        if ( pi->pendingLegsAnim ) {
 
171
                anim = pi->pendingLegsAnim;
 
172
                pi->pendingLegsAnim = 0;
 
173
        }
 
174
        UI_ForceLegsAnim( pi, anim );
 
175
}
 
176
 
 
177
 
 
178
/*
 
179
===============
 
180
UI_ForceTorsoAnim
 
181
===============
 
182
*/
 
183
static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) {
 
184
        pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
 
185
 
 
186
        if ( anim == TORSO_GESTURE ) {
 
187
                pi->torsoAnimationTimer = UI_TIMER_GESTURE;
 
188
        }
 
189
 
 
190
        if ( anim == TORSO_ATTACK || anim == TORSO_ATTACK2 ) {
 
191
                pi->torsoAnimationTimer = UI_TIMER_ATTACK;
 
192
        }
 
193
}
 
194
 
 
195
 
 
196
/*
 
197
===============
 
198
UI_SetTorsoAnim
 
199
===============
 
200
*/
 
201
static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) {
 
202
        if ( pi->pendingTorsoAnim ) {
 
203
                anim = pi->pendingTorsoAnim;
 
204
                pi->pendingTorsoAnim = 0;
 
205
        }
 
206
 
 
207
        UI_ForceTorsoAnim( pi, anim );
 
208
}
 
209
 
 
210
 
 
211
/*
 
212
===============
 
213
UI_TorsoSequencing
 
214
===============
 
215
*/
 
216
static void UI_TorsoSequencing( playerInfo_t *pi ) {
 
217
        int             currentAnim;
 
218
 
 
219
        currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
 
220
 
 
221
        if ( pi->weapon != pi->currentWeapon ) {
 
222
                if ( currentAnim != TORSO_DROP ) {
 
223
                        pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
 
224
                        UI_ForceTorsoAnim( pi, TORSO_DROP );
 
225
                }
 
226
        }
 
227
 
 
228
        if ( pi->torsoAnimationTimer > 0 ) {
 
229
                return;
 
230
        }
 
231
 
 
232
        if( currentAnim == TORSO_GESTURE ) {
 
233
                UI_SetTorsoAnim( pi, TORSO_STAND );
 
234
                return;
 
235
        }
 
236
 
 
237
        if( currentAnim == TORSO_ATTACK || currentAnim == TORSO_ATTACK2 ) {
 
238
                UI_SetTorsoAnim( pi, TORSO_STAND );
 
239
                return;
 
240
        }
 
241
 
 
242
        if ( currentAnim == TORSO_DROP ) {
 
243
                UI_PlayerInfo_SetWeapon( pi, pi->weapon );
 
244
                pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH;
 
245
                UI_ForceTorsoAnim( pi, TORSO_RAISE );
 
246
                return;
 
247
        }
 
248
 
 
249
        if ( currentAnim == TORSO_RAISE ) {
 
250
                UI_SetTorsoAnim( pi, TORSO_STAND );
 
251
                return;
 
252
        }
 
253
}
 
254
 
 
255
 
 
256
/*
 
257
===============
 
258
UI_LegsSequencing
 
259
===============
 
260
*/
 
261
static void UI_LegsSequencing( playerInfo_t *pi ) {
 
262
        int             currentAnim;
 
263
 
 
264
        currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
 
265
 
 
266
        if ( pi->legsAnimationTimer > 0 ) {
 
267
                if ( currentAnim == LEGS_JUMP ) {
 
268
                        jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP );
 
269
                }
 
270
                return;
 
271
        }
 
272
 
 
273
        if ( currentAnim == LEGS_JUMP ) {
 
274
                UI_ForceLegsAnim( pi, LEGS_LAND );
 
275
                pi->legsAnimationTimer = UI_TIMER_LAND;
 
276
                jumpHeight = 0;
 
277
                return;
 
278
        }
 
279
 
 
280
        if ( currentAnim == LEGS_LAND ) {
 
281
                UI_SetLegsAnim( pi, LEGS_IDLE );
 
282
                return;
 
283
        }
 
284
}
 
285
 
 
286
 
 
287
/*
 
288
======================
 
289
UI_PositionEntityOnTag
 
290
======================
 
291
*/
 
292
static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, 
 
293
                                                        clipHandle_t parentModel, char *tagName ) {
 
294
        int                             i;
 
295
        orientation_t   lerped;
 
296
        
 
297
        // lerp the tag
 
298
        trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
 
299
                1.0 - parent->backlerp, tagName );
 
300
 
 
301
        // FIXME: allow origin offsets along tag?
 
302
        VectorCopy( parent->origin, entity->origin );
 
303
        for ( i = 0 ; i < 3 ; i++ ) {
 
304
                VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
 
305
        }
 
306
 
 
307
        // cast away const because of compiler problems
 
308
        MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis );
 
309
        entity->backlerp = parent->backlerp;
 
310
}
 
311
 
 
312
 
 
313
/*
 
314
======================
 
315
UI_PositionRotatedEntityOnTag
 
316
======================
 
317
*/
 
318
static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, 
 
319
                                                        clipHandle_t parentModel, char *tagName ) {
 
320
        int                             i;
 
321
        orientation_t   lerped;
 
322
        vec3_t                  tempAxis[3];
 
323
 
 
324
        // lerp the tag
 
325
        trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
 
326
                1.0 - parent->backlerp, tagName );
 
327
 
 
328
        // FIXME: allow origin offsets along tag?
 
329
        VectorCopy( parent->origin, entity->origin );
 
330
        for ( i = 0 ; i < 3 ; i++ ) {
 
331
                VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
 
332
        }
 
333
 
 
334
        // cast away const because of compiler problems
 
335
        MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis );
 
336
        MatrixMultiply( lerped.axis, tempAxis, entity->axis );
 
337
}
 
338
 
 
339
 
 
340
/*
 
341
===============
 
342
UI_SetLerpFrameAnimation
 
343
===============
 
344
*/
 
345
static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
 
346
        animation_t     *anim;
 
347
 
 
348
        lf->animationNumber = newAnimation;
 
349
        newAnimation &= ~ANIM_TOGGLEBIT;
 
350
 
 
351
        if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) {
 
352
                trap_Error( va("Bad animation number: %i", newAnimation) );
 
353
        }
 
354
 
 
355
        anim = &ci->animations[ newAnimation ];
 
356
 
 
357
        lf->animation = anim;
 
358
        lf->animationTime = lf->frameTime + anim->initialLerp;
 
359
}
 
360
 
 
361
 
 
362
/*
 
363
===============
 
364
UI_RunLerpFrame
 
365
===============
 
366
*/
 
367
static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
 
368
        int                     f;
 
369
        animation_t     *anim;
 
370
 
 
371
        // see if the animation sequence is switching
 
372
        if ( newAnimation != lf->animationNumber || !lf->animation ) {
 
373
                UI_SetLerpFrameAnimation( ci, lf, newAnimation );
 
374
        }
 
375
 
 
376
        // if we have passed the current frame, move it to
 
377
        // oldFrame and calculate a new frame
 
378
        if ( dp_realtime >= lf->frameTime ) {
 
379
                lf->oldFrame = lf->frame;
 
380
                lf->oldFrameTime = lf->frameTime;
 
381
 
 
382
                // get the next frame based on the animation
 
383
                anim = lf->animation;
 
384
                if ( dp_realtime < lf->animationTime ) {
 
385
                        lf->frameTime = lf->animationTime;              // initial lerp
 
386
                } else {
 
387
                        lf->frameTime = lf->oldFrameTime + anim->frameLerp;
 
388
                }
 
389
                f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
 
390
                if ( f >= anim->numFrames ) {
 
391
                        f -= anim->numFrames;
 
392
                        if ( anim->loopFrames ) {
 
393
                                f %= anim->loopFrames;
 
394
                                f += anim->numFrames - anim->loopFrames;
 
395
                        } else {
 
396
                                f = anim->numFrames - 1;
 
397
                                // the animation is stuck at the end, so it
 
398
                                // can immediately transition to another sequence
 
399
                                lf->frameTime = dp_realtime;
 
400
                        }
 
401
                }
 
402
                lf->frame = anim->firstFrame + f;
 
403
                if ( dp_realtime > lf->frameTime ) {
 
404
                        lf->frameTime = dp_realtime;
 
405
                }
 
406
        }
 
407
 
 
408
        if ( lf->frameTime > dp_realtime + 200 ) {
 
409
                lf->frameTime = dp_realtime;
 
410
        }
 
411
 
 
412
        if ( lf->oldFrameTime > dp_realtime ) {
 
413
                lf->oldFrameTime = dp_realtime;
 
414
        }
 
415
        // calculate current lerp value
 
416
        if ( lf->frameTime == lf->oldFrameTime ) {
 
417
                lf->backlerp = 0;
 
418
        } else {
 
419
                lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
 
420
        }
 
421
}
 
422
 
 
423
 
 
424
/*
 
425
===============
 
426
UI_PlayerAnimation
 
427
===============
 
428
*/
 
429
static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp,
 
430
                                                int *torsoOld, int *torso, float *torsoBackLerp ) {
 
431
 
 
432
        // legs animation
 
433
        pi->legsAnimationTimer -= uis.frametime;
 
434
        if ( pi->legsAnimationTimer < 0 ) {
 
435
                pi->legsAnimationTimer = 0;
 
436
        }
 
437
 
 
438
        UI_LegsSequencing( pi );
 
439
 
 
440
        if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) {
 
441
                UI_RunLerpFrame( pi, &pi->legs, LEGS_TURN );
 
442
        } else {
 
443
                UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim );
 
444
        }
 
445
        *legsOld = pi->legs.oldFrame;
 
446
        *legs = pi->legs.frame;
 
447
        *legsBackLerp = pi->legs.backlerp;
 
448
 
 
449
        // torso animation
 
450
        pi->torsoAnimationTimer -= uis.frametime;
 
451
        if ( pi->torsoAnimationTimer < 0 ) {
 
452
                pi->torsoAnimationTimer = 0;
 
453
        }
 
454
 
 
455
        UI_TorsoSequencing( pi );
 
456
 
 
457
        UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim );
 
458
        *torsoOld = pi->torso.oldFrame;
 
459
        *torso = pi->torso.frame;
 
460
        *torsoBackLerp = pi->torso.backlerp;
 
461
}
 
462
 
 
463
 
 
464
/*
 
465
==================
 
466
UI_SwingAngles
 
467
==================
 
468
*/
 
469
static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance,
 
470
                                        float speed, float *angle, qboolean *swinging ) {
 
471
        float   swing;
 
472
        float   move;
 
473
        float   scale;
 
474
 
 
475
        if ( !*swinging ) {
 
476
                // see if a swing should be started
 
477
                swing = AngleSubtract( *angle, destination );
 
478
                if ( swing > swingTolerance || swing < -swingTolerance ) {
 
479
                        *swinging = qtrue;
 
480
                }
 
481
        }
 
482
 
 
483
        if ( !*swinging ) {
 
484
                return;
 
485
        }
 
486
        
 
487
        // modify the speed depending on the delta
 
488
        // so it doesn't seem so linear
 
489
        swing = AngleSubtract( destination, *angle );
 
490
        scale = fabs( swing );
 
491
        if ( scale < swingTolerance * 0.5 ) {
 
492
                scale = 0.5;
 
493
        } else if ( scale < swingTolerance ) {
 
494
                scale = 1.0;
 
495
        } else {
 
496
                scale = 2.0;
 
497
        }
 
498
 
 
499
        // swing towards the destination angle
 
500
        if ( swing >= 0 ) {
 
501
                move = uis.frametime * scale * speed;
 
502
                if ( move >= swing ) {
 
503
                        move = swing;
 
504
                        *swinging = qfalse;
 
505
                }
 
506
                *angle = AngleMod( *angle + move );
 
507
        } else if ( swing < 0 ) {
 
508
                move = uis.frametime * scale * -speed;
 
509
                if ( move <= swing ) {
 
510
                        move = swing;
 
511
                        *swinging = qfalse;
 
512
                }
 
513
                *angle = AngleMod( *angle + move );
 
514
        }
 
515
 
 
516
        // clamp to no more than tolerance
 
517
        swing = AngleSubtract( destination, *angle );
 
518
        if ( swing > clampTolerance ) {
 
519
                *angle = AngleMod( destination - (clampTolerance - 1) );
 
520
        } else if ( swing < -clampTolerance ) {
 
521
                *angle = AngleMod( destination + (clampTolerance - 1) );
 
522
        }
 
523
}
 
524
 
 
525
 
 
526
/*
 
527
======================
 
528
UI_MovedirAdjustment
 
529
======================
 
530
*/
 
531
static float UI_MovedirAdjustment( playerInfo_t *pi ) {
 
532
        vec3_t          relativeAngles;
 
533
        vec3_t          moveVector;
 
534
 
 
535
        VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles );
 
536
        AngleVectors( relativeAngles, moveVector, NULL, NULL );
 
537
        if ( Q_fabs( moveVector[0] ) < 0.01 ) {
 
538
                moveVector[0] = 0.0;
 
539
        }
 
540
        if ( Q_fabs( moveVector[1] ) < 0.01 ) {
 
541
                moveVector[1] = 0.0;
 
542
        }
 
543
 
 
544
        if ( moveVector[1] == 0 && moveVector[0] > 0 ) {
 
545
                return 0;
 
546
        }
 
547
        if ( moveVector[1] < 0 && moveVector[0] > 0 ) {
 
548
                return 22;
 
549
        }
 
550
        if ( moveVector[1] < 0 && moveVector[0] == 0 ) {
 
551
                return 45;
 
552
        }
 
553
        if ( moveVector[1] < 0 && moveVector[0] < 0 ) {
 
554
                return -22;
 
555
        }
 
556
        if ( moveVector[1] == 0 && moveVector[0] < 0 ) {
 
557
                return 0;
 
558
        }
 
559
        if ( moveVector[1] > 0 && moveVector[0] < 0 ) {
 
560
                return 22;
 
561
        }
 
562
        if ( moveVector[1] > 0 && moveVector[0] == 0 ) {
 
563
                return  -45;
 
564
        }
 
565
 
 
566
        return -22;
 
567
}
 
568
 
 
569
 
 
570
/*
 
571
===============
 
572
UI_PlayerAngles
 
573
===============
 
574
*/
 
575
static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) {
 
576
        vec3_t          legsAngles, torsoAngles, headAngles;
 
577
        float           dest;
 
578
        float           adjust;
 
579
 
 
580
        VectorCopy( pi->viewAngles, headAngles );
 
581
        headAngles[YAW] = AngleMod( headAngles[YAW] );
 
582
        VectorClear( legsAngles );
 
583
        VectorClear( torsoAngles );
 
584
 
 
585
        // --------- yaw -------------
 
586
 
 
587
        // allow yaw to drift a bit
 
588
        if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE 
 
589
                || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND  ) {
 
590
                // if not standing still, always point all in the same direction
 
591
                pi->torso.yawing = qtrue;       // always center
 
592
                pi->torso.pitching = qtrue;     // always center
 
593
                pi->legs.yawing = qtrue;        // always center
 
594
        }
 
595
 
 
596
        // adjust legs for movement dir
 
597
        adjust = UI_MovedirAdjustment( pi );
 
598
        legsAngles[YAW] = headAngles[YAW] + adjust;
 
599
        torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust;
 
600
 
 
601
 
 
602
        // torso
 
603
        UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing );
 
604
        UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing );
 
605
 
 
606
        torsoAngles[YAW] = pi->torso.yawAngle;
 
607
        legsAngles[YAW] = pi->legs.yawAngle;
 
608
 
 
609
        // --------- pitch -------------
 
610
 
 
611
        // only show a fraction of the pitch angle in the torso
 
612
        if ( headAngles[PITCH] > 180 ) {
 
613
                dest = (-360 + headAngles[PITCH]) * 0.75;
 
614
        } else {
 
615
                dest = headAngles[PITCH] * 0.75;
 
616
        }
 
617
        UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
 
618
        torsoAngles[PITCH] = pi->torso.pitchAngle;
 
619
 
 
620
        // pull the angles back out of the hierarchial chain
 
621
        AnglesSubtract( headAngles, torsoAngles, headAngles );
 
622
        AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
 
623
        AnglesToAxis( legsAngles, legs );
 
624
        AnglesToAxis( torsoAngles, torso );
 
625
        AnglesToAxis( headAngles, head );
 
626
}
 
627
 
 
628
 
 
629
/*
 
630
===============
 
631
UI_PlayerFloatSprite
 
632
===============
 
633
*/
 
634
static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) {
 
635
        refEntity_t             ent;
 
636
 
 
637
        memset( &ent, 0, sizeof( ent ) );
 
638
        VectorCopy( origin, ent.origin );
 
639
        ent.origin[2] += 48;
 
640
        ent.reType = RT_SPRITE;
 
641
        ent.customShader = shader;
 
642
        ent.radius = 10;
 
643
        ent.renderfx = 0;
 
644
        trap_R_AddRefEntityToScene( &ent );
 
645
}
 
646
 
 
647
 
 
648
/*
 
649
======================
 
650
UI_MachinegunSpinAngle
 
651
======================
 
652
*/
 
653
float   UI_MachinegunSpinAngle( playerInfo_t *pi ) {
 
654
        int             delta;
 
655
        float   angle;
 
656
        float   speed;
 
657
        int             torsoAnim;
 
658
 
 
659
        delta = dp_realtime - pi->barrelTime;
 
660
        if ( pi->barrelSpinning ) {
 
661
                angle = pi->barrelAngle + delta * SPIN_SPEED;
 
662
        } else {
 
663
                if ( delta > COAST_TIME ) {
 
664
                        delta = COAST_TIME;
 
665
                }
 
666
 
 
667
                speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
 
668
                angle = pi->barrelAngle + delta * speed;
 
669
        }
 
670
 
 
671
        torsoAnim = pi->torsoAnim  & ~ANIM_TOGGLEBIT;
 
672
        if( torsoAnim == TORSO_ATTACK2 ) {
 
673
                torsoAnim = TORSO_ATTACK;
 
674
        }
 
675
        if ( pi->barrelSpinning == !(torsoAnim == TORSO_ATTACK) ) {
 
676
                pi->barrelTime = dp_realtime;
 
677
                pi->barrelAngle = AngleMod( angle );
 
678
                pi->barrelSpinning = !!(torsoAnim == TORSO_ATTACK);
 
679
        }
 
680
 
 
681
        return angle;
 
682
}
 
683
 
 
684
 
 
685
/*
 
686
===============
 
687
UI_DrawPlayer
 
688
===============
 
689
*/
 
690
void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) {
 
691
        refdef_t                refdef;
 
692
        refEntity_t             legs;
 
693
        refEntity_t             torso;
 
694
        refEntity_t             head;
 
695
        refEntity_t             gun;
 
696
        refEntity_t             barrel;
 
697
        refEntity_t             flash;
 
698
        vec3_t                  origin;
 
699
        int                             renderfx;
 
700
        vec3_t                  mins = {-16, -16, -24};
 
701
        vec3_t                  maxs = {16, 16, 32};
 
702
        float                   len;
 
703
        float                   xx;
 
704
 
 
705
        if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) {
 
706
                return;
 
707
        }
 
708
 
 
709
        dp_realtime = time;
 
710
 
 
711
        if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) {
 
712
                pi->weapon = pi->pendingWeapon;
 
713
                pi->lastWeapon = pi->pendingWeapon;
 
714
                pi->pendingWeapon = -1;
 
715
                pi->weaponTimer = 0;
 
716
                if( pi->currentWeapon != pi->weapon ) {
 
717
                        trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL );
 
718
                }
 
719
        }
 
720
 
 
721
        UI_AdjustFrom640( &x, &y, &w, &h );
 
722
 
 
723
        y -= jumpHeight;
 
724
 
 
725
        memset( &refdef, 0, sizeof( refdef ) );
 
726
        memset( &legs, 0, sizeof(legs) );
 
727
        memset( &torso, 0, sizeof(torso) );
 
728
        memset( &head, 0, sizeof(head) );
 
729
 
 
730
        refdef.rdflags = RDF_NOWORLDMODEL;
 
731
 
 
732
        AxisClear( refdef.viewaxis );
 
733
 
 
734
        refdef.x = x;
 
735
        refdef.y = y;
 
736
        refdef.width = w;
 
737
        refdef.height = h;
 
738
 
 
739
        refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
 
740
        xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
 
741
        refdef.fov_y = atan2( refdef.height, xx );
 
742
        refdef.fov_y *= ( 360 / M_PI );
 
743
 
 
744
        // calculate distance so the player nearly fills the box
 
745
        len = 0.7 * ( maxs[2] - mins[2] );              
 
746
        origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
 
747
        origin[1] = 0.5 * ( mins[1] + maxs[1] );
 
748
        origin[2] = -0.5 * ( mins[2] + maxs[2] );
 
749
 
 
750
        refdef.time = dp_realtime;
 
751
 
 
752
        trap_R_ClearScene();
 
753
 
 
754
        // get the rotation information
 
755
        UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis );
 
756
        
 
757
        // get the animation state (after rotation, to allow feet shuffle)
 
758
        UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp,
 
759
                 &torso.oldframe, &torso.frame, &torso.backlerp );
 
760
 
 
761
        renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
 
762
 
 
763
        //
 
764
        // add the legs
 
765
        //
 
766
        legs.hModel = pi->legsModel;
 
767
        legs.customSkin = pi->legsSkin;
 
768
 
 
769
        VectorCopy( origin, legs.origin );
 
770
 
 
771
        VectorCopy( origin, legs.lightingOrigin );
 
772
        legs.renderfx = renderfx;
 
773
        VectorCopy (legs.origin, legs.oldorigin);
 
774
 
 
775
        trap_R_AddRefEntityToScene( &legs );
 
776
 
 
777
        if (!legs.hModel) {
 
778
                return;
 
779
        }
 
780
 
 
781
        //
 
782
        // add the torso
 
783
        //
 
784
        torso.hModel = pi->torsoModel;
 
785
        if (!torso.hModel) {
 
786
                return;
 
787
        }
 
788
 
 
789
        torso.customSkin = pi->torsoSkin;
 
790
 
 
791
        VectorCopy( origin, torso.lightingOrigin );
 
792
 
 
793
        UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso");
 
794
 
 
795
        torso.renderfx = renderfx;
 
796
 
 
797
        trap_R_AddRefEntityToScene( &torso );
 
798
 
 
799
        //
 
800
        // add the head
 
801
        //
 
802
        head.hModel = pi->headModel;
 
803
        if (!head.hModel) {
 
804
                return;
 
805
        }
 
806
        head.customSkin = pi->headSkin;
 
807
 
 
808
        VectorCopy( origin, head.lightingOrigin );
 
809
 
 
810
        UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head");
 
811
 
 
812
        head.renderfx = renderfx;
 
813
 
 
814
        trap_R_AddRefEntityToScene( &head );
 
815
 
 
816
        //
 
817
        // add the gun
 
818
        //
 
819
        if ( pi->currentWeapon != WP_NONE ) {
 
820
                memset( &gun, 0, sizeof(gun) );
 
821
                gun.hModel = pi->weaponModel;
 
822
                VectorCopy( origin, gun.lightingOrigin );
 
823
                UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon");
 
824
                gun.renderfx = renderfx;
 
825
                trap_R_AddRefEntityToScene( &gun );
 
826
        }
 
827
 
 
828
        //
 
829
        // add the spinning barrel
 
830
        //
 
831
        if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
 
832
                vec3_t  angles;
 
833
 
 
834
                memset( &barrel, 0, sizeof(barrel) );
 
835
                VectorCopy( origin, barrel.lightingOrigin );
 
836
                barrel.renderfx = renderfx;
 
837
 
 
838
                barrel.hModel = pi->barrelModel;
 
839
                angles[YAW] = 0;
 
840
                angles[PITCH] = 0;
 
841
                angles[ROLL] = UI_MachinegunSpinAngle( pi );
 
842
                if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
 
843
                        angles[PITCH] = angles[ROLL];
 
844
                        angles[ROLL] = 0;
 
845
                }
 
846
                AnglesToAxis( angles, barrel.axis );
 
847
 
 
848
                UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
 
849
 
 
850
                trap_R_AddRefEntityToScene( &barrel );
 
851
        }
 
852
 
 
853
        //
 
854
        // add muzzle flash
 
855
        //
 
856
        if ( dp_realtime <= pi->muzzleFlashTime ) {
 
857
                if ( pi->flashModel ) {
 
858
                        memset( &flash, 0, sizeof(flash) );
 
859
                        flash.hModel = pi->flashModel;
 
860
                        VectorCopy( origin, flash.lightingOrigin );
 
861
                        UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
 
862
                        flash.renderfx = renderfx;
 
863
                        trap_R_AddRefEntityToScene( &flash );
 
864
                }
 
865
 
 
866
                // make a dlight for the flash
 
867
                if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
 
868
                        trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
 
869
                                pi->flashDlightColor[1], pi->flashDlightColor[2] );
 
870
                }
 
871
        }
 
872
 
 
873
        //
 
874
        // add the chat icon
 
875
        //
 
876
        if ( pi->chat ) {
 
877
                UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
 
878
        }
 
879
 
 
880
        //
 
881
        // add an accent light
 
882
        //
 
883
        origin[0] -= 100;       // + = behind, - = in front
 
884
        origin[1] += 100;       // + = left, - = right
 
885
        origin[2] += 100;       // + = above, - = below
 
886
        trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );
 
887
 
 
888
        origin[0] -= 100;
 
889
        origin[1] -= 100;
 
890
        origin[2] -= 100;
 
891
        trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );
 
892
 
 
893
        trap_R_RenderScene( &refdef );
 
894
}
 
895
 
 
896
 
 
897
/*
 
898
==========================
 
899
UI_RegisterClientSkin
 
900
==========================
 
901
*/
 
902
static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName ) {
 
903
        char            filename[MAX_QPATH];
 
904
 
 
905
        Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName );
 
906
        pi->legsSkin = trap_R_RegisterSkin( filename );
 
907
 
 
908
        Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName );
 
909
        pi->torsoSkin = trap_R_RegisterSkin( filename );
 
910
 
 
911
        Com_sprintf( filename, sizeof( filename ), "models/players/%s/head_%s.skin", modelName, skinName );
 
912
        pi->headSkin = trap_R_RegisterSkin( filename );
 
913
 
 
914
        if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {
 
915
                return qfalse;
 
916
        }
 
917
 
 
918
        return qtrue;
 
919
}
 
920
 
 
921
 
 
922
/*
 
923
======================
 
924
UI_ParseAnimationFile
 
925
======================
 
926
*/
 
927
static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {
 
928
        char            *text_p, *prev;
 
929
        int                     len;
 
930
        int                     i;
 
931
        char            *token;
 
932
        float           fps;
 
933
        int                     skip;
 
934
        char            text[20000];
 
935
        fileHandle_t    f;
 
936
 
 
937
        memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
 
938
 
 
939
        // load the file
 
940
        len = trap_FS_FOpenFile( filename, &f, FS_READ );
 
941
        if ( len <= 0 ) {
 
942
                return qfalse;
 
943
        }
 
944
        if ( len >= ( sizeof( text ) - 1 ) ) {
 
945
                Com_Printf( "File %s too long\n", filename );
 
946
                trap_FS_FCloseFile( f );
 
947
                return qfalse;
 
948
        }
 
949
        trap_FS_Read( text, len, f );
 
950
        text[len] = 0;
 
951
        trap_FS_FCloseFile( f );
 
952
 
 
953
        // parse the text
 
954
        text_p = text;
 
955
        skip = 0;       // quite the compiler warning
 
956
 
 
957
        // read optional parameters
 
958
        while ( 1 ) {
 
959
                prev = text_p;  // so we can unget
 
960
                token = COM_Parse( &text_p );
 
961
                if ( !token ) {
 
962
                        break;
 
963
                }
 
964
                if ( !Q_stricmp( token, "footsteps" ) ) {
 
965
                        token = COM_Parse( &text_p );
 
966
                        if ( !token ) {
 
967
                                break;
 
968
                        }
 
969
                        continue;
 
970
                } else if ( !Q_stricmp( token, "headoffset" ) ) {
 
971
                        for ( i = 0 ; i < 3 ; i++ ) {
 
972
                                token = COM_Parse( &text_p );
 
973
                                if ( !token ) {
 
974
                                        break;
 
975
                                }
 
976
                        }
 
977
                        continue;
 
978
                } else if ( !Q_stricmp( token, "sex" ) ) {
 
979
                        token = COM_Parse( &text_p );
 
980
                        if ( !token ) {
 
981
                                break;
 
982
                        }
 
983
                        continue;
 
984
                }
 
985
 
 
986
                // if it is a number, start parsing animations
 
987
                if ( token[0] >= '0' && token[0] <= '9' ) {
 
988
                        text_p = prev;  // unget the token
 
989
                        break;
 
990
                }
 
991
 
 
992
                Com_Printf( "unknown token '%s' is %s\n", token, filename );
 
993
        }
 
994
 
 
995
        // read information for each frame
 
996
        for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
 
997
 
 
998
                token = COM_Parse( &text_p );
 
999
                if ( !token ) {
 
1000
                        break;
 
1001
                }
 
1002
                animations[i].firstFrame = atoi( token );
 
1003
                // leg only frames are adjusted to not count the upper body only frames
 
1004
                if ( i == LEGS_WALKCR ) {
 
1005
                        skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
 
1006
                }
 
1007
                if ( i >= LEGS_WALKCR ) {
 
1008
                        animations[i].firstFrame -= skip;
 
1009
                }
 
1010
 
 
1011
                token = COM_Parse( &text_p );
 
1012
                if ( !token ) {
 
1013
                        break;
 
1014
                }
 
1015
                animations[i].numFrames = atoi( token );
 
1016
 
 
1017
                token = COM_Parse( &text_p );
 
1018
                if ( !token ) {
 
1019
                        break;
 
1020
                }
 
1021
                animations[i].loopFrames = atoi( token );
 
1022
 
 
1023
                token = COM_Parse( &text_p );
 
1024
                if ( !token ) {
 
1025
                        break;
 
1026
                }
 
1027
                fps = atof( token );
 
1028
                if ( fps == 0 ) {
 
1029
                        fps = 1;
 
1030
                }
 
1031
                animations[i].frameLerp = 1000 / fps;
 
1032
                animations[i].initialLerp = 1000 / fps;
 
1033
        }
 
1034
 
 
1035
        if ( i != MAX_ANIMATIONS ) {
 
1036
                Com_Printf( "Error parsing animation file: %s", filename );
 
1037
                return qfalse;
 
1038
        }
 
1039
 
 
1040
        return qtrue;
 
1041
}
 
1042
 
 
1043
 
 
1044
/*
 
1045
==========================
 
1046
UI_RegisterClientModelname
 
1047
==========================
 
1048
*/
 
1049
qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName ) {
 
1050
        char            modelName[MAX_QPATH];
 
1051
        char            skinName[MAX_QPATH];
 
1052
        char            filename[MAX_QPATH];
 
1053
        char            *slash;
 
1054
 
 
1055
        pi->torsoModel = 0;
 
1056
        pi->headModel = 0;
 
1057
 
 
1058
        if ( !modelSkinName[0] ) {
 
1059
                return qfalse;
 
1060
        }
 
1061
 
 
1062
        Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) );
 
1063
 
 
1064
        slash = strchr( modelName, '/' );
 
1065
        if ( !slash ) {
 
1066
                // modelName did not include a skin name
 
1067
                Q_strncpyz( skinName, "default", sizeof( skinName ) );
 
1068
        } else {
 
1069
                Q_strncpyz( skinName, slash + 1, sizeof( skinName ) );
 
1070
                // truncate modelName
 
1071
                *slash = 0;
 
1072
        }
 
1073
 
 
1074
        // load cmodels before models so filecache works
 
1075
 
 
1076
        Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
 
1077
        pi->legsModel = trap_R_RegisterModel( filename );
 
1078
        if ( !pi->legsModel ) {
 
1079
                Com_Printf( "Failed to load model file %s\n", filename );
 
1080
                return qfalse;
 
1081
        }
 
1082
 
 
1083
        Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
 
1084
        pi->torsoModel = trap_R_RegisterModel( filename );
 
1085
        if ( !pi->torsoModel ) {
 
1086
                Com_Printf( "Failed to load model file %s\n", filename );
 
1087
                return qfalse;
 
1088
        }
 
1089
 
 
1090
        Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", modelName );
 
1091
        pi->headModel = trap_R_RegisterModel( filename );
 
1092
        if ( !pi->headModel ) {
 
1093
                Com_Printf( "Failed to load model file %s\n", filename );
 
1094
                return qfalse;
 
1095
        }
 
1096
 
 
1097
        // if any skins failed to load, fall back to default
 
1098
        if ( !UI_RegisterClientSkin( pi, modelName, skinName ) ) {
 
1099
                if ( !UI_RegisterClientSkin( pi, modelName, "default" ) ) {
 
1100
                        Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
 
1101
                        return qfalse;
 
1102
                }
 
1103
        }
 
1104
 
 
1105
        // load the animations
 
1106
        Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
 
1107
        if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
 
1108
                Com_Printf( "Failed to load animation file %s\n", filename );
 
1109
                return qfalse;
 
1110
        }
 
1111
 
 
1112
        return qtrue;
 
1113
}
 
1114
 
 
1115
 
 
1116
/*
 
1117
===============
 
1118
UI_PlayerInfo_SetModel
 
1119
===============
 
1120
*/
 
1121
void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model ) {
 
1122
        memset( pi, 0, sizeof(*pi) );
 
1123
        UI_RegisterClientModelname( pi, model );
 
1124
        pi->weapon = WP_MACHINEGUN;
 
1125
        pi->currentWeapon = pi->weapon;
 
1126
        pi->lastWeapon = pi->weapon;
 
1127
        pi->pendingWeapon = -1;
 
1128
        pi->weaponTimer = 0;
 
1129
        pi->chat = qfalse;
 
1130
        pi->newModel = qtrue;
 
1131
        UI_PlayerInfo_SetWeapon( pi, pi->weapon );
 
1132
}
 
1133
 
 
1134
 
 
1135
/*
 
1136
===============
 
1137
UI_PlayerInfo_SetInfo
 
1138
===============
 
1139
*/
 
1140
void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
 
1141
        int                     currentAnim;
 
1142
        weapon_t        weaponNum;
 
1143
 
 
1144
        pi->chat = chat;
 
1145
 
 
1146
        // view angles
 
1147
        VectorCopy( viewAngles, pi->viewAngles );
 
1148
 
 
1149
        // move angles
 
1150
        VectorCopy( moveAngles, pi->moveAngles );
 
1151
 
 
1152
        if ( pi->newModel ) {
 
1153
                pi->newModel = qfalse;
 
1154
 
 
1155
                jumpHeight = 0;
 
1156
                pi->pendingLegsAnim = 0;
 
1157
                UI_ForceLegsAnim( pi, legsAnim );
 
1158
                pi->legs.yawAngle = viewAngles[YAW];
 
1159
                pi->legs.yawing = qfalse;
 
1160
 
 
1161
                pi->pendingTorsoAnim = 0;
 
1162
                UI_ForceTorsoAnim( pi, torsoAnim );
 
1163
                pi->torso.yawAngle = viewAngles[YAW];
 
1164
                pi->torso.yawing = qfalse;
 
1165
 
 
1166
                if ( weaponNumber != -1 ) {
 
1167
                        pi->weapon = weaponNumber;
 
1168
                        pi->currentWeapon = weaponNumber;
 
1169
                        pi->lastWeapon = weaponNumber;
 
1170
                        pi->pendingWeapon = -1;
 
1171
                        pi->weaponTimer = 0;
 
1172
                        UI_PlayerInfo_SetWeapon( pi, pi->weapon );
 
1173
                }
 
1174
 
 
1175
                return;
 
1176
        }
 
1177
 
 
1178
        // weapon
 
1179
        if ( weaponNumber == -1 ) {
 
1180
                pi->pendingWeapon = -1;
 
1181
                pi->weaponTimer = 0;
 
1182
        }
 
1183
        else if ( weaponNumber != WP_NONE ) {
 
1184
                pi->pendingWeapon = weaponNumber;
 
1185
                pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
 
1186
        }
 
1187
        weaponNum = pi->lastWeapon;
 
1188
        pi->weapon = weaponNum;
 
1189
 
 
1190
        if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
 
1191
                torsoAnim = legsAnim = BOTH_DEATH1;
 
1192
                pi->weapon = pi->currentWeapon = WP_NONE;
 
1193
                UI_PlayerInfo_SetWeapon( pi, pi->weapon );
 
1194
 
 
1195
                jumpHeight = 0;
 
1196
                pi->pendingLegsAnim = 0;
 
1197
                UI_ForceLegsAnim( pi, legsAnim );
 
1198
 
 
1199
                pi->pendingTorsoAnim = 0;
 
1200
                UI_ForceTorsoAnim( pi, torsoAnim );
 
1201
 
 
1202
                return;
 
1203
        }
 
1204
 
 
1205
        // leg animation
 
1206
        currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
 
1207
        if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
 
1208
                pi->pendingLegsAnim = legsAnim;
 
1209
        }
 
1210
        else if ( legsAnim != currentAnim ) {
 
1211
                jumpHeight = 0;
 
1212
                pi->pendingLegsAnim = 0;
 
1213
                UI_ForceLegsAnim( pi, legsAnim );
 
1214
        }
 
1215
 
 
1216
        // torso animation
 
1217
        if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
 
1218
                if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
 
1219
                        torsoAnim = TORSO_STAND2;
 
1220
                }
 
1221
                else {
 
1222
                        torsoAnim = TORSO_STAND;
 
1223
                }
 
1224
        }
 
1225
 
 
1226
        if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
 
1227
                if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
 
1228
                        torsoAnim = TORSO_ATTACK2;
 
1229
                }
 
1230
                else {
 
1231
                        torsoAnim = TORSO_ATTACK;
 
1232
                }
 
1233
                pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
 
1234
                //FIXME play firing sound here
 
1235
        }
 
1236
 
 
1237
        currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
 
1238
 
 
1239
        if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
 
1240
                pi->pendingTorsoAnim = torsoAnim;
 
1241
        }
 
1242
        else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
 
1243
                pi->pendingTorsoAnim = torsoAnim;
 
1244
        }
 
1245
        else if ( torsoAnim != currentAnim ) {
 
1246
                pi->pendingTorsoAnim = 0;
 
1247
                UI_ForceTorsoAnim( pi, torsoAnim );
 
1248
        }
 
1249
}