~ubuntu-branches/ubuntu/hardy/openarena/hardy-backports

« back to all changes in this revision

Viewing changes to code/game/bg_pmove.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
// bg_pmove.c -- both games player movement code
 
24
// takes a playerstate and a usercmd as input and returns a modifed playerstate
 
25
 
 
26
#include "../qcommon/q_shared.h"
 
27
#include "bg_public.h"
 
28
#include "bg_local.h"
 
29
 
 
30
pmove_t         *pm;
 
31
pml_t           pml;
 
32
 
 
33
// movement parameters
 
34
float   pm_stopspeed = 100.0f;
 
35
float   pm_duckScale = 0.25f;
 
36
float   pm_swimScale = 0.50f;
 
37
float   pm_wadeScale = 0.70f;
 
38
 
 
39
float   pm_accelerate = 10.0f;
 
40
float   pm_airaccelerate = 1.0f;
 
41
float   pm_wateraccelerate = 4.0f;
 
42
float   pm_flyaccelerate = 8.0f;
 
43
 
 
44
float   pm_friction = 6.0f;
 
45
float   pm_waterfriction = 1.0f;
 
46
float   pm_flightfriction = 3.0f;
 
47
float   pm_spectatorfriction = 5.0f;
 
48
 
 
49
int             c_pmove = 0;
 
50
 
 
51
 
 
52
/*
 
53
===============
 
54
PM_AddEvent
 
55
 
 
56
===============
 
57
*/
 
58
void PM_AddEvent( int newEvent ) {
 
59
        BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );
 
60
}
 
61
 
 
62
/*
 
63
===============
 
64
PM_AddTouchEnt
 
65
===============
 
66
*/
 
67
void PM_AddTouchEnt( int entityNum ) {
 
68
        int             i;
 
69
 
 
70
        if ( entityNum == ENTITYNUM_WORLD ) {
 
71
                return;
 
72
        }
 
73
        if ( pm->numtouch == MAXTOUCH ) {
 
74
                return;
 
75
        }
 
76
 
 
77
        // see if it is already added
 
78
        for ( i = 0 ; i < pm->numtouch ; i++ ) {
 
79
                if ( pm->touchents[ i ] == entityNum ) {
 
80
                        return;
 
81
                }
 
82
        }
 
83
 
 
84
        // add it
 
85
        pm->touchents[pm->numtouch] = entityNum;
 
86
        pm->numtouch++;
 
87
}
 
88
 
 
89
/*
 
90
===================
 
91
PM_StartTorsoAnim
 
92
===================
 
93
*/
 
94
static void PM_StartTorsoAnim( int anim ) {
 
95
        if ( pm->ps->pm_type >= PM_DEAD ) {
 
96
                return;
 
97
        }
 
98
        pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
 
99
                | anim;
 
100
}
 
101
static void PM_StartLegsAnim( int anim ) {
 
102
        if ( pm->ps->pm_type >= PM_DEAD ) {
 
103
                return;
 
104
        }
 
105
        if ( pm->ps->legsTimer > 0 ) {
 
106
                return;         // a high priority animation is running
 
107
        }
 
108
        pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
 
109
                | anim;
 
110
}
 
111
 
 
112
static void PM_ContinueLegsAnim( int anim ) {
 
113
        if ( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) {
 
114
                return;
 
115
        }
 
116
        if ( pm->ps->legsTimer > 0 ) {
 
117
                return;         // a high priority animation is running
 
118
        }
 
119
        PM_StartLegsAnim( anim );
 
120
}
 
121
 
 
122
static void PM_ContinueTorsoAnim( int anim ) {
 
123
        if ( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) {
 
124
                return;
 
125
        }
 
126
        if ( pm->ps->torsoTimer > 0 ) {
 
127
                return;         // a high priority animation is running
 
128
        }
 
129
        PM_StartTorsoAnim( anim );
 
130
}
 
131
 
 
132
static void PM_ForceLegsAnim( int anim ) {
 
133
        pm->ps->legsTimer = 0;
 
134
        PM_StartLegsAnim( anim );
 
135
}
 
136
 
 
137
 
 
138
/*
 
139
==================
 
140
PM_ClipVelocity
 
141
 
 
142
Slide off of the impacting surface
 
143
==================
 
144
*/
 
145
void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) {
 
146
        float   backoff;
 
147
        float   change;
 
148
        int             i;
 
149
        
 
150
        backoff = DotProduct (in, normal);
 
151
        
 
152
        if ( backoff < 0 ) {
 
153
                backoff *= overbounce;
 
154
        } else {
 
155
                backoff /= overbounce;
 
156
        }
 
157
 
 
158
        for ( i=0 ; i<3 ; i++ ) {
 
159
                change = normal[i]*backoff;
 
160
                out[i] = in[i] - change;
 
161
        }
 
162
}
 
163
 
 
164
 
 
165
/*
 
166
==================
 
167
PM_Friction
 
168
 
 
169
Handles both ground friction and water friction
 
170
==================
 
171
*/
 
172
static void PM_Friction( void ) {
 
173
        vec3_t  vec;
 
174
        float   *vel;
 
175
        float   speed, newspeed, control;
 
176
        float   drop;
 
177
        
 
178
        vel = pm->ps->velocity;
 
179
        
 
180
        VectorCopy( vel, vec );
 
181
        if ( pml.walking ) {
 
182
                vec[2] = 0;     // ignore slope movement
 
183
        }
 
184
 
 
185
        speed = VectorLength(vec);
 
186
        if (speed < 1) {
 
187
                vel[0] = 0;
 
188
                vel[1] = 0;             // allow sinking underwater
 
189
                // FIXME: still have z friction underwater?
 
190
                return;
 
191
        }
 
192
 
 
193
        drop = 0;
 
194
 
 
195
        // apply ground friction
 
196
        if ( pm->waterlevel <= 1 ) {
 
197
                if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
 
198
                        // if getting knocked back, no friction
 
199
                        if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
 
200
                                control = speed < pm_stopspeed ? pm_stopspeed : speed;
 
201
                                drop += control*pm_friction*pml.frametime;
 
202
                        }
 
203
                }
 
204
        }
 
205
 
 
206
        // apply water friction even if just wading
 
207
        if ( pm->waterlevel ) {
 
208
                drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
 
209
        }
 
210
 
 
211
        // apply flying friction
 
212
        if ( pm->ps->powerups[PW_FLIGHT]) {
 
213
                drop += speed*pm_flightfriction*pml.frametime;
 
214
        }
 
215
 
 
216
        if ( pm->ps->pm_type == PM_SPECTATOR) {
 
217
                drop += speed*pm_spectatorfriction*pml.frametime;
 
218
        }
 
219
 
 
220
        // scale the velocity
 
221
        newspeed = speed - drop;
 
222
        if (newspeed < 0) {
 
223
                newspeed = 0;
 
224
        }
 
225
        newspeed /= speed;
 
226
 
 
227
        vel[0] = vel[0] * newspeed;
 
228
        vel[1] = vel[1] * newspeed;
 
229
        vel[2] = vel[2] * newspeed;
 
230
}
 
231
 
 
232
 
 
233
/*
 
234
==============
 
235
PM_Accelerate
 
236
 
 
237
Handles user intended acceleration
 
238
==============
 
239
*/
 
240
static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) {
 
241
#if 1
 
242
        // q2 style
 
243
        int                     i;
 
244
        float           addspeed, accelspeed, currentspeed;
 
245
 
 
246
        currentspeed = DotProduct (pm->ps->velocity, wishdir);
 
247
        addspeed = wishspeed - currentspeed;
 
248
        if (addspeed <= 0) {
 
249
                return;
 
250
        }
 
251
        accelspeed = accel*pml.frametime*wishspeed;
 
252
        if (accelspeed > addspeed) {
 
253
                accelspeed = addspeed;
 
254
        }
 
255
        
 
256
        for (i=0 ; i<3 ; i++) {
 
257
                pm->ps->velocity[i] += accelspeed*wishdir[i];   
 
258
        }
 
259
#else
 
260
        // proper way (avoids strafe jump maxspeed bug), but feels bad
 
261
        vec3_t          wishVelocity;
 
262
        vec3_t          pushDir;
 
263
        float           pushLen;
 
264
        float           canPush;
 
265
 
 
266
        VectorScale( wishdir, wishspeed, wishVelocity );
 
267
        VectorSubtract( wishVelocity, pm->ps->velocity, pushDir );
 
268
        pushLen = VectorNormalize( pushDir );
 
269
 
 
270
        canPush = accel*pml.frametime*wishspeed;
 
271
        if (canPush > pushLen) {
 
272
                canPush = pushLen;
 
273
        }
 
274
 
 
275
        VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity );
 
276
#endif
 
277
}
 
278
 
 
279
 
 
280
 
 
281
/*
 
282
============
 
283
PM_CmdScale
 
284
 
 
285
Returns the scale factor to apply to cmd movements
 
286
This allows the clients to use axial -127 to 127 values for all directions
 
287
without getting a sqrt(2) distortion in speed.
 
288
============
 
289
*/
 
