1 
2 //**************************************************************************
3 //**
4 //** p_user.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile: p_user.c,v $
7 //** $Revision: 1.123 $
8 //** $Date: 96/01/05 14:21:01 $
9 //** $Author: bgokey $
10 //**
11 //**************************************************************************
12 
13 #include "h2def.h"
14 #include "p_local.h"
15 #include "soundst.h"
16 
17 void P_PlayerNextArtifact(player_t *player);
18 
19 // Macros
20 
21 #define MAXBOB 0x100000 // 16 pixels of bob
22 
23 // Data
24 
25 boolean onground;
26 int newtorch; // used in the torch flicker effect.
27 int newtorchdelta;
28 
29 int PStateNormal[NUMCLASSES] =
30 {
31 	S_FPLAY,
32 	S_CPLAY,
33 	S_MPLAY,
34 	S_PIGPLAY
35 };
36 
37 int PStateRun[NUMCLASSES] =
38 {
39 	S_FPLAY_RUN1,
40 	S_CPLAY_RUN1,
41 	S_MPLAY_RUN1,
42 	S_PIGPLAY_RUN1
43 };
44 
45 int PStateAttack[NUMCLASSES] =
46 {
47 	S_FPLAY_ATK1,
48 	S_CPLAY_ATK1,
49 	S_MPLAY_ATK1,
50 	S_PIGPLAY_ATK1
51 };
52 
53 int PStateAttackEnd[NUMCLASSES] =
54 {
55 	S_FPLAY_ATK2,
56 	S_CPLAY_ATK3,
57 	S_MPLAY_ATK2,
58 	S_PIGPLAY_ATK1
59 };
60 
61 int ArmorMax[NUMCLASSES] = { 20, 18, 16, 1 };
62 /*
63 ==================
64 =
65 = P_Thrust
66 =
67 = moves the given origin along a given angle
68 =
69 ==================
70 */
71 
P_Thrust(player_t * player,angle_t angle,fixed_t move)72 void P_Thrust(player_t *player, angle_t angle, fixed_t move)
73 {
74 	angle >>= ANGLETOFINESHIFT;
75 	if(player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
76 	{
77 		player->mo->momx += FixedMul(move, finecosine[angle]);
78 		player->mo->momy += FixedMul(move, finesine[angle]);
79 	}
80 	else if(P_GetThingFloorType(player->mo) == FLOOR_ICE) // Friction_Low
81 	{
82 		player->mo->momx += FixedMul(move>>1, finecosine[angle]);
83 		player->mo->momy += FixedMul(move>>1, finesine[angle]);
84 	}
85 	else
86 	{
87 		player->mo->momx += FixedMul(move, finecosine[angle]);
88 		player->mo->momy += FixedMul(move, finesine[angle]);
89 	}
90 }
91 
92 
93 /*
94 ==================
95 =
96 = P_CalcHeight
97 =
98 =Calculate the walking / running height adjustment
99 =
100 ==================
101 */
102 
P_CalcHeight(player_t * player)103 void P_CalcHeight (player_t *player)
104 {
105 	int		angle;
106 	fixed_t	bob;
107 
108 //
109 // regular movement bobbing (needs to be calculated for gun swing even
110 // if not on ground)
111 // OPTIMIZE: tablify angle
112 
113 	player->bob = FixedMul (player->mo->momx, player->mo->momx)+
114 	FixedMul (player->mo->momy,player->mo->momy);
115 	player->bob >>= 2;
116 	if (player->bob>MAXBOB)
117 		player->bob = MAXBOB;
118 	if(player->mo->flags2&MF2_FLY && !onground)
119 	{
120 		player->bob = FRACUNIT/2;
121 	}
122 
123 	if ((player->cheats & CF_NOMOMENTUM))
124 	{
125 		player->viewz = player->mo->z + VIEWHEIGHT;
126 		if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
127 			player->viewz = player->mo->ceilingz-4*FRACUNIT;
128 		player->viewz = player->mo->z + player->viewheight;
129 		return;
130 	}
131 
132 	angle = (FINEANGLES/20*leveltime)&FINEMASK;
133 	bob = FixedMul ( player->bob/2, finesine[angle]);
134 
135 //
136 // move viewheight
137 //
138 	if (player->playerstate == PST_LIVE)
139 	{
140 		player->viewheight += player->deltaviewheight;
141 		if (player->viewheight > VIEWHEIGHT)
142 		{
143 			player->viewheight = VIEWHEIGHT;
144 			player->deltaviewheight = 0;
145 		}
146 		if (player->viewheight < VIEWHEIGHT/2)
147 		{
148 			player->viewheight = VIEWHEIGHT/2;
149 			if (player->deltaviewheight <= 0)
150 				player->deltaviewheight = 1;
151 		}
152 
153 		if (player->deltaviewheight)
154 		{
155 			player->deltaviewheight += FRACUNIT/4;
156 			if (!player->deltaviewheight)
157 				player->deltaviewheight = 1;
158 		}
159 	}
160 
161 	if(player->morphTics)
162 	{
163 		player->viewz = player->mo->z+player->viewheight-(20*FRACUNIT);
164 	}
165 	else
166 	{
167 		player->viewz = player->mo->z+player->viewheight+bob;
168 	}
169 	if(player->mo->floorclip && player->playerstate != PST_DEAD
170 		&& player->mo->z <= player->mo->floorz)
171 	{
172 		player->viewz -= player->mo->floorclip;
173 	}
174 	if(player->viewz > player->mo->ceilingz-4*FRACUNIT)
175 	{
176 		player->viewz = player->mo->ceilingz-4*FRACUNIT;
177 	}
178 	if(player->viewz < player->mo->floorz+4*FRACUNIT)
179 	{
180 		player->viewz = player->mo->floorz+4*FRACUNIT;
181 	}
182 }
183 
184 /*
185 =================
186 =
187 = P_MovePlayer
188 =
189 =================
190 */
191 
P_MovePlayer(player_t * player)192 void P_MovePlayer(player_t *player)
193 {
194 	int look;
195 	int fly;
196 	ticcmd_t *cmd;
197 
198 	cmd = &player->cmd;
199 	player->mo->angle += (cmd->angleturn<<16);
200 
201 	onground = (player->mo->z <= player->mo->floorz
202 		|| (player->mo->flags2&MF2_ONMOBJ));
203 
204 	if(cmd->forwardmove)
205 	{
206 		if(onground || player->mo->flags2&MF2_FLY)
207 		{
208 			P_Thrust(player, player->mo->angle, cmd->forwardmove*2048);
209 		}
210 		else
211 		{
212 			P_Thrust(player, player->mo->angle, FRACUNIT>>8);
213 		}
214 	}
215 	if(cmd->sidemove)
216 	{
217 		if(onground || player->mo->flags2&MF2_FLY)
218 			{
219 			P_Thrust(player, player->mo->angle-ANG90, cmd->sidemove*2048);
220 		}
221 		else
222 		{
223 			P_Thrust(player, player->mo->angle, FRACUNIT>>8);
224 		}
225 	}
226 	if(cmd->forwardmove || cmd->sidemove)
227 	{
228 		if(player->mo->state == &states[PStateNormal[player->class]])
229 		{
230 			P_SetMobjState(player->mo, PStateRun[player->class]);
231 		}
232 	}
233 
234 	look = cmd->lookfly&15;
235 	if(look > 7)
236 	{
237 		look -= 16;
238 	}
239 	if(look)
240 	{
241 		if(look == TOCENTER)
242 		{
243 			player->centering = true;
244 		}
245 		else
246 		{
247 			player->lookdir += 5*look;
248 			if(player->lookdir > 90 || player->lookdir < -110)
249 			{
250 				player->lookdir -= 5*look;
251 			}
252 		}
253 	}
254 	if(player->centering)
255 	{
256 		if(player->lookdir > 0)
257 		{
258 			player->lookdir -= 8;
259 		}
260 		else if(player->lookdir < 0)
261 		{
262 			player->lookdir += 8;
263 		}
264 		if(abs(player->lookdir) < 8)
265 		{
266 			player->lookdir = 0;
267 			player->centering = false;
268 		}
269 	}
270 	fly = cmd->lookfly>>4;
271 	if(fly > 7)
272 	{
273 		fly -= 16;
274 	}
275 	if(fly && player->powers[pw_flight])
276 	{
277 		if(fly != TOCENTER)
278 		{
279 			player->flyheight = fly*2;
280 			if(!(player->mo->flags2&MF2_FLY))
281 			{
282 				player->mo->flags2 |= MF2_FLY;
283 				player->mo->flags |= MF_NOGRAVITY;
284 				if(player->mo->momz <= -39*FRACUNIT)
285 				{ // stop falling scream
286 					S_StopSound(player->mo);
287 				}
288 			}
289 		}
290 		else
291 		{
292 			player->mo->flags2 &= ~MF2_FLY;
293 			player->mo->flags &= ~MF_NOGRAVITY;
294 		}
295 	}
296 	else if(fly > 0)
297 	{
298 		P_PlayerUseArtifact(player, arti_fly);
299 	}
300 	if(player->mo->flags2&MF2_FLY)
301 	{
302 		player->mo->momz = player->flyheight*FRACUNIT;
303 		if(player->flyheight)
304 		{
305 			player->flyheight /= 2;
306 		}
307 	}
308 }
309 
310 //==========================================================================
311 //
312 // P_DeathThink
313 //
314 //==========================================================================
315 
P_DeathThink(player_t * player)316 void P_DeathThink(player_t *player)
317 {
318 	int dir;
319 	angle_t delta;
320 	int lookDelta;
321 	extern int inv_ptr;
322 	extern int curpos;
323 
324 	P_MovePsprites(player);
325 
326 	onground = (player->mo->z <= player->mo->floorz);
327 	if(player->mo->type == MT_BLOODYSKULL || player->mo->type == MT_ICECHUNK)
328 	{ // Flying bloody skull or flying ice chunk
329 		player->viewheight = 6*FRACUNIT;
330 		player->deltaviewheight = 0;
331 		//player->damagecount = 20;
332 		if(onground)
333 		{
334 			if(player->lookdir < 60)
335 			{
336 				lookDelta = (60-player->lookdir)/8;
337 				if(lookDelta < 1 && (leveltime&1))
338 				{
339 					lookDelta = 1;
340 				}
341 				else if(lookDelta > 6)
342 				{
343 					lookDelta = 6;
344 				}
345 				player->lookdir += lookDelta;
346 			}
347 		}
348 	}
349 	else if(!(player->mo->flags2&MF2_ICEDAMAGE))
350 	{ // Fall to ground (if not frozen)
351 		player->deltaviewheight = 0;
352 		if(player->viewheight > 6*FRACUNIT)
353 		{
354 			player->viewheight -= FRACUNIT;
355 		}
356 		if(player->viewheight < 6*FRACUNIT)
357 		{
358 			player->viewheight = 6*FRACUNIT;
359 		}
360 		if(player->lookdir > 0)
361 		{
362 			player->lookdir -= 6;
363 		}
364 		else if(player->lookdir < 0)
365 		{
366 			player->lookdir += 6;
367 		}
368 		if(abs(player->lookdir) < 6)
369 		{
370 			player->lookdir = 0;
371 		}
372 	}
373 	P_CalcHeight(player);
374 
375 	if(player->attacker && player->attacker != player->mo)
376 	{ // Watch killer
377 		dir = P_FaceMobj(player->mo, player->attacker, &delta);
378 		if(delta < ANGLE_1*10)
379 		{ // Looking at killer, so fade damage and poison counters
380 			if(player->damagecount)
381 			{
382 				player->damagecount--;
383 			}
384 			if(player->poisoncount)
385 			{
386 				player->poisoncount--;
387 			}
388 		}
389 		delta = delta/8;
390 		if(delta > ANGLE_1*5)
391 		{
392 			delta = ANGLE_1*5;
393 		}
394 		if(dir)
395 		{ // Turn clockwise
396 			player->mo->angle += delta;
397 		}
398 		else
399 		{ // Turn counter clockwise
400 			player->mo->angle -= delta;
401 		}
402 	}
403 	else if(player->damagecount || player->poisoncount)
404 	{
405 		if(player->damagecount)
406 		{
407 			player->damagecount--;
408 		}
409 		else
410 		{
411 			player->poisoncount--;
412 		}
413 	}
414 
415 	if(player->cmd.buttons&BT_USE)
416 	{
417 		if(player == &players[consoleplayer])
418 		{
419 			I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE));
420 			inv_ptr = 0;
421 			curpos = 0;
422 			newtorch = 0;
423 			newtorchdelta = 0;
424 		}
425 		player->playerstate = PST_REBORN;
426 		player->mo->special1 = player->class;
427 		if(player->mo->special1 > 2)
428 		{
429 			player->mo->special1 = 0;
430 		}
431 		// Let the mobj know the player has entered the reborn state.  Some
432 		// mobjs need to know when it's ok to remove themselves.
433 		player->mo->special2 = 666;
434 	}
435 }
436 
437 //----------------------------------------------------------------------------
438 //
439 // PROC P_MorphPlayerThink
440 //
441 //----------------------------------------------------------------------------
442 
P_MorphPlayerThink(player_t * player)443 void P_MorphPlayerThink(player_t *player)
444 {
445 	mobj_t *pmo;
446 
447 	if(player->morphTics&15)
448 	{
449 		return;
450 	}
451 	pmo = player->mo;
452 	if(!(pmo->momx+pmo->momy) && P_Random() < 64)
453 	{ // Snout sniff
454 		P_SetPspriteNF(player, ps_weapon, S_SNOUTATK2);
455 		S_StartSound(pmo, SFX_PIG_ACTIVE1); // snort
456 		return;
457 	}
458 	if(P_Random() < 48)
459 	{
460 		if(P_Random() < 128)
461 		{
462 			S_StartSound(pmo, SFX_PIG_ACTIVE1);
463 		}
464 		else
465 		{
466 			S_StartSound(pmo, SFX_PIG_ACTIVE2);
467 		}
468 	}
469 }
470 
471 //----------------------------------------------------------------------------
472 //
473 // FUNC P_GetPlayerNum
474 //
475 //----------------------------------------------------------------------------
476 
P_GetPlayerNum(player_t * player)477 int P_GetPlayerNum(player_t *player)
478 {
479 	int i;
480 
481 	for(i = 0; i < MAXPLAYERS; i++)
482 	{
483 		if(player == &players[i])
484 		{
485 			return(i);
486 		}
487 	}
488 	return(0);
489 }
490 
491 //----------------------------------------------------------------------------
492 //
493 // FUNC P_UndoPlayerMorph
494 //
495 //----------------------------------------------------------------------------
496 
P_UndoPlayerMorph(player_t * player)497 boolean P_UndoPlayerMorph(player_t *player)
498 {
499 	mobj_t *fog;
500 	mobj_t *mo;
501 	mobj_t *pmo;
502 	fixed_t x;
503 	fixed_t y;
504 	fixed_t z;
505 	angle_t angle;
506 	int playerNum;
507 	weapontype_t weapon;
508 	int oldFlags;
509 	int oldFlags2;
510 	int oldBeast;
511 
512 
513 	if (player->cheats & CF_FUNNYPIGGY) {
514 	  player->morphTics = 10000;
515 	  return(false);
516 	}
517 	pmo = player->mo;
518 	x = pmo->x;
519 	y = pmo->y;
520 	z = pmo->z;
521 	angle = pmo->angle;
522 	weapon = pmo->special1;
523 	oldFlags = pmo->flags;
524 	oldFlags2 = pmo->flags2;
525 	oldBeast = pmo->type;
526 	P_SetMobjState(pmo, S_FREETARGMOBJ);
527 	playerNum = P_GetPlayerNum(player);
528 	switch(PlayerClass[playerNum])
529 	{
530 		case PCLASS_FIGHTER:
531 			mo = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
532 			break;
533 		case PCLASS_CLERIC:
534 			mo = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
535 			break;
536 		case PCLASS_MAGE:
537 			mo = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
538 			break;
539 		default:
540 			I_Error("P_UndoPlayerMorph:  Unknown player class %d\n",
541 				player->class);
542 	}
543 	if(P_TestMobjLocation(mo) == false)
544 	{ // Didn't fit
545 		P_RemoveMobj(mo);
546 		mo = P_SpawnMobj(x, y, z, oldBeast);
547 		mo->angle = angle;
548 		mo->health = player->health;
549 		mo->special1 = weapon;
550 		mo->player = player;
551 		mo->flags = oldFlags;
552 		mo->flags2 = oldFlags2;
553 		player->mo = mo;
554 		player->morphTics = 2*35;
555 		return(false);
556 	}
557 	if(player->class == PCLASS_FIGHTER)
558 	{
559 		// The first type should be blue, and the third should be the
560 		// Fighter's original gold color
561 		if(playerNum == 0)
562 		{
563 			mo->flags |= 2<<MF_TRANSSHIFT;
564 		}
565 		else if(playerNum != 2)
566 		{
567 			mo->flags |= playerNum<<MF_TRANSSHIFT;
568 		}
569 	}
570 	else if(playerNum)
571 	{ // Set color translation bits for player sprites
572 		mo->flags |= playerNum<<MF_TRANSSHIFT;
573 	}
574 	mo->angle = angle;
575 	mo->player = player;
576 	mo->reactiontime = 18;
577 	if(oldFlags2&MF2_FLY)
578 	{
579 		mo->flags2 |= MF2_FLY;
580 		mo->flags |= MF_NOGRAVITY;
581 	}
582 	player->morphTics = 0;
583 	player->health = mo->health = MAXHEALTH;
584 	player->mo = mo;
585 	player->class = PlayerClass[playerNum];
586 	angle >>= ANGLETOFINESHIFT;
587 	fog = P_SpawnMobj(x+20*finecosine[angle],
588 		y+20*finesine[angle], z+TELEFOGHEIGHT, MT_TFOG);
589 	S_StartSound(fog, SFX_TELEPORT);
590 	P_PostMorphWeapon(player, weapon);
591 	return(true);
592 }
593 
594 
595 //----------------------------------------------------------------------------
596 //
597 // PROC P_PlayerThink
598 //
599 //----------------------------------------------------------------------------
600 
P_PlayerThink(player_t * player)601 void P_PlayerThink(player_t *player)
602 {
603 	ticcmd_t *cmd;
604 	weapontype_t newweapon;
605 	int floorType;
606 	mobj_t *pmo;
607 
608 	if (!player)
609 	  I_Error("P_PlayerThink: no player!");
610 	if (!player->mo)
611 	 I_Error("P_PlayerThink: no player->mo!");
612 
613 	// No-clip cheat
614 	if(player->cheats&CF_NOCLIP)
615 	{
616 		player->mo->flags |= MF_NOCLIP;
617 	}
618 	else
619 	{
620 		player->mo->flags &= ~MF_NOCLIP;
621 	}
622 	cmd = &player->cmd;
623 	if(player->mo->flags&MF_JUSTATTACKED)
624 	{ // Gauntlets attack auto forward motion
625 		cmd->angleturn = 0;
626 		cmd->forwardmove = 0xc800/512;
627 		cmd->sidemove = 0;
628 		player->mo->flags &= ~MF_JUSTATTACKED;
629 	}
630 // messageTics is above the rest of the counters so that messages will
631 // 		go away, even in death.
632 	player->messageTics--; // Can go negative
633 	if(!player->messageTics || player->messageTics == -1)
634 	{ // Refresh the screen when a message goes away
635 		player->ultimateMessage = false; // clear out any chat messages.
636 		player->yellowMessage = false;
637 		if(player == &players[consoleplayer])
638 		{
639 			BorderTopRefresh = true;
640 		}
641 	}
642 	player->worldTimer++;
643 	if(player->playerstate == PST_DEAD)
644 	{
645 		P_DeathThink(player);
646 		return;
647 	}
648 	if(player->jumpTics)
649 	{
650 		player->jumpTics--;
651 	}
652 	if(player->morphTics)
653 	{
654 		P_MorphPlayerThink(player);
655 	}
656 	// Handle movement
657 	if(player->mo->reactiontime)
658 	{ // Player is frozen
659 		player->mo->reactiontime--;
660 	}
661 	else
662 	{
663 		P_MovePlayer(player);
664 		pmo = player->mo;
665 		if(player->powers[pw_speed] && !(leveltime&1)
666 			&& P_AproxDistance(pmo->momx, pmo->momy) > 12*FRACUNIT)
667 		{
668 			mobj_t *speedMo;
669 			int playerNum;
670 
671 			speedMo = P_SpawnMobj(pmo->x, pmo->y, pmo->z, MT_PLAYER_SPEED);
672 			if(speedMo)
673 			{
674 				speedMo->angle = pmo->angle;
675 				playerNum = P_GetPlayerNum(player);
676 				if(player->class == PCLASS_FIGHTER)
677 				{
678 					// The first type should be blue, and the
679 					// third should be the Fighter's original gold color
680 					if(playerNum == 0)
681 					{
682 						speedMo->flags |= 2<<MF_TRANSSHIFT;
683 					}
684 					else if(playerNum != 2)
685 					{
686 						speedMo->flags |= playerNum<<MF_TRANSSHIFT;
687 					}
688 				}
689 				else if(playerNum)
690 				{ // Set color translation bits for player sprites
691 					speedMo->flags |= playerNum<<MF_TRANSSHIFT;
692 				}
693 				speedMo->target = pmo;
694 				speedMo->special1 = player->class;
695 				if(speedMo->special1 > 2)
696 				{
697 					speedMo->special1 = 0;
698 				}
699 				speedMo->sprite = pmo->sprite;
700 				speedMo->floorclip = pmo->floorclip;
701 				if(player == &players[consoleplayer])
702 				{
703 					speedMo->flags2 |= MF2_DONTDRAW;
704 				}
705 			}
706 		}
707 	}
708 	P_CalcHeight(player);
709 	if(player->mo->subsector->sector->special)
710 	{
711 		P_PlayerInSpecialSector(player);
712 	}
713 	if((floorType = P_GetThingFloorType(player->mo)) != FLOOR_SOLID)
714 	{
715 		P_PlayerOnSpecialFlat(player, floorType);
716 	}
717 	switch(player->class)
718 	{
719 		case PCLASS_FIGHTER:
720 			if(player->mo->momz <= -35*FRACUNIT
721 				&& player->mo->momz >= -40*FRACUNIT && !player->morphTics
722 				&& !S_GetSoundPlayingInfo(player->mo,
723 				SFX_PLAYER_FIGHTER_FALLING_SCREAM))
724 				{
725 					S_StartSound(player->mo,
726 						SFX_PLAYER_FIGHTER_FALLING_SCREAM);
727 				}
728 			break;
729 		case PCLASS_CLERIC:
730 			if(player->mo->momz <= -35*FRACUNIT
731 				&& player->mo->momz >= -40*FRACUNIT && !player->morphTics
732 				&& !S_GetSoundPlayingInfo(player->mo,
733 				SFX_PLAYER_CLERIC_FALLING_SCREAM))
734 				{
735 					S_StartSound(player->mo,
736 						SFX_PLAYER_CLERIC_FALLING_SCREAM);
737 				}
738 			break;
739 		case PCLASS_MAGE:
740 			if(player->mo->momz <= -35*FRACUNIT
741 				&& player->mo->momz >= -40*FRACUNIT && !player->morphTics
742 				&& !S_GetSoundPlayingInfo(player->mo,
743 				SFX_PLAYER_MAGE_FALLING_SCREAM))
744 				{
745 					S_StartSound(player->mo,
746 						SFX_PLAYER_MAGE_FALLING_SCREAM);
747 				}
748 			break;
749 		default:
750 			break;
751 	}
752 	if(cmd->arti)
753 	{ // Use an artifact
754 		if((cmd->arti&AFLAG_JUMP) && onground && !player->jumpTics)
755 		{
756 			if(player->morphTics)
757 			{
758 				player->mo->momz = 6*FRACUNIT;
759 			}
760 			else
761 			{
762 				player->mo->momz = 9*FRACUNIT;
763 			}
764 			player->mo->flags2 &= ~MF2_ONMOBJ;
765 			player->jumpTics = 18;
766 		}
767 		else if(cmd->arti&AFLAG_SUICIDE)
768 		{
769 			P_DamageMobj(player->mo, NULL, NULL, 10000);
770 		}
771 		if(cmd->arti == NUMARTIFACTS)
772 		{ // use one of each artifact (except puzzle artifacts)
773 			int i;
774 
775 			for(i = 1; i < arti_firstpuzzitem; i++)
776 			{
777 				P_PlayerUseArtifact(player, i);
778 			}
779 		}
780 		else
781 		{
782 			P_PlayerUseArtifact(player, cmd->arti&AFLAG_MASK);
783 		}
784 	}
785 	// Check for weapon change
786 	if(cmd->buttons&BT_SPECIAL)
787 	{ // A special event has no other buttons
788 		cmd->buttons = 0;
789 	}
790 	if(cmd->buttons&BT_CHANGE && !player->morphTics)
791 	{
792 		// The actual changing of the weapon is done when the weapon
793 		// psprite can do it (A_WeaponReady), so it doesn't happen in
794 		// the middle of an attack.
795 		newweapon = (cmd->buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT;
796 		if(player->weaponowned[newweapon]
797 			&& newweapon != player->readyweapon)
798 		{
799 			player->pendingweapon = newweapon;
800 		}
801 	}
802 	// Check for use
803 	if(cmd->buttons&BT_USE)
804 	{
805 		if(!player->usedown)
806 		{
807 			P_UseLines(player);
808 			player->usedown = true;
809 		}
810 	}
811 	else
812 	{
813 		player->usedown = false;
814 	}
815 	// Morph counter
816 	if(player->morphTics)
817 	{
818 		if(!--player->morphTics)
819 		{ // Attempt to undo the pig
820 			P_UndoPlayerMorph(player);
821 		}
822 	}
823 	// Cycle psprites
824 	P_MovePsprites(player);
825 	// Other Counters
826 	if(player->powers[pw_invulnerability])
827 	{
828 		if(player->class == PCLASS_CLERIC)
829 		{
830 			if(!(leveltime&7) && player->mo->flags&MF_SHADOW
831 				&& !(player->mo->flags2&MF2_DONTDRAW))
832 			{
833 				player->mo->flags &= ~MF_SHADOW;
834 				if(!(player->mo->flags&MF_ALTSHADOW))
835 				{
836 					player->mo->flags2 |= MF2_DONTDRAW|MF2_NONSHOOTABLE;
837 				}
838 			}
839 			if(!(leveltime&31))
840 			{
841 				if(player->mo->flags2&MF2_DONTDRAW)
842 				{
843 					if(!(player->mo->flags&MF_SHADOW))
844 					{
845 						player->mo->flags |= MF_SHADOW|MF_ALTSHADOW;
846 					}
847 					else
848 					{
849 						player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
850 					}
851 				}
852 				else
853 				{
854 					player->mo->flags |= MF_SHADOW;
855 					player->mo->flags &= ~MF_ALTSHADOW;
856 				}
857 			}
858 		}
859 		if(!(--player->powers[pw_invulnerability]))
860 		{
861 			player->mo->flags2 &= ~(MF2_INVULNERABLE|MF2_REFLECTIVE);
862 			if(player->class == PCLASS_CLERIC)
863 			{
864 				player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
865 				player->mo->flags &= ~(MF_SHADOW|MF_ALTSHADOW);
866 			}
867 		}
868 	}
869 	if(player->powers[pw_minotaur])
870 	{
871 		player->powers[pw_minotaur]--;
872 	}
873 	if(player->powers[pw_infrared])
874 	{
875 		player->powers[pw_infrared]--;
876 	}
877 	if(player->powers[pw_flight] && netgame)
878 	{
879 		if(!--player->powers[pw_flight])
880 		{
881 			if(player->mo->z != player->mo->floorz)
882 			{
883 #ifdef __WATCOMC__
884 				if(!useexterndriver)
885 				{
886 					player->centering = true;
887 				}
888 #else
889 				player->centering = true;
890 #endif
891 			}
892 			player->mo->flags2 &= ~MF2_FLY;
893 			player->mo->flags &= ~MF_NOGRAVITY;
894 			BorderTopRefresh = true; //make sure the sprite's cleared out
895 		}
896 	}
897 	if(player->powers[pw_speed])
898 	{
899 		player->powers[pw_speed]--;
900 	}
901 	if(player->damagecount)
902 	{
903 		player->damagecount--;
904 	}
905 	if(player->bonuscount)
906 	{
907 		player->bonuscount--;
908 	}
909 	if(player->poisoncount && !(leveltime&15))
910 	{
911 		player->poisoncount -= 5;
912 		if(player->poisoncount < 0)
913 		{
914 			player->poisoncount = 0;
915 		}
916 		P_PoisonDamage(player, player->poisoner, 1, true);
917 	}
918 	// Colormaps
919 //	if(player->powers[pw_invulnerability])
920 //	{
921 //		if(player->powers[pw_invulnerability] > BLINKTHRESHOLD
922 //			|| (player->powers[pw_invulnerability]&8))
923 //		{
924 //			player->fixedcolormap = INVERSECOLORMAP;
925 //		}
926 //		else
927 //		{
928 //			player->fixedcolormap = 0;
929 //		}
930 //	}
931 //	else
932 	if(player->powers[pw_infrared])
933 	{
934 		if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
935 		{
936 			if(player->powers[pw_infrared]&8)
937 			{
938 				player->fixedcolormap = 0;
939 			}
940 			else
941 			{
942 				player->fixedcolormap = 1;
943 			}
944 		}
945 		else if(!(leveltime&16) && player == &players[consoleplayer])
946 		{
947 			if(newtorch)
948 			{
949 				if(player->fixedcolormap+newtorchdelta > 7
950 					|| player->fixedcolormap+newtorchdelta < 1
951 					|| newtorch == player->fixedcolormap)
952 				{
953 					newtorch = 0;
954 				}
955 				else
956 				{
957 					player->fixedcolormap += newtorchdelta;
958 				}
959 			}
960 			else
961 			{
962 				newtorch = (M_Random()&7)+1;
963 				newtorchdelta = (newtorch == player->fixedcolormap) ?
964 						0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
965 			}
966 		}
967 	}
968 	else
969 	{
970 		player->fixedcolormap = 0;
971 	}
972 }
973 
974 //----------------------------------------------------------------------------
975 //
976 // PROC P_ArtiTele
977 //
978 //----------------------------------------------------------------------------
979 
P_ArtiTele(player_t * player)980 void P_ArtiTele(player_t *player)
981 {
982 	int i;
983 	int selections;
984 	fixed_t destX;
985 	fixed_t destY;
986 	angle_t destAngle;
987 
988 	if(deathmatch)
989 	{
990 		selections = deathmatch_p-deathmatchstarts;
991 		i = P_Random()%selections;
992 		destX = deathmatchstarts[i].x<<FRACBITS;
993 		destY = deathmatchstarts[i].y<<FRACBITS;
994 		destAngle = ANG45*(deathmatchstarts[i].angle/45);
995 	}
996 	else
997 	{
998 		destX = playerstarts[0][0].x<<FRACBITS;
999 		destY = playerstarts[0][0].y<<FRACBITS;
1000 		destAngle = ANG45*(playerstarts[0][0].angle/45);
1001 	}
1002 	P_Teleport(player->mo, destX, destY, destAngle, true);
1003 	if(player->morphTics)
1004 	{ // Teleporting away will undo any morph effects (pig)
1005 		P_UndoPlayerMorph(player);
1006 	}
1007 	//S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1008 }
1009 
1010 
1011 //----------------------------------------------------------------------------
1012 //
1013 // PROC P_ArtiTeleportOther
1014 //
1015 //----------------------------------------------------------------------------
1016 
P_ArtiTeleportOther(player_t * player)1017 void P_ArtiTeleportOther(player_t *player)
1018 {
1019 	mobj_t *mo;
1020 
1021 	mo=P_SpawnPlayerMissile(player->mo, MT_TELOTHER_FX1);
1022 	if (mo)
1023 	{
1024 		mo->target = player->mo;
1025 	}
1026 }
1027 
1028 
P_TeleportToPlayerStarts(mobj_t * victim)1029 void P_TeleportToPlayerStarts(mobj_t *victim)
1030 {
1031 	int i,selections=0;
1032 	fixed_t destX,destY;
1033 	angle_t destAngle;
1034 
1035 	for (i=0;i<MAXPLAYERS;i++)
1036 	{
1037 	    if (!playeringame[i]) continue;
1038 		selections++;
1039 	}
1040 	i = P_Random()%selections;
1041 	destX = playerstarts[0][i].x<<FRACBITS;
1042 	destY = playerstarts[0][i].y<<FRACBITS;
1043 	destAngle = ANG45*(playerstarts[0][i].angle/45);
1044 	P_Teleport(victim, destX, destY, destAngle, true);
1045 	//S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1046 }
1047 
P_TeleportToDeathmatchStarts(mobj_t * victim)1048 void P_TeleportToDeathmatchStarts(mobj_t *victim)
1049 {
1050 	int i,selections;
1051 	fixed_t destX,destY;
1052 	angle_t destAngle;
1053 
1054 	selections = deathmatch_p-deathmatchstarts;
1055 	if (selections)
1056 	{
1057 		i = P_Random()%selections;
1058 		destX = deathmatchstarts[i].x<<FRACBITS;
1059 		destY = deathmatchstarts[i].y<<FRACBITS;
1060 		destAngle = ANG45*(deathmatchstarts[i].angle/45);
1061 		P_Teleport(victim, destX, destY, destAngle, true);
1062 		//S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1063 	}
1064 	else
1065 	{
1066 	 	P_TeleportToPlayerStarts(victim);
1067 	}
1068 }
1069 
1070 
1071 
1072 //----------------------------------------------------------------------------
1073 //
1074 // PROC P_TeleportOther
1075 //
1076 //----------------------------------------------------------------------------
P_TeleportOther(mobj_t * victim)1077 void P_TeleportOther(mobj_t *victim)
1078 {
1079 	if (victim->player)
1080 	{
1081 		if (deathmatch)
1082 			P_TeleportToDeathmatchStarts(victim);
1083 		else
1084 			P_TeleportToPlayerStarts(victim);
1085 	}
1086 	else
1087 	{
1088 		// If death action, run it upon teleport
1089 		if (victim->flags&MF_COUNTKILL && victim->special)
1090 		{
1091 			P_RemoveMobjFromTIDList(victim);
1092 			P_ExecuteLineSpecial(victim->special, victim->args,
1093 					NULL, 0, victim);
1094 			victim->special = 0;
1095 		}
1096 
1097 		// Send all monsters to deathmatch spots
1098 		P_TeleportToDeathmatchStarts(victim);
1099 	}
1100 }
1101 
1102 
1103 
1104 #define BLAST_RADIUS_DIST	255*FRACUNIT
1105 #define BLAST_SPEED			20*FRACUNIT
1106 #define BLAST_FULLSTRENGTH	255
1107 
ResetBlasted(mobj_t * mo)1108 void ResetBlasted(mobj_t *mo)
1109 {
1110 	mo->flags2 &= ~MF2_BLASTED;
1111 	if (!(mo->flags&MF_ICECORPSE))
1112 	{
1113 		mo->flags2 &= ~MF2_SLIDE;
1114 	}
1115 }
1116 
P_BlastMobj(mobj_t * source,mobj_t * victim,fixed_t strength)1117 void P_BlastMobj(mobj_t *source, mobj_t *victim, fixed_t strength)
1118 {
1119 	angle_t angle,ang;
1120 	mobj_t *mo;
1121 	fixed_t x,y,z;
1122 
1123 	angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y);
1124 	angle >>= ANGLETOFINESHIFT;
1125 	if (strength < BLAST_FULLSTRENGTH)
1126 	{
1127 		victim->momx = FixedMul(strength, finecosine[angle]);
1128 		victim->momy = FixedMul(strength, finesine[angle]);
1129 		if (victim->player)
1130 		{
1131 			// Players handled automatically
1132 		}
1133 		else
1134 		{
1135 			victim->flags2 |= MF2_SLIDE;
1136 			victim->flags2 |= MF2_BLASTED;
1137 		}
1138 	}
1139 	else		// full strength blast from artifact
1140 	{
1141 		if (victim->flags&MF_MISSILE)
1142 		{
1143 			switch(victim->type)
1144 			{
1145 				case MT_SORCBALL1:	// don't blast sorcerer balls
1146 				case MT_SORCBALL2:
1147 				case MT_SORCBALL3:
1148 					return;
1149 					break;
1150 				case MT_MSTAFF_FX2:	// Reflect to originator
1151 					victim->special1 = (int)victim->target;
1152 					victim->target = source;
1153 					break;
1154 				default:
1155 					break;
1156 			}
1157 		}
1158 		if (victim->type == MT_HOLY_FX)
1159 		{
1160 			if ((mobj_t *)(victim->special1) == source)
1161 			{
1162 				victim->special1 = (int)victim->target;
1163 				victim->target = source;
1164 			}
1165 		}
1166 		victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]);
1167 		victim->momy = FixedMul(BLAST_SPEED, finesine[angle]);
1168 
1169 		// Spawn blast puff
1170 		ang = R_PointToAngle2(victim->x, victim->y, source->x, source->y);
1171 		ang >>= ANGLETOFINESHIFT;
1172 		x = victim->x + FixedMul(victim->radius+FRACUNIT, finecosine[ang]);
1173 		y = victim->y + FixedMul(victim->radius+FRACUNIT, finesine[ang]);
1174 		z = victim->z - victim->floorclip + (victim->height>>1);
1175 		mo=P_SpawnMobj(x, y, z, MT_BLASTEFFECT);
1176 		if (mo)
1177 		{
1178 			mo->momx = victim->momx;
1179 			mo->momy = victim->momy;
1180 		}
1181 
1182 		if (victim->flags&MF_MISSILE)
1183 		{
1184 			victim->momz = 8*FRACUNIT;
1185 			mo->momz = victim->momz;
1186 		}
1187 		else
1188 		{
1189 			victim->momz = (1000/victim->info->mass)<<FRACBITS;
1190 		}
1191 		if (victim->player)
1192 		{
1193 			// Players handled automatically
1194 		}
1195 		else
1196 		{
1197 			victim->flags2 |= MF2_SLIDE;
1198 			victim->flags2 |= MF2_BLASTED;
1199 		}
1200 	}
1201 }
1202 
1203 
1204 // Blast all mobj things away
P_BlastRadius(player_t * player)1205 void P_BlastRadius(player_t *player)
1206 {
1207 	mobj_t *mo;
1208 	mobj_t *pmo=player->mo;
1209 	thinker_t *think;
1210 	fixed_t dist;
1211 
1212 	S_StartSound(pmo, SFX_ARTIFACT_BLAST);
1213 	P_NoiseAlert(player->mo, player->mo);
1214 
1215 	for(think = thinkercap.next; think != &thinkercap; think = think->next)
1216 	{
1217 		if(think->function != P_MobjThinker)
1218 		{ // Not a mobj thinker
1219 			continue;
1220 		}
1221 		mo = (mobj_t *)think;
1222 		if((mo == pmo) || (mo->flags2&MF2_BOSS))
1223 		{ // Not a valid monster
1224 			continue;
1225 		}
1226 		if ((mo->type == MT_POISONCLOUD) ||		// poison cloud
1227 			(mo->type == MT_HOLY_FX) ||			// holy fx
1228 			(mo->flags&MF_ICECORPSE))			// frozen corpse
1229 		{
1230 			// Let these special cases go
1231 		}
1232 		else if ((mo->flags&MF_COUNTKILL) &&
1233 			(mo->health <= 0))
1234 		{
1235 			continue;
1236 		}
1237 		else if (!(mo->flags&MF_COUNTKILL) &&
1238 			!(mo->player) &&
1239 			!(mo->flags&MF_MISSILE))
1240 		{	// Must be monster, player, or missile
1241 			continue;
1242 		}
1243 		if (mo->flags2&MF2_DORMANT)
1244 		{
1245 			continue;		// no dormant creatures
1246 		}
1247 		if ((mo->type == MT_WRAITHB) && (mo->flags2&MF2_DONTDRAW))
1248 		{
1249 			continue;		// no underground wraiths
1250 		}
1251 		if ((mo->type == MT_SPLASHBASE) ||
1252 			(mo->type == MT_SPLASH))
1253 		{
1254 			continue;
1255 		}
1256 		if(mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER)
1257 		{
1258 			continue;
1259 		}
1260 		dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
1261 		if(dist > BLAST_RADIUS_DIST)
1262 		{ // Out of range
1263 			continue;
1264 		}
1265 		P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH);
1266 	}
1267 }
1268 
1269 
1270 #define HEAL_RADIUS_DIST	255*FRACUNIT
1271 
1272 // Do class specific effect for everyone in radius
P_HealRadius(player_t * player)1273 boolean P_HealRadius(player_t *player)
1274 {
1275 	mobj_t *mo;
1276 	mobj_t *pmo=player->mo;
1277 	thinker_t *think;
1278 	fixed_t dist;
1279 	int effective=false;
1280 	int amount;
1281 
1282 	for(think = thinkercap.next; think != &thinkercap; think = think->next)
1283 	{
1284 		if(think->function != P_MobjThinker)
1285 		{ // Not a mobj thinker
1286 			continue;
1287 		}
1288 		mo = (mobj_t *)think;
1289 
1290 		if (!mo->player) continue;
1291 		if (mo->health <= 0) continue;
1292 		dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
1293 		if(dist > HEAL_RADIUS_DIST)
1294 		{ // Out of range
1295 			continue;
1296 		}
1297 
1298 		switch(player->class)
1299 		{
1300 			case PCLASS_FIGHTER:		// Radius armor boost
1301 				if ((P_GiveArmor(mo->player, ARMOR_ARMOR, 1)) ||
1302 					(P_GiveArmor(mo->player, ARMOR_SHIELD, 1)) ||
1303 					(P_GiveArmor(mo->player, ARMOR_HELMET, 1)) ||
1304 					(P_GiveArmor(mo->player, ARMOR_AMULET, 1)))
1305 				{
1306 					effective=true;
1307 					S_StartSound(mo, SFX_MYSTICINCANT);
1308 				}
1309 				break;
1310 			case PCLASS_CLERIC:			// Radius heal
1311 				amount = 50 + (P_Random()%50);
1312 				if (P_GiveBody(mo->player, amount))
1313 				{
1314 					effective=true;
1315 					S_StartSound(mo, SFX_MYSTICINCANT);
1316 				}
1317 				break;
1318 			case PCLASS_MAGE:			// Radius mana boost
1319 				amount = 50 + (P_Random()%50);
1320 				if ((P_GiveMana(mo->player, MANA_1, amount)) ||
1321 					(P_GiveMana(mo->player, MANA_2, amount)))
1322 				{
1323 					effective=true;
1324 					S_StartSound(mo, SFX_MYSTICINCANT);
1325 				}
1326 				break;
1327 			case PCLASS_PIG:
1328 			default:
1329 				break;
1330 		}
1331 	}
1332 	return(effective);
1333 }
1334 
1335 
1336 //----------------------------------------------------------------------------
1337 //
1338 // PROC P_PlayerNextArtifact
1339 //
1340 //----------------------------------------------------------------------------
1341 
P_PlayerNextArtifact(player_t * player)1342 void P_PlayerNextArtifact(player_t *player)
1343 {
1344 	extern int inv_ptr;
1345 	extern int curpos;
1346 
1347 	if(player == &players[consoleplayer])
1348 	{
1349 		inv_ptr--;
1350 		if(inv_ptr < 6)
1351 		{
1352 			curpos--;
1353 			if(curpos < 0)
1354 			{
1355 				curpos = 0;
1356 			}
1357 		}
1358 		if(inv_ptr < 0)
1359 		{
1360 			inv_ptr = player->inventorySlotNum-1;
1361 			if(inv_ptr < 6)
1362 			{
1363 				curpos = inv_ptr;
1364 			}
1365 			else
1366 			{
1367 				curpos = 6;
1368 			}
1369 		}
1370 		player->readyArtifact =
1371 			player->inventory[inv_ptr].type;
1372 	}
1373 }
1374 
1375 //----------------------------------------------------------------------------
1376 //
1377 // PROC P_PlayerRemoveArtifact
1378 //
1379 //----------------------------------------------------------------------------
1380 
P_PlayerRemoveArtifact(player_t * player,int slot)1381 void P_PlayerRemoveArtifact(player_t *player, int slot)
1382 {
1383 	int i;
1384 	extern int inv_ptr;
1385 	extern int curpos;
1386 
1387 	player->artifactCount--;
1388 	if(!(--player->inventory[slot].count))
1389 	{ // Used last of a type - compact the artifact list
1390 		player->readyArtifact = arti_none;
1391 		player->inventory[slot].type = arti_none;
1392 		for(i = slot+1; i < player->inventorySlotNum; i++)
1393 		{
1394 			player->inventory[i-1] = player->inventory[i];
1395 		}
1396 		player->inventorySlotNum--;
1397 		if(player == &players[consoleplayer])
1398 		{ // Set position markers and get next readyArtifact
1399 			inv_ptr--;
1400 			if(inv_ptr < 6)
1401 			{
1402 				curpos--;
1403 				if(curpos < 0)
1404 				{
1405 					curpos = 0;
1406 				}
1407 			}
1408 			if(inv_ptr >= player->inventorySlotNum)
1409 			{
1410 				inv_ptr = player->inventorySlotNum-1;
1411 			}
1412 			if(inv_ptr < 0)
1413 			{
1414 				inv_ptr = 0;
1415 			}
1416 			player->readyArtifact =
1417 				player->inventory[inv_ptr].type;
1418 		}
1419 	}
1420 }
1421 
1422 //----------------------------------------------------------------------------
1423 //
1424 // PROC P_PlayerUseArtifact
1425 //
1426 //----------------------------------------------------------------------------
1427 
P_PlayerUseArtifact(player_t * player,artitype_t arti)1428 void P_PlayerUseArtifact(player_t *player, artitype_t arti)
1429 {
1430 	int i;
1431 
1432 	for(i = 0; i < player->inventorySlotNum; i++)
1433 	{
1434 		if(player->inventory[i].type == arti)
1435 		{ // Found match - try to use
1436 			if(P_UseArtifact(player, arti))
1437 			{ // Artifact was used - remove it from inventory
1438 				P_PlayerRemoveArtifact(player, i);
1439 				if(player == &players[consoleplayer])
1440 				{
1441 					if(arti < arti_firstpuzzitem)
1442 					{
1443 						S_StartSound(NULL, SFX_ARTIFACT_USE);
1444 					}
1445 					else
1446 					{
1447 						S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
1448 					}
1449 					ArtifactFlash = 4;
1450 				}
1451 			}
1452 			else if(arti < arti_firstpuzzitem)
1453 			{ // Unable to use artifact, advance pointer
1454 				P_PlayerNextArtifact(player);
1455 			}
1456 			break;
1457 		}
1458 	}
1459 }
1460 
1461 //==========================================================================
1462 //
1463 // P_UseArtifact
1464 //
1465 // Returns true if the artifact was used.
1466 //
1467 //==========================================================================
1468 
P_UseArtifact(player_t * player,artitype_t arti)1469 boolean P_UseArtifact(player_t *player, artitype_t arti)
1470 {
1471 	mobj_t *mo;
1472 	angle_t angle;
1473 	int i;
1474 	int count;
1475 
1476 	switch(arti)
1477 	{
1478 		case arti_invulnerability:
1479 			if(!P_GivePower(player, pw_invulnerability))
1480 			{
1481 				return(false);
1482 			}
1483 			break;
1484 		case arti_health:
1485 			if(!P_GiveBody(player, 25))
1486 			{
1487 				return(false);
1488 			}
1489 			break;
1490 		case arti_superhealth:
1491 			if(!P_GiveBody(player, 100))
1492 			{
1493 				return(false);
1494 			}
1495 			break;
1496 		case arti_healingradius:
1497 			if (!P_HealRadius(player))
1498 			{
1499 				return(false);
1500 			}
1501 			break;
1502 		case arti_torch:
1503 			if(!P_GivePower(player, pw_infrared))
1504 			{
1505 				return(false);
1506 			}
1507 			break;
1508 		case arti_egg:
1509 			mo = player->mo;
1510 			P_SpawnPlayerMissile(mo, MT_EGGFX);
1511 			P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/6));
1512 			P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/6));
1513 			P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/3));
1514 			P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/3));
1515 			break;
1516 		case arti_fly:
1517 			if(!P_GivePower(player, pw_flight))
1518 			{
1519 				return(false);
1520 			}
1521 			if(player->mo->momz <= -35*FRACUNIT)
1522 			{ // stop falling scream
1523 				S_StopSound(player->mo);
1524 			}
1525 			break;
1526 		case arti_summon:
1527 			mo = P_SpawnPlayerMissile(player->mo, MT_SUMMON_FX);
1528 			if (mo)
1529 			{
1530 				mo->target = player->mo;
1531 				mo->special1 = (int)(player->mo);
1532 				mo->momz = 5*FRACUNIT;
1533 			}
1534 			break;
1535 		case arti_teleport:
1536 			P_ArtiTele(player);
1537 			break;
1538 		case arti_teleportother:
1539 			P_ArtiTeleportOther(player);
1540 			break;
1541 		case arti_poisonbag:
1542 			angle = player->mo->angle>>ANGLETOFINESHIFT;
1543 			if(player->class == PCLASS_CLERIC)
1544 			{
1545 				mo = P_SpawnMobj(player->mo->x+16*finecosine[angle],
1546 					player->mo->y+24*finesine[angle], player->mo->z-
1547 					player->mo->floorclip+8*FRACUNIT, MT_POISONBAG);
1548 				if(mo)
1549 				{
1550 					mo->target = player->mo;
1551 				}
1552 			}
1553 			else if(player->class == PCLASS_MAGE)
1554 			{
1555 				mo = P_SpawnMobj(player->mo->x+16*finecosine[angle],
1556 					player->mo->y+24*finesine[angle], player->mo->z-
1557 					player->mo->floorclip+8*FRACUNIT, MT_FIREBOMB);
1558 				if(mo)
1559 				{
1560 					mo->target = player->mo;
1561 				}
1562 			}
1563 			else // PCLASS_FIGHTER, obviously (also pig, not so obviously)
1564 			{
1565 				mo = P_SpawnMobj(player->mo->x, player->mo->y,
1566 					player->mo->z-player->mo->floorclip+35*FRACUNIT,
1567 					MT_THROWINGBOMB);
1568 				if(mo)
1569 				{
1570 					mo->angle = player->mo->angle+(((P_Random()&7)-4)<<24);
1571 					mo->momz = 4*FRACUNIT+((player->lookdir)<<(FRACBITS-4));
1572 					mo->z += player->lookdir<<(FRACBITS-4);
1573 					P_ThrustMobj(mo, mo->angle, mo->info->speed);
1574 					mo->momx += player->mo->momx>>1;
1575 					mo->momy += player->mo->momy>>1;
1576 					mo->target = player->mo;
1577 					mo->tics -= P_Random()&3;
1578 					P_CheckMissileSpawn(mo);
1579 				}
1580 			}
1581 			break;
1582 		case arti_speed:
1583 			if(!P_GivePower(player, pw_speed))
1584 			{
1585 				return(false);
1586 			}
1587 			break;
1588 		case arti_boostmana:
1589 			if(!P_GiveMana(player, MANA_1, MAX_MANA))
1590 			{
1591 				if(!P_GiveMana(player, MANA_2, MAX_MANA))
1592 				{
1593 					return false;
1594 				}
1595 
1596 			}
1597 			else
1598 			{
1599 				P_GiveMana(player, MANA_2, MAX_MANA);
1600 			}
1601 			break;
1602 		case arti_boostarmor:
1603 			count = 0;
1604 
1605 			for(i = 0; i < NUMARMOR; i++)
1606 			{
1607 				count += P_GiveArmor(player, i, 1); // 1 point per armor type
1608 			}
1609 			if(!count)
1610 			{
1611 				return false;
1612 			}
1613 			break;
1614 		case arti_blastradius:
1615 			P_BlastRadius(player);
1616 			break;
1617 
1618 		case arti_puzzskull:
1619 		case arti_puzzgembig:
1620 		case arti_puzzgemred:
1621 		case arti_puzzgemgreen1:
1622 		case arti_puzzgemgreen2:
1623 		case arti_puzzgemblue1:
1624 		case arti_puzzgemblue2:
1625 		case arti_puzzbook1:
1626 		case arti_puzzbook2:
1627 		case arti_puzzskull2:
1628 		case arti_puzzfweapon:
1629 		case arti_puzzcweapon:
1630 		case arti_puzzmweapon:
1631 		case arti_puzzgear1:
1632 		case arti_puzzgear2:
1633 		case arti_puzzgear3:
1634 		case arti_puzzgear4:
1635 			if(P_UsePuzzleItem(player, arti-arti_firstpuzzitem))
1636 			{
1637 				return true;
1638 			}
1639 			else
1640 			{
1641 				P_SetYellowMessage(player, TXT_USEPUZZLEFAILED, false);
1642 				return false;
1643 			}
1644 			break;
1645 		default:
1646 			return false;
1647 	}
1648 	return true;
1649 }
1650 
1651 //============================================================================
1652 //
1653 // A_SpeedFade
1654 //
1655 //============================================================================
1656 
A_SpeedFade(mobj_t * actor)1657 void A_SpeedFade(mobj_t *actor)
1658 {
1659 	actor->flags |= MF_SHADOW;
1660 	actor->flags &= ~MF_ALTSHADOW;
1661 	actor->sprite = actor->target->sprite;
1662 }
1663