1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2000 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *      Player related stuff.
31  *      Bobbing POV/weapon, movement.
32  *      Pending weapon.
33  *
34  *-----------------------------------------------------------------------------*/
35 
36 #include "doomstat.h"
37 #include "d_event.h"
38 #include "r_main.h"
39 #include "p_map.h"
40 #include "p_spec.h"
41 #include "p_user.h"
42 #include "r_demo.h"
43 #include "r_fps.h"
44 
45 // Index of the special effects (INVUL inverse) map.
46 
47 #define INVERSECOLORMAP 32
48 
49 //
50 // Movement.
51 //
52 
53 // 16 pixels of bob
54 
55 #define MAXBOB  0x100000
56 
57 boolean onground; // whether player is on ground or in air
58 
59 //
60 // P_Thrust
61 // Moves the given origin along a given angle.
62 //
63 
P_Thrust(player_t * player,angle_t angle,fixed_t move)64 void P_Thrust(player_t* player,angle_t angle,fixed_t move)
65   {
66   angle >>= ANGLETOFINESHIFT;
67   player->mo->momx += FixedMul(move,finecosine[angle]);
68   player->mo->momy += FixedMul(move,finesine[angle]);
69   }
70 
71 
72 /*
73  * P_Bob
74  * Same as P_Thrust, but only affects bobbing.
75  *
76  * killough 10/98: We apply thrust separately between the real physical player
77  * and the part which affects bobbing. This way, bobbing only comes from player
78  * motion, nothing external, avoiding many problems, e.g. bobbing should not
79  * occur on conveyors, unless the player walks on one, and bobbing should be
80  * reduced at a regular rate, even on ice (where the player coasts).
81  */
82 
P_Bob(player_t * player,angle_t angle,fixed_t move)83 static void P_Bob(player_t *player, angle_t angle, fixed_t move)
84 {
85   //e6y
86   if (!mbf_features)
87     return;
88 
89   player->momx += FixedMul(move,finecosine[angle >>= ANGLETOFINESHIFT]);
90   player->momy += FixedMul(move,finesine[angle]);
91 }
92 
93 //
94 // P_CalcHeight
95 // Calculate the walking / running height adjustment
96 //
97 
P_CalcHeight(player_t * player)98 void P_CalcHeight (player_t* player)
99   {
100   int     angle;
101   fixed_t bob;
102 
103   // Regular movement bobbing
104   // (needs to be calculated for gun swing
105   // even if not on ground)
106   // OPTIMIZE: tablify angle
107   // Note: a LUT allows for effects
108   //  like a ramp with low health.
109 
110 
111   /* killough 10/98: Make bobbing depend only on player-applied motion.
112    *
113    * Note: don't reduce bobbing here if on ice: if you reduce bobbing here,
114    * it causes bobbing jerkiness when the player moves from ice to non-ice,
115    * and vice-versa.
116    */
117   player->bob = !mbf_features ?
118     (FixedMul (player->mo->momx, player->mo->momx)
119      + FixedMul (player->mo->momy,player->mo->momy))>>2 :
120     player_bobbing ? (FixedMul(player->momx,player->momx) +
121         FixedMul(player->momy,player->momy))>>2 : 0;
122 
123     //e6y
124     if (compatibility_level >= boom_202_compatibility &&
125         compatibility_level <= lxdoom_1_compatibility &&
126         player->mo->friction > ORIG_FRICTION) // ice?
127     {
128       if (player->bob > (MAXBOB>>2))
129         player->bob = MAXBOB>>2;
130     }
131     else
132 
133   if (player->bob > MAXBOB)
134     player->bob = MAXBOB;
135 
136   if (!onground || player->cheats & CF_NOMOMENTUM)
137     {
138     player->viewz = player->mo->z + VIEWHEIGHT;
139 
140     if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
141       player->viewz = player->mo->ceilingz-4*FRACUNIT;
142 
143 // The following line was in the Id source and appears      // phares 2/25/98
144 // to be a bug. player->viewz is checked in a similar
145 // manner at a different exit below.
146 
147 //  player->viewz = player->mo->z + player->viewheight;
148     return;
149     }
150 
151   angle = (FINEANGLES/20*leveltime)&FINEMASK;
152   bob = FixedMul(player->bob/2,finesine[angle]);
153 
154   // move viewheight
155 
156   if (player->playerstate == PST_LIVE)
157     {
158     player->viewheight += player->deltaviewheight;
159 
160     if (player->viewheight > VIEWHEIGHT)
161       {
162       player->viewheight = VIEWHEIGHT;
163       player->deltaviewheight = 0;
164       }
165 
166     if (player->viewheight < VIEWHEIGHT/2)
167       {
168       player->viewheight = VIEWHEIGHT/2;
169       if (player->deltaviewheight <= 0)
170         player->deltaviewheight = 1;
171       }
172 
173     if (player->deltaviewheight)
174       {
175       player->deltaviewheight += FRACUNIT/4;
176       if (!player->deltaviewheight)
177         player->deltaviewheight = 1;
178       }
179     }
180 
181   player->viewz = player->mo->z + player->viewheight + bob;
182 
183   if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
184     player->viewz = player->mo->ceilingz-4*FRACUNIT;
185   }
186 
187 
188 //
189 // P_MovePlayer
190 //
191 // Adds momentum if the player is not in the air
192 //
193 // killough 10/98: simplified
194 
P_MovePlayer(player_t * player)195 void P_MovePlayer (player_t* player)
196 {
197   ticcmd_t *cmd = &player->cmd;
198   mobj_t *mo = player->mo;
199 
200   mo->angle += cmd->angleturn << 16;
201   onground = mo->z <= mo->floorz;
202 
203   // e6y
204   if (demo_smoothturns && player == &players[displayplayer])
205     R_SmoothPlaying_Add(cmd->angleturn << 16);
206 
207   // killough 10/98:
208   //
209   // We must apply thrust to the player and bobbing separately, to avoid
210   // anomalies. The thrust applied to bobbing is always the same strength on
211   // ice, because the player still "works just as hard" to move, while the
212   // thrust applied to the movement varies with 'movefactor'.
213 
214   //e6y
215   if ((!demo_compatibility && !mbf_features) || (cmd->forwardmove | cmd->sidemove)) // killough 10/98
216     {
217       if (onground || mo->flags & MF_BOUNCES) // killough 8/9/98
218       {
219         int friction, movefactor = P_GetMoveFactor(mo, &friction);
220 
221         // killough 11/98:
222         // On sludge, make bobbing depend on efficiency.
223         // On ice, make it depend on effort.
224 
225         int bobfactor =
226           friction < ORIG_FRICTION ? movefactor : ORIG_FRICTION_FACTOR;
227 
228         if (cmd->forwardmove)
229         {
230           P_Bob(player,mo->angle,cmd->forwardmove*bobfactor);
231           P_Thrust(player,mo->angle,cmd->forwardmove*movefactor);
232         }
233 
234         if (cmd->sidemove)
235         {
236           P_Bob(player,mo->angle-ANG90,cmd->sidemove*bobfactor);
237           P_Thrust(player,mo->angle-ANG90,cmd->sidemove*movefactor);
238         }
239       }
240       if (mo->state == states+S_PLAY)
241         P_SetMobjState(mo,S_PLAY_RUN1);
242     }
243 }
244 
245 #define ANG5 (ANG90/18)
246 
247 //
248 // P_DeathThink
249 // Fall on your face when dying.
250 // Decrease POV height to floor height.
251 //
252 
P_DeathThink(player_t * player)253 void P_DeathThink (player_t* player)
254   {
255   angle_t angle;
256   angle_t delta;
257 
258   P_MovePsprites (player);
259 
260   // fall to the ground
261 
262   if (player->viewheight > 6*FRACUNIT)
263     player->viewheight -= FRACUNIT;
264 
265   if (player->viewheight < 6*FRACUNIT)
266     player->viewheight = 6*FRACUNIT;
267 
268   player->deltaviewheight = 0;
269   onground = (player->mo->z <= player->mo->floorz);
270   P_CalcHeight (player);
271 
272   if (player->attacker && player->attacker != player->mo)
273     {
274     angle = R_PointToAngle2 (player->mo->x,
275                              player->mo->y,
276                              player->attacker->x,
277                              player->attacker->y);
278 
279     delta = angle - player->mo->angle;
280 
281     if (delta < ANG5 || delta > (unsigned)-ANG5)
282       {
283       // Looking at killer,
284       //  so fade damage flash down.
285 
286       player->mo->angle = angle;
287 
288       if (player->damagecount)
289         player->damagecount--;
290       }
291     else if (delta < ANG180)
292       player->mo->angle += ANG5;
293     else
294       player->mo->angle -= ANG5;
295     }
296   else if (player->damagecount)
297     player->damagecount--;
298 
299   if (player->cmd.buttons & BT_USE)
300     player->playerstate = PST_REBORN;
301   R_SmoothPlaying_Reset(player); // e6y
302   }
303 
304 
305 //
306 // P_PlayerThink
307 //
308 
P_PlayerThink(player_t * player)309 void P_PlayerThink (player_t* player)
310   {
311   ticcmd_t*    cmd;
312   weapontype_t newweapon;
313 
314   if (movement_smooth && players && &players[displayplayer] == player)
315   {
316     original_view_vars.viewx = player->mo->x;
317     original_view_vars.viewy = player->mo->y;
318     original_view_vars.viewz = player->viewz;
319     original_view_vars.viewangle = R_SmoothPlaying_Get(player->mo->angle) + viewangleoffset;
320   }
321 
322   // killough 2/8/98, 3/21/98:
323   if (player->cheats & CF_NOCLIP)
324     player->mo->flags |= MF_NOCLIP;
325   else
326     player->mo->flags &= ~MF_NOCLIP;
327 
328   // chain saw run forward
329 
330   cmd = &player->cmd;
331   if (player->mo->flags & MF_JUSTATTACKED)
332     {
333     cmd->angleturn = 0;
334     cmd->forwardmove = 0xc800/512;
335     cmd->sidemove = 0;
336     player->mo->flags &= ~MF_JUSTATTACKED;
337     }
338 
339   if (player->playerstate == PST_DEAD)
340     {
341     P_DeathThink (player);
342     return;
343     }
344 
345   // Move around.
346   // Reactiontime is used to prevent movement
347   //  for a bit after a teleport.
348 
349   if (player->mo->reactiontime)
350     player->mo->reactiontime--;
351   else
352     P_MovePlayer (player);
353 
354   P_CalcHeight (player); // Determines view height and bobbing
355 
356   // Determine if there's anything about the sector you're in that's
357   // going to affect you, like painful floors.
358 
359   if (player->mo->subsector->sector->special)
360     P_PlayerInSpecialSector (player);
361 
362   // Check for weapon change.
363 
364   if (cmd->buttons & BT_CHANGE)
365     {
366     // The actual changing of the weapon is done
367     //  when the weapon psprite can do it
368     //  (read: not in the middle of an attack).
369 
370     newweapon = (cmd->buttons & BT_WEAPONMASK)>>BT_WEAPONSHIFT;
371 
372     // killough 3/22/98: For demo compatibility we must perform the fist
373     // and SSG weapons switches here, rather than in G_BuildTiccmd(). For
374     // other games which rely on user preferences, we must use the latter.
375 
376     if (demo_compatibility)
377       { // compatibility mode -- required for old demos -- killough
378       if (newweapon == wp_fist && player->weaponowned[wp_chainsaw] &&
379         (player->readyweapon != wp_chainsaw ||
380          !player->powers[pw_strength]))
381         newweapon = wp_chainsaw;
382       if (gamemode == commercial &&
383         newweapon == wp_shotgun &&
384         player->weaponowned[wp_supershotgun] &&
385         player->readyweapon != wp_supershotgun)
386         newweapon = wp_supershotgun;
387       }
388 
389     // killough 2/8/98, 3/22/98 -- end of weapon selection changes
390 
391     if (player->weaponowned[newweapon] && newweapon != player->readyweapon)
392 
393       // Do not go to plasma or BFG in shareware,
394       //  even if cheated.
395 
396       if ((newweapon != wp_plasma && newweapon != wp_bfg)
397           || (gamemode != shareware) )
398         player->pendingweapon = newweapon;
399     }
400 
401   // check for use
402 
403   if (cmd->buttons & BT_USE)
404     {
405     if (!player->usedown)
406       {
407       P_UseLines (player);
408       player->usedown = true;
409       }
410     }
411   else
412     player->usedown = false;
413 
414   // cycle psprites
415 
416   P_MovePsprites (player);
417 
418   // Counters, time dependent power ups.
419 
420   // Strength counts up to diminish fade.
421 
422   if (player->powers[pw_strength])
423     player->powers[pw_strength]++;
424 
425   // killough 1/98: Make idbeholdx toggle:
426 
427   if (player->powers[pw_invulnerability] > 0) // killough
428     player->powers[pw_invulnerability]--;
429 
430   if (player->powers[pw_invisibility] > 0)    // killough
431     if (! --player->powers[pw_invisibility] )
432       player->mo->flags &= ~MF_SHADOW;
433 
434   if (player->powers[pw_infrared] > 0)        // killough
435     player->powers[pw_infrared]--;
436 
437   if (player->powers[pw_ironfeet] > 0)        // killough
438     player->powers[pw_ironfeet]--;
439 
440   if (player->damagecount)
441     player->damagecount--;
442 
443   if (player->bonuscount)
444     player->bonuscount--;
445 
446   // Handling colormaps.
447   // killough 3/20/98: reformat to terse C syntax
448 
449   player->fixedcolormap = player->powers[pw_invulnerability] > 4*32 ||
450     player->powers[pw_invulnerability] & 8 ? INVERSECOLORMAP :
451     player->powers[pw_infrared] > 4*32 || player->powers[pw_infrared] & 8;
452   }
453