290
static float PM_CmdScale( usercmd_t *cmd ) {
 
291
        int             max;
 
292
        float   total;
 
293
        float   scale;
 
294
 
 
295
        max = abs( cmd->forwardmove );
 
296
        if ( abs( cmd->rightmove ) > max ) {
 
297
                max = abs( cmd->rightmove );
 
298
        }
 
299
        if ( abs( cmd->upmove ) > max ) {
 
300
                max = abs( cmd->upmove );
 
301
        }
 
302
        if ( !max ) {
 
303
                return 0;
 
304
        }
 
305
 
 
306
        total = sqrt( cmd->forwardmove * cmd->forwardmove
 
307
                + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );
 
308
        scale = (float)pm->ps->speed * max / ( 127.0 * total );
 
309
 
 
310
        return scale;
 
311
}
 
312
 
 
313
 
 
314
/*
 
315
================
 
316
PM_SetMovementDir
 
317
 
 
318
Determine the rotation of the legs reletive
 
319
to the facing dir
 
320
================
 
321
*/
 
322
static void PM_SetMovementDir( void ) {
 
323
        if ( pm->cmd.forwardmove || pm->cmd.rightmove ) {
 
324
                if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) {
 
325
                        pm->ps->movementDir = 0;
 
326
                } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) {
 
327
                        pm->ps->movementDir = 1;
 
328
                } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) {
 
329
                        pm->ps->movementDir = 2;
 
330
                } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) {
 
331
                        pm->ps->movementDir = 3;
 
332
                } else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) {
 
333
                        pm->ps->movementDir = 4;
 
334
                } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) {
 
335
                        pm->ps->movementDir = 5;
 
336
                } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) {
 
337
                        pm->ps->movementDir = 6;
 
338
                } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) {
 
339
                        pm->ps->movementDir = 7;
 
340
                }
 
341
        } else {
 
342
                // if they aren't actively going directly sideways,
 
343
                // change the animation to the diagonal so they
 
344
                // don't stop too crooked
 
345
                if ( pm->ps->movementDir == 2 ) {
 
346
                        pm->ps->movementDir = 1;
 
347
                } else if ( pm->ps->movementDir == 6 ) {
 
348
                        pm->ps->movementDir = 7;
 
349
                } 
 
350
        }
 
351
}
 
352
 
 
353
 
 
354
/*
 
355
=============
 
356
PM_CheckJump
 
357
=============
 
358
*/
 
359
static qboolean PM_CheckJump( void ) {
 
360
        if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
 
361
                return qfalse;          // don't allow jump until all buttons are up
 
362
        }
 
363
 
 
364
        if ( pm->cmd.upmove < 10 ) {
 
365
                // not holding jump
 
366
                return qfalse;
 
367
        }
 
368
 
 
369
        // must wait for jump to be released
 
370
        if ( pm->ps->pm_flags & PMF_JUMP_HELD ) {
 
371
                // clear upmove so cmdscale doesn't lower running speed
 
372
                pm->cmd.upmove = 0;
 
373
                return qfalse;
 
374
        }
 
375
 
 
376
        pml.groundPlane = qfalse;               // jumping away
 
377
        pml.walking = qfalse;
 
378
        pm->ps->pm_flags |= PMF_JUMP_HELD;
 
379
 
 
380
        pm->ps->groundEntityNum = ENTITYNUM_NONE;
 
381
        pm->ps->velocity[2] = JUMP_VELOCITY;
 
382
        PM_AddEvent( EV_JUMP );
 
383
 
 
384
        if ( pm->cmd.forwardmove >= 0 ) {
 
385
                PM_ForceLegsAnim( LEGS_JUMP );
 
386
                pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
 
387
        } else {
 
388
                PM_ForceLegsAnim( LEGS_JUMPB );
 
389
                pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
 
390
        }
 
391
 
 
392
        return qtrue;
 
393
}
 
394
 
 
395
/*
 
396
=============
 
397
PM_CheckWaterJump
 
398
=============
 
399
*/
 
400
static qboolean PM_CheckWaterJump( void ) {
 
401
        vec3_t  spot;
 
402
        int             cont;
 
403
        vec3_t  flatforward;
 
404
 
 
405
        if (pm->ps->pm_time) {
 
406
                return qfalse;
 
407
        }
 
408
 
 
409
        // check for water jump
 
410
        if ( pm->waterlevel != 2 ) {
 
411
                return qfalse;
 
412
        }
 
413
 
 
414
        flatforward[0] = pml.forward[0];
 
415
        flatforward[1] = pml.forward[1];
 
416
        flatforward[2] = 0;
 
417
        VectorNormalize (flatforward);
 
418
 
 
419
        VectorMA (pm->ps->origin, 30, flatforward, spot);
 
420
        spot[2] += 4;
 
421
        cont = pm->pointcontents (spot, pm->ps->clientNum );
 
422
        if ( !(cont & CONTENTS_SOLID) ) {
 
423
                return qfalse;
 
424
        }
 
425
 
 
426
        spot[2] += 16;
 
427
        cont = pm->pointcontents (spot, pm->ps->clientNum );
 
428
        if ( cont ) {
 
429
                return qfalse;
 
430
        }
 
431
 
 
432
        // jump out of water
 
433
        VectorScale (pml.forward, 200, pm->ps->velocity);
 
434
        pm->ps->velocity[2] = 350;
 
435
 
 
436
        pm->ps->pm_flags |= PMF_TIME_WATERJUMP;
 
437
        pm->ps->pm_time = 2000;
 
438
 
 
439
        return qtrue;
 
440
}
 
441
 
 
442
//============================================================================
 
443
 
 
444
 
 
445
/*
 
446
===================
 
447
PM_WaterJumpMove
 
448
 
 
449
Flying out of the water
 
450
===================
 
451
*/
 
452
static void PM_WaterJumpMove( void ) {
 
453
        // waterjump has no control, but falls
 
454
 
 
455
        PM_StepSlideMove( qtrue );
 
456
 
 
457
        pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
 
458
        if (pm->ps->velocity[2] < 0) {
 
459
                // cancel as soon as we are falling down again
 
460
                pm->ps->pm_flags &= ~PMF_ALL_TIMES;
 
461
                pm->ps->pm_time = 0;
 
462
        }
 
463
}
 
464
 
 
465
/*
 
466
===================
 
467
PM_WaterMove
 
468
 
 
469
===================
 
470
*/
 
471
static void PM_WaterMove( void ) {
 
472
        int             i;
 
473
        vec3_t  wishvel;
 
474
        float   wishspeed;
 
475
        vec3_t  wishdir;
 
476
        float   scale;
 
477
        float   vel;
 
478
 
 
479
        if ( PM_CheckWaterJump() ) {
 
480
                PM_WaterJumpMove();
 
481
                return;
 
482
        }
 
483
#if 0
 
484
        // jump = head for surface
 
485
        if ( pm->cmd.upmove >= 10 ) {
 
486
                if (pm->ps->velocity[2] > -300) {
 
487
                        if ( pm->watertype == CONTENTS_WATER ) {
 
488
                                pm->ps->velocity[2] = 100;
 
489
                        } else if (pm->watertype == CONTENTS_SLIME) {
 
490
                                pm->ps->velocity[2] = 80;
 
491
                        } else {
 
492
                                pm->ps->velocity[2] = 50;
 
493
                        }
 
494
                }
 
495
        }
 
496
#endif
 
497
        PM_Friction ();
 
498
 
 
499
        scale = PM_CmdScale( &pm->cmd );
 
500
        //
 
501
        // user intentions
 
502
        //
 
503
        if ( !scale ) {
 
504
                wishvel[0] = 0;
 
505
                wishvel[1] = 0;
 
506
                wishvel[2] = -60;               // sink towards bottom
 
507
        } else {
 
508
                for (i=0 ; i<3 ; i++)
 
509
                        wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
 
510
 
 
511
                wishvel[2] += scale * pm->cmd.upmove;
 
512
        }
 
513
 
 
514
        VectorCopy (wishvel, wishdir);
 
515
        wishspeed = VectorNormalize(wishdir);
 
516
 
 
517
        if ( wishspeed > pm->ps->speed * pm_swimScale ) {
 
518
                wishspeed = pm->ps->speed * pm_swimScale;
 
519
        }
 
520
 
 
521
        PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
 
522
 
 
523
        // make sure we can go up slopes easily under water
 
524
        if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) {
 
525
                vel = VectorLength(pm->ps->velocity);
 
526
                // slide along the ground plane
 
527
                PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
 
528
                        pm->ps->velocity, OVERCLIP );
 
529
 
 
530
                VectorNormalize(pm->ps->velocity);
 
531
                VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
 
532
        }
 
533
 
 
534
        PM_SlideMove( qfalse );
 
535
}
 
536
 
 
537
#ifdef MISSIONPACK
 
538
/*
 
539
===================
 
540
PM_InvulnerabilityMove
 
541
 
 
542
Only with the invulnerability powerup
 
543
===================
 
544
*/
 
545
static void PM_InvulnerabilityMove( void ) {
 
546
        pm->cmd.forwardmove = 0;
 
547
        pm->cmd.rightmove = 0;
 
548
        pm->cmd.upmove = 0;
 
549
        VectorClear(pm->ps->velocity);
 
550
}
 
551
#endif
 
552
 
 
553
/*
 
554
===================
 
555
PM_FlyMove
 
556
 
 
557
Only with the flight powerup
 
558
===================
 
559
*/
 
