1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: p_user.c 1513 2020-04-18 10:49:18Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2000 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: p_user.c,v $
21 // Revision 1.17 2004/07/27 08:19:37 exl
22 // New fmod, fs functions, bugfix or 2, patrol nodes
23 //
24 // Revision 1.16 2003/07/14 12:37:54 darkwolf95
25 // Fixed bug where frags don't display for Player 2 on death while in splitscreen.
26 //
27 // Revision 1.15 2001/05/27 13:42:48 bpereira
28 //
29 // Revision 1.14 2001/04/04 20:24:21 judgecutor
30 // Added support for the 3D Sound
31 //
32 // Revision 1.13 2001/03/03 06:17:33 bpereira
33 // Revision 1.12 2001/01/27 11:02:36 bpereira
34 //
35 // Revision 1.11 2001/01/25 22:15:44 bpereira
36 // added heretic support
37 //
38 // Revision 1.10 2000/11/04 16:23:43 bpereira
39 //
40 // Revision 1.9 2000/11/02 17:50:09 stroggonmeth
41 // Big 3Dfloors & FraggleScript commit!!
42 //
43 // Revision 1.8 2000/10/21 08:43:31 bpereira
44 // Revision 1.7 2000/08/31 14:30:56 bpereira
45 // Revision 1.6 2000/08/03 17:57:42 bpereira
46 // Revision 1.5 2000/04/23 16:19:52 bpereira
47 // Revision 1.4 2000/04/16 18:38:07 bpereira
48 // Revision 1.3 2000/03/29 19:39:48 bpereira
49 // Revision 1.2 2000/02/27 00:42:10 hurdler
50 // Revision 1.1.1.1 2000/02/22 20:32:32 hurdler
51 // Initial import into CVS (v1.29 pr3)
52 //
53 //
54 // DESCRIPTION:
55 // Player related stuff.
56 // Bobbing POV/weapon, movement.
57 // Pending weapon.
58 //
59 //-----------------------------------------------------------------------------
60
61 #include "doomincl.h"
62 #include "d_event.h"
63 #include "g_game.h"
64 #include "p_local.h"
65 #include "r_main.h"
66 #include "r_things.h"
67 // skins
68 #include "s_sound.h"
69 #include "p_setup.h"
70 #include "p_inter.h"
71 #include "m_random.h"
72
73 #include "hardware/hw3sound.h"
74
75
76 // Index of the special effects (INVUL inverse) map.
77 #define INVERSECOLORMAP 32
78
79
80 //
81 // Movement.
82 //
83
84 // 16 pixels of bob
85 #define MAXBOB 0x100000
86
87 //added:22-02-98: initial momz when player jumps (moves up)
88 fixed_t jumpgravity = (6*FRACUNIT/NEWTICRATERATIO); // variable by fragglescript
89
90 boolean onground;
91 int extramovefactor = 0;
92
93
94 //
95 // P_Thrust
96 // Moves the given origin along a given angle.
97 //
P_Thrust(player_t * player,angle_t angle,fixed_t move)98 void P_Thrust(player_t *player, angle_t angle, fixed_t move)
99 {
100 mobj_t * pmo = player->mo;
101 #if 0
102 // friction and movefactor are now sector attributes
103 if(pmo->subsector->sector->special == 15 // heretic ice
104 && !(player->powers[pw_flight] && (pmo->z > pmo->floorz)))
105 {
106 move>>=2; // Friction_Low
107 }
108 #endif
109 pmo->momx += FixedMul(move, cosine_ANG(angle));
110 pmo->momy += FixedMul(move, sine_ANG(angle));
111 }
112
113
114 // P_Thrust_Bob
115 // [WDJ] Thrust and independent bob.
116 // Contribute to bob effort, independent of thrust momentum.
117 // Do not bob when riding along on conveyors, or sliding, even though moving.
118 // Bob is adapted for effort in mud and ice by the caller.
119
P_Thrust_Bob(player_t * player,angle_t angle,fixed_t moveth,fixed_t movebob)120 static void P_Thrust_Bob( player_t * player, angle_t angle, fixed_t moveth, fixed_t movebob )
121 {
122 int angf = ANGLE_TO_FINE( angle );
123 // thrust
124 player->mo->momx += FixedMul(moveth, finecosine[angf]);
125 player->mo->momy += FixedMul(moveth, finesine[angf]);
126 // bob
127 player->bob_momx += FixedMul(movebob, finecosine[angf]);
128 player->bob_momy += FixedMul(movebob, finesine[angf]);
129 }
130
131
132
133 #ifdef CLIENTPREDICTION2
134 //
135 // P_ThrustSpirit
136 // Moves the given origin along a given angle.
137 //
P_ThrustSpirit(player_t * player,angle_t angle,fixed_t move)138 void P_ThrustSpirit(player_t *player, angle_t angle, fixed_t move)
139 {
140 #if 0
141 // friction and movefactor are now sector attributes
142 if(player->spirit->subsector->sector->special == 15
143 && !(player->powers[pw_flight] && !(player->spirit->z <= player->spirit->floorz))) // Friction_Low
144 {
145 move>>=2; // Friction_Low
146 }
147 #endif
148 player->spirit->momx += FixedMul(move, cosine_ANG(angle));
149 player->spirit->momy += FixedMul(move, sine_ANG(angle));
150 }
151 #endif
152
153
154 static fixed_t prev_viewheight = -1; // detect changes in cv_viewheight
155
156 //
157 // P_CalcHeight
158 // Calculate the walking / running height adjustment
159 //
160 // Called from P_PlayerThink after P_PlayerMove
161 // Called from P_MoveSpirit from Local_Maketic
162 // Called from P_DeathThink from P_PlayerThink, without P_PlayerMove
P_CalcHeight(player_t * player)163 void P_CalcHeight (player_t* player)
164 {
165 int angle;
166 fixed_t bob;
167 fixed_t calc_viewheight, on_floor_viewheight;
168 mobj_t * pmo = player->mo;
169 mobj_t * smo = pmo; // spirit (same as pmo unless using CLIENTPREDICTION2)
170
171 // Regular movement bobbing
172 // (needs to be calculated for gun swing even if not on ground)
173 // OPTIMIZE: tablify angle
174 // Note: a LUT allows for effects like a ramp with low health.
175
176 #ifdef CLIENTPREDICTION2
177 if( player->spirit )
178 smo = player->spirit;
179 #endif
180
181 player->bob = ((FixedMul (player->bob_momx,player->bob_momx)
182 +FixedMul (player->bob_momy,player->bob_momy))*NEWTICRATERATIO)>>2;
183
184 // [WDJ] Boom 2.02, when on ice, limited bob to MAXBOB>>2.
185 // Moving onto ice would cause sudden bob position change.
186 // Went obsolete with MBF player bob.
187
188 if (player->bob>MAXBOB)
189 player->bob = MAXBOB;
190
191 // from heretic
192 if( pmo->flags2&MF2_FLY && !onground )
193 player->bob = FRACUNIT/2;
194
195 if (player->cheats & CF_NOMOMENTUM) // as in heretic because of fly bob
196 {
197 //added:15-02-98: it seems to be useless code!
198 //player->viewz = pmo->z + (((unsigned int)cv_viewheight.EV)<<FRACBITS);
199
200 //if (player->viewz > pmo->ceilingz-4*FRACUNIT)
201 // player->viewz = pmo->ceilingz-4*FRACUNIT;
202 player->viewz = smo->z + player->viewheight;
203 return;
204 }
205
206 if( EV_legacy )
207 #ifdef CLIENTPREDICTION2
208 angle = (FINEANGLES/20*localgametic/NEWTICRATERATIO)&FINEMASK;
209 #else
210 angle = (FINEANGLES/20*leveltime/NEWTICRATERATIO)&FINEMASK;
211 #endif
212 else
213 angle = (FINEANGLES/20*leveltime)&FINEMASK;
214 bob = FixedMul ( player->bob/2, finesine[angle]);
215
216 // move viewheight
217 calc_viewheight = ((unsigned int)cv_viewheight.EV) << FRACBITS; // default eye view height
218
219 // The original was designed for a constant viewheight.
220 // Some users want to vary it during play using fragglescript.
221 if (player->playerstate == PST_LIVE)
222 {
223 on_floor_viewheight = calc_viewheight;
224
225 if (calc_viewheight != prev_viewheight)
226 {
227 // cv_viewheight has changed
228 if ( prev_viewheight < 0 )
229 {
230 player->viewheight = calc_viewheight; // init quickly
231 }
232 else
233 {
234 // provide a gradual viewheight change
235 fixed_t dv = (calc_viewheight - prev_viewheight) >> 3;
236 // when dv == 0, let through unaltered viewheight,
237 // otherwise altered viewheight keeps retriggering this code
238 if (dv)
239 calc_viewheight = prev_viewheight + dv; // slow rise and fall
240 on_floor_viewheight = prev_viewheight; // lessen falling effect
241 player->deltaviewheight = (calc_viewheight - player->viewheight) >> 3;
242 }
243 prev_viewheight = calc_viewheight;
244 }
245
246 player->viewheight += player->deltaviewheight;
247
248 if (player->viewheight > on_floor_viewheight)
249 {
250 // player feet not on floor, so fall to viewheight
251 player->viewheight = calc_viewheight;
252 player->deltaviewheight = 0;
253 }
254
255 if (player->viewheight < calc_viewheight/2)
256 {
257 // rise from floor
258 player->viewheight = calc_viewheight/2;
259 if (player->deltaviewheight <= 0)
260 player->deltaviewheight = 1;
261 }
262
263 // changers of viewheight will have also set deltaviewheight
264 if (player->deltaviewheight)
265 {
266 player->deltaviewheight += FRACUNIT/4;
267 if (!player->deltaviewheight)
268 player->deltaviewheight = 1;
269 }
270 }
271
272 if(player->chickenTics) // heretic chicken morph
273 player->viewz = smo->z + player->viewheight-(20*FRACUNIT);
274 else
275 player->viewz = smo->z + player->viewheight + bob;
276
277 if(pmo->flags2&MF2_FEETARECLIPPED
278 && player->playerstate != PST_DEAD
279 && pmo->z <= pmo->floorz)
280 {
281 player->viewz -= FOOTCLIPSIZE;
282 }
283
284 if (player->viewz > smo->ceilingz-4*FRACUNIT)
285 player->viewz = smo->ceilingz-4*FRACUNIT;
286 if (player->viewz < smo->floorz+4*FRACUNIT)
287 player->viewz = smo->floorz+4*FRACUNIT;
288 }
289
290
291
292 static byte EN_move_doom = 0;
293 static byte EN_cmd_abs_angle = 1; // legacy absolute angle commands
294
295 // local version control
DemoAdapt_p_user(void)296 void DemoAdapt_p_user( void )
297 {
298 // Move for Doom, Boom, MBF demo
299 EN_move_doom =
300 EN_doom_etc
301 && (EV_legacy < 128); // Legacy demo, orig Doom, Boom, MBF
302
303 // abs angle in legacy demos only
304 EN_cmd_abs_angle = (EV_legacy >= 125);
305 }
306
307
308 //
309 // P_MovePlayer
310 //
311 // Called from P_PlayerThink
P_MovePlayer(player_t * player)312 void P_MovePlayer (player_t* player)
313 {
314 mobj_t * pmo = player->mo;
315 ticcmd_t* cmd = &player->cmd;
316 int movefactor = ORIG_FRICTION_FACTOR; // default
317 int bobfactor = ORIG_FRICTION_FACTOR;
318
319 if(EN_cmd_abs_angle)
320 pmo->angle = (cmd->angleturn<<16);
321 else
322 pmo->angle += (cmd->angleturn<<16);
323
324 stat_tic_moved++;
325 #ifdef TICCMD_148
326 if( (cmd->ticflags & TC_received) == 0)
327 stat_tic_miss++;
328 #else
329 if( (cmd->angleturn & TICCMD_RECEIVED) == 0)
330 stat_tic_miss++;
331 #endif
332
333 // Do not let the player control movement
334 // if not onground.
335 onground = (pmo->z <= pmo->floorz)
336 || (pmo->flags & MF_BOUNCES) // MBF
337 || (pmo->flags2&(MF2_ONMOBJ|MF2_FLY)) // heretic
338 || (player->cheats & CF_FLYAROUND); // cheat
339
340 if(EN_variable_friction && onground)
341 {
342 movefactor = P_GetMoveFactor(pmo); // gets got_movefactor, got_friction
343 // CONS_Printf("friction: %X, movefactor: %i\n", got_friction, movefactor);
344
345 // [WDJ] bobfactor from killough, via prboom, adapted to legacy.
346 // killough 11/98:
347 // On sludge, make bobbing depend on efficiency.
348 // On ice, make it depend on effort.
349
350 // [WDJ] Test the friction and movefactor from GetMovefactor.
351 bobfactor = (got_friction < ORIG_FRICTION) ?
352 got_movefactor // mud
353 : ORIG_FRICTION_FACTOR; // ice (killough)
354 // : (ORIG_FRICTION_FACTOR + got_movefactor)/2; // ice [WDJ]
355
356 }
357
358 if (!onground)
359 bobfactor >>= 2; // air and underwater
360 else if (pmo->eflags & MF_UNDERWATER)
361 bobfactor >>= 1;
362
363 if( EN_move_doom )
364 {
365 // Doom, Boom, MBF movement
366 boolean jumpover = player->cheats & CF_JUMPOVER; // legacy cheat
367 if (cmd->forwardmove && (onground || jumpover))
368 {
369 // dirty hack to let the player avatar walk over a small wall
370 // while in the air
371 if (jumpover)
372 {
373 if(pmo->momz > 0)
374 P_Thrust (player, pmo->angle, 5*movefactor);
375 }
376 else
377 {
378 P_Thrust_Bob( player, pmo->angle, cmd->forwardmove*movefactor, cmd->forwardmove*bobfactor );
379 }
380 }
381
382 if (cmd->sidemove && onground)
383 {
384 P_Thrust_Bob( player, pmo->angle-ANG90, cmd->sidemove*movefactor, cmd->sidemove*bobfactor );
385 }
386
387 player->aiming = (signed char)cmd->aiming;
388 }
389 else
390 {
391 // most current
392 fixed_t movepushforward=0, movepushside=0;
393 player->aiming = cmd->aiming<<16;
394 if( player->chickenTics )
395 {
396 // [WDJ] Moved to after other movefactor, so it can have some effect.
397 // movefactor = 2500; // heretic chicken
398 // Modify movefactor to chicken size, (chicken on ice)
399 movefactor = movefactor * 625 / 512;
400 // * 2500 / 2048
401 }
402
403 if (cmd->forwardmove)
404 {
405 movepushforward = cmd->forwardmove * (movefactor + extramovefactor);
406
407 if (pmo->eflags & MF_UNDERWATER)
408 {
409 // half forward speed when waist under water
410 // a little better grip if feets touch the ground
411 if (!onground)
412 movepushforward >>= 1;
413 else
414 movepushforward = movepushforward *3/4;
415 }
416 else
417 {
418 // allow very small movement while in air for gameplay
419 if (!onground)
420 movepushforward >>= 3;
421 }
422
423 P_Thrust_Bob( player, pmo->angle, movepushforward, cmd->forwardmove*bobfactor);
424 }
425
426 if (cmd->sidemove)
427 {
428 movepushside = cmd->sidemove * (movefactor + extramovefactor);
429 if (pmo->eflags & MF_UNDERWATER)
430 {
431 if (!onground)
432 movepushside >>= 1;
433 else
434 movepushside = movepushside *3/4;
435 }
436 else
437 {
438 if (!onground)
439 movepushside >>= 3;
440 }
441
442 P_Thrust_Bob( player, pmo->angle-ANG90, movepushside, cmd->sidemove*bobfactor);
443 }
444
445 // mouselook swim when waist underwater
446 pmo->eflags &= ~MF_SWIMMING;
447 if (pmo->eflags & MF_UNDERWATER)
448 {
449 fixed_t a;
450 // swim up/down full move when forward full speed
451 a = FixedMul( movepushforward*50, sine_ANG(player->aiming) >>5 );
452
453 if ( a != 0 ) {
454 pmo->eflags |= MF_SWIMMING;
455 pmo->momz += a;
456 }
457 }
458 }
459
460 //added:22-02-98: jumping
461 if (cmd->buttons & BT_JUMP)
462 {
463 if( pmo->flags2&MF2_FLY )
464 player->flyheight = 10;
465 else
466 if(pmo->eflags & MF_UNDERWATER)
467 //TODO: goub gloub when push up in water
468 pmo->momz = jumpgravity/2;
469 else
470 // can't jump while in air, can't jump while jumping
471 if( onground && !(player->jumpdown & 1))
472 {
473 pmo->momz = jumpgravity;
474 if( !(player->cheats & CF_FLYAROUND) )
475 {
476 S_StartScreamSound (pmo, sfx_jump);
477 // keep jumping ok if FLY mode.
478 player->jumpdown |= 1;
479 }
480 }
481 }
482 else
483 player->jumpdown &= ~1;
484
485
486 if (cmd->forwardmove || cmd->sidemove)
487 {
488 if( player->chickenTics )
489 {
490 if( pmo->state == &states[S_CHICPLAY])
491 P_SetMobjState(pmo, S_CHICPLAY_RUN1);
492 }
493 else
494 if(pmo->state == &states[S_PLAY])
495 P_SetMobjState(pmo, S_PLAY_RUN1);
496 }
497 #ifdef TICCMD_148
498 if( EN_heretic && (cmd->ticflags & TC_flydown) )
499 #else
500 if( EN_heretic && (cmd->angleturn & BT_FLYDOWN) )
501 #endif
502 {
503 player->flyheight = -10;
504 }
505 /* HERETODO
506 fly = cmd->lookfly>>4;
507 if(fly > 7)
508 fly -= 16;
509 if(fly && player->powers[pw_flight])
510 {
511 if(fly != TOCENTER)
512 {
513 player->flyheight = fly*2;
514 if(!(pmo->flags2&MF2_FLY))
515 {
516 pmo->flags2 |= MF2_FLY;
517 pmo->flags |= MF_NOGRAVITY;
518 }
519 }
520 else
521 {
522 pmo->flags2 &= ~MF2_FLY;
523 pmo->flags &= ~MF_NOGRAVITY;
524 }
525 }
526 else if(fly > 0)
527 {
528 P_PlayerUseArtifact(player, arti_fly);
529 }*/
530 if(pmo->flags2&MF2_FLY)
531 {
532 pmo->momz = player->flyheight*FRACUNIT;
533 if(player->flyheight)
534 player->flyheight /= 2;
535 }
536 }
537
538
539
540 //
541 // P_DeathThink
542 // Fall on your face when dying.
543 // Decrease POV height to floor height.
544 //
545 #define ANG5 (ANG90/18)
546
P_DeathThink(player_t * player)547 void P_DeathThink (player_t* player)
548 {
549 mobj_t * pmo = player->mo;
550 angle_t angle;
551
552 P_MovePsprites (player);
553
554 // fall to the ground
555 if (player->viewheight > 6*FRACUNIT)
556 player->viewheight -= FRACUNIT;
557
558 if (player->viewheight < 6*FRACUNIT)
559 player->viewheight = 6*FRACUNIT;
560
561 player->deltaviewheight = 0;
562 onground = pmo->z <= pmo->floorz;
563
564 P_CalcHeight (player);
565
566 mobj_t *attacker = player->attacker;
567
568 // watch my killer (if there is one)
569 if (attacker && attacker != pmo)
570 {
571 angle = R_PointToAngle2 (pmo->x,
572 pmo->y,
573 player->attacker->x,
574 player->attacker->y);
575
576 angle_t delta = angle - pmo->angle;
577
578 if (delta < ANG5 || delta > (unsigned)-ANG5)
579 {
580 // Looking at killer,
581 // so fade damage flash down.
582 pmo->angle = angle;
583
584 if (player->damagecount)
585 player->damagecount--;
586 }
587 else if (delta < ANG180)
588 pmo->angle += ANG5;
589 else
590 pmo->angle -= ANG5;
591
592 //added:22-02-98:
593 // change aiming to look up or down at the attacker (DOESNT WORK)
594 // FIXME : the aiming returned seems to be too up or down... later
595 /*
596 fixed_t dist = P_AproxDistance(attacker->x - pmo->x, attacker->y - pmo->y);
597 fixed_t dz = attacker->z +(attacker->height>>1) -pmo->z;
598 angle_t pitch = 0;
599 if (dist)
600 pitch = ArcTan(FixedDiv(dz, dist));
601 */
602 int32_t pitch = (attacker->z - pmo->z)>>17;
603 player->aiming = G_ClipAimingPitch(pitch);
604
605 }
606 else if (player->damagecount)
607 player->damagecount--;
608
609 if (player->cmd.buttons & BT_USE)
610 {
611 player->playerstate = PST_REBORN;
612 pmo->special2 = 666;
613 }
614 }
615
616 //----------------------------------------------------------------------------
617 //
618 // PROC P_ChickenPlayerThink
619 //
620 //----------------------------------------------------------------------------
621
P_ChickenPlayerThink(player_t * player)622 void P_ChickenPlayerThink(player_t *player)
623 {
624 mobj_t * pmo = player->mo;
625
626 if(player->health > 0)
627 { // Handle beak movement
628 P_UpdateBeak(player, &player->psprites[ps_weapon]);
629 }
630 if(player->chickenTics&15)
631 {
632 return;
633 }
634 // Heretic uses of P_Random
635 if(!(pmo->momx+pmo->momy) && PP_Random(ph_chickenthink) < 160)
636 { // Twitch view angle
637 pmo->angle += PP_SignedRandom(ph_chickenthink)<<19;
638 }
639 if((pmo->z <= pmo->floorz) && (PP_Random(ph_chickenthink) < 32))
640 { // Jump and noise
641 pmo->momz += FRACUNIT;
642 P_SetMobjState(pmo, S_CHICPLAY_PAIN);
643 return;
644 }
645 if(PP_Random(ph_chickenthink) < 48)
646 { // Just noise
647 S_StartScreamSound(pmo, sfx_chicact);
648 }
649 }
650
651 //----------------------------------------------------------------------------
652 //
653 // FUNC P_UndoPlayerChicken
654 //
655 //----------------------------------------------------------------------------
656
657 // [WDJ] Fixed to keep the same player mobj.
658 // Used to change the player mobj, and hide the prev as a corpse above
659 // the ceiling using S_FREETARGMOBJ.
P_UndoPlayerChicken(player_t * player)660 boolean P_UndoPlayerChicken(player_t *player)
661 {
662 mobj_t *fog;
663 mobj_t * pmo = player->mo;
664 weapontype_t weapon;
665 int oldflags2;
666
667 weapon = pmo->special1; // saved by player morph
668 oldflags2 = pmo->flags2;
669 // Morph back into player
670 if( ! P_MorphMobj(pmo, MT_PLAYER, MM_testsize,
671 #ifdef PLAYER_CHICKEN_KEEPS_SHADOW
672 MF_SHADOW
673 #else
674 0
675 #endif
676 ) )
677 { // Didn't fit
678 player->chickenTics = 2*35; // retry later
679 return false;
680 }
681 if(oldflags2&MF2_FLY) // preserve fly flags
682 {
683 pmo->flags2 |= MF2_FLY;
684 pmo->flags |= MF_NOGRAVITY;
685 }
686 // Restore player skin and skincolor.
687 pmo->skin = skins[player->skin]; // restore player skin
688 pmo->tflags |= (player->skincolor) << MFT_TRANSSHIFT;
689 pmo->reactiontime = 18;
690 player->chickenTics = 0;
691 #ifndef PLAYER_CHICKEN_KEEPS_SHADOW
692 // Not in vanilla Heretic, but implied by clearing MF_SHADOW.
693 // Legacy2 clears it.
694 player->powers[pw_invisibility] = 0;
695 #endif
696 player->powers[pw_weaponlevel2] = 0;
697 player->weaponinfo = wpnlev1info;
698 player->health = pmo->health = MAXHEALTH;
699
700 // This telefog is placed differently than others.
701 int angf = ANGLE_TO_FINE( pmo->angle );
702 fog = P_SpawnMobj(pmo->x+20*finecosine[angf], pmo->y+20*finesine[angf],
703 pmo->z+TELEFOGHEIGHT, MT_TFOG);
704 S_StartObjSound(fog, sfx_telept);
705 P_PostChickenWeapon(player, weapon);
706 return true;
707 }
708
709 //
710 // P_MoveCamera : make sure the camera is not outside the world
711 // and looks at the player avatar
712 //
713
714 // [WDJ] There is only one camera, so when there are two players, it can
715 // only be used as chase camera for one, and that is player1
716 // It now records who it is chasing.
717 camera_t camera;
718
719 //#define VIEWCAM_DIST (128<<FRACBITS)
720 //#define VIEWCAM_HEIGHT (20<<FRACBITS)
721
722 consvar_t cv_cam_dist = {"cam_dist" ,"128" ,CV_FLOAT,NULL};
723 consvar_t cv_cam_height = {"cam_height", "20" ,CV_FLOAT,NULL};
724 consvar_t cv_cam_speed = {"cam_speed" , "0.25",CV_FLOAT,NULL};
725
P_ResetCamera(player_t * player)726 void P_ResetCamera (player_t *player)
727 {
728 fixed_t x,y,z;
729
730 camera.chase = player;
731 x = player->mo->x;
732 y = player->mo->y;
733 z = player->mo->z + (((unsigned int)cv_viewheight.EV)<<FRACBITS);
734
735 // hey we should make sure that the sounds are heard from the camera
736 // instead of the marine's head : TO DO
737
738 // set bits for the camera object
739 if (!camera.mo)
740 camera.mo = P_SpawnMobj (x,y,z, MT_CHASECAM);
741 else
742 {
743 camera.mo->x = x;
744 camera.mo->y = y;
745 camera.mo->z = z;
746 }
747
748 camera.mo->angle = player->mo->angle;
749 camera.aiming = 0;
750 }
751
752 // Unused
753 #if 0
754 fixed_t cameraz;
755
756 boolean PTR_FindCameraPoint (intercept_t* in)
757 {
758 // Disabled all except return false
759 #if 0
760 int side;
761 fixed_t slope;
762 fixed_t dist;
763 line_t* li;
764
765 li = in->d.line;
766
767 if ( !(li->flags & ML_TWOSIDED) )
768 return false;
769
770 // crosses a two sided line
771 //added:16-02-98: Fab comments : sets opentop, openbottom, openrange
772 // lowfloor is the height of the lowest floor
773 // (be it front or back)
774 P_LineOpening (li);
775
776 dist = FixedMul (attackrange, in->frac);
777
778 if (li->frontsector->floorheight != li->backsector->floorheight)
779 {
780 //added:18-02-98: comments :
781 // find the slope aiming on the border between the two floors
782 slope = FixedDiv (openbottom - cameraz , dist);
783 if (slope > aimslope)
784 return false;
785 }
786
787 if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
788 {
789 slope = FixedDiv (opentop - shootz , dist);
790 if (slope < aimslope)
791 goto hitline;
792 }
793
794 return true;
795
796 // hit line
797 hitline:
798 #endif
799 // stop the search
800 return false;
801 }
802 #endif
803
804
805
P_MoveChaseCamera(player_t * player)806 void P_MoveChaseCamera (player_t *player)
807 {
808 angle_t angle;
809 int angf;
810 fixed_t x, y, z, viewpointx, viewpointy;
811 fixed_t dist;
812 float f1, f2;
813 subsector_t* newsubsec;
814 mobj_t* pmo = player->mo;
815
816 if (!camera.mo)
817 P_ResetCamera (player);
818
819 angf = ANGLE_TO_FINE( pmo->angle );
820
821 // sets ideal cam pos
822 dist = cv_cam_dist.value;
823 x = pmo->x - FixedMul( finecosine[angf], dist);
824 y = pmo->y - FixedMul( finesine[angf], dist);
825 z = pmo->z + (((unsigned int)cv_viewheight.EV)<<FRACBITS) + cv_cam_height.value;
826
827 /* P_PathTraverse ( pmo->x, pmo->y, x, y, PT_ADDLINES, PTR_UseTraverse );*/
828
829 // move camera down to move under lower ceilings
830 newsubsec = R_IsPointInSubsector ((pmo->x + camera.mo->x)>>1,(pmo->y + camera.mo->y)>>1);
831 if (!newsubsec)
832 {
833 // use player sector
834 if (pmo->subsector->sector->ceilingheight - camera.mo->height < z)
835 z = pmo->subsector->sector->ceilingheight - camera.mo->height-11*FRACUNIT; // don't be blocked by a opened door
836 }
837 else
838 // camera fit ?
839 if (newsubsec->sector->ceilingheight - camera.mo->height < z)
840 {
841 // no fit
842 z = newsubsec->sector->ceilingheight - camera.mo->height - 11*FRACUNIT;
843 }
844
845 // does the camera fit in its own sector
846 newsubsec = R_PointInSubsector (camera.mo->x, camera.mo->y);
847 if (newsubsec->sector->ceilingheight - camera.mo->height < z)
848 z = newsubsec->sector->ceilingheight - camera.mo->height - 11*FRACUNIT;
849
850
851 // point viewed by the camera
852 // this point is just 64 unit forward the player
853 dist = 64 << FRACBITS;
854 viewpointx = pmo->x + FixedMul( finecosine[angf], dist); // player angle
855 viewpointy = pmo->y + FixedMul( finesine[angf], dist);
856
857 camera.mo->angle = R_PointToAngle2(camera.mo->x, camera.mo->y,
858 viewpointx, viewpointy);
859
860 // follow the player
861 camera.mo->momx = FixedMul(x - camera.mo->x, cv_cam_speed.value);
862 camera.mo->momy = FixedMul(y - camera.mo->y, cv_cam_speed.value);
863 camera.mo->momz = FixedMul(z - camera.mo->z, cv_cam_speed.value);
864
865 // compute aiming to look toward the viewed point
866 f1=FIXED_TO_FLOAT(viewpointx - camera.mo->x);
867 f2=FIXED_TO_FLOAT(viewpointy - camera.mo->y);
868 dist=sqrt(f1*f1+f2*f2)*FRACUNIT;
869 angle=R_PointToAngle2(0, camera.mo->z, dist,
870 pmo->z + (pmo->height>>1) + sine_ANG(player->aiming)*64);
871
872 angle = G_ClipAimingPitch(angle);
873 dist = camera.aiming - angle;
874 camera.aiming -= (dist>>3);
875 }
876
877
878 byte weapontobutton[NUMWEAPONS]=
879 {wp_fist <<BT_WEAPONSHIFT,
880 wp_pistol <<BT_WEAPONSHIFT,
881 wp_shotgun <<BT_WEAPONSHIFT,
882 wp_chaingun<<BT_WEAPONSHIFT,
883 wp_missile <<BT_WEAPONSHIFT,
884 wp_plasma <<BT_WEAPONSHIFT,
885 wp_bfg <<BT_WEAPONSHIFT,
886 (wp_fist <<BT_WEAPONSHIFT) | BT_EXTRAWEAPON,// wp_chainsaw
887 (wp_shotgun <<BT_WEAPONSHIFT) | BT_EXTRAWEAPON};//wp_supershotgun
888
889 #ifdef CLIENTPREDICTION2
890
CL_ResetSpiritPosition(mobj_t * mobj)891 void CL_ResetSpiritPosition(mobj_t *mobj)
892 {
893 P_UnsetThingPosition(mobj->player->spirit);
894 mobj->player->spirit->x=mobj->x;
895 mobj->player->spirit->y=mobj->y;
896 mobj->player->spirit->z=mobj->z;
897 mobj->player->spirit->momx=0;
898 mobj->player->spirit->momy=0;
899 mobj->player->spirit->momz=0;
900 mobj->player->spirit->angle=mobj->angle;
901 P_SetThingPosition(mobj->player->spirit);
902 }
903
P_ProcessCmdSpirit(player_t * player,ticcmd_t * cmd)904 void P_ProcessCmdSpirit (player_t* player,ticcmd_t *cmd)
905 {
906 fixed_t movepushforward=0, movepushside=0;
907 #ifdef PARANOIA
908 if(!player)
909 I_Error("P_MoveSpirit : player null");
910 if(!player->spirit)
911 I_Error("P_MoveSpirit : player->spirit null");
912 if(!cmd)
913 I_Error("P_MoveSpirit : cmd null");
914 #endif
915
916 // don't move if dead
917 if( player->playerstate != PST_LIVE )
918 {
919 #ifdef TICCMD_148
920 cmd->ticflags &= ~TC_XY; // turn off clientprediction
921 #else
922 cmd->angleturn &= ~TICCMD_XY;
923 #endif
924 return;
925 }
926 onground = (player->spirit->z <= player->spirit->floorz) ||
927 (player->cheats & CF_FLYAROUND);
928
929 if (player->spirit->reactiontime)
930 {
931 player->spirit->reactiontime--;
932 return;
933 }
934
935 player->spirit->angle = cmd->angleturn<<16;
936 #ifdef TICCMD_148
937 cmd->ticflags |= TC_XY;
938 #else
939 cmd->angleturn |= TICCMD_XY;
940 #endif
941 /*
942 // now weapon is allways send change is detected at receiver side
943 if(cmd->buttons & BT_CHANGE)
944 {
945 player->spirit->movedir = cmd->buttons & (BT_WEAPONMASK | BT_EXTRAWEAPON);
946 cmd->buttons &=~BT_CHANGE;
947 }
948 else
949 {
950 if( player->pendingweapon!=wp_nochange )
951 player->spirit->movedir=weapontobutton[player->pendingweapon];
952 cmd->buttons&=~(BT_WEAPONMASK | BT_EXTRAWEAPON);
953 cmd->buttons|=player->spirit->movedir;
954 }
955 */
956 if (cmd->forwardmove)
957 {
958 movepushforward = cmd->forwardmove * movefactor;
959
960 if (player->spirit->eflags & MF_UNDERWATER)
961 {
962 // half forward speed when waist under water
963 // a little better grip if feets touch the ground
964 if (!onground)
965 movepushforward >>= 1;
966 else
967 movepushforward = movepushforward *3/4;
968 }
969 else
970 {
971 // allow very small movement while in air for gameplay
972 if (!onground)
973 movepushforward >>= 3;
974 }
975
976 P_ThrustSpirit (player->spirit, player->spirit->angle, movepushforward);
977 }
978
979 if (cmd->sidemove)
980 {
981 movepushside = cmd->sidemove * movefactor;
982 if (player->spirit->eflags & MF_UNDERWATER)
983 {
984 if (!onground)
985 movepushside >>= 1;
986 else
987 movepushside = movepushside *3/4;
988 }
989 else
990 if (!onground)
991 movepushside >>= 3;
992
993 P_ThrustSpirit (player->spirit, player->spirit->angle-ANG90, movepushside);
994 }
995
996 // mouselook swim when waist underwater
997 player->spirit->eflags &= ~MF_SWIMMING;
998 if (player->spirit->eflags & MF_UNDERWATER)
999 {
1000 fixed_t a;
1001 // swim up/down full move when forward full speed
1002 a = FixedMul( movepushforward*50, finesine[ (cmd->aiming>>(ANGLETOFINESHIFT-16)) ] >>5 );
1003
1004 if ( a != 0 ) {
1005 player->spirit->eflags |= MF_SWIMMING;
1006 player->spirit->momz += a;
1007 }
1008 }
1009
1010 //added:22-02-98: jumping
1011 if (cmd->buttons & BT_JUMP)
1012 {
1013 // can't jump while in air, can't jump while jumping
1014 if (!(player->jumpdown & 2) &&
1015 (onground || (player->spirit->eflags & MF_UNDERWATER)) )
1016 {
1017 if (onground)
1018 player->spirit->momz = jumpgravity;
1019 else //water content
1020 player->spirit->momz = jumpgravity/2;
1021
1022 //TODO: goub gloub when push up in water
1023
1024 if ( !(player->cheats & CF_FLYAROUND) && onground && !(player->spirit->eflags & MF_UNDERWATER))
1025 {
1026 S_StartScreamSound(player->spirit, sfx_jump);
1027
1028 // keep jumping ok if FLY mode.
1029 player->jumpdown |= 2;
1030 }
1031 }
1032 }
1033 else
1034 player->jumpdown &= ~2;
1035
1036 }
1037
P_MoveSpirit(player_t * p,ticcmd_t * cmd,int realtics)1038 void P_MoveSpirit (player_t* p,ticcmd_t *cmd, int realtics)
1039 {
1040 if( gamestate != GS_LEVEL )
1041 return;
1042
1043 if(p->spirit)
1044 {
1045 int i;
1046
1047 p->spirit->flags|=MF_SOLID;
1048 for(i=0;i<realtics;i++)
1049 {
1050 P_ProcessCmdSpirit(p,cmd);
1051 P_MobjThinker(p->spirit);
1052 }
1053 p->spirit->flags&=~MF_SOLID;
1054 P_CalcHeight (p); // z-bobing of player
1055 A_TicWeapon(p, &p->psprites[0]); // bobing of weapon
1056 cmd->x=p->spirit->x;
1057 cmd->y=p->spirit->y;
1058 spirit_update=true;
1059 }
1060 else
1061 if(p->mo)
1062 {
1063 cmd->x=p->mo->x;
1064 cmd->y=p->mo->y;
1065 }
1066 }
1067
1068 #endif
1069
1070
1071 //
1072 // P_PlayerThink
1073 //
1074
1075 boolean playerdeadview; //Fab:25-04-98:show dm rankings while in death view
1076
1077 // Fixed to not change the player mobj.
P_PlayerThink(player_t * player)1078 void P_PlayerThink (player_t* player)
1079 {
1080 ticcmd_t* cmd;
1081 weapontype_t newweapon;
1082 mobj_t * pmo = player->mo;
1083
1084 #ifdef PARANOIA
1085 if(!pmo) I_Error("p_playerthink : players[%d].mo == NULL",player-players);
1086 #endif
1087
1088 // fixme: do this in the cheat code
1089 if (player->cheats & CF_NOCLIP)
1090 pmo->flags |= MF_NOCLIP;
1091 else
1092 pmo->flags &= ~MF_NOCLIP;
1093
1094 // chain saw run forward
1095 cmd = &player->cmd;
1096 if (pmo->flags & MF_JUSTATTACKED)
1097 {
1098 // added : now angle turn is a absolute value not relative
1099 if( ! EN_cmd_abs_angle )
1100 cmd->angleturn = 0;
1101 cmd->forwardmove = 0xc800/512;
1102 cmd->sidemove = 0;
1103 #ifdef TICCMD_148
1104 cmd->ticflags = 0; // stun
1105 #endif
1106 pmo->flags &= ~MF_JUSTATTACKED;
1107 }
1108
1109 if (player->playerstate == PST_REBORN)
1110 {
1111 #ifdef PARANOIA
1112 I_SoftError("player %d is in PST_REBORN\n");
1113 #endif
1114 // it is not "normal" but far to be critical
1115 return;
1116 }
1117
1118 if (player->playerstate == PST_DEAD)
1119 {
1120 //Fab:25-04-98: show the dm rankings while dead, only in deathmatch
1121 //DarkWolf95:July 03, 2003:fixed bug where rankings only show on player1's death
1122 if (player== displayplayer_ptr
1123 || player== displayplayer2_ptr ) // NULL when unused
1124 playerdeadview = true;
1125
1126 P_DeathThink (player);
1127
1128 //added:26-02-98:camera may still move when guy is dead
1129 if (camera.chase == player)
1130 P_MoveChaseCamera ( player );
1131 return;
1132 }
1133 else
1134 {
1135 if ( player== displayplayer_ptr )
1136 playerdeadview = false;
1137 }
1138 if( player->chickenTics )
1139 P_ChickenPlayerThink(player);
1140
1141 // check water content, set stuff in mobj
1142 P_MobjCheckWater (pmo);
1143
1144 // Move around.
1145 // Reactiontime is used to prevent movement
1146 // for a bit after a teleport.
1147 if (pmo->reactiontime)
1148 pmo->reactiontime--;
1149 else
1150 P_MovePlayer (player);
1151
1152 //added:26-02-98: calculate the camera movement
1153 //added:22-02-98: bob view only if looking by the marine's eyes
1154 if (camera.chase == player)
1155 P_MoveChaseCamera ( player ); // camera view adjust
1156 else
1157 #ifdef CLIENTPREDICTION2
1158 ;
1159 #else
1160 P_CalcHeight (player); // viewheight adjust, bob view
1161 #endif
1162
1163
1164 // check special sectors : damage & secrets
1165 P_PlayerInSpecialSector (player);
1166
1167 //
1168 // TODO water splashes
1169 //
1170 #if 0
1171 if( (EV_legacy >= 125) && player->specialsector == )
1172 {
1173 if ((pmo->momx > (2*FRACUNIT) ||
1174 pmo->momx < (-2*FRACUNIT) ||
1175 pmo->momy > (2*FRACUNIT) ||
1176 pmo->momy < (-2*FRACUNIT) ||
1177 pmo->momz > (2*FRACUNIT)) && // jump out of water
1178 !(gametic % (32 * NEWTICRATERATIO)) )
1179 {
1180 //
1181 // make sure we disturb the surface of water (we touch it)
1182 //
1183 int waterz = pmo->subsector->sector->floorheight + (FRACUNIT/4);
1184
1185 // half in the water
1186 if(pmo->eflags & MF_TOUCHWATER)
1187 {
1188 if (pmo->z <= pmo->floorz) // onground
1189 {
1190 fixed_t whater_height = waterz - pmo->subsector->sector->floorheight;
1191
1192 if( whater_height < (pmo->height>>2))
1193 S_StartObjSound(pmo, sfx_splash);
1194 else
1195 S_StartObjSound(pmo, sfx_floush);
1196 }
1197 else
1198 S_StartObjSound(pmo, sfx_floush);
1199 }
1200 }
1201 }
1202 #endif
1203
1204 // Check for weapon change.
1205 //#ifndef CLIENTPREDICTION2
1206 if (cmd->buttons & BT_CHANGE)
1207 //#endif
1208 {
1209
1210 // The actual changing of the weapon is done
1211 // when the weapon psprite can do it
1212 // (read: not in the middle of an attack).
1213 newweapon = (cmd->buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT;
1214 if(demoversion<128)
1215 {
1216 // Old Doom, !EN_boom
1217 if (newweapon == wp_fist
1218 && player->weaponowned[wp_chainsaw]
1219 && !(player->readyweapon == wp_chainsaw
1220 && player->powers[pw_strength]))
1221 {
1222 newweapon = wp_chainsaw;
1223 }
1224
1225 if ( (gamemode == doom2_commercial)
1226 && newweapon == wp_shotgun
1227 && player->weaponowned[wp_supershotgun]
1228 && player->readyweapon != wp_supershotgun)
1229 {
1230 newweapon = wp_supershotgun;
1231 }
1232 }
1233 else
1234 {
1235 if(cmd->buttons&BT_EXTRAWEAPON)
1236 switch(newweapon) {
1237 case wp_shotgun :
1238 if( (gamemode == doom2_commercial)
1239 && player->weaponowned[wp_supershotgun])
1240 newweapon = wp_supershotgun;
1241 break;
1242 case wp_fist :
1243 if( player->weaponowned[wp_chainsaw])
1244 newweapon = wp_chainsaw;
1245 break;
1246 default:
1247 break;
1248 }
1249 }
1250
1251 if (player->weaponowned[newweapon]
1252 && newweapon != player->readyweapon)
1253 {
1254 // Do not go to plasma or BFG in shareware,
1255 // even if cheated.
1256 if ((newweapon != wp_plasma
1257 && newweapon != wp_bfg)
1258 || (gamemode != doom_shareware) )
1259 {
1260 player->pendingweapon = newweapon;
1261 }
1262 }
1263 }
1264
1265 // check for use
1266 if (cmd->buttons & BT_USE)
1267 {
1268 if (!player->usedown)
1269 {
1270 P_UseLines (player);
1271 player->usedown = true;
1272 }
1273 }
1274 else
1275 player->usedown = false;
1276 // Chicken counter
1277 if(player->chickenTics)
1278 {
1279 // Chicken attack counter
1280 if(player->chickenPeck)
1281 player->chickenPeck -= 3;
1282 // Attempt to undo the chicken
1283 if(!--player->chickenTics)
1284 {
1285 // Fixed to not change the player mobj.
1286 P_UndoPlayerChicken(player);
1287 }
1288 }
1289
1290 // cycle psprites
1291 P_MovePsprites (player);
1292 // Counters, time dependend power ups.
1293
1294 // Strength counts up to diminish fade.
1295 if (player->powers[pw_strength])
1296 player->powers[pw_strength]++;
1297
1298 if (player->powers[pw_invulnerability])
1299 player->powers[pw_invulnerability]--;
1300
1301 // the MF_SHADOW activates the tr_transhi translucency while it is set
1302 // (it doesnt use a preset value through FF_TRANSMASK)
1303 if (player->powers[pw_invisibility])
1304 if (! --player->powers[pw_invisibility] )
1305 pmo->flags &= ~MF_SHADOW;
1306
1307 if (player->powers[pw_infrared])
1308 player->powers[pw_infrared]--;
1309
1310 if (player->powers[pw_ironfeet])
1311 player->powers[pw_ironfeet]--;
1312
1313 if (player->powers[pw_flight])
1314 {
1315 if(!--player->powers[pw_flight])
1316 {
1317 /* HERETODO
1318 if(pmo->z != pmo->floorz)
1319 player->centering = true;
1320 */
1321 // timed out heretic fly power
1322 pmo->flags2 &= ~MF2_FLY;
1323 pmo->flags &= ~MF_NOGRAVITY;
1324 // BorderTopRefresh = true; //make sure the sprite's cleared out
1325 }
1326 }
1327 if(player->powers[pw_weaponlevel2])
1328 {
1329 if( --player->powers[pw_weaponlevel2] == 0 )
1330 {
1331 player->weaponinfo = wpnlev1info;
1332 // end of weaponlevel2 power
1333 if((player->readyweapon == wp_phoenixrod)
1334 && (player->psprites[ps_weapon].state
1335 != &states[S_PHOENIXREADY])
1336 && (player->psprites[ps_weapon].state
1337 != &states[S_PHOENIXUP]))
1338 {
1339 P_SetPsprite(player, ps_weapon, S_PHOENIXREADY);
1340 player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
1341 player->refire = 0;
1342 }
1343 else if((player->readyweapon == wp_gauntlets)
1344 || (player->readyweapon == wp_staff))
1345 {
1346 player->pendingweapon = player->readyweapon;
1347 }
1348 //BorderTopRefresh = true;
1349 }
1350 }
1351
1352 if (player->damagecount)
1353 player->damagecount--;
1354
1355 if (player->bonuscount)
1356 player->bonuscount--;
1357
1358 if (player->key_pickup)
1359 player->key_pickup--;
1360 if (player->health_pickup)
1361 player->health_pickup--;
1362 if (player->armor_pickup)
1363 player->armor_pickup--;
1364 if (player->ammo_pickup)
1365 player->ammo_pickup--;
1366 if (player->weapon_pickup)
1367 player->weapon_pickup--;
1368
1369 // Handling colormaps.
1370 if (player->powers[pw_invulnerability])
1371 {
1372 if (player->powers[pw_invulnerability] > BLINKTHRESHOLD
1373 || (player->powers[pw_invulnerability]&8) )
1374 player->fixedcolormap = INVERSECOLORMAP;
1375 else
1376 player->fixedcolormap = 0;
1377 }
1378 else if (player->powers[pw_infrared])
1379 {
1380 if (player->powers[pw_infrared] > BLINKTHRESHOLD
1381 || (player->powers[pw_infrared]&8) )
1382 {
1383 // almost full bright
1384 player->fixedcolormap = 1;
1385 }
1386 else
1387 player->fixedcolormap = 0;
1388 }
1389 else
1390 player->fixedcolormap = 0;
1391 }
1392
1393 //----------------------------------------------------------------------------
1394 //
1395 // PROC P_PlayerNextArtifact
1396 //
1397 //----------------------------------------------------------------------------
1398
P_PlayerNextArtifact(player_t * player)1399 void P_PlayerNextArtifact(player_t *player)
1400 {
1401 player->inv_ptr--;
1402 if(player->inv_ptr < 6)
1403 {
1404 player->st_curpos--;
1405 if(player->st_curpos < 0)
1406 player->st_curpos = 0;
1407 }
1408 if(player->inv_ptr < 0)
1409 {
1410 player->inv_ptr = player->inventorySlotNum-1;
1411 if(player->inv_ptr < 6)
1412 player->st_curpos = player->inv_ptr;
1413 else
1414 player->st_curpos = 6;
1415 }
1416 }
1417
1418 //----------------------------------------------------------------------------
1419 //
1420 // PROC P_PlayerRemoveArtifact
1421 //
1422 //----------------------------------------------------------------------------
1423
P_PlayerRemoveArtifact(player_t * player,int slot)1424 static void P_PlayerRemoveArtifact(player_t *player, int slot)
1425 {
1426 int i;
1427
1428 if(!(--player->inventory[slot].count))
1429 { // Used last of a type - compact the artifact list
1430 player->inventory[slot].type = arti_none;
1431 for(i = slot+1; i < player->inventorySlotNum; i++)
1432 player->inventory[i-1] = player->inventory[i];
1433 player->inventorySlotNum--;
1434
1435 // Set position markers and get next readyArtifact
1436 player->inv_ptr--;
1437 if(player->inv_ptr < 6)
1438 {
1439 player->st_curpos--;
1440 if( player->st_curpos < 0 )
1441 player->st_curpos = 0;
1442 }
1443 if( player->inv_ptr >= player->inventorySlotNum)
1444 player->inv_ptr = player->inventorySlotNum-1;
1445 if( player->inv_ptr < 0)
1446 player->inv_ptr = 0;
1447 }
1448 }
1449
1450 //----------------------------------------------------------------------------
1451 //
1452 // PROC P_PlayerUseArtifact
1453 //
1454 //----------------------------------------------------------------------------
1455
P_PlayerUseArtifact(player_t * player,artitype_t arti)1456 void P_PlayerUseArtifact(player_t *player, artitype_t arti)
1457 {
1458 int i;
1459
1460 for(i = 0; i < player->inventorySlotNum; i++)
1461 {
1462 if(player->inventory[i].type == arti)
1463 { // Found match - try to use
1464 if(P_UseArtifact(player, arti))
1465 { // Artifact was used - remove it from inventory
1466 P_PlayerRemoveArtifact(player, i);
1467 if(player == consoleplayer_ptr
1468 || player == displayplayer2_ptr ) // NULL when unused
1469 {
1470 S_StartSound(sfx_artiuse);
1471 H_ArtifactFlash = 4;
1472 }
1473 }
1474 else
1475 { // Unable to use artifact, advance pointer
1476 P_PlayerNextArtifact(player);
1477 }
1478 break;
1479 }
1480 }
1481 }
1482
1483 //----------------------------------------------------------------------------
1484 //
1485 // PROC P_ArtiTele
1486 //
1487 //----------------------------------------------------------------------------
1488
P_ArtiTele(player_t * player)1489 void P_ArtiTele(player_t *player)
1490 {
1491 int i;
1492 fixed_t destX;
1493 fixed_t destY;
1494 angle_t destAngle;
1495 mapthing_t * mtp;
1496
1497 if( deathmatch )
1498 {
1499 // Heretic use of P_Random
1500 i = PP_Random(ph_telearti) % numdmstarts;
1501 mtp = deathmatchstarts[i];
1502 }
1503 else
1504 {
1505 mtp = playerstarts[0];
1506 }
1507
1508 destX = mtp->x<<FRACBITS;
1509 destY = mtp->y<<FRACBITS;
1510 destAngle = wad_to_angle(mtp->angle);
1511 P_Teleport(player->mo, destX, destY, destAngle);
1512 S_StartSound(sfx_wpnup); // Full volume laugh
1513 }
1514
1515
1516 //----------------------------------------------------------------------------
1517 //
1518 // FUNC P_UseArtifact
1519 //
1520 // Returns true if artifact was used.
1521 //
1522 //----------------------------------------------------------------------------
1523
P_UseArtifact(player_t * player,artitype_t arti)1524 boolean P_UseArtifact(player_t *player, artitype_t arti)
1525 {
1526 mobj_t *mo;
1527 mobj_t * pmo = player->mo;
1528 angle_t angle;
1529
1530 switch(arti)
1531 {
1532 case arti_invulnerability:
1533 if(!P_GivePower(player, pw_invulnerability))
1534 goto ret_fail;
1535 break;
1536 case arti_invisibility:
1537 if(!P_GivePower(player, pw_invisibility))
1538 goto ret_fail;
1539 break;
1540 case arti_health:
1541 if(!P_GiveHealth(player, 25))
1542 goto ret_fail;
1543 break;
1544 case arti_superhealth:
1545 if(!P_GiveHealth(player, 100))
1546 goto ret_fail;
1547 break;
1548 case arti_tomeofpower:
1549 if(player->chickenTics)
1550 { // Attempt to undo chicken
1551 // Fixed to not change the player mobj.
1552 if(P_UndoPlayerChicken(player) == false)
1553 { // Failed
1554 P_DamageMobj(pmo, NULL, NULL, 10000);
1555 }
1556 else
1557 { // Succeeded
1558 player->chickenTics = 0;
1559 #ifdef XPEREMNTAL_HW3S
1560 S_StartScreamSound(pmo, sfx_wpnup);
1561 #else
1562 S_StartObjSound(pmo, sfx_wpnup);
1563 #endif
1564 }
1565 }
1566 else
1567 {
1568 if(!P_GivePower(player, pw_weaponlevel2))
1569 goto ret_fail;
1570 if(player->readyweapon == wp_staff)
1571 {
1572 P_SetPsprite(player, ps_weapon, S_STAFFREADY2_1);
1573 }
1574 else if(player->readyweapon == wp_gauntlets)
1575 {
1576 P_SetPsprite(player, ps_weapon, S_GAUNTLETREADY2_1);
1577 }
1578 }
1579 break;
1580 case arti_torch:
1581 if(!P_GivePower(player, pw_infrared))
1582 goto ret_fail;
1583 break;
1584 case arti_firebomb:
1585 angle = pmo->angle>>ANGLETOFINESHIFT;
1586 mo = P_SpawnMobj(pmo->x+24*finecosine[angle],
1587 pmo->y+24*finesine[angle], pmo->z - 15*FRACUNIT*
1588 ((pmo->flags2&MF2_FEETARECLIPPED) != 0), MT_FIREBOMB);
1589 mo->target = pmo;
1590 break;
1591 case arti_egg:
1592 P_SpawnPlayerMissile(pmo, MT_EGGFX);
1593 P_SPMAngle(pmo, MT_EGGFX, pmo->angle-(ANG45/6));
1594 P_SPMAngle(pmo, MT_EGGFX, pmo->angle+(ANG45/6));
1595 P_SPMAngle(pmo, MT_EGGFX, pmo->angle-(ANG45/3));
1596 P_SPMAngle(pmo, MT_EGGFX, pmo->angle+(ANG45/3));
1597 break;
1598 case arti_fly:
1599 if(!P_GivePower(player, pw_flight))
1600 goto ret_fail;
1601 break;
1602 case arti_teleport:
1603 P_ArtiTele(player);
1604 break;
1605 default:
1606 goto ret_fail;
1607 }
1608 return(true);
1609
1610 ret_fail:
1611 return(false);
1612 }
1613
1614
P_SetPlayer_color(player_t * player,byte color)1615 void P_SetPlayer_color( player_t * player, byte color )
1616 {
1617 color = color % NUMSKINCOLORS;
1618 player->skincolor = color;
1619
1620 // a copy of color, in proper position for use with color tables
1621 mobj_t * pmo = player->mo;
1622 if( pmo )
1623 pmo->tflags = (pmo->tflags & ~MFT_TRANSLATION6) | (color << MFT_TRANSSHIFT);
1624 }
1625