1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: p_user.cpp 4542 2014-02-09 17:39:42Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex 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 // DESCRIPTION:
20 //		Player related stuff.
21 //		Bobbing POV/weapon, movement.
22 //		Pending weapon.
23 //
24 //-----------------------------------------------------------------------------
25 
26 #include "cmdlib.h"
27 #include "doomdef.h"
28 #include "d_event.h"
29 #include "p_local.h"
30 #include "doomstat.h"
31 #include "s_sound.h"
32 #include "i_system.h"
33 #include "i_net.h"
34 #include "gi.h"
35 
36 #include "p_snapshot.h"
37 
38 // Index of the special effects (INVUL inverse) map.
39 #define INVERSECOLORMAP 		32
40 
41 //
42 // Movement.
43 //
44 
45 // 16 pixels of bob
46 #define MAXBOB			0x100000
47 
48 EXTERN_CVAR (sv_allowjump)
49 EXTERN_CVAR (cl_mouselook)
50 EXTERN_CVAR (sv_freelook)
51 EXTERN_CVAR (co_zdoomphys)
52 EXTERN_CVAR (cl_deathcam)
53 EXTERN_CVAR (sv_forcerespawn)
54 EXTERN_CVAR (sv_forcerespawntime)
55 EXTERN_CVAR (sv_spawndelaytime)
56 
57 extern bool predicting, step_mode;
58 
59 static player_t nullplayer;		// used to indicate 'player not found' when searching
60 EXTERN_CVAR (sv_allowmovebob)
EXTERN_CVAR(cl_movebob)61 EXTERN_CVAR (cl_movebob)
62 
63 player_t &idplayer(byte id)
64 {
65 	// Put a cached lookup mechanism in here.
66 
67 	// full search
68 	for (Players::iterator it = players.begin();it != players.end();++it)
69 	{
70 		// Add to the cache while we search
71 		if (it->id == id)
72 			return *it;
73 	}
74 
75 	return nullplayer;
76 }
77 
78 /**
79  * Find player by netname.  Note that this search is case-insensitive.
80  *
81  * @param  netname Name of player to look for.
82  * @return         Player reference of found player, or nullplayer.
83  */
nameplayer(const std::string & netname)84 player_t &nameplayer(const std::string &netname)
85 {
86 	for (Players::iterator it = players.begin();it != players.end();++it)
87 	{
88 		if (iequals(netname, it->userinfo.netname))
89 			return *it;
90 	}
91 
92 	return nullplayer;
93 }
94 
validplayer(player_t & ref)95 bool validplayer(player_t &ref)
96 {
97 	if (&ref == &nullplayer)
98 		return false;
99 
100 	if (players.empty())
101 		return false;
102 
103 	return true;
104 }
105 
106 //
107 // P_NumPlayersInGame()
108 //
109 // Returns the number of players who are active in the current game.  This does
110 // not include spectators or downloaders.
111 //
P_NumPlayersInGame()112 size_t P_NumPlayersInGame()
113 {
114 	size_t num_players = 0;
115 
116 	for (Players::const_iterator it = players.begin();it != players.end();++it)
117 	{
118 		if (!(it->spectator) && it->ingame())
119 			num_players += 1;
120 	}
121 
122 	return num_players;
123 }
124 
125 //
126 // P_NumReadyPlayersInGame()
127 //
128 // Returns the number of players who are marked ready in the current game.
129 // This does not include spectators or downloaders.
130 //
P_NumReadyPlayersInGame()131 size_t P_NumReadyPlayersInGame()
132 {
133 	size_t num_players = 0;
134 
135 	for (Players::const_iterator it = players.begin();it != players.end();++it)
136 	{
137 		if (!(it->spectator) && it->ingame() && it->ready)
138 			num_players += 1;
139 	}
140 
141 	return num_players;
142 }
143 
144 // P_NumPlayersOnTeam()
145 //
146 // Returns the number of active players on a team.  No specs or downloaders.
P_NumPlayersOnTeam(team_t team)147 size_t P_NumPlayersOnTeam(team_t team)
148 {
149 	size_t num_players = 0;
150 
151 	for (Players::const_iterator it = players.begin();it != players.end();++it)
152 	{
153 		if (!(it->spectator) && it->ingame() && it->userinfo.team == team)
154 			num_players += 1;
155 	}
156 
157 	return num_players;
158 }
159 
160 //
161 // P_Thrust
162 // Moves the given origin along a given angle.
163 //
P_SideThrust(player_t * player,angle_t angle,fixed_t move)164 void P_SideThrust (player_t *player, angle_t angle, fixed_t move)
165 {
166 	angle = (angle - ANG90) >> ANGLETOFINESHIFT;
167 
168 	player->mo->momx += FixedMul (move, finecosine[angle]);
169 	player->mo->momy += FixedMul (move, finesine[angle]);
170 }
171 
P_ForwardThrust(player_t * player,angle_t angle,fixed_t move)172 void P_ForwardThrust (player_t *player, angle_t angle, fixed_t move)
173 {
174 	angle >>= ANGLETOFINESHIFT;
175 
176 	if ((player->mo->waterlevel || (player->mo->flags2 & MF2_FLY))
177 		&& player->mo->pitch != 0)
178 	{
179 		angle_t pitch = (angle_t)player->mo->pitch >> ANGLETOFINESHIFT;
180 		fixed_t zpush = FixedMul (move, finesine[pitch]);
181 		if (player->mo->waterlevel && player->mo->waterlevel < 2 && zpush < 0)
182 			zpush = 0;
183 		player->mo->momz -= zpush;
184 		move = FixedMul (move, finecosine[pitch]);
185 	}
186 	player->mo->momx += FixedMul (move, finecosine[angle]);
187 	player->mo->momy += FixedMul (move, finesine[angle]);
188 }
189 
190 //
191 // P_CalcHeight
192 // Calculate the walking / running height adjustment
193 //
P_CalcHeight(player_t * player)194 void P_CalcHeight (player_t *player)
195 {
196 	int 		angle;
197 	fixed_t 	bob;
198 
199 	// Regular movement bobbing
200 	// (needs to be calculated for gun swing even if not on ground)
201 	// OPTIMIZE: tablify angle
202 
203 	// killough 10/98: Make bobbing depend only on player-applied motion.
204 	//
205 	// Note: don't reduce bobbing here if on ice: if you reduce bobbing here,
206 	// it causes bobbing jerkiness when the player moves from ice to non-ice,
207 	// and vice-versa.
208 
209 	if ((player->mo->flags2 & MF2_FLY) && !player->mo->onground)
210 	{
211 		player->bob = FRACUNIT / 2;
212 	}
213 
214 	if ((serverside || !predicting) && !player->spectator)
215 	{
216 		player->bob = FixedMul (player->mo->momx, player->mo->momx)
217 					+ FixedMul (player->mo->momy, player->mo->momy);
218 		player->bob >>= 2;
219 
220 		if (player->bob > MAXBOB)
221 			player->bob = MAXBOB;
222 	}
223 
224     if (player->cheats & CF_NOMOMENTUM || (!co_zdoomphys && !player->mo->onground))
225 	{
226 		player->viewz = player->mo->z + VIEWHEIGHT;
227 
228 		if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
229 			player->viewz = player->mo->ceilingz-4*FRACUNIT;
230 
231 		return;
232 	}
233 
234 	angle = (FINEANGLES/20*level.time) & FINEMASK;
235 	if (!player->spectator)
236 		bob = FixedMul (player->bob>>(player->mo->waterlevel > 1 ? 2 : 1), finesine[angle]);
237 	else
238 		bob = 0;
239 
240 	// move viewheight
241 	if (player->playerstate == PST_LIVE)
242 	{
243 		player->viewheight += player->deltaviewheight;
244 
245 		if (player->viewheight > VIEWHEIGHT)
246 		{
247 			player->viewheight = VIEWHEIGHT;
248 			player->deltaviewheight = 0;
249 		}
250 		else if (player->viewheight < VIEWHEIGHT/2)
251 		{
252 			player->viewheight = VIEWHEIGHT/2;
253 			if (player->deltaviewheight <= 0)
254 				player->deltaviewheight = 1;
255 		}
256 
257 		if (player->deltaviewheight)
258 		{
259 			player->deltaviewheight += FRACUNIT/4;
260 			if (!player->deltaviewheight)
261 				player->deltaviewheight = 1;
262 		}
263 	}
264 
265 	// [SL] Scale view-bobbing based on user's preference (if the server allows)
266 	if (sv_allowmovebob)
267 		bob *= cl_movebob;
268 
269 	player->viewz = player->mo->z + player->viewheight + bob;
270 
271 	if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
272 		player->viewz = player->mo->ceilingz-4*FRACUNIT;
273 	if (player->viewz < player->mo->floorz + 4*FRACUNIT)
274 		player->viewz = player->mo->floorz + 4*FRACUNIT;
275 }
276 
277 //
278 // P_PlayerLookUpDown
279 //
P_PlayerLookUpDown(player_t * p)280 void P_PlayerLookUpDown (player_t *p)
281 {
282 	// [RH] Look up/down stuff
283 	if (!sv_freelook)
284 	{
285 		p->mo->pitch = 0;
286 	}
287 	else
288 	{
289 		int look = p->cmd.pitch << 16;
290 
291 		// The player's view pitch is clamped between -32 and +56 degrees,
292 		// which translates to about half a screen height up and (more than)
293 		// one full screen height down from straight ahead when view panning
294 		// is used.
295 		if (look)
296 		{
297 			if (look == -32768 << 16)
298 			{ // center view
299 				p->mo->pitch = 0;
300 			}
301 			else if (look > 0)
302 			{ // look up
303 				p->mo->pitch -= look;
304 				if (p->mo->pitch < -ANG(32))
305 					p->mo->pitch = -ANG(32);
306 			}
307 			else
308 			{ // look down
309 				p->mo->pitch -= look;
310 				if (p->mo->pitch > ANG(56))
311 					p->mo->pitch = ANG(56);
312 			}
313 		}
314 	}
315 }
316 
CVAR_FUNC_IMPL(sv_aircontrol)317 CVAR_FUNC_IMPL (sv_aircontrol)
318 {
319 	level.aircontrol = (fixed_t)((float)var * 65536.f);
320 	G_AirControlChanged ();
321 }
322 
323 //
324 // P_MovePlayer
325 //
P_MovePlayer(player_t * player)326 void P_MovePlayer (player_t *player)
327 {
328 	if (!player || !player->mo || player->playerstate == PST_DEAD)
329 		return;
330 
331 	AActor *mo = player->mo;
332 
333 	mo->onground = (mo->z <= mo->floorz) || (mo->flags2 & MF2_ONMOBJ);
334 
335 	// [RH] Don't let frozen players move
336 	if (player->cheats & CF_FROZEN)
337 		return;
338 
339 	// Move around.
340 	// Reactiontime is used to prevent movement
341 	//	for a bit after a teleport.
342 	if (player->mo->reactiontime)
343 	{
344 		player->mo->reactiontime--;
345 		return;
346 	}
347 
348 	if (player->cmd.upmove == -32768)
349 	{
350 		// Only land if in the air
351 		if ((player->mo->flags2 & MF2_FLY) && player->mo->waterlevel < 2)
352 		{
353 			player->mo->flags2 &= ~MF2_FLY;
354 			player->mo->flags &= ~MF_NOGRAVITY;
355 		}
356 	}
357 	else if (player->cmd.upmove != 0)
358 	{
359 		if (player->mo->waterlevel >= 2 || player->mo->flags2 & MF2_FLY)
360 		{
361 			player->mo->momz = player->cmd.upmove << 9;
362 
363 			if (player->mo->waterlevel < 2 && !(player->mo->flags2 & MF2_FLY))
364 			{
365 				player->mo->flags2 |= MF2_FLY;
366 				player->mo->flags |= MF_NOGRAVITY;
367 				if (player->mo->momz <= -39*FRACUNIT)
368 					S_StopSound(player->mo, CHAN_VOICE);	// Stop falling scream
369 			}
370 		}
371 	}
372 
373 	// Look left/right
374 	if(clientside || step_mode)
375 	{
376 		mo->angle += player->cmd.yaw << 16;
377 
378 		// Look up/down stuff
379 		P_PlayerLookUpDown(player);
380 	}
381 
382 	// killough 10/98:
383 	//
384 	// We must apply thrust to the player and bobbing separately, to avoid
385 	// anomalies. The thrust applied to bobbing is always the same strength on
386 	// ice, because the player still "works just as hard" to move, while the
387 	// thrust applied to the movement varies with 'movefactor'.
388 
389 	if (player->cmd.forwardmove | player->cmd.sidemove)
390 	{
391 		fixed_t forwardmove, sidemove;
392 		int bobfactor;
393 		int friction, movefactor;
394 
395 		movefactor = P_GetMoveFactor (mo, &friction);
396 		bobfactor = friction < ORIG_FRICTION ? movefactor : ORIG_FRICTION_FACTOR;
397 		if (!mo->onground && !(mo->flags2 & MF2_FLY) && !mo->waterlevel)
398 		{
399 			// [RH] allow very limited movement if not on ground.
400 			if (co_zdoomphys)
401 			{
402 				movefactor = FixedMul (movefactor, level.aircontrol);
403 				bobfactor = FixedMul (bobfactor, level.aircontrol);
404 			}
405 			else
406 			{
407 				movefactor >>= 8;
408 				bobfactor >>= 8;
409 			}
410 		}
411 		forwardmove = (player->cmd.forwardmove * movefactor) >> 8;
412 		sidemove = (player->cmd.sidemove * movefactor) >> 8;
413 
414 		// [ML] Check for these conditions unless advanced physics is on
415 		if(co_zdoomphys ||
416 			(!co_zdoomphys && (mo->onground || (mo->flags2 & MF2_FLY) || mo->waterlevel)))
417 		{
418 			if (forwardmove)
419 			{
420 				P_ForwardThrust (player, mo->angle, forwardmove);
421 			}
422 			if (sidemove)
423 			{
424 				P_SideThrust (player, mo->angle, sidemove);
425 			}
426 		}
427 
428 		if (mo->state == &states[S_PLAY])
429 		{
430 			// denis - fixme - this function might destoy player->mo without setting it to 0
431 			P_SetMobjState (player->mo, S_PLAY_RUN1);
432 		}
433 
434 		if (player->cheats & CF_REVERTPLEASE)
435 		{
436 			player->cheats &= ~CF_REVERTPLEASE;
437 			player->camera = player->mo;
438 		}
439 	}
440 
441 	// [RH] check for jump
442 	if (player->jumpTics)
443 		player->jumpTics--;
444 
445 	if ((player->cmd.buttons & BT_JUMP) == BT_JUMP)
446 	{
447 		if (player->mo->waterlevel >= 2)
448 		{
449 			player->mo->momz = 4*FRACUNIT;
450 		}
451 		else if (player->mo->flags2 & MF2_FLY)
452 		{
453 			player->mo->momz = 3*FRACUNIT;
454 		}
455 		else if (sv_allowjump && player->mo->onground && !player->jumpTics)
456 		{
457 			player->mo->momz += 8*FRACUNIT;
458 			if(!player->spectator)
459 				UV_SoundAvoidPlayer(player->mo, CHAN_VOICE, "player/male/jump1", ATTN_NORM);
460 
461             player->mo->flags2 &= ~MF2_ONMOBJ;
462             player->jumpTics = 18;
463 		}
464 	}
465 }
466 
467 // [RH] (Adapted from Q2)
468 // P_FallingDamage
469 //
P_FallingDamage(AActor * ent)470 void P_FallingDamage (AActor *ent)
471 {
472 	float	delta;
473 	int		damage;
474 
475 	if (!ent->player)
476 		return;		// not a player
477 
478 	if (ent->flags & MF_NOCLIP)
479 		return;
480 
481 	if ((ent->player->oldvelocity[2] < 0)
482 		&& (ent->momz > ent->player->oldvelocity[2])
483 		&& (!(ent->flags2 & MF2_ONMOBJ)
484 			|| !(ent->z <= ent->floorz)))
485 	{
486 		delta = (float)ent->player->oldvelocity[2];
487 	}
488 	else
489 	{
490 		if (!(ent->flags2 & MF2_ONMOBJ))
491 			return;
492 		delta = (float)(ent->momz - ent->player->oldvelocity[2]);
493 	}
494 	delta = delta*delta * 2.03904313e-11f;
495 
496 	if (delta < 1)
497 		return;
498 
499 	if (delta < 15)
500 	{
501 		//ent->s.event = EV_FOOTSTEP;
502 		return;
503 	}
504 
505 	if (delta > 30)
506 	{
507 		damage = (int)((delta-30)/2);
508 		if (damage < 1)
509 			damage = 1;
510 
511 		if (0)
512 			P_DamageMobj (ent, NULL, NULL, damage, MOD_FALLING);
513 	}
514 	else
515 	{
516 		//ent->s.event = EV_FALLSHORT;
517 		return;
518 	}
519 }
520 
521 //
522 // P_DeathThink
523 // Fall on your face when dying.
524 // Decrease POV height to floor height.
525 //
526 #define ANG5	(ANG90/18)
527 
P_DeathThink(player_t * player)528 void P_DeathThink (player_t *player)
529 {
530 	bool reduce_redness = true;
531 
532 	P_MovePsprites (player);
533 	player->mo->onground = (player->mo->z <= player->mo->floorz);
534 
535 	// fall to the ground
536 	if (player->viewheight > 6*FRACUNIT)
537 		player->viewheight -= FRACUNIT;
538 
539 	if (player->viewheight < 6*FRACUNIT)
540 		player->viewheight = 6*FRACUNIT;
541 
542 	player->deltaviewheight = 0;
543 	P_CalcHeight (player);
544 
545 	// adjust the player's view to follow its attacker
546 	if (cl_deathcam && clientside &&
547 		player->attacker && player->attacker != player->mo)
548 	{
549 		angle_t angle = P_PointToAngle (player->mo->x,
550 								 		player->mo->y,
551 								 		player->attacker->x,
552 								 		player->attacker->y);
553 
554 		angle_t delta = angle - player->mo->angle;
555 
556 		if (delta < ANG5 || delta > (unsigned)-ANG5)
557 			player->mo->angle = angle;
558 		else
559 		{
560 			if (delta < ANG180)
561 				player->mo->angle += ANG5;
562 			else
563 				player->mo->angle -= ANG5;
564 
565 			// not yet looking at killer so keep the red tinting
566 			reduce_redness = false;
567 		}
568 	}
569 
570 	if (player->damagecount && reduce_redness && !predicting)
571 		player->damagecount--;
572 
573 	if(serverside)
574 	{
575 		bool force_respawn =	(!clientside && sv_forcerespawn &&
576 								level.time >= player->death_time + sv_forcerespawntime * TICRATE);
577 
578 		// [SL] Can we respawn yet?
579 		int respawn_time = player->death_time + sv_spawndelaytime * TICRATE;
580 		bool delay_respawn =	(!clientside && level.time < respawn_time);
581 
582 		// [Toke - dmflags] Old location of DF_FORCE_RESPAWN
583 		if (player->ingame() && ((player->cmd.buttons & BT_USE && !delay_respawn) || force_respawn))
584 		{
585 			player->playerstate = PST_REBORN;
586 		}
587 	}
588 }
589 
P_AreTeammates(player_t & a,player_t & b)590 bool P_AreTeammates(player_t &a, player_t &b)
591 {
592 	// not your own teammate (at least for friendly fire, etc)
593 	if (a.id == b.id)
594 		return false;
595 
596 	return (sv_gametype == GM_COOP) ||
597 		  ((a.userinfo.team == b.userinfo.team) &&
598 		   (sv_gametype == GM_TEAMDM || sv_gametype == GM_CTF));
599 }
600 
P_CanSpy(player_t & viewer,player_t & other)601 bool P_CanSpy(player_t &viewer, player_t &other)
602 {
603 	if (other.spectator || !other.mo)
604 		return false;
605 
606 	return (viewer.spectator || P_AreTeammates(viewer, other) || demoplayback);
607 }
608 
609 void SV_SendPlayerInfo(player_t &);
610 
611 //
612 // P_PlayerThink
613 //
P_PlayerThink(player_t * player)614 void P_PlayerThink (player_t *player)
615 {
616 	weapontype_t newweapon;
617 
618 	// [SL] 2011-10-31 - Thinker called before the client has received a message
619 	// to spawn a mobj from the server.  Just bail from this function and
620 	// hope the client receives the spawn message at a later time.
621 	if (!player->mo && clientside && multiplayer)
622 	{
623 		DPrintf("Warning: P_PlayerThink called for player %s without a valid Actor.\n",
624 				player->userinfo.netname.c_str());
625 		return;
626 	}
627 	else if (!player->mo)
628 		I_Error ("No player %d start\n", player->id);
629 
630 	player->xviewshift = 0;		// [RH] Make sure view is in right place
631 	player->prevviewz = player->viewz;
632 	player->mo->prevangle = player->mo->angle;
633 	player->mo->prevpitch = player->mo->pitch;
634 
635 	// fixme: do this in the cheat code
636 	if (player->cheats & CF_NOCLIP)
637 		player->mo->flags |= MF_NOCLIP;
638 	else
639 		player->mo->flags &= ~MF_NOCLIP;
640 
641 	if (player->cheats & CF_FLY)
642 		player->mo->flags |= MF_NOGRAVITY, player->mo->flags2 |= MF2_FLY;
643 	else
644 		player->mo->flags &= ~MF_NOGRAVITY, player->mo->flags2 &= ~MF2_FLY;
645 
646 	// chain saw run forward
647 	if (player->mo->flags & MF_JUSTATTACKED)
648 	{
649 		player->cmd.yaw = 0;
650 		player->cmd.forwardmove = 0xc800/2;
651 		player->cmd.sidemove = 0;
652 		player->mo->flags &= ~MF_JUSTATTACKED;
653 	}
654 
655 	if (player->playerstate == PST_DEAD)
656 	{
657 		P_DeathThink(player);
658 		return;
659 	}
660 
661 	P_MovePlayer (player);
662 	P_CalcHeight (player);
663 
664 	if (player->mo->subsector && (player->mo->subsector->sector->special || player->mo->subsector->sector->damage))
665 		P_PlayerInSpecialSector (player);
666 
667 	// Check for weapon change.
668 
669 	// A special event has no other buttons.
670 	if (player->cmd.buttons & BT_SPECIAL)
671 		player->cmd.buttons = 0;
672 
673 	if ((player->cmd.buttons & BT_CHANGE) || player->cmd.impulse >= 50)
674 	{
675 		// [RH] Support direct weapon changes
676 		if (player->cmd.impulse) {
677 			newweapon = (weapontype_t)(player->cmd.impulse - 50);
678 		} else {
679 			// The actual changing of the weapon is done
680 			//	when the weapon psprite can do it
681 			//	(read: not in the middle of an attack).
682 			newweapon = (weapontype_t)((player->cmd.buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT);
683 
684 			if (newweapon == wp_fist
685 				&& player->weaponowned[wp_chainsaw]
686 				&& !(player->readyweapon == wp_chainsaw
687 					 && player->powers[pw_strength]))
688 			{
689 				newweapon = wp_chainsaw;
690 			}
691 
692 			if ((gameinfo.flags & GI_MAPxx)
693 				&& newweapon == wp_shotgun
694 				&& player->weaponowned[wp_supershotgun]
695 				&& player->readyweapon != wp_supershotgun)
696 			{
697 				newweapon = wp_supershotgun;
698 			}
699 		}
700 
701 		if ((newweapon >= 0 && newweapon < NUMWEAPONS)
702 			&& player->weaponowned[newweapon]
703 			&& newweapon != player->readyweapon)
704 		{
705 			// NEVER go to plasma or BFG in shareware,
706 			if ((newweapon != wp_plasma && newweapon != wp_bfg)
707 			|| (gamemode != shareware) )
708 			{
709 				player->pendingweapon = newweapon;
710 			}
711 		}
712 	}
713 
714 	// check for use
715 	if (player->cmd.buttons & BT_USE)
716 	{
717 		if (!player->usedown)
718 		{
719 			P_UseLines (player);
720 			player->usedown = true;
721 		}
722 	}
723 	else
724 		player->usedown = false;
725 
726 	// cycle psprites
727 	P_MovePsprites (player);
728 
729 	// Counters, time dependent power ups.
730 
731 	// Strength counts up to diminish fade.
732 	if (player->powers[pw_strength])
733 		player->powers[pw_strength]++;
734 
735 	if (player->powers[pw_invulnerability])
736 		player->powers[pw_invulnerability]--;
737 
738 	if (player->powers[pw_invisibility])
739 		if (! --player->powers[pw_invisibility] )
740 			player->mo->flags &= ~MF_SHADOW;
741 
742 	if (player->powers[pw_infrared])
743 		player->powers[pw_infrared]--;
744 
745 	if (player->powers[pw_ironfeet])
746 		player->powers[pw_ironfeet]--;
747 
748 	if (player->damagecount)
749 		player->damagecount--;
750 
751 	if (player->bonuscount)
752 		player->bonuscount--;
753 
754 	// Handling colormaps.
755 	if (displayplayer().powers[pw_invulnerability])
756 	{
757 		if (displayplayer().powers[pw_invulnerability] > 4*32
758 			|| (displayplayer().powers[pw_invulnerability]&8) )
759 			displayplayer().fixedcolormap = INVERSECOLORMAP;
760 		else
761 			displayplayer().fixedcolormap = 0;
762 	}
763 	else if (player->powers[pw_infrared])
764 	{
765 		if (player->powers[pw_infrared] > 4*32
766 			|| (player->powers[pw_infrared]&8) )
767 		{
768 			// almost full bright
769 			player->fixedcolormap = 1;
770 		}
771 		else
772 			player->fixedcolormap = 0;
773 	}
774 	else
775 		player->fixedcolormap = 0;
776 
777 	// Handle air supply
778 	if (player->mo->waterlevel < 3 || player->powers[pw_ironfeet])
779 	{
780 		player->air_finished = level.time + 10*TICRATE;
781 	}
782 	else if (player->air_finished <= level.time && !(level.time & 31))
783 	{
784 		P_DamageMobj (player->mo, NULL, NULL, 2 + 2*((level.time-player->air_finished)/TICRATE), MOD_WATER, DMG_NO_ARMOR);
785 	}
786 }
787 
Serialize(FArchive & arc)788 void player_s::Serialize (FArchive &arc)
789 {
790 	size_t i;
791 
792 	if (arc.IsStoring ())
793 	{ // saving to archive
794 		arc << id
795 			<< playerstate
796 			<< spectator
797 			<< cmd
798 			<< userinfo
799 			<< viewz
800 			<< viewheight
801 			<< deltaviewheight
802 			<< bob
803 			<< health
804 			<< armorpoints
805 			<< armortype
806 			<< backpack
807 			<< fragcount
808 			<< readyweapon
809 			<< pendingweapon
810 			<< attackdown
811 			<< usedown
812 			<< cheats
813 			<< refire
814 			<< killcount
815 			<< itemcount
816 			<< secretcount
817 			<< damagecount
818 			<< bonuscount
819 			<< points
820 			/*<< attacker->netid*/
821 			<< extralight
822 			<< fixedcolormap
823 			<< xviewshift
824 			<< jumpTics
825 			<< death_time
826 			<< air_finished;
827 		for (i = 0; i < NUMPOWERS; i++)
828 			arc << powers[i];
829 		for (i = 0; i < NUMCARDS; i++)
830 			arc << cards[i];
831 		for (i = 0; i < NUMWEAPONS; i++)
832 			arc << weaponowned[i];
833 		for (i = 0; i < NUMAMMO; i++)
834 			arc << ammo[i] << maxammo[i];
835 		for (i = 0; i < NUMPSPRITES; i++)
836 			arc << psprites[i];
837 		for (i = 0; i < 3; i++)
838 			arc << oldvelocity[i];
839 	}
840 	else
841 	{ // Restoring from archive
842 		UserInfo dummyuserinfo;
843 
844 		arc >> id
845 			>> playerstate
846 			>> spectator
847 			>> cmd
848 			>> userinfo // Q: Would it be better to restore the userinfo from the archive?
849 			>> viewz
850 			>> viewheight
851 			>> deltaviewheight
852 			>> bob
853 			>> health
854 			>> armorpoints
855 			>> armortype
856 			>> backpack
857 			>> fragcount
858 			>> readyweapon
859 			>> pendingweapon
860 			>> attackdown
861 			>> usedown
862 			>> cheats
863 			>> refire
864 			>> killcount
865 			>> itemcount
866 			>> secretcount
867 			>> damagecount
868 			>> bonuscount
869 			>> points
870 			/*>> attacker->netid*/
871 			>> extralight
872 			>> fixedcolormap
873 			>> xviewshift
874 			>> jumpTics
875 			>> death_time
876 			>> air_finished;
877 		for (i = 0; i < NUMPOWERS; i++)
878 			arc >> powers[i];
879 		for (i = 0; i < NUMCARDS; i++)
880 			arc >> cards[i];
881 		for (i = 0; i < NUMWEAPONS; i++)
882 			arc >> weaponowned[i];
883 		for (i = 0; i < NUMAMMO; i++)
884 			arc >> ammo[i] >> maxammo[i];
885 		for (i = 0; i < NUMPSPRITES; i++)
886 			arc >> psprites[i];
887 		for (i = 0; i < 3; i++)
888 			arc >> oldvelocity[i];
889 
890 		camera = mo;
891 
892 //		if (&consoleplayer() != this)
893 //			userinfo = dummyuserinfo;
894 	}
895 }
896 
player_s()897 player_s::player_s()
898 {
899 	size_t i;
900 
901 	// GhostlyDeath -- Initialize EVERYTHING
902 	id = 0;
903 	playerstate = PST_LIVE;
904 	mo = AActor::AActorPtr();
905 	cmd.clear();
906 	fov = 90.0;
907 	viewz = 0 << FRACBITS;
908 	viewheight = 0 << FRACBITS;
909 	deltaviewheight = 0 << FRACBITS;
910 	bob = 0 << FRACBITS;
911 	health = 0;
912 	armorpoints = 0;
913 	armortype = 0;
914 	for (i = 0; i < NUMPOWERS; i++)
915 		powers[i] = 0;
916 	for (i = 0; i < NUMCARDS; i++)
917 		cards[i] = false;
918 	backpack = false;
919 	points = 0;
920 	for (i = 0; i < NUMFLAGS; i++)
921 		flags[i] = false;
922 	fragcount = 0;
923 	deathcount = 0;
924 	killcount = 0;
925 	pendingweapon = wp_nochange;
926 	readyweapon = wp_nochange;
927 	for (i = 0; i < NUMWEAPONS; i++)
928 		weaponowned[i] = false;
929 	for (i = 0; i < NUMAMMO; i++)
930 	{
931 		ammo[i] = 0;
932 		maxammo[i] = 0;
933 	}
934 	attackdown = 0;
935 	usedown = 0;
936 	cheats = 0;
937 	refire = 0;
938 	damagecount = 0;
939 	bonuscount = 0;
940 	attacker = AActor::AActorPtr();
941 	extralight = 0;
942 	fixedcolormap = 0;
943 	xviewshift = 0;
944 	memset(psprites, 0, sizeof(pspdef_t) * NUMPSPRITES);
945 	jumpTics = 0;
946 	death_time = 0;
947 	memset(oldvelocity, 0, sizeof(oldvelocity));
948 	camera = AActor::AActorPtr();
949 	air_finished = 0;
950 	GameTime = 0;
951 	JoinTime = 0;
952 	ping = 0;
953 	last_received = 0;
954 	tic = 0;
955 	spying = id;
956 	spectator = false;
957 
958 	joinafterspectatortime = level.time - TICRATE*5;
959 	timeout_callvote = 0;
960 	timeout_vote = 0;
961 
962 	ready = false;
963 	timeout_ready = 0;
964 
965 	prefcolor = 0;
966 
967 	LastMessage.Time = 0;
968 	LastMessage.Message = "";
969 
970 	BlendR = 0;
971 	BlendG = 0;
972 	BlendB = 0;
973 	BlendA = 0;
974 
975 	memset(netcmds, 0, sizeof(ticcmd_t) * BACKUPTICS);
976 }
977 
operator =(const player_s & other)978 player_s &player_s::operator =(const player_s &other)
979 {
980 	size_t i;
981 
982 	id = other.id;
983 	playerstate = other.playerstate;
984 	mo = other.mo;
985 	cmd = other.cmd;
986 	cmdqueue = other.cmdqueue;
987 	userinfo = other.userinfo;
988 	fov = other.fov;
989 	viewz = other.viewz;
990 	viewheight = other.viewheight;
991 	deltaviewheight = other.deltaviewheight;
992 	bob = other.bob;
993 
994 	health = other.health;
995 	armorpoints = other.armorpoints;
996 	armortype = other.armortype;
997 
998 	for(i = 0; i < NUMPOWERS; i++)
999 		powers[i] = other.powers[i];
1000 
1001 	for(i = 0; i < NUMCARDS; i++)
1002 		cards[i] = other.cards[i];
1003 
1004 	for(i = 0; i < NUMFLAGS; i++)
1005 		flags[i] = other.flags[i];
1006 
1007 	points = other.points;
1008 	backpack = other.backpack;
1009 
1010 	fragcount = other.fragcount;
1011 	deathcount = other.deathcount;
1012 	killcount = other.killcount;
1013 
1014 	pendingweapon = other.pendingweapon;
1015 	readyweapon = other.readyweapon;
1016 
1017 	for(i = 0; i < NUMWEAPONS; i++)
1018 		weaponowned[i] = other.weaponowned[i];
1019 	for(i = 0; i < NUMAMMO; i++)
1020 		ammo[i] = other.ammo[i];
1021 	for(i = 0; i < NUMAMMO; i++)
1022 		maxammo[i] = other.maxammo[i];
1023 
1024 	attackdown = other.attackdown;
1025 	usedown = other.usedown;
1026 
1027 	cheats = other.cheats;
1028 
1029 	refire = other.refire;
1030 
1031 	damagecount = other.damagecount;
1032 	bonuscount = other.bonuscount;
1033 
1034 	attacker = other.attacker;
1035 
1036 	extralight = other.extralight;
1037 	fixedcolormap = other.fixedcolormap;
1038 
1039 	xviewshift = other.xviewshift;
1040 
1041 	for(i = 0; i < NUMPSPRITES; i++)
1042 		psprites[i] = other.psprites[i];
1043 
1044     jumpTics = other.jumpTics;
1045 
1046 	death_time = other.death_time;
1047 
1048 	memcpy(oldvelocity, other.oldvelocity, sizeof(oldvelocity));
1049 
1050 	camera = other.camera;
1051 	air_finished = other.air_finished;
1052 
1053 	GameTime = other.GameTime;
1054 	JoinTime = other.JoinTime;
1055 	ping = other.ping;
1056 
1057 	last_received = other.last_received;
1058 
1059 	tic = other.tic;
1060 	spying = other.spying;
1061 	spectator = other.spectator;
1062 	joinafterspectatortime = other.joinafterspectatortime;
1063 	timeout_callvote = other.timeout_callvote;
1064 	timeout_vote = other.timeout_vote;
1065 
1066 	ready = other.ready;
1067 	timeout_ready = other.timeout_ready;
1068 
1069 	prefcolor = other.prefcolor;
1070 
1071 	for(i = 0; i < BACKUPTICS; i++)
1072 		netcmds[i] = other.netcmds[i];
1073 
1074     LastMessage.Time = other.LastMessage.Time;
1075 	LastMessage.Message = other.LastMessage.Message;
1076 
1077 	BlendR = other.BlendR;
1078 	BlendG = other.BlendG;
1079 	BlendB = other.BlendB;
1080 	BlendA = other.BlendA;
1081 
1082 	client = other.client;
1083 
1084 	snapshots = other.snapshots;
1085 
1086 	to_spawn = other.to_spawn;
1087 
1088 	return *this;
1089 }
1090 
~player_s()1091 player_s::~player_s()
1092 {
1093 }
1094 
1095 VERSION_CONTROL (p_user_cpp, "$Id: p_user.cpp 4542 2014-02-09 17:39:42Z dr_sean $")
1096 
1097