560
static void PM_FlyMove( void ) {
 
561
        int             i;
 
562
        vec3_t  wishvel;
 
563
        float   wishspeed;
 
564
        vec3_t  wishdir;
 
565
        float   scale;
 
566
 
 
567
        // normal slowdown
 
568
        PM_Friction ();
 
569
 
 
570
        scale = PM_CmdScale( &pm->cmd );
 
571
        //
 
572
        // user intentions
 
573
        //
 
574
        if ( !scale ) {
 
575
                wishvel[0] = 0;
 
576
                wishvel[1] = 0;
 
577
                wishvel[2] = 0;
 
578
        } else {
 
579
                for (i=0 ; i<3 ; i++) {
 
580
                        wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
 
581
                }
 
582
 
 
583
                wishvel[2] += scale * pm->cmd.upmove;
 
584
        }
 
585
 
 
586
        VectorCopy (wishvel, wishdir);
 
587
        wishspeed = VectorNormalize(wishdir);
 
588
 
 
589
        PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate);
 
590
 
 
591
        PM_StepSlideMove( qfalse );
 
592
}
 
593
 
 
594
 
 
595
/*
 
596
===================
 
597
PM_AirMove
 
598
 
 
599
===================
 
600
*/
 
601
static void PM_AirMove( void ) {
 
602
        int                     i;
 
603
        vec3_t          wishvel;
 
604
        float           fmove, smove;
 
605
        vec3_t          wishdir;
 
606
        float           wishspeed;
 
607
        float           scale;
 
608
        usercmd_t       cmd;
 
609
 
 
610
        PM_Friction();
 
611
 
 
612
        fmove = pm->cmd.forwardmove;
 
613
        smove = pm->cmd.rightmove;
 
614
 
 
615
        cmd = pm->cmd;
 
616
        scale = PM_CmdScale( &cmd );
 
617
 
 
618
        // set the movementDir so clients can rotate the legs for strafing
 
619
        PM_SetMovementDir();
 
620
 
 
621
        // project moves down to flat plane
 
622
        pml.forward[2] = 0;
 
623
        pml.right[2] = 0;
 
624
        VectorNormalize (pml.forward);
 
625
        VectorNormalize (pml.right);
 
626
 
 
627
        for ( i = 0 ; i < 2 ; i++ ) {
 
628
                wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
 
629
        }
 
630
        wishvel[2] = 0;
 
631
 
 
632
        VectorCopy (wishvel, wishdir);
 
633
        wishspeed = VectorNormalize(wishdir);
 
634
        wishspeed *= scale;
 
635
 
 
636
        // not on ground, so little effect on velocity
 
637
        PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);
 
638
 
 
639
        // we may have a ground plane that is very steep, even
 
640
        // though we don't have a groundentity
 
641
        // slide along the steep plane
 
642
        if ( pml.groundPlane ) {
 
643
                PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
 
644
                        pm->ps->velocity, OVERCLIP );
 
645
        }
 
646
 
 
647
#if 0
 
648
        //ZOID:  If we are on the grapple, try stair-stepping
 
649
        //this allows a player to use the grapple to pull himself
 
650
        //over a ledge
 
651
        if (pm->ps->pm_flags & PMF_GRAPPLE_PULL)
 
652
                PM_StepSlideMove ( qtrue );
 
653
        else
 
654
                PM_SlideMove ( qtrue );
 
655
#endif
 
656
 
 
657
        PM_StepSlideMove ( qtrue );
 
658
}
 
659
 
 
660
/*
 
661
===================
 
662
PM_GrappleMove
 
663
 
 
664
===================
 
665
*/
 
666
static void PM_GrappleMove( void ) {
 
667
        vec3_t vel, v;
 
668
        float vlen;
 
669
 
 
670
        VectorScale(pml.forward, -16, v);
 
671
        VectorAdd(pm->ps->grapplePoint, v, v);
 
672
        VectorSubtract(v, pm->ps->origin, vel);
 
673
        vlen = VectorLength(vel);
 
674
        VectorNormalize( vel );
 
675
 
 
676
        if (vlen <= 100)
 
677
                VectorScale(vel, 10 * vlen, vel);
 
678
        else
 
679
                VectorScale(vel, 800, vel);
 
680
 
 
681
        VectorCopy(vel, pm->ps->velocity);
 
682
 
 
683
        pml.groundPlane = qfalse;
 
684
}
 
685
 
 
686
/*
 
687
===================
 
688
PM_WalkMove
 
689
 
 
690
===================
 
691
*/
 
692
static void PM_WalkMove( void ) {
 
693
        int                     i;
 
694
        vec3_t          wishvel;
 
695
        float           fmove, smove;
 
696
        vec3_t          wishdir;
 
697
        float           wishspeed;
 
698
        float           scale;
 
699
        usercmd_t       cmd;
 
700
        float           accelerate;
 
701
        float           vel;
 
702
 
 
703
        if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) {
 
704
                // begin swimming
 
705
                PM_WaterMove();
 
706
                return;
 
707
        }
 
708
 
 
709
 
 
710
        if ( PM_CheckJump () ) {
 
711
                // jumped away
 
712
                if ( pm->waterlevel > 1 ) {
 
713
                        PM_WaterMove();
 
714
                } else {
 
715
                        PM_AirMove();
 
716
                }
 
717
                return;
 
718
        }
 
719
 
 
720
        PM_Friction ();
 
721
 
 
722
        fmove = pm->cmd.forwardmove;
 
723
        smove = pm->cmd.rightmove;
 
724
 
 
725
        cmd = pm->cmd;
 
726
        scale = PM_CmdScale( &cmd );
 
727
 
 
728
        // set the movementDir so clients can rotate the legs for strafing
 
729
        PM_SetMovementDir();
 
730
 
 
731
        // project moves down to flat plane
 
732
        pml.forward[2] = 0;
 
733
        pml.right[2] = 0;
 
734
 
 
735
        // project the forward and right directions onto the ground plane
 
736
        PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
 
737
        PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
 
738
        //
 
739
        VectorNormalize (pml.forward);
 
740
        VectorNormalize (pml.right);
 
741
 
 
742
        for ( i = 0 ; i < 3 ; i++ ) {
 
743
                wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
 
744
        }
 
745
        // when going up or down slopes the wish velocity should Not be zero
 
746
//      wishvel[2] = 0;
 
747
 
 
748
        VectorCopy (wishvel, wishdir);
 
749
        wishspeed = VectorNormalize(wishdir);
 
750
        wishspeed *= scale;
 
751
 
 
752
        // clamp the speed lower if ducking
 
753
        if ( pm->ps->pm_flags & PMF_DUCKED ) {
 
754
                if ( wishspeed > pm->ps->speed * pm_duckScale ) {
 
755
                        wishspeed = pm->ps->speed * pm_duckScale;
 
756
                }
 
757
        }
 
758
 
 
759
        // clamp the speed lower if wading or walking on the bottom
 
760
        if ( pm->waterlevel ) {
 
761
                float   waterScale;
 
762
 
 
763
                waterScale = pm->waterlevel / 3.0;
 
764
                waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;
 
765
                if ( wishspeed > pm->ps->speed * waterScale ) {
 
766
                        wishspeed = pm->ps->speed * waterScale;
 
767
                }
 
768
        }
 
769
 
 
770
        // when a player gets hit, they temporarily lose
 
771
        // full control, which allows them to be moved a bit
 
772
        if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
 
773
                accelerate = pm_airaccelerate;
 
774
        } else {
 
775
                accelerate = pm_accelerate;
 
776
        }
 
777
 
 
778
        PM_Accelerate (wishdir, wishspeed, accelerate);
 
779
 
 
780
        //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]);
 
781
        //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity));
 
782
 
 
783
        if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
 
784
                pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
 
785
        } else {
 
786
                // don't reset the z velocity for slopes
 
787
//              pm->ps->velocity[2] = 0;
 
788
        }
 
789
 
 
790
        vel = VectorLength(pm->ps->velocity);
 
791
 
 
792
        // slide along the ground plane
 
793
        PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
 
794
                pm->ps->velocity, OVERCLIP );
 
795
 
 
796
        // don't decrease velocity when going up or down a slope
 
797
        VectorNormalize(pm->ps->velocity);
 
798
        VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
 
799
 
 
800
        // don't do anything if standing still
 
801
        if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) {
 
802
                return;
 
803
        }
 
804
 
 
805
        PM_StepSlideMove( qfalse );
 
806
 
 
807
        //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity));
 
808
 
 
809
}
 
810
 
 
811
 
 
812
/*
 
813
==============
 
814
PM_DeadMove
 
815
==============
 
816
*/
 
817
static void PM_DeadMove( void ) {
 
818
        float   forward;
 
819
 
 
820
        if ( !pml.walking ) {
 
821
                return;
 
822
        }
 
823
 
 
824
        // extra friction
 
825
 
 
826
        forward = VectorLength (pm->ps->velocity);
 
827
        forward -= 20;
 
828
        if ( forward <= 0 ) {
 
829
                VectorClear (pm->ps->velocity);
 
830
        } else {
 
831
                VectorNormalize (pm->ps->velocity);
 
832
                VectorScale (pm->ps->velocity, forward, pm->ps->velocity);
 
833
        }
 
834
}
 
835
 
 
836
 
 
837
/*
 
838
===============
 
839
PM_NoclipMove
 
840
===============
 
841
*/
 
842
static void PM_NoclipMove( void ) {
 
843
        float   speed, drop, friction, control, newspeed;
 
844
        int                     i;
 
845
        vec3_t          wishvel;
 
846
        float           fmove, smove;
 
847
        vec3_t          wishdir;
 
848
        float           wishspeed;
 
849
        float           scale;
 
850
 
 
851
        pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
 
852
 
 
853
        // friction
 
854
 
 
855
        speed = VectorLength (pm->ps->velocity);
 
856
        if (speed < 1)
 
857
        {
 
858
                VectorCopy (vec3_origin, pm->ps->velocity);
 
859
        }
 
860
        else
 
861
        {
 
862
                drop = 0;
 
863
 
 
864
                friction = pm_friction*1.5;     // extra friction
 
865
                control = speed < pm_stopspeed ? pm_stopspeed : speed;
 
866
                drop += control*friction*pml.frametime;
 
867
 
 
868
                // scale the velocity
 
869
                newspeed = speed - drop;
 
870
                if (newspeed < 0)
 
871
                        newspeed = 0;
 
872
                newspeed /= speed;
 
873
 
 
874
                VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity);
 
875
        }
 
876
 
 
877
        // accelerate
 
878
        scale = PM_CmdScale( &pm->cmd );
 
879
 
 
880
        fmove = pm->cmd.forwardmove;
 
881
        smove = pm->cmd.rightmove;
 
882
        
 
883
        for (i=0 ; i<3 ; i++)
 
884
                wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
 
885
        wishvel[2] += pm->cmd.upmove;
 
886
 
 
887
        VectorCopy (wishvel, wishdir);
 
888
        wishspeed = VectorNormalize(wishdir);
 
889
        wishspeed *= scale;
 
890
 
 
891
        PM_Accelerate( wishdir, wishspeed, pm_accelerate );
 
892
 
 
893
        // move
 
894
        VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin);
 
895
}
 
896
 
 
897
//============================================================================
 
898
 
 
899
/*
 
900
================
 
901
PM_FootstepForSurface
 
902
 
 
903
Returns an event number apropriate for the groundsurface
 
904
================
 
905
*/
 
906
static int PM_FootstepForSurface( void ) {
 
907
        if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) {
 
908
                return 0;
 
909
        }
 
910
        if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) {
 
911
                return EV_FOOTSTEP_METAL;
 
912
        }
 
913
        return EV_FOOTSTEP;
 
914
}
 
915
 
 
916
 
 
917
/*
 
918
=================
 
919
PM_CrashLand
 
920
 
 
921
Check for hard landings that generate sound events
 
922
=================
 
923
*/
 
924
static void PM_CrashLand( void ) {
 
925
        float           delta;
 
926
        float           dist;
 
927
        float           vel, acc;
 
928
        float           t;
 
929
        float           a, b, c, den;
 
930
 
 
931
        // decide which landing animation to use
 
932
        if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) {
 
933
                PM_ForceLegsAnim( LEGS_LANDB );
 
934
        } else {
 
935
                PM_ForceLegsAnim( LEGS_LAND );
 
936
        }
 
937
 
 
938
        pm->ps->legsTimer = TIMER_LAND;
 
939
 
 
940
        // calculate the exact velocity on landing
 
941
        dist = pm->ps->origin[2] - pml.previous_origin[2];
 
942
        vel = pml.previous_velocity[2];
 
943
        acc = -pm->ps->gravity;
 
944
 
 
945
        a = acc / 2;
 
946
        b = vel;
 
947
        c = -dist;
 
948
 
 
949
        den =  b * b - 4 * a * c;
 
950
        if ( den < 0 ) {
 
951
                return;
 
952
        }
 
953
        t = (-b - sqrt( den ) ) / ( 2 * a );
 
954
 
 
955
        delta = vel + t * acc;
 
956
        delta = delta*delta * 0.0001;
 
957
 
 
958
        // ducking while falling doubles damage
 
959
        if ( pm->ps->pm_flags & PMF_DUCKED ) {
 
960
                delta *= 2;
 
961
        }
 
962
 
 
963
        // never take falling damage if completely underwater
 
964
        if ( pm->waterlevel == 3 ) {
 
965
                return;
 
966
        }
 
967
 
 
968
        // reduce falling damage if there is standing water
 
969
        if ( pm->waterlevel == 2 ) {
 
970
                delta *= 0.25;
 
971
        }
 
972
        if ( pm->waterlevel == 1 ) {
 
973
                delta *= 0.5;
 
974
        }
 
975
 
 
976
        if ( delta < 1 ) {
 
977
                return;
 
978
        }
 
979
 
 
980
        // create a local entity event to play the sound
 
981
 
 
982
        // SURF_NODAMAGE is used for bounce pads where you don't ever
 
983
        // want to take damage or play a crunch sound
 
984
        if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) )  {
 
985
                if ( delta > 60 ) {
 
986
                        PM_AddEvent( EV_FALL_FAR );
 
987
                } else if ( delta > 40 ) {
 
988
                        // this is a pain grunt, so don't play it if dead
 
989
                        if ( pm->ps->stats[STAT_HEALTH] > 0 ) {
 
990
                                PM_AddEvent( EV_FALL_MEDIUM );
 
991
                        }
 
992
                } else if ( delta > 7 ) {
 
993
                        PM_AddEvent( EV_FALL_SHORT );
 
994
                } else {
 
995
                        PM_AddEvent( PM_FootstepForSurface() );
 
996
                }
 
997
        }
 
998
 
 
999
        // start footstep cycle over
 
1000
        pm->ps->bobCycle = 0;
 
1001
}
 
1002
 
 
1003
/*
 
1004
=============
 
1005
PM_CheckStuck
 
1006
=============
 
1007
*/
 
1008
/*
 
1009
void PM_CheckStuck(void) {
 
1010
        trace_t trace;
 
1011
 
 
1012
        pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask);
 
1013
        if (trace.allsolid) {
 
1014
                //int shit = qtrue;
 
1015
        }
 
1016
}
 
1017
*/
 
1018
 
 
1019
/*
 
1020
=============
 
1021
PM_CorrectAllSolid
 
1022
=============
 
1023
*/
 
1024
static int PM_CorrectAllSolid( trace_t *trace ) {
 
1025
        int                     i, j, k;
 
1026
        vec3_t          point;
 
1027
 
 
1028
        if ( pm->debugLevel ) {
 
1029
                Com_Printf("%i:allsolid\n", c_pmove);
 
1030
        }
 
1031
 
 
1032
        // jitter around
 
1033
        for (i = -1; i <= 1; i++) {
 
1034
                for (j = -1; j <= 1; j++) {
 
1035
                        for (k = -1; k <= 1; k++) {
 
1036
                                VectorCopy(pm->ps->origin, point);
 
1037
                                point[0] += (float) i;
 
1038
                                point[1] += (float) j;
 
1039
                                point[2] += (float) k;
 
1040
                                pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
 
1041
                                if ( !trace->allsolid ) {
 
1042
                                        point[0] = pm->ps->origin[0];
 
1043
                                        point[1] = pm->ps->origin[1];
 
1044
                                        point[2] = pm->ps->origin[2] - 0.25;
 
1045
 
 
1046
                                        pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
 
1047
                                        pml.groundTrace = *trace;
 
1048
                                        return qtrue;
 
1049
                                }
 
1050
                        }
 
1051
                }
 
1052
        }
 
1053
 
 
1054
        pm->ps->groundEntityNum = ENTITYNUM_NONE;
 
1055
        pml.groundPlane = qfalse;
 
1056
        pml.walking = qfalse;
 
1057
 
 
1058
        return qfalse;
 
1059
}
 
1060
 
 
1061
 
 
1062
/*
 
1063
=============
 
1064
PM_GroundTraceMissed
 
1065
 
 
1066
The ground trace didn't hit a surface, so we are in freefall
 
1067
=============
 
1068
*/
 
1069
static void PM_GroundTraceMissed( void ) {
 
1070
        trace_t         trace;
 
1071
        vec3_t          point;
 
1072
 
 
1073
        if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {
 
1074
                // we just transitioned into freefall
 
1075
                if ( pm->debugLevel ) {
 
1076
                        Com_Printf("%i:lift\n", c_pmove);
 
1077
                }
 
1078
 
 
1079
                // if they aren't in a jumping animation and the ground is a ways away, force into it
 
1080
                // if we didn't do the trace, the player would be backflipping down staircases
 
1081
                VectorCopy( pm->ps->origin, point );
 
1082
                point[2] -= 64;
 
1083
 
 
1084
                pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
 
1085
                if ( trace.fraction == 1.0 ) {
 
1086
                        if ( pm->cmd.forwardmove >= 0 ) {
 
1087
                                PM_ForceLegsAnim( LEGS_JUMP );
 
1088
                                pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
 
1089
                        } else {
 
1090
                                PM_ForceLegsAnim( LEGS_JUMPB );
 
1091
                                pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
 
1092
                        }
 
1093
                }
 
1094
        }
 
1095
 
 
1096
        pm->ps->groundEntityNum = ENTITYNUM_NONE;
 
1097
        pml.groundPlane = qfalse;
 
1098
        pml.walking = qfalse;
 
1099
}
 
1100
 
 
1101
 
 
1102
/*
 
1103
=============
 
1104
PM_GroundTrace
 
1105
=============
 
1106
*/
 
1107
static void PM_GroundTrace( void ) {
 
1108
        vec3_t          point;
 
1109
        trace_t         trace;
 
1110
 
 
1111
        point[0] = pm->ps->origin[0];
 
1112
        point[1] = pm->ps->origin[1];
 
1113
        point[2] = pm->ps->origin[2] - 0.25;
 
1114
 
 
1115
        pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
 
1116
        pml.groundTrace = trace;
 
1117
 
 
1118
        // do something corrective if the trace starts in a solid...
 
1119
        if ( trace.allsolid ) {
 
1120
                if ( !PM_CorrectAllSolid(&trace) )
 
1121
                        return;
 
1122
        }
 
1123
 
 
1124
        // if the trace didn't hit anything, we are in free fall
 
1125
        if ( trace.fraction == 1.0 ) {
 
1126
                PM_GroundTraceMissed();
 
1127
                pml.groundPlane = qfalse;
 
1128
                pml.walking = qfalse;
 
1129
                return;
 
1130
        }
 
1131
 
 
1132
        // check if getting thrown off the ground
 
1133
        if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) {
 
1134
                if ( pm->debugLevel ) {
 
1135
                        Com_Printf("%i:kickoff\n", c_pmove);
 
1136
                }
 
1137
                // go into jump animation
 
1138
                if ( pm->cmd.forwardmove >= 0 ) {
 
1139
                        PM_ForceLegsAnim( LEGS_JUMP );
 
1140
                        pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
 
1141
                } else {
 
1142
                        PM_ForceLegsAnim( LEGS_JUMPB );
 
1143
                        pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
 
1144
                }
 
1145
 
 
1146
                pm->ps->groundEntityNum = ENTITYNUM_NONE;
 
1147
                pml.groundPlane = qfalse;
 
1148
                pml.walking = qfalse;
 
1149
                return;
 
1150
        }
 
1151
        
 
1152
        // slopes that are too steep will not be considered onground
 
1153
        if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) {
 
1154
                if ( pm->debugLevel ) {
 
1155
                        Com_Printf("%i:steep\n", c_pmove);
 
1156
                }
 
1157
                // FIXME: if they can't slide down the slope, let them
 
1158
                // walk (sharp crevices)
 
1159
                pm->ps->groundEntityNum = ENTITYNUM_NONE;
 
1160
                pml.groundPlane = qtrue;
 
1161
                pml.walking = qfalse;
 
1162
                return;
 
1163
        }
 
1164
 
 
1165
        pml.groundPlane = qtrue;
 
1166
        pml.walking = qtrue;
 
1167
 
 
1168
        // hitting solid ground will end a waterjump
 
1169
        if (pm->ps->pm_flags & PMF_TIME_WATERJUMP)
 
1170
        {
 
1171
                pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
 
1172
                pm->ps->pm_time = 0;
 
1173
        }
 
1174
 
 
1175
        if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
 
1176
                // just hit the ground
 
1177
                if ( pm->debugLevel ) {
 
1178
                        Com_Printf("%i:Land\n", c_pmove);
 
1179
                }
 
1180
                
 
1181
                PM_CrashLand();
 
1182
 
 
1183
                // don't do landing time if we were just going down a slope
 
1184
                if ( pml.previous_velocity[2] < -200 ) {
 
1185
                        // don't allow another jump for a little while
 
1186
                        pm->ps->pm_flags |= PMF_TIME_LAND;
 
1187
                        pm->ps->pm_time = 250;
 
1188
                }
 
1189
        }
 
1190
 
 
1191
        pm->ps->groundEntityNum = trace.entityNum;
 
1192
 
 
1193
        // don't reset the z velocity for slopes
 
1194
//      pm->ps->velocity[2] = 0;
 
1195
 
 
1196
        PM_AddTouchEnt( trace.entityNum );
 
1197
}
 
1198
 
 
1199
 
 
1200
/*
 
1201
=============
 
1202
PM_SetWaterLevel        FIXME: avoid this twice?  certainly if not moving
 
1203
=============
 
1204
*/
 
1205
static void PM_SetWaterLevel( void ) {
 
1206
        vec3_t          point;
 
1207
        int                     cont;
 
1208
        int                     sample1;
 
1209
        int                     sample2;
 
1210
 
 
1211
        //
 
1212
        // get waterlevel, accounting for ducking
 
1213
        //
 
1214
        pm->waterlevel = 0;
 
1215
        pm->watertype = 0;
 
1216
 
 
1217
        point[0] = pm->ps->origin[0];
 
1218
        point[1] = pm->ps->origin[1];
 
1219
        point[2] = pm->ps->origin[2] + MINS_Z + 1;      
 
1220
        cont = pm->pointcontents( point, pm->ps->clientNum );
 
1221
 
 
1222
        if ( cont & MASK_WATER ) {
 
1223
                sample2 = pm->ps->viewheight - MINS_Z;
 
1224
                sample1 = sample2 / 2;
 
1225
 
 
1226
                pm->watertype = cont;
 
1227
                pm->waterlevel = 1;
 
1228
                point[2] = pm->ps->origin[2] + MINS_Z + sample1;
 
1229
                cont = pm->pointcontents (point, pm->ps->clientNum );
 
1230
                if ( cont & MASK_WATER ) {
 
1231
                        pm->waterlevel = 2;
 
1232
                        point[2] = pm->ps->origin[2] + MINS_Z + sample2;
 
1233
                        cont = pm->pointcontents (point, pm->ps->clientNum );
 
1234
                        if ( cont & MASK_WATER ){
 
1235
                                pm->waterlevel = 3;
 
1236
                        }
 
1237
                }
 
1238
        }
 
1239
 
 
1240
}
 
1241
 
 
1242
/*
 
1243
==============
 
1244
PM_CheckDuck
 
1245
 
 
1246
Sets mins, maxs, and pm->ps->viewheight
 
1247
==============
 
1248
*/
 
1249
static void PM_CheckDuck (void)
 
1250
{
 
1251
        trace_t trace;
 
1252
 
 
1253
        if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
 
1254
                if ( pm->ps->pm_flags & PMF_INVULEXPAND ) {
 
1255
                        // invulnerability sphere has a 42 units radius
 
1256
                        VectorSet( pm->mins, -42, -42, -42 );
 
1257
                        VectorSet( pm->maxs, 42, 42, 42 );
 
1258
                }
 
1259
                else {
 
1260
                        VectorSet( pm->mins, -15, -15, MINS_Z );
 
1261
                        VectorSet( pm->maxs, 15, 15, 16 );
 
1262
                }
 
1263
                pm->ps->pm_flags |= PMF_DUCKED;
 
1264
                pm->ps->viewheight = CROUCH_VIEWHEIGHT;
 
1265
                return;
 
1266
        }
 
1267
        pm->ps->pm_flags &= ~PMF_INVULEXPAND;
 
1268
 
 
1269
        pm->mins[0] = -15;
 
1270
        pm->mins[1] = -15;
 
1271
 
 
1272
        pm->maxs[0] = 15;
 
1273
        pm->maxs[1] = 15;
 
1274
 
 
1275
        pm->mins[2] = MINS_Z;
 
1276
 
 
1277
        if (pm->ps->pm_type == PM_DEAD)
 
1278
        {
 
1279
                pm->maxs[2] = -8;
 
1280
                pm->ps->viewheight = DEAD_VIEWHEIGHT;
 
1281
                return;
 
1282
        }
 
1283
 
 
1284
        if (pm->cmd.upmove < 0)
 
1285
        {       // duck
 
1286
                pm->ps->pm_flags |= PMF_DUCKED;
 
1287
        }
 
1288
        else
 
1289
        {       // stand up if possible
 
1290
                if (pm->ps->pm_flags & PMF_DUCKED)
 
1291
                {
 
1292
                        // try to stand up
 
1293
                        pm->maxs[2] = 32;
 
1294
                        pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask );
 
1295
                        if (!trace.allsolid)
 
1296
                                pm->ps->pm_flags &= ~PMF_DUCKED;
 
1297
                }
 
1298
        }
 
1299
 
 
1300
        if (pm->ps->pm_flags & PMF_DUCKED)
 
1301
        {
 
1302
                pm->maxs[2] = 16;
 
1303
                pm->ps->viewheight = CROUCH_VIEWHEIGHT;
 
1304
        }
 
1305
        else
 
1306
        {
 
1307
                pm->maxs[2] = 32;
 
1308
                pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
 
1309
        }
 
1310
}
 
1311
 
 
1312
 
 
1313
 
 
1314
//===================================================================
 
1315
 
 
1316
 
 
1317
/*
 
1318
===============
 
1319
PM_Footsteps
 
1320
===============
 
1321
*/
 
1322
static void PM_Footsteps( void ) {
 
1323
        float           bobmove;
 
1324
        int                     old;
 
1325
        qboolean        footstep;
 
1326
 
 
1327
        //
 
1328
        // calculate speed and cycle to be used for
 
1329
        // all cyclic walking effects
 
1330
        //
 
1331
        pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0]
 
1332
                +  pm->ps->velocity[1] * pm->ps->velocity[1] );
 
1333
 
 
1334
        if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
 
1335
 
 
1336
                if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
 
1337
                        PM_ContinueLegsAnim( LEGS_IDLECR );
 
1338
                }
 
1339
                // airborne leaves position in cycle intact, but doesn't advance
 
1340
                if ( pm->waterlevel > 1 ) {
 
1341
                        PM_ContinueLegsAnim( LEGS_SWIM );
 
1342
                }
 
1343
                return;
 
1344
        }
 
1345
 
 
1346
        // if not trying to move
 
1347
        if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) {
 
1348
                if (  pm->xyspeed < 5 ) {
 
1349
                        pm->ps->bobCycle = 0;   // start at beginning of cycle again
 
1350
                        if ( pm->ps->pm_flags & PMF_DUCKED ) {
 
1351
                                PM_ContinueLegsAnim( LEGS_IDLECR );
 
1352
                        } else {
 
1353
                                PM_ContinueLegsAnim( LEGS_IDLE );
 
1354
                        }
 
1355
                }
 
1356
                return;
 
1357
        }
 
1358
        
 
1359
 
 
1360
        footstep = qfalse;
 
1361
 
 
1362
        if ( pm->ps->pm_flags & PMF_DUCKED ) {
 
1363
                bobmove = 0.5;  // ducked characters bob much faster
 
1364
                if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
 
1365
                        PM_ContinueLegsAnim( LEGS_BACKCR );
 
1366
                }
 
1367
                else {
 
1368
                        PM_ContinueLegsAnim( LEGS_WALKCR );
 
1369
                }
 
1370
                // ducked characters never play footsteps
 
1371
        /*
 
1372
        } else  if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
 
1373
                if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
 
1374
                        bobmove = 0.4;  // faster speeds bob faster
 
1375
                        footstep = qtrue;
 
1376
                } else {
 
1377
                        bobmove = 0.3;
 
1378
                }
 
1379
                PM_ContinueLegsAnim( LEGS_BACK );
 
1380
        */
 
1381
        } else {
 
1382
                if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
 
1383
                        bobmove = 0.4f; // faster speeds bob faster
 
1384
                        if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
 
1385
                                PM_ContinueLegsAnim( LEGS_BACK );
 
1386
                        }
 
1387
                        else {
 
1388
                                PM_ContinueLegsAnim( LEGS_RUN );
 
1389
                        }
 
1390
                        footstep = qtrue;
 
1391
                } else {
 
1392
                        bobmove = 0.3f; // walking bobs slow
 
1393
                        if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
 
1394
                                PM_ContinueLegsAnim( LEGS_BACKWALK );
 
1395
                        }
 
1396
                        else {
 
1397
                                PM_ContinueLegsAnim( LEGS_WALK );
 
1398
                        }
 
1399
                }
 
1400
        }
 
1401
 
 
1402
        // check for footstep / splash sounds
 
1403
        old = pm->ps->bobCycle;
 
1404
        pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;
 
1405
 
 
1406
        // if we just crossed a cycle boundary, play an apropriate footstep event
 
1407
        if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) {
 
1408
                if ( pm->waterlevel == 0 ) {
 
1409
                        // on ground will only play sounds if running
 
1410
                        if ( footstep && !pm->noFootsteps ) {
 
1411
                                PM_AddEvent( PM_FootstepForSurface() );
 
1412
                        }
 
1413
                } else if ( pm->waterlevel == 1 ) {
 
1414
                        // splashing
 
1415
                        PM_AddEvent( EV_FOOTSPLASH );
 
1416
                } else if ( pm->waterlevel == 2 ) {
 
1417
                        // wading / swimming at surface
 
1418
                        PM_AddEvent( EV_SWIM );
 
1419
                } else if ( pm->waterlevel == 3 ) {
 
1420
                        // no sound when completely underwater
 
1421
 
 
1422
                }
 
1423
        }
 
1424
}
 
1425
 
 
1426
/*
 
1427
==============
 
1428
PM_WaterEvents
 
1429
 
 
1430
Generate sound events for entering and leaving water
 
1431
==============
 
1432
*/
 
1433
static void PM_WaterEvents( void ) {            // FIXME?
 
1434
        //
 
1435
        // if just entered a water volume, play a sound
 
1436
        //
 
1437
        if (!pml.previous_waterlevel && pm->waterlevel) {
 
1438
                PM_AddEvent( EV_WATER_TOUCH );
 
1439
        }
 
1440
 
 
1441
        //
 
1442
        // if just completely exited a water volume, play a sound
 
1443
        //
 
1444
        if (pml.previous_waterlevel && !pm->waterlevel) {
 
1445
                PM_AddEvent( EV_WATER_LEAVE );
 
1446
        }
 
1447
 
 
1448
        //
 
1449
        // check for head just going under water
 
1450
        //
 
1451
        if (pml.previous_waterlevel != 3 && pm->waterlevel == 3) {
 
1452
                PM_AddEvent( EV_WATER_UNDER );
 
1453
        }
 
1454
 
 
1455
        //
 
1456
        // check for head just coming out of water
 
1457
        //
 
1458
        if (pml.previous_waterlevel == 3 && pm->waterlevel != 3) {
 
1459
                PM_AddEvent( EV_WATER_CLEAR );
 
1460
        }
 
1461
}
 
1462
 
 
1463
 
 
1464
/*
 
1465
===============
 
1466
PM_BeginWeaponChange
 
1467
===============
 
1468
*/
 
1469
static void PM_BeginWeaponChange( int weapon ) {
 
1470
        if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) {
 
1471
                return;
 
1472
        }
 
1473
 
 
1474
        if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
 
1475
                return;
 
1476
        }
 
1477
        
 
1478
        if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
 
1479
                return;
 
1480
        }
 
1481
 
 
1482
        PM_AddEvent( EV_CHANGE_WEAPON );
 
1483
        pm->ps->weaponstate = WEAPON_DROPPING;
 
1484
        pm->ps->weaponTime += 200;
 
1485
        PM_StartTorsoAnim( TORSO_DROP );
 
1486
}
 
1487
 
 
1488
 
 
1489
/*
 
1490
===============
 
1491
PM_FinishWeaponChange
 
1492
===============
 
1493
*/
 
1494
static void PM_FinishWeaponChange( void ) {
 
1495
        int             weapon;
 
1496
 
 
1497
        weapon = pm->cmd.weapon;
 
1498
        if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) {
 
1499
                weapon = WP_NONE;
 
1500
        }
 
1501
 
 
1502
        if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
 
1503
                weapon = WP_NONE;
 
1504
        }
 
1505
 
 
1506
        pm->ps->weapon = weapon;
 
1507
        pm->ps->weaponstate = WEAPON_RAISING;
 
1508
        pm->ps->weaponTime += 250;
 
1509
        PM_StartTorsoAnim( TORSO_RAISE );
 
1510
}
 
1511
 
 
1512
 
 
1513
/*
 
1514
==============
 
1515
PM_TorsoAnimation
 
1516
 
 
1517
==============
 
1518
*/
 
1519
static void PM_TorsoAnimation( void ) {
 
1520
        if ( pm->ps->weaponstate == WEAPON_READY ) {
 
1521
                if ( pm->ps->weapon == WP_GAUNTLET ) {
 
1522
                        PM_ContinueTorsoAnim( TORSO_STAND2 );
 
1523
                } else {
 
1524
                        PM_ContinueTorsoAnim( TORSO_STAND );
 
1525
                }
 
1526
                return;
 
1527
        }
 
1528
}
 
1529
 
 
1530
 
 
1531
/*
 
1532
==============
 
1533
PM_Weapon
 
1534
 
 
1535
Generates weapon events and modifes the weapon counter
 
1536
==============
 
1537
*/
 
1538
static void PM_Weapon( void ) {
 
1539
        int             addTime;
 
1540
 
 
1541
        // don't allow attack until all buttons are up
 
1542
        if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
 
1543
                return;
 
1544
        }
 
1545
 
 
1546
        // ignore if spectator
 
1547
        if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
 
1548
                return;
 
1549
        }
 
1550
 
 
1551
        // check for dead player
 
1552
        if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
 
1553
                pm->ps->weapon = WP_NONE;
 
1554
                return;
 
1555
        }
 
1556
 
 
1557
        // check for item using
 
1558
        if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) {
 
1559
                if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) {
 
1560
                        if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT
 
1561
                                && pm->ps->stats[STAT_HEALTH] >= (pm->ps->stats[STAT_MAX_HEALTH] + 25) ) {
 
1562
                                // don't use medkit if at max health
 
1563
                        } else {
 
1564
                                pm->ps->pm_flags |= PMF_USE_ITEM_HELD;
 
1565
                                PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag );
 
1566
                                pm->ps->stats[STAT_HOLDABLE_ITEM] = 0;
 
1567
                        }
 
1568
                        return;
 
1569
                }
 
1570
        } else {
 
1571
                pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD;
 
1572
        }
 
1573
 
 
1574
 
 
1575
        // make weapon function
 
1576
        if ( pm->ps->weaponTime > 0 ) {
 
1577
                pm->ps->weaponTime -= pml.msec;
 
1578
        }
 
1579
 
 
1580
        // check for weapon change
 
1581
        // can't change if weapon is firing, but can change
 
1582
        // again if lowering or raising
 
1583
        if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
 
1584
                if ( pm->ps->weapon != pm->cmd.weapon ) {
 
1585
                        PM_BeginWeaponChange( pm->cmd.weapon );
 
1586
                }
 
1587
        }
 
1588
 
 
1589
        if ( pm->ps->weaponTime > 0 ) {
 
1590
                return;
 
1591
        }
 
1592
 
 
1593
        // change weapon if time
 
1594
        if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
 
1595
                PM_FinishWeaponChange();
 
1596
                return;
 
1597
        }
 
1598
 
 
1599
        if ( pm->ps->weaponstate == WEAPON_RAISING ) {
 
1600
                pm->ps->weaponstate = WEAPON_READY;
 
1601
                if ( pm->ps->weapon == WP_GAUNTLET ) {
 
1602
                        PM_StartTorsoAnim( TORSO_STAND2 );
 
1603
                } else {
 
1604
                        PM_StartTorsoAnim( TORSO_STAND );
 
1605
                }
 
1606
                return;
 
1607
        }
 
1608
 
 
1609
        // check for fire
 
1610
        if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) {
 
1611
                pm->ps->weaponTime = 0;
 
1612
                pm->ps->weaponstate = WEAPON_READY;
 
1613
                return;
 
1614
        }
 
1615
 
 
1616
        // start the animation even if out of ammo
 
1617
        if ( pm->ps->weapon == WP_GAUNTLET ) {
 
1618
                // the guantlet only "fires" when it actually hits something
 
1619
                if ( !pm->gauntletHit ) {
 
1620
                        pm->ps->weaponTime = 0;
 
1621
                        pm->ps->weaponstate = WEAPON_READY;
 
1622
                        return;
 
1623
                }
 
1624
                PM_StartTorsoAnim( TORSO_ATTACK2 );
 
1625
        } else {
 
1626
                PM_StartTorsoAnim( TORSO_ATTACK );
 
1627
        }
 
1628
 
 
1629
        pm->ps->weaponstate = WEAPON_FIRING;
 
1630
 
 
1631
        // check for out of ammo
 
1632
        if ( ! pm->ps->ammo[ pm->ps->weapon ] ) {
 
1633
                PM_AddEvent( EV_NOAMMO );
 
1634
                pm->ps->weaponTime += 500;
 
1635
                return;
 
1636
        }
 
1637
 
 
1638
        // take an ammo away if not infinite
 
1639
        if ( pm->ps->ammo[ pm->ps->weapon ] != -1 ) {
 
1640
                pm->ps->ammo[ pm->ps->weapon ]--;
 
1641
        }
 
1642
 
 
1643
        // fire weapon
 
1644
        PM_AddEvent( EV_FIRE_WEAPON );
 
1645
 
 
1646
        switch( pm->ps->weapon ) {
 
1647
        default:
 
1648
        case WP_GAUNTLET:
 
1649
                addTime = 400;
 
1650
                break;
 
1651
        case WP_LIGHTNING:
 
1652
                addTime = 50;
 
1653
                break;
 
1654
        case WP_SHOTGUN:
 
1655
                addTime = 1000;
 
1656
                break;
 
1657
        case WP_MACHINEGUN:
 
1658
                addTime = 100;
 
1659
                break;
 
1660
        case WP_GRENADE_LAUNCHER:
 
1661
                addTime = 800;
 
1662
                break;
 
1663
        case WP_ROCKET_LAUNCHER:
 
1664
                addTime = 800;
 
1665
                break;
 
1666
        case WP_PLASMAGUN:
 
1667
                addTime = 100;
 
1668
                break;
 
1669
        case WP_RAILGUN:
 
1670
                addTime = 1500;
 
1671
                break;
 
1672
        case WP_BFG:
 
1673
                addTime = 200;
 
1674
                break;
 
1675
        case WP_GRAPPLING_HOOK:
 
1676
                addTime = 400;
 
1677
                break;
 
1678
#ifdef MISSIONPACK
 
1679
        case WP_NAILGUN:
 
1680
                addTime = 1000;
 
1681
                break;
 
1682
        case WP_PROX_LAUNCHER:
 
1683
                addTime = 800;
 
1684
                break;
 
1685
        case WP_CHAINGUN:
 
1686
                addTime = 30;
 
1687
                break;
 
1688
#endif
 
1689
        }
 
1690
 
 
1691
#ifdef MISSIONPACK
 
1692
        if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
 
1693
                addTime /= 1.5;
 
1694
        }
 
1695
        else
 
1696
        if( bg_itemlist[pm->ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_AMMOREGEN ) {
 
1697
                addTime /= 1.3;
 
1698
  }
 
1699
  else
 
1700
#endif
 
1701
        if ( pm->ps->powerups[PW_HASTE] ) {
 
1702
                addTime /= 1.3;
 
1703
        }
 
1704
 
 
1705
        pm->ps->weaponTime += addTime;
 
1706
}
 
1707
 
 
1708
/*
 
1709
================
 
1710
PM_Animate
 
1711
================
 
1712
*/
 
1713
 
 
1714
static void PM_Animate( void ) {
 
1715
        if ( pm->cmd.buttons & BUTTON_GESTURE ) {
 
1716
                if ( pm->ps->torsoTimer == 0 ) {
 
1717
                        PM_StartTorsoAnim( TORSO_GESTURE );
 
1718
                        pm->ps->torsoTimer = TIMER_GESTURE;
 
1719
                        PM_AddEvent( EV_TAUNT );
 
1720
                }
 
1721
#ifdef MISSIONPACK
 
1722
        } else if ( pm->cmd.buttons & BUTTON_GETFLAG ) {
 
1723
                if ( pm->ps->torsoTimer == 0 ) {
 
1724
                        PM_StartTorsoAnim( TORSO_GETFLAG );
 
1725
                        pm->ps->torsoTimer = 600;       //TIMER_GESTURE;
 
1726
                }
 
1727
        } else if ( pm->cmd.buttons & BUTTON_GUARDBASE ) {
 
1728
                if ( pm->ps->torsoTimer == 0 ) {
 
1729
                        PM_StartTorsoAnim( TORSO_GUARDBASE );
 
1730
                        pm->ps->torsoTimer = 600;       //TIMER_GESTURE;
 
1731
                }
 
1732
        } else if ( pm->cmd.buttons & BUTTON_PATROL ) {
 
1733
                if ( pm->ps->torsoTimer == 0 ) {
 
1734
                        PM_StartTorsoAnim( TORSO_PATROL );
 
1735
                        pm->ps->torsoTimer = 600;       //TIMER_GESTURE;
 
1736
                }
 
1737
        } else if ( pm->cmd.buttons & BUTTON_FOLLOWME ) {
 
1738
                if ( pm->ps->torsoTimer == 0 ) {
 
1739
                        PM_StartTorsoAnim( TORSO_FOLLOWME );
 
1740
                        pm->ps->torsoTimer = 600;       //TIMER_GESTURE;
 
1741
                }
 
1742
        } else if ( pm->cmd.buttons & BUTTON_AFFIRMATIVE ) {
 
1743
                if ( pm->ps->torsoTimer == 0 ) {
 
1744
                        PM_StartTorsoAnim( TORSO_AFFIRMATIVE);
 
1745
                        pm->ps->torsoTimer = 600;       //TIMER_GESTURE;
 
1746
                }
 
1747
        } else if ( pm->cmd.buttons & BUTTON_NEGATIVE ) {
 
1748
                if ( pm->ps->torsoTimer == 0 ) {
 
1749
                        PM_StartTorsoAnim( TORSO_NEGATIVE );
 
1750
                        pm->ps->torsoTimer = 600;       //TIMER_GESTURE;
 
1751
                }
 
1752
#endif
 
1753
        }
 
1754
}
 
1755
 
 
1756
 
 
1757
/*
 
1758
================
 
1759
PM_DropTimers
 
1760
================
 
1761
*/
 
1762
static void PM_DropTimers( void ) {
 
1763
        // drop misc timing counter
 
1764
        if ( pm->ps->pm_time ) {
 
1765
                if ( pml.msec >= pm->ps->pm_time ) {
 
1766
                        pm->ps->pm_flags &= ~PMF_ALL_TIMES;
 
1767
                        pm->ps->pm_time = 0;
 
1768
                } else {
 
1769
                        pm->ps->pm_time -= pml.msec;
 
1770
                }
 
1771
        }
 
1772
 
 
1773
        // drop animation counter
 
1774
        if ( pm->ps->legsTimer > 0 ) {
 
1775
                pm->ps->legsTimer -= pml.msec;
 
1776
                if ( pm->ps->legsTimer < 0 ) {
 
1777
                        pm->ps->legsTimer = 0;
 
1778
                }
 
1779
        }
 
1780
 
 
1781
        if ( pm->ps->torsoTimer > 0 ) {
 
1782
                pm->ps->torsoTimer -= pml.msec;
 
1783
                if ( pm->ps->torsoTimer < 0 ) {
 
1784
                        pm->ps->torsoTimer = 0;
 
1785
                }
 
1786
        }
 
1787
}
 
1788
 
 
1789
/*
 
1790
================
 
1791
PM_UpdateViewAngles
 
1792
 
 
1793
This can be used as another entry point when only the viewangles
 
1794
are being updated isntead of a full move
 
1795
================
 
1796
*/
 
1797
void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
 
1798
        short           temp;
 
1799
        int             i;
 
1800
 
 
1801
        if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) {
 
1802
                return;         // no view changes at all
 
1803
        }
 
1804
 
 
1805
        if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) {
 
1806
                return;         // no view changes at all
 
1807
        }
 
1808
 
 
1809
        // circularly clamp the angles with deltas
 
1810
        for (i=0 ; i<3 ; i++) {
 
1811
                temp = cmd->angles[i] + ps->delta_angles[i];
 
1812
                if ( i == PITCH ) {
 
1813
                        // don't let the player look up or down more than 90 degrees
 
1814
                        if ( temp > 16000 ) {
 
1815
                                ps->delta_angles[i] = 16000 - cmd->angles[i];
 
1816
                                temp = 16000;
 
1817
                        } else if ( temp < -16000 ) {
 
1818
                                ps->delta_angles[i] = -16000 - cmd->angles[i];
 
1819
                                temp = -16000;
 
1820
                        }
 
1821
                }
 
1822
                ps->viewangles[i] = SHORT2ANGLE(temp);
 
1823
        }
 
1824
 
 
1825
}
 
1826
 
 
1827
 
 
1828
/*
 
1829
================
 
1830
PmoveSingle
 
1831
 
 
1832
================
 
1833
*/
 
1834
void trap_SnapVector( float *v );
 
1835
 
 
1836
void PmoveSingle (pmove_t *pmove) {
 
1837
        pm = pmove;
 
1838
 
 
1839
        // this counter lets us debug movement problems with a journal
 
1840
        // by setting a conditional breakpoint fot the previous frame
 
1841
        c_pmove++;
 
1842
 
 
1843
        // clear results
 
1844
        pm->numtouch = 0;
 
1845
        pm->watertype = 0;
 
1846
        pm->waterlevel = 0;
 
1847
 
 
1848
        if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
 
1849
                pm->tracemask &= ~CONTENTS_BODY;        // corpses can fly through bodies
 
1850
        }
 
1851
 
 
1852
        // make sure walking button is clear if they are running, to avoid
 
1853
        // proxy no-footsteps cheats
 
1854
        if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) {
 
1855
                pm->cmd.buttons &= ~BUTTON_WALKING;
 
1856
        }
 
1857
 
 
1858
        // set the talk balloon flag
 
1859
        if ( pm->cmd.buttons & BUTTON_TALK ) {
 
1860
                pm->ps->eFlags |= EF_TALK;
 
1861
        } else {
 
1862
                pm->ps->eFlags &= ~EF_TALK;
 
1863
        }
 
1864
 
 
1865
        // set the firing flag for continuous beam weapons
 
1866
        if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION
 
1867
                && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) {
 
1868
                pm->ps->eFlags |= EF_FIRING;
 
1869
        } else {
 
1870
                pm->ps->eFlags &= ~EF_FIRING;
 
1871
        }
 
1872
 
 
1873
        // clear the respawned flag if attack and use are cleared
 
1874
        if ( pm->ps->stats[STAT_HEALTH] > 0 && 
 
1875
                !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) {
 
1876
                pm->ps->pm_flags &= ~PMF_RESPAWNED;
 
1877
        }
 
1878
 
 
1879
        // if talk button is down, dissallow all other input
 
1880
        // this is to prevent any possible intercept proxy from
 
1881
        // adding fake talk balloons
 
1882
        if ( pmove->cmd.buttons & BUTTON_TALK ) {
 
1883
                // keep the talk button set tho for when the cmd.serverTime > 66 msec
 
1884
                // and the same cmd is used multiple times in Pmove
 
1885
                pmove->cmd.buttons = BUTTON_TALK;
 
1886
                pmove->cmd.forwardmove = 0;
 
1887
                pmove->cmd.rightmove = 0;
 
1888
                pmove->cmd.upmove = 0;
 
1889
        }
 
1890
 
 
1891
        // clear all pmove local vars
 
1892
        memset (&pml, 0, sizeof(pml));
 
1893
 
 
1894
        // determine the time
 
1895
        pml.msec = pmove->cmd.serverTime - pm->ps->commandTime;
 
1896
        if ( pml.msec < 1 ) {
 
1897
                pml.msec = 1;
 
1898
        } else if ( pml.msec > 200 ) {
 
1899
                pml.msec = 200;
 
1900
        }
 
1901
        pm->ps->commandTime = pmove->cmd.serverTime;
 
1902
 
 
1903
        // save old org in case we get stuck
 
1904
        VectorCopy (pm->ps->origin, pml.previous_origin);
 
1905
 
 
1906
        // save old velocity for crashlanding
 
1907
        VectorCopy (pm->ps->velocity, pml.previous_velocity);
 
1908
 
 
1909
        pml.frametime = pml.msec * 0.001;
 
1910
 
 
1911
        // update the viewangles
 
1912
        PM_UpdateViewAngles( pm->ps, &pm->cmd );
 
1913
 
 
1914
        AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up);
 
1915
 
 
1916
        if ( pm->cmd.upmove < 10 ) {
 
1917
                // not holding jump
 
1918
                pm->ps->pm_flags &= ~PMF_JUMP_HELD;
 
1919
        }
 
1920
 
 
1921
        // decide if backpedaling animations should be used
 
1922
        if ( pm->cmd.forwardmove < 0 ) {
 
1923
                pm->ps->pm_flags |= PMF_BACKWARDS_RUN;
 
1924
        } else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) {
 
1925
                pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;
 
1926
        }
 
1927
 
 
1928
        if ( pm->ps->pm_type >= PM_DEAD ) {
 
1929
                pm->cmd.forwardmove = 0;
 
1930
                pm->cmd.rightmove = 0;
 
1931
                pm->cmd.upmove = 0;
 
1932
        }
 
1933
 
 
1934
        if ( pm->ps->pm_type == PM_SPECTATOR ) {
 
1935
                PM_CheckDuck ();
 
1936
                PM_FlyMove ();
 
1937
                PM_DropTimers ();
 
1938
                return;
 
1939
        }
 
1940
 
 
1941
        if ( pm->ps->pm_type == PM_NOCLIP ) {
 
1942
                PM_NoclipMove ();
 
1943
                PM_DropTimers ();
 
1944
                return;
 
1945
        }
 
1946
 
 
1947
        if (pm->ps->pm_type == PM_FREEZE) {
 
1948
                return;         // no movement at all
 
1949
        }
 
1950
 
 
1951
        if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION) {
 
1952
                return;         // no movement at all
 
1953
        }
 
1954
 
 
1955
        // set watertype, and waterlevel
 
1956
        PM_SetWaterLevel();
 
1957
        pml.previous_waterlevel = pmove->waterlevel;
 
1958
 
 
1959
        // set mins, maxs, and viewheight
 
1960
        PM_CheckDuck ();
 
1961
 
 
1962
        // set groundentity
 
1963
        PM_GroundTrace();
 
1964
 
 
1965
        if ( pm->ps->pm_type == PM_DEAD ) {
 
1966
                PM_DeadMove ();
 
1967
        }
 
1968
 
 
1969
        PM_DropTimers();
 
1970
 
 
1971
#ifdef MISSIONPACK
 
1972
        if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
 
1973
                PM_InvulnerabilityMove();
 
1974
        } else
 
1975
#endif
 
1976
        if ( pm->ps->powerups[PW_FLIGHT] ) {
 
1977
                // flight powerup doesn't allow jump and has different friction
 
1978
                PM_FlyMove();
 
1979
        } else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {
 
1980
                PM_GrappleMove();
 
1981
                // We can wiggle a bit
 
1982
                PM_AirMove();
 
1983
        } else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) {
 
1984
                PM_WaterJumpMove();
 
1985
        } else if ( pm->waterlevel > 1 ) {
 
1986
                // swimming
 
1987
                PM_WaterMove();
 
1988
        } else if ( pml.walking ) {
 
1989
                // walking on ground
 
1990
                PM_WalkMove();
 
1991
        } else {
 
1992
                // airborne
 
1993
                PM_AirMove();
 
1994
        }
 
1995
 
 
1996
        PM_Animate();
 
1997
 
 
1998
        // set groundentity, watertype, and waterlevel
 
1999
        PM_GroundTrace();
 
2000
        PM_SetWaterLevel();
 
2001
 
 
2002
        // weapons
 
2003
        PM_Weapon();
 
2004
 
 
2005
        // torso animation
 
2006
        PM_TorsoAnimation();
 
2007
 
 
2008
        // footstep events / legs animations
 
2009
        PM_Footsteps();
 
2010
 
 
2011
        // entering / leaving water splashes
 
2012
        PM_WaterEvents();
 
2013
 
 
2014
        // snap some parts of playerstate to save network bandwidth
 
2015
        trap_SnapVector( pm->ps->velocity );
 
2016
}
 
2017
 
 
2018
 
 
2019
/*
 
2020
================
 
2021
Pmove
 
2022
 
 
2023
Can be called by either the server or the client
 
2024
================
 
2025
*/
 
2026
void Pmove (pmove_t *pmove) {
 
2027
        int                     finalTime;
 
2028
 
 
2029
        finalTime = pmove->cmd.serverTime;
 
2030
 
 
2031
        if ( finalTime < pmove->ps->commandTime ) {
 
2032
                return; // should not happen
 
2033
        }
 
2034
 
 
2035
        if ( finalTime > pmove->ps->commandTime + 1000 ) {
 
2036
                pmove->ps->commandTime = finalTime - 1000;
 
2037
        }
 
2038
 
 
2039
        pmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<<PS_PMOVEFRAMECOUNTBITS)-1);
 
2040
 
 
2041
        // chop the move up if it is too long, to prevent framerate
 
2042
        // dependent behavior
 
2043
        while ( pmove->ps->commandTime != finalTime ) {
 
2044
                int             msec;
 
2045
 
 
2046
                msec = finalTime - pmove->ps->commandTime;
 
2047
 
 
2048
                if ( pmove->pmove_fixed ) {
 
2049
                        if ( msec > pmove->pmove_msec ) {
 
2050
                                msec = pmove->pmove_msec;
 
2051
                        }
 
2052
                }
 
2053
                else {
 
2054
                        if ( msec > 66 ) {
 
2055
                                msec = 66;
 
2056
                        }
 
2057
                }
 
2058
                pmove->cmd.serverTime = pmove->ps->commandTime + msec;
 
2059
                PmoveSingle( pmove );
 
2060
 
 
2061
                if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) {
 
2062
                        pmove->cmd.upmove = 20;
 
2063
                }
 
2064
        }
 
2065
 
 
2066
        //PM_CheckStuck();
 
2067
 
 
2068
}
 
2069