1 #include "info.h"
2 #include "a_pickups.h"
3 #include "d_player.h"
4 #include "p_local.h"
5 #include "c_dispatch.h"
6 #include "gi.h"
7 #include "s_sound.h"
8 #include "p_local.h"
9 #include "p_spec.h"
10 #include "p_lnspec.h"
11 #include "p_effect.h"
12 #include "a_artifacts.h"
13 #include "sbar.h"
14 #include "d_player.h"
15 #include "m_random.h"
16 #include "v_video.h"
17 #include "templates.h"
18 #include "a_morph.h"
19 #include "g_level.h"
20 #include "doomstat.h"
21 #include "v_palette.h"
22 #include "farchive.h"
23 #include "r_data/colormaps.h"
24 
25 static FRandom pr_torch ("Torch");
26 
27 /* Those are no longer needed, except maybe as reference?
28  * They're not used anywhere in the code anymore, except
29  * MAULATORTICS as redefined in a_minotaur.cpp...
30 #define	INVULNTICS (30*TICRATE)
31 #define	INVISTICS (60*TICRATE)
32 #define	INFRATICS (120*TICRATE)
33 #define	IRONTICS (60*TICRATE)
34 #define WPNLEV2TICS (40*TICRATE)
35 #define FLIGHTTICS (60*TICRATE)
36 #define SPEEDTICS (45*TICRATE)
37 #define MAULATORTICS (25*TICRATE)
38 #define	TIMEFREEZE_TICS	( 12 * TICRATE )
39 */
40 
IMPLEMENT_CLASS(APowerup)41 IMPLEMENT_CLASS (APowerup)
42 
43 // Powerup-Giver -------------------------------------------------------------
44 
45 //===========================================================================
46 //
47 // APowerupGiver :: Use
48 //
49 //===========================================================================
50 
51 bool APowerupGiver::Use (bool pickup)
52 {
53 	if (PowerupType == NULL) return true;	// item is useless
54 
55 	APowerup *power = static_cast<APowerup *> (Spawn (PowerupType, 0, 0, 0, NO_REPLACE));
56 
57 	if (EffectTics != 0)
58 	{
59 		power->EffectTics = EffectTics;
60 	}
61 	if (BlendColor != 0)
62 	{
63 		if (BlendColor != MakeSpecialColormap(65535)) power->BlendColor = BlendColor;
64 		else power->BlendColor = 0;
65 	}
66 	if (Mode != NAME_None)
67 	{
68 		power->Mode = Mode;
69 	}
70 	if (Strength != 0)
71 	{
72 		power->Strength = Strength;
73 	}
74 
75 	power->ItemFlags |= ItemFlags & (IF_ALWAYSPICKUP|IF_ADDITIVETIME|IF_NOTELEPORTFREEZE);
76 	if (power->CallTryPickup (Owner))
77 	{
78 		return true;
79 	}
80 	power->GoAwayAndDie ();
81 	return false;
82 }
83 
84 //===========================================================================
85 //
86 // APowerupGiver :: Serialize
87 //
88 //===========================================================================
89 
Serialize(FArchive & arc)90 void APowerupGiver::Serialize (FArchive &arc)
91 {
92 	Super::Serialize (arc);
93 	arc << PowerupType;
94 	arc << EffectTics << BlendColor << Mode;
95 	arc << Strength;
96 }
97 
98 // Powerup -------------------------------------------------------------------
99 
100 //===========================================================================
101 //
102 // APowerup :: Tick
103 //
104 //===========================================================================
105 
Tick()106 void APowerup::Tick ()
107 {
108 	// Powerups cannot exist outside an inventory
109 	if (Owner == NULL)
110 	{
111 		Destroy ();
112 	}
113 	if (EffectTics > 0 && --EffectTics == 0)
114 	{
115 		Destroy ();
116 	}
117 }
118 
119 //===========================================================================
120 //
121 // APowerup :: Serialize
122 //
123 //===========================================================================
124 
Serialize(FArchive & arc)125 void APowerup::Serialize (FArchive &arc)
126 {
127 	Super::Serialize (arc);
128 	arc << EffectTics << BlendColor << Mode;
129 	arc << Strength;
130 }
131 
132 //===========================================================================
133 //
134 // APowerup :: GetBlend
135 //
136 //===========================================================================
137 
GetBlend()138 PalEntry APowerup::GetBlend ()
139 {
140 	if (EffectTics <= BLINKTHRESHOLD && !(EffectTics & 8))
141 		return 0;
142 
143 	if (IsSpecialColormap(BlendColor)) return 0;
144 	return BlendColor;
145 }
146 
147 //===========================================================================
148 //
149 // APowerup :: InitEffect
150 //
151 //===========================================================================
152 
InitEffect()153 void APowerup::InitEffect ()
154 {
155 }
156 
157 //===========================================================================
158 //
159 // APowerup :: DoEffect
160 //
161 //===========================================================================
162 
DoEffect()163 void APowerup::DoEffect ()
164 {
165 	if (Owner == NULL || Owner->player == NULL)
166 	{
167 		return;
168 	}
169 
170 	if (EffectTics > 0)
171 	{
172 		int Colormap = GetSpecialColormap(BlendColor);
173 
174 		if (Colormap != NOFIXEDCOLORMAP)
175 		{
176 			if (EffectTics > BLINKTHRESHOLD || (EffectTics & 8))
177 			{
178 				Owner->player->fixedcolormap = Colormap;
179 			}
180 			else if (Owner->player->fixedcolormap == Colormap)
181 			{
182 				// only unset if the fixed colormap comes from this item
183 				Owner->player->fixedcolormap = NOFIXEDCOLORMAP;
184 			}
185 		}
186 	}
187 }
188 
189 //===========================================================================
190 //
191 // APowerup :: EndEffect
192 //
193 //===========================================================================
194 
EndEffect()195 void APowerup::EndEffect ()
196 {
197 	int colormap = GetSpecialColormap(BlendColor);
198 
199 	if (colormap != NOFIXEDCOLORMAP && Owner && Owner->player && Owner->player->fixedcolormap == colormap)
200 	{ // only unset if the fixed colormap comes from this item
201 		Owner->player->fixedcolormap = NOFIXEDCOLORMAP;
202 	}
203 }
204 
205 //===========================================================================
206 //
207 // APowerup :: Destroy
208 //
209 //===========================================================================
210 
Destroy()211 void APowerup::Destroy ()
212 {
213 	EndEffect ();
214 	Super::Destroy ();
215 }
216 
217 //===========================================================================
218 //
219 // APowerup :: DrawPowerup
220 //
221 //===========================================================================
222 
DrawPowerup(int x,int y)223 bool APowerup::DrawPowerup (int x, int y)
224 {
225 	if (!Icon.isValid())
226 	{
227 		return false;
228 	}
229 	if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16))
230 	{
231 		FTexture *pic = TexMan(Icon);
232 		screen->DrawTexture (pic, x, y,
233 			DTA_HUDRules, HUD_Normal,
234 //			DTA_TopOffset, pic->GetHeight()/2,
235 //			DTA_LeftOffset, pic->GetWidth()/2,
236 			TAG_DONE);
237 	}
238 	return true;
239 }
240 
241 //===========================================================================
242 //
243 // APowerup :: HandlePickup
244 //
245 //===========================================================================
246 
HandlePickup(AInventory * item)247 bool APowerup::HandlePickup (AInventory *item)
248 {
249 	if (item->GetClass() == GetClass())
250 	{
251 		APowerup *power = static_cast<APowerup*>(item);
252 		if (power->EffectTics == 0)
253 		{
254 			power->ItemFlags |= IF_PICKUPGOOD;
255 			return true;
256 		}
257 		// Color gets transferred if the new item has an effect.
258 
259 		// Increase the effect's duration.
260 		if (power->ItemFlags & IF_ADDITIVETIME)
261 		{
262 			EffectTics += power->EffectTics;
263 			BlendColor = power->BlendColor;
264 		}
265 		// If it's not blinking yet, you can't replenish the power unless the
266 		// powerup is required to be picked up.
267 		else if (EffectTics > BLINKTHRESHOLD && !(power->ItemFlags & IF_ALWAYSPICKUP))
268 		{
269 			return true;
270 		}
271 		// Reset the effect duration.
272 		else if (power->EffectTics > EffectTics)
273 		{
274 			EffectTics = power->EffectTics;
275 			BlendColor = power->BlendColor;
276 		}
277 		power->ItemFlags |= IF_PICKUPGOOD;
278 		return true;
279 	}
280 	if (Inventory != NULL)
281 	{
282 		return Inventory->HandlePickup (item);
283 	}
284 	return false;
285 }
286 
287 //===========================================================================
288 //
289 // APowerup :: CreateCopy
290 //
291 //===========================================================================
292 
CreateCopy(AActor * other)293 AInventory *APowerup::CreateCopy (AActor *other)
294 {
295 	// Get the effective effect time.
296 	EffectTics = abs (EffectTics);
297 	// Abuse the Owner field to tell the
298 	// InitEffect method who started it;
299 	// this should be cleared afterwards,
300 	// as this powerup instance is not
301 	// properly attached to anything yet.
302 	Owner = other;
303 	// Actually activate the powerup.
304 	InitEffect ();
305 	// Clear the Owner field, unless it was
306 	// changed by the activation, for example,
307 	// if this instance is a morph powerup;
308 	// the flag tells the caller that the
309 	// ownership has changed so that they
310 	// can properly handle the situation.
311 	if (!(ItemFlags & IF_CREATECOPYMOVED))
312 	{
313 		Owner = NULL;
314 	}
315 	// All done.
316 	return this;
317 }
318 
319 //===========================================================================
320 //
321 // APowerup :: CreateTossable
322 //
323 // Powerups are never droppable, even without IF_UNDROPPABLE set.
324 //
325 //===========================================================================
326 
CreateTossable()327 AInventory *APowerup::CreateTossable ()
328 {
329 	return NULL;
330 }
331 
332 //===========================================================================
333 //
334 // APowerup :: OwnerDied
335 //
336 // Powerups don't last beyond death.
337 //
338 //===========================================================================
339 
OwnerDied()340 void APowerup::OwnerDied ()
341 {
342 	Destroy ();
343 }
344 
345 //===========================================================================
346 //
347 // AInventory :: GetNoTeleportFreeze
348 //
349 //===========================================================================
350 
GetNoTeleportFreeze()351 bool APowerup::GetNoTeleportFreeze ()
352 {
353 	if (ItemFlags & IF_NOTELEPORTFREEZE) return true;
354 	return Super::GetNoTeleportFreeze();
355 }
356 
357 // Invulnerability Powerup ---------------------------------------------------
358 
IMPLEMENT_CLASS(APowerInvulnerable)359 IMPLEMENT_CLASS (APowerInvulnerable)
360 
361 //===========================================================================
362 //
363 // APowerInvulnerable :: InitEffect
364 //
365 //===========================================================================
366 
367 void APowerInvulnerable::InitEffect ()
368 {
369 	Super::InitEffect();
370 	Owner->effects &= ~FX_RESPAWNINVUL;
371 	Owner->flags2 |= MF2_INVULNERABLE;
372 	if (Mode == NAME_None)
373 	{
374 		Mode = (ENamedName)RUNTIME_TYPE(Owner)->Meta.GetMetaInt(APMETA_InvulMode);
375 	}
376 	if (Mode == NAME_Reflective)
377 	{
378 		Owner->flags2 |= MF2_REFLECTIVE;
379 	}
380 }
381 
382 //===========================================================================
383 //
384 // APowerInvulnerable :: DoEffect
385 //
386 //===========================================================================
387 
DoEffect()388 void APowerInvulnerable::DoEffect ()
389 {
390 	Super::DoEffect ();
391 
392 	if (Owner == NULL)
393 	{
394 		return;
395 	}
396 
397 	if (Mode == NAME_Ghost)
398 	{
399 		if (!(Owner->flags & MF_SHADOW))
400 		{
401 			// Don't mess with the translucency settings if an
402 			// invisibility powerup is active.
403 			Owner->RenderStyle = STYLE_Translucent;
404 			if (!(level.time & 7) && Owner->alpha > 0 && Owner->alpha < OPAQUE)
405 			{
406 				if (Owner->alpha == HX_SHADOW)
407 				{
408 					Owner->alpha = HX_ALTSHADOW;
409 				}
410 				else
411 				{
412 					Owner->alpha = 0;
413 					Owner->flags2 |= MF2_NONSHOOTABLE;
414 				}
415 			}
416 			if (!(level.time & 31))
417 			{
418 				if (Owner->alpha == 0)
419 				{
420 					Owner->flags2 &= ~MF2_NONSHOOTABLE;
421 					Owner->alpha = HX_ALTSHADOW;
422 				}
423 				else
424 				{
425 					Owner->alpha = HX_SHADOW;
426 				}
427 			}
428 		}
429 		else
430 		{
431 			Owner->flags2 &= ~MF2_NONSHOOTABLE;
432 		}
433 	}
434 }
435 
436 //===========================================================================
437 //
438 // APowerInvulnerable :: EndEffect
439 //
440 //===========================================================================
441 
EndEffect()442 void APowerInvulnerable::EndEffect ()
443 {
444 	Super::EndEffect();
445 
446 	if (Owner == NULL)
447 	{
448 		return;
449 	}
450 
451 	Owner->flags2 &= ~MF2_INVULNERABLE;
452 	Owner->effects &= ~FX_RESPAWNINVUL;
453 	if (Mode == NAME_Ghost)
454 	{
455 		Owner->flags2 &= ~MF2_NONSHOOTABLE;
456 		if (!(Owner->flags & MF_SHADOW))
457 		{
458 			// Don't mess with the translucency settings if an
459 			// invisibility powerup is active.
460 			Owner->RenderStyle = STYLE_Normal;
461 			Owner->alpha = OPAQUE;
462 		}
463 	}
464 	else if (Mode == NAME_Reflective)
465 	{
466 		Owner->flags2 &= ~MF2_REFLECTIVE;
467 	}
468 
469 	if (Owner->player != NULL)
470 	{
471 		Owner->player->fixedcolormap = NOFIXEDCOLORMAP;
472 	}
473 }
474 
475 //===========================================================================
476 //
477 // APowerInvulnerable :: AlterWeaponSprite
478 //
479 //===========================================================================
480 
AlterWeaponSprite(visstyle_t * vis)481 int APowerInvulnerable::AlterWeaponSprite (visstyle_t *vis)
482 {
483 	int changed = Inventory == NULL ? false : Inventory->AlterWeaponSprite(vis);
484 	if (Owner != NULL)
485 	{
486 		if (Mode == NAME_Ghost && !(Owner->flags & MF_SHADOW))
487 		{
488 			fixed_t wp_alpha = MIN<fixed_t>(FRACUNIT/4 + Owner->alpha*3/4, FRACUNIT);
489 			if (wp_alpha != FIXED_MAX) vis->alpha = wp_alpha;
490 		}
491 	}
492 	return changed;
493 }
494 
495 // Strength (aka Berserk) Powerup --------------------------------------------
496 
IMPLEMENT_CLASS(APowerStrength)497 IMPLEMENT_CLASS (APowerStrength)
498 
499 //===========================================================================
500 //
501 // APowerStrength :: HandlePickup
502 //
503 //===========================================================================
504 
505 bool APowerStrength::HandlePickup (AInventory *item)
506 {
507 	if (item->GetClass() == GetClass())
508 	{ // Setting EffectTics to 0 will force Powerup's HandlePickup()
509 	  // method to reset the tic count so you get the red flash again.
510 		EffectTics = 0;
511 	}
512 	return Super::HandlePickup (item);
513 }
514 
515 //===========================================================================
516 //
517 // APowerStrength :: InitEffect
518 //
519 //===========================================================================
520 
InitEffect()521 void APowerStrength::InitEffect ()
522 {
523 	Super::InitEffect();
524 }
525 
526 //===========================================================================
527 //
528 // APowerStrength :: DoEffect
529 //
530 //===========================================================================
531 
Tick()532 void APowerStrength::Tick ()
533 {
534 	// Strength counts up to diminish the fade.
535 	assert(EffectTics < (INT_MAX - 1)); // I can't see a game lasting nearly two years, but...
536 	EffectTics += 2;
537 	Super::Tick();
538 }
539 
540 //===========================================================================
541 //
542 // APowerStrength :: GetBlend
543 //
544 //===========================================================================
545 
GetBlend()546 PalEntry APowerStrength::GetBlend ()
547 {
548 	// slowly fade the berserk out
549 	int cnt = 12 - (EffectTics >> 6);
550 
551 	if (cnt > 0)
552 	{
553 		cnt = (cnt + 7) >> 3;
554 		return PalEntry (BlendColor.a*cnt*255/9,
555 			BlendColor.r, BlendColor.g, BlendColor.b);
556 	}
557 	return 0;
558 }
559 
560 // Invisibility Powerup ------------------------------------------------------
561 
IMPLEMENT_CLASS(APowerInvisibility)562 IMPLEMENT_CLASS (APowerInvisibility)
563 
564 // Invisibility flag combos
565 #define INVISIBILITY_FLAGS1	(MF_SHADOW)
566 #define INVISIBILITY_FLAGS3	(MF3_GHOST)
567 #define INVISIBILITY_FLAGS5	(MF5_CANTSEEK)
568 
569 //===========================================================================
570 //
571 // APowerInvisibility :: InitEffect
572 //
573 //===========================================================================
574 
575 void APowerInvisibility::InitEffect ()
576 {
577 	Super::InitEffect();
578 	// This used to call CommonInit(), which used to contain all the code that's repeated every
579 	// tic, plus the following code that needs to happen once and only once.
580 	// The CommonInit() code has been moved to DoEffect(), so this now ends with a call to DoEffect(),
581 	// and DoEffect() no longer needs to call InitEffect(). CommonInit() has been removed for being redundant.
582 	if (Owner != NULL)
583 	{
584 		flags &= ~(Owner->flags  & INVISIBILITY_FLAGS1);
585 		Owner->flags  |= flags & INVISIBILITY_FLAGS1;
586 		flags3 &= ~(Owner->flags3 & INVISIBILITY_FLAGS3);
587 		Owner->flags3 |= flags3 & INVISIBILITY_FLAGS3;
588 		flags5 &= ~(Owner->flags5 & INVISIBILITY_FLAGS5);
589 		Owner->flags5 |= flags5 & INVISIBILITY_FLAGS5;
590 
591 		DoEffect();
592 	}
593 }
594 
595 //===========================================================================
596 //
597 // APowerInvisibility :: DoEffect
598 //
599 //===========================================================================
DoEffect()600 void APowerInvisibility::DoEffect ()
601 {
602 	Super::DoEffect();
603 	// Due to potential interference with other PowerInvisibility items
604 	// the effect has to be refreshed each tic.
605 	fixed_t ts = (Strength/100) * (special1 + 1); if (ts > FRACUNIT) ts = FRACUNIT;
606 	Owner->alpha = clamp<fixed_t>((OPAQUE - ts), 0, OPAQUE);
607 	switch (Mode)
608 	{
609 	case (NAME_Fuzzy):
610 		Owner->RenderStyle = STYLE_OptFuzzy;
611 		break;
612 	case (NAME_Opaque):
613 		Owner->RenderStyle = STYLE_Normal;
614 		break;
615 	case (NAME_Additive):
616 		Owner->RenderStyle = STYLE_Add;
617 		break;
618 	case (NAME_Stencil):
619 		Owner->RenderStyle = STYLE_Stencil;
620 		break;
621 	case (NAME_AddStencil) :
622 		Owner->RenderStyle = STYLE_AddStencil;
623 		break;
624 	case (NAME_TranslucentStencil) :
625 		Owner->RenderStyle = STYLE_TranslucentStencil;
626 		break;
627 	case (NAME_None) :
628 	case (NAME_Cumulative):
629 	case (NAME_Translucent):
630 		Owner->RenderStyle = STYLE_Translucent;
631 		break;
632 	default: // Something's wrong
633 		Owner->RenderStyle = STYLE_Normal;
634 		Owner->alpha = OPAQUE;
635 		break;
636 	}
637 }
638 
639 //===========================================================================
640 //
641 // APowerInvisibility :: EndEffect
642 //
643 //===========================================================================
644 
EndEffect()645 void APowerInvisibility::EndEffect ()
646 {
647 	Super::EndEffect();
648 	if (Owner != NULL)
649 	{
650 		Owner->flags  &= ~(flags  & INVISIBILITY_FLAGS1);
651 		Owner->flags3 &= ~(flags3 & INVISIBILITY_FLAGS3);
652 		Owner->flags5 &= ~(flags5 & INVISIBILITY_FLAGS5);
653 
654 		Owner->RenderStyle = STYLE_Normal;
655 		Owner->alpha = OPAQUE;
656 
657 		// Check whether there are other invisibility items and refresh their effect.
658 		// If this isn't done there will be one incorrectly drawn frame when this
659 		// item expires.
660 		AInventory *item = Owner->Inventory;
661 		while (item != NULL)
662 		{
663 			if (item->IsKindOf(RUNTIME_CLASS(APowerInvisibility)) && item != this)
664 			{
665 				static_cast<APowerInvisibility*>(item)->DoEffect();
666 			}
667 			item = item->Inventory;
668 		}
669 	}
670 }
671 
672 //===========================================================================
673 //
674 // APowerInvisibility :: AlterWeaponSprite
675 //
676 //===========================================================================
677 
AlterWeaponSprite(visstyle_t * vis)678 int APowerInvisibility::AlterWeaponSprite (visstyle_t *vis)
679 {
680 	int changed = Inventory == NULL ? false : Inventory->AlterWeaponSprite(vis);
681 	// Blink if the powerup is wearing off
682 	if (changed == 0 && EffectTics < 4*32 && !(EffectTics & 8))
683 	{
684 		vis->RenderStyle = STYLE_Normal;
685 		vis->alpha = OPAQUE;
686 		return 1;
687 	}
688 	else if (changed == 1)
689 	{
690 		// something else set the weapon sprite back to opaque but this item is still active.
691 		fixed_t ts = (Strength/100) * (special1 + 1); if (ts > FRACUNIT) ts = FRACUNIT;
692 		vis->alpha = clamp<fixed_t>((OPAQUE - ts), 0, OPAQUE);
693 		switch (Mode)
694 		{
695 		case (NAME_Fuzzy):
696 			vis->RenderStyle = STYLE_OptFuzzy;
697 			break;
698 		case (NAME_Opaque):
699 			vis->RenderStyle = STYLE_Normal;
700 			break;
701 		case (NAME_Additive):
702 			vis->RenderStyle = STYLE_Add;
703 			break;
704 		case (NAME_Stencil):
705 			vis->RenderStyle = STYLE_Stencil;
706 			break;
707 		case (NAME_TranslucentStencil) :
708 			vis->RenderStyle = STYLE_TranslucentStencil;
709 			break;
710 		case (NAME_AddStencil) :
711 			vis->RenderStyle = STYLE_AddStencil;
712 			break;
713 		case (NAME_None) :
714 		case (NAME_Cumulative):
715 		case (NAME_Translucent):
716 		default:
717 			vis->RenderStyle = STYLE_Translucent;
718 			break;
719 		}
720 	}
721 	// Handling of Strife-like cumulative invisibility powerups, the weapon itself shouldn't become invisible
722 	if ((vis->alpha < TRANSLUC25 && special1 > 0) || (vis->alpha == 0))
723 	{
724 		vis->alpha = clamp<fixed_t>((OPAQUE - (Strength/100)), 0, OPAQUE);
725 		vis->colormap = SpecialColormaps[INVERSECOLORMAP].Colormap;
726 	}
727 	return -1;	// This item is valid so another one shouldn't reset the translucency
728 }
729 
730 //===========================================================================
731 //
732 // APowerInvisibility :: HandlePickup
733 //
734 // If the player already has the first stage of a cumulative powerup, getting
735 // it again increases the player's alpha. (But shouldn't this be in Use()?)
736 //
737 //===========================================================================
738 
HandlePickup(AInventory * item)739 bool APowerInvisibility::HandlePickup (AInventory *item)
740 {
741 	if (Mode == NAME_Cumulative && ((Strength * special1) < FRACUNIT) && item->GetClass() == GetClass())
742 	{
743 		APowerup *power = static_cast<APowerup *>(item);
744 		if (power->EffectTics == 0)
745 		{
746 			power->ItemFlags |= IF_PICKUPGOOD;
747 			return true;
748 		}
749 		// Only increase the EffectTics, not decrease it.
750 		// Color also gets transferred only when the new item has an effect.
751 		if (power->EffectTics > EffectTics)
752 		{
753 			EffectTics = power->EffectTics;
754 			BlendColor = power->BlendColor;
755 		}
756 		special1++;	// increases power
757 		power->ItemFlags |= IF_PICKUPGOOD;
758 		return true;
759 	}
760 	return Super::HandlePickup (item);
761 }
762 
763 // Ironfeet Powerup ----------------------------------------------------------
764 
IMPLEMENT_CLASS(APowerIronFeet)765 IMPLEMENT_CLASS (APowerIronFeet)
766 
767 //===========================================================================
768 //
769 // APowerIronFeet :: AbsorbDamage
770 //
771 //===========================================================================
772 
773 void APowerIronFeet::AbsorbDamage (int damage, FName damageType, int &newdamage)
774 {
775 	if (damageType == NAME_Drowning)
776 	{
777 		newdamage = 0;
778 	}
779 	else if (Inventory != NULL)
780 	{
781 		Inventory->AbsorbDamage (damage, damageType, newdamage);
782 	}
783 }
784 
785 //===========================================================================
786 //
787 // APowerIronFeet :: DoEffect
788 //
789 //===========================================================================
790 
DoEffect()791 void APowerIronFeet::DoEffect ()
792 {
793 	if (Owner->player != NULL)
794 	{
795 		Owner->player->mo->ResetAirSupply ();
796 	}
797 }
798 
799 
800 // Strife Environment Suit Powerup -------------------------------------------
801 
IMPLEMENT_CLASS(APowerMask)802 IMPLEMENT_CLASS (APowerMask)
803 
804 //===========================================================================
805 //
806 // APowerMask :: AbsorbDamage
807 //
808 //===========================================================================
809 
810 void APowerMask::AbsorbDamage (int damage, FName damageType, int &newdamage)
811 {
812 	if (damageType == NAME_Fire)
813 	{
814 		newdamage = 0;
815 	}
816 	else
817 	{
818 		Super::AbsorbDamage (damage, damageType, newdamage);
819 	}
820 }
821 
822 //===========================================================================
823 //
824 // APowerMask :: DoEffect
825 //
826 //===========================================================================
827 
DoEffect()828 void APowerMask::DoEffect ()
829 {
830 	Super::DoEffect ();
831 	if (!(level.time & 0x3f))
832 	{
833 		S_Sound (Owner, CHAN_AUTO, "misc/mask", 1, ATTN_STATIC);
834 	}
835 }
836 
837 // Light-Amp Powerup ---------------------------------------------------------
838 
IMPLEMENT_CLASS(APowerLightAmp)839 IMPLEMENT_CLASS (APowerLightAmp)
840 
841 //===========================================================================
842 //
843 // APowerLightAmp :: DoEffect
844 //
845 //===========================================================================
846 
847 void APowerLightAmp::DoEffect ()
848 {
849 	Super::DoEffect ();
850 
851 	if (Owner->player != NULL && Owner->player->fixedcolormap < NUMCOLORMAPS)
852 	{
853 		if (EffectTics > BLINKTHRESHOLD || (EffectTics & 8))
854 		{
855 			Owner->player->fixedlightlevel = 1;
856 		}
857 		else
858 		{
859 			Owner->player->fixedlightlevel = -1;
860 		}
861 	}
862 }
863 
864 //===========================================================================
865 //
866 // APowerLightAmp :: EndEffect
867 //
868 //===========================================================================
869 
EndEffect()870 void APowerLightAmp::EndEffect ()
871 {
872 	Super::EndEffect();
873 	if (Owner != NULL && Owner->player != NULL && Owner->player->fixedcolormap < NUMCOLORMAPS)
874 	{
875 		Owner->player->fixedlightlevel = -1;
876 	}
877 }
878 
879 // Torch Powerup -------------------------------------------------------------
880 
IMPLEMENT_CLASS(APowerTorch)881 IMPLEMENT_CLASS (APowerTorch)
882 
883 //===========================================================================
884 //
885 // APowerTorch :: Serialize
886 //
887 //===========================================================================
888 
889 void APowerTorch::Serialize (FArchive &arc)
890 {
891 	Super::Serialize (arc);
892 	arc << NewTorch << NewTorchDelta;
893 }
894 
895 //===========================================================================
896 //
897 // APowerTorch :: DoEffect
898 //
899 //===========================================================================
900 
DoEffect()901 void APowerTorch::DoEffect ()
902 {
903 	if (Owner == NULL || Owner->player == NULL)
904 	{
905 		return;
906 	}
907 
908 	if (EffectTics <= BLINKTHRESHOLD || Owner->player->fixedcolormap >= NUMCOLORMAPS)
909 	{
910 		Super::DoEffect ();
911 	}
912 	else
913 	{
914 		APowerup::DoEffect ();
915 
916 		if (!(level.time & 16) && Owner->player != NULL)
917 		{
918 			if (NewTorch != 0)
919 			{
920 				if (Owner->player->fixedlightlevel + NewTorchDelta > 7
921 					|| Owner->player->fixedlightlevel + NewTorchDelta < 0
922 					|| NewTorch == Owner->player->fixedlightlevel)
923 				{
924 					NewTorch = 0;
925 				}
926 				else
927 				{
928 					Owner->player->fixedlightlevel += NewTorchDelta;
929 				}
930 			}
931 			else
932 			{
933 				NewTorch = (pr_torch() & 7) + 1;
934 				NewTorchDelta = (NewTorch == Owner->player->fixedlightlevel) ?
935 					0 : ((NewTorch > Owner->player->fixedlightlevel) ? 1 : -1);
936 			}
937 		}
938 	}
939 }
940 
941 // Flight (aka Wings of Wrath) powerup ---------------------------------------
942 
IMPLEMENT_CLASS(APowerFlight)943 IMPLEMENT_CLASS (APowerFlight)
944 
945 //===========================================================================
946 //
947 // APowerFlight :: Serialize
948 //
949 //===========================================================================
950 
951 void APowerFlight::Serialize (FArchive &arc)
952 {
953 	Super::Serialize (arc);
954 	arc << HitCenterFrame;
955 }
956 
957 //===========================================================================
958 //
959 // APowerFlight :: InitEffect
960 //
961 //===========================================================================
962 
InitEffect()963 void APowerFlight::InitEffect ()
964 {
965 	Super::InitEffect();
966 	Owner->flags2 |= MF2_FLY;
967 	Owner->flags |= MF_NOGRAVITY;
968 	if (Owner->Z() <= Owner->floorz)
969 	{
970 		Owner->velz = 4*FRACUNIT;	// thrust the player in the air a bit
971 	}
972 	if (Owner->velz <= -35*FRACUNIT)
973 	{ // stop falling scream
974 		S_StopSound (Owner, CHAN_VOICE);
975 	}
976 }
977 
978 //===========================================================================
979 //
980 // APowerFlight :: DoEffect
981 //
982 //===========================================================================
983 
Tick()984 void APowerFlight::Tick ()
985 {
986 	// The Wings of Wrath only expire in multiplayer and non-hub games
987 	if (!multiplayer && (level.flags2 & LEVEL2_INFINITE_FLIGHT))
988 	{
989 		assert(EffectTics < INT_MAX); // I can't see a game lasting nearly two years, but...
990 		EffectTics++;
991 	}
992 
993 	Super::Tick ();
994 
995 //	Owner->flags |= MF_NOGRAVITY;
996 //	Owner->flags2 |= MF2_FLY;
997 }
998 
999 //===========================================================================
1000 //
1001 // APowerFlight :: EndEffect
1002 //
1003 //===========================================================================
1004 
EndEffect()1005 void APowerFlight::EndEffect ()
1006 {
1007 	Super::EndEffect();
1008 	if (Owner == NULL || Owner->player == NULL)
1009 	{
1010 		return;
1011 	}
1012 
1013 	if (!(Owner->flags7 & MF7_FLYCHEAT))
1014 	{
1015 		if (Owner->Z() != Owner->floorz)
1016 		{
1017 			Owner->player->centering = true;
1018 		}
1019 		Owner->flags2 &= ~MF2_FLY;
1020 		Owner->flags &= ~MF_NOGRAVITY;
1021 	}
1022 //	BorderTopRefresh = screen->GetPageCount (); //make sure the sprite's cleared out
1023 }
1024 
1025 //===========================================================================
1026 //
1027 // APowerFlight :: DrawPowerup
1028 //
1029 //===========================================================================
1030 
DrawPowerup(int x,int y)1031 bool APowerFlight::DrawPowerup (int x, int y)
1032 {
1033 	// If this item got a valid icon use that instead of the default spinning wings.
1034 	if (Icon.isValid())
1035 	{
1036 		return Super::DrawPowerup(x, y);
1037 	}
1038 
1039 	if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16))
1040 	{
1041 		FTextureID picnum = TexMan.CheckForTexture ("SPFLY0", FTexture::TEX_MiscPatch);
1042 		int frame = (level.time/3) & 15;
1043 
1044 		if (!picnum.isValid())
1045 		{
1046 			return false;
1047 		}
1048 		if (Owner->flags & MF_NOGRAVITY)
1049 		{
1050 			if (HitCenterFrame && (frame != 15 && frame != 0))
1051 			{
1052 				screen->DrawTexture (TexMan[picnum+15], x, y,
1053 					DTA_HUDRules, HUD_Normal, TAG_DONE);
1054 			}
1055 			else
1056 			{
1057 				screen->DrawTexture (TexMan[picnum+frame], x, y,
1058 					DTA_HUDRules, HUD_Normal, TAG_DONE);
1059 				HitCenterFrame = false;
1060 			}
1061 		}
1062 		else
1063 		{
1064 			if (!HitCenterFrame && (frame != 15 && frame != 0))
1065 			{
1066 				screen->DrawTexture (TexMan[picnum+frame], x, y,
1067 					DTA_HUDRules, HUD_Normal, TAG_DONE);
1068 				HitCenterFrame = false;
1069 			}
1070 			else
1071 			{
1072 				screen->DrawTexture (TexMan[picnum+15], x, y,
1073 					DTA_HUDRules, HUD_Normal, TAG_DONE);
1074 				HitCenterFrame = true;
1075 			}
1076 		}
1077 	}
1078 	return true;
1079 }
1080 
1081 // Weapon Level 2 (aka Tome of Power) Powerup --------------------------------
1082 
IMPLEMENT_CLASS(APowerWeaponLevel2)1083 IMPLEMENT_CLASS (APowerWeaponLevel2)
1084 
1085 //===========================================================================
1086 //
1087 // APowerWeaponLevel2 :: InitEffect
1088 //
1089 //===========================================================================
1090 
1091 void APowerWeaponLevel2::InitEffect ()
1092 {
1093 	AWeapon *weapon, *sister;
1094 
1095 	Super::InitEffect();
1096 
1097 	if (Owner->player == NULL)
1098 		return;
1099 
1100 	weapon = Owner->player->ReadyWeapon;
1101 
1102 	if (weapon == NULL)
1103 		return;
1104 
1105 	sister = weapon->SisterWeapon;
1106 
1107 	if (sister == NULL)
1108 		return;
1109 
1110 	if (!(sister->WeaponFlags & WIF_POWERED_UP))
1111 		return;
1112 
1113 	assert (sister->SisterWeapon == weapon);
1114 
1115 	Owner->player->ReadyWeapon = sister;
1116 
1117 	if (weapon->GetReadyState() != sister->GetReadyState())
1118 	{
1119 		P_SetPsprite (Owner->player, ps_weapon, sister->GetReadyState());
1120 	}
1121 }
1122 
1123 //===========================================================================
1124 //
1125 // APowerWeaponLevel2 :: EndEffect
1126 //
1127 //===========================================================================
1128 
EndEffect()1129 void APowerWeaponLevel2::EndEffect ()
1130 {
1131 	player_t *player = Owner != NULL ? Owner->player : NULL;
1132 
1133 	Super::EndEffect();
1134 	if (player != NULL)
1135 	{
1136 		if (player->ReadyWeapon != NULL &&
1137 			player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP)
1138 		{
1139 			player->ReadyWeapon->EndPowerup ();
1140 		}
1141 		if (player->PendingWeapon != NULL && player->PendingWeapon != WP_NOCHANGE &&
1142 			player->PendingWeapon->WeaponFlags & WIF_POWERED_UP &&
1143 			player->PendingWeapon->SisterWeapon != NULL)
1144 		{
1145 			player->PendingWeapon = player->PendingWeapon->SisterWeapon;
1146 		}
1147 	}
1148 }
1149 
1150 // Player Speed Trail (used by the Speed Powerup) ----------------------------
1151 
1152 class APlayerSpeedTrail : public AActor
1153 {
1154 	DECLARE_CLASS (APlayerSpeedTrail, AActor)
1155 public:
1156 	void Tick ();
1157 };
1158 
IMPLEMENT_CLASS(APlayerSpeedTrail)1159 IMPLEMENT_CLASS (APlayerSpeedTrail)
1160 
1161 //===========================================================================
1162 //
1163 // APlayerSpeedTrail :: Tick
1164 //
1165 //===========================================================================
1166 
1167 void APlayerSpeedTrail::Tick ()
1168 {
1169 	const int fade = OPAQUE*6/10/8;
1170 	if (alpha <= fade)
1171 	{
1172 		Destroy ();
1173 	}
1174 	else
1175 	{
1176 		alpha -= fade;
1177 	}
1178 }
1179 
1180 // Speed Powerup -------------------------------------------------------------
1181 
IMPLEMENT_CLASS(APowerSpeed)1182 IMPLEMENT_CLASS (APowerSpeed)
1183 
1184 //===========================================================================
1185 //
1186 // APowerSpeed :: Serialize
1187 //
1188 //===========================================================================
1189 
1190 void APowerSpeed::Serialize(FArchive &arc)
1191 {
1192 	Super::Serialize (arc);
1193 	if (SaveVersion < 4146)
1194 	{
1195 		SpeedFlags = 0;
1196 	}
1197 	else
1198 	{
1199 		arc << SpeedFlags;
1200 	}
1201 }
1202 
1203 //===========================================================================
1204 //
1205 // APowerSpeed :: GetSpeedFactor
1206 //
1207 //===========================================================================
1208 
GetSpeedFactor()1209 fixed_t APowerSpeed ::GetSpeedFactor ()
1210 {
1211 	if (Inventory != NULL)
1212 		return FixedMul(Speed, Inventory->GetSpeedFactor());
1213 	else
1214 		return Speed;
1215 }
1216 
1217 //===========================================================================
1218 //
1219 // APowerSpeed :: DoEffect
1220 //
1221 //===========================================================================
1222 
DoEffect()1223 void APowerSpeed::DoEffect ()
1224 {
1225 	Super::DoEffect ();
1226 
1227 	if (Owner == NULL || Owner->player == NULL)
1228 		return;
1229 
1230 	if (Owner->player->cheats & CF_PREDICTING)
1231 		return;
1232 
1233 	if (SpeedFlags & PSF_NOTRAIL)
1234 		return;
1235 
1236 	if (level.time & 1)
1237 		return;
1238 
1239 	// Check if another speed item is present to avoid multiple drawing of the speed trail.
1240 	// Only the last PowerSpeed without PSF_NOTRAIL set will actually draw the trail.
1241 	for (AInventory *item = Inventory; item != NULL; item = item->Inventory)
1242 	{
1243 		if (item->IsKindOf(RUNTIME_CLASS(APowerSpeed)) &&
1244 			!(static_cast<APowerSpeed *>(item)->SpeedFlags & PSF_NOTRAIL))
1245 		{
1246 			return;
1247 		}
1248 	}
1249 
1250 	if (P_AproxDistance (Owner->velx, Owner->vely) <= 12*FRACUNIT)
1251 		return;
1252 
1253 	AActor *speedMo = Spawn<APlayerSpeedTrail> (Owner->Pos(), NO_REPLACE);
1254 	if (speedMo)
1255 	{
1256 		speedMo->angle = Owner->angle;
1257 		speedMo->Translation = Owner->Translation;
1258 		speedMo->target = Owner;
1259 		speedMo->sprite = Owner->sprite;
1260 		speedMo->frame = Owner->frame;
1261 		speedMo->floorclip = Owner->floorclip;
1262 
1263 		// [BC] Also get the scale from the owner.
1264 		speedMo->scaleX = Owner->scaleX;
1265 		speedMo->scaleY = Owner->scaleY;
1266 
1267 		if (Owner == players[consoleplayer].camera &&
1268 			!(Owner->player->cheats & CF_CHASECAM))
1269 		{
1270 			speedMo->renderflags |= RF_INVISIBLE;
1271 		}
1272 	}
1273 }
1274 
1275 // Minotaur (aka Dark Servant) powerup ---------------------------------------
1276 
1277 IMPLEMENT_CLASS (APowerMinotaur)
1278 
1279 // Targeter powerup ---------------------------------------------------------
1280 
IMPLEMENT_CLASS(APowerTargeter)1281 IMPLEMENT_CLASS (APowerTargeter)
1282 
1283 void APowerTargeter::Travelled ()
1284 {
1285 	InitEffect ();
1286 }
1287 
InitEffect()1288 void APowerTargeter::InitEffect ()
1289 {
1290 	player_t *player;
1291 
1292 	Super::InitEffect();
1293 
1294 	if ((player = Owner->player) == NULL)
1295 		return;
1296 
1297 	FState *state = FindState("Targeter");
1298 
1299 	if (state != NULL)
1300 	{
1301 		P_SetPsprite (player, ps_targetcenter, state + 0);
1302 		P_SetPsprite (player, ps_targetleft, state + 1);
1303 		P_SetPsprite (player, ps_targetright, state + 2);
1304 	}
1305 
1306 	player->psprites[ps_targetcenter].sx = (160-3)*FRACUNIT;
1307 	player->psprites[ps_targetcenter].sy =
1308 		player->psprites[ps_targetleft].sy =
1309 		player->psprites[ps_targetright].sy = (100-3)*FRACUNIT;
1310 	PositionAccuracy ();
1311 }
1312 
HandlePickup(AInventory * item)1313 bool APowerTargeter::HandlePickup(AInventory *item)
1314 {
1315 	if (Super::HandlePickup(item))
1316 	{
1317 		InitEffect();	// reset the HUD sprites
1318 		return true;
1319 	}
1320 	return false;
1321 }
1322 
1323 
1324 
DoEffect()1325 void APowerTargeter::DoEffect ()
1326 {
1327 	Super::DoEffect ();
1328 
1329 	if (Owner != NULL && Owner->player != NULL)
1330 	{
1331 		player_t *player = Owner->player;
1332 
1333 		PositionAccuracy ();
1334 		if (EffectTics < 5*TICRATE)
1335 		{
1336 			FState *state = FindState("Targeter");
1337 
1338 			if (state != NULL)
1339 			{
1340 				if (EffectTics & 32)
1341 				{
1342 					P_SetPsprite (player, ps_targetright, NULL);
1343 					P_SetPsprite (player, ps_targetleft, state+1);
1344 				}
1345 				else if (EffectTics & 16)
1346 				{
1347 					P_SetPsprite (player, ps_targetright, state+2);
1348 					P_SetPsprite (player, ps_targetleft, NULL);
1349 				}
1350 			}
1351 		}
1352 	}
1353 }
1354 
EndEffect()1355 void APowerTargeter::EndEffect ()
1356 {
1357 	Super::EndEffect();
1358 	if (Owner != NULL && Owner->player != NULL)
1359 	{
1360 		P_SetPsprite (Owner->player, ps_targetcenter, NULL);
1361 		P_SetPsprite (Owner->player, ps_targetleft, NULL);
1362 		P_SetPsprite (Owner->player, ps_targetright, NULL);
1363 	}
1364 }
1365 
PositionAccuracy()1366 void APowerTargeter::PositionAccuracy ()
1367 {
1368 	player_t *player = Owner->player;
1369 
1370 	if (player != NULL)
1371 	{
1372 		player->psprites[ps_targetleft].sx = (160-3)*FRACUNIT - ((100 - player->mo->accuracy) << FRACBITS);
1373 		player->psprites[ps_targetright].sx = (160-3)*FRACUNIT + ((100 - player->mo->accuracy) << FRACBITS);
1374 	}
1375 }
1376 
1377 // Frightener Powerup --------------------------------
1378 
IMPLEMENT_CLASS(APowerFrightener)1379 IMPLEMENT_CLASS (APowerFrightener)
1380 
1381 //===========================================================================
1382 //
1383 // APowerFrightener :: InitEffect
1384 //
1385 //===========================================================================
1386 
1387 void APowerFrightener::InitEffect ()
1388 {
1389 	Super::InitEffect();
1390 
1391 	if (Owner== NULL || Owner->player == NULL)
1392 		return;
1393 
1394 	Owner->player->cheats |= CF_FRIGHTENING;
1395 }
1396 
1397 //===========================================================================
1398 //
1399 // APowerFrightener :: EndEffect
1400 //
1401 //===========================================================================
1402 
EndEffect()1403 void APowerFrightener::EndEffect ()
1404 {
1405 	Super::EndEffect();
1406 
1407 	if (Owner== NULL || Owner->player == NULL)
1408 		return;
1409 
1410 	Owner->player->cheats &= ~CF_FRIGHTENING;
1411 }
1412 
1413 // Buddha Powerup --------------------------------
1414 
IMPLEMENT_CLASS(APowerBuddha)1415 IMPLEMENT_CLASS (APowerBuddha)
1416 
1417 //===========================================================================
1418 //
1419 // APowerBuddha :: InitEffect
1420 //
1421 //===========================================================================
1422 
1423 void APowerBuddha::InitEffect ()
1424 {
1425 	Super::InitEffect();
1426 
1427 	if (Owner== NULL || Owner->player == NULL)
1428 		return;
1429 
1430 	Owner->player->cheats |= CF_BUDDHA;
1431 }
1432 
1433 //===========================================================================
1434 //
1435 // APowerBuddha :: EndEffect
1436 //
1437 //===========================================================================
1438 
EndEffect()1439 void APowerBuddha::EndEffect ()
1440 {
1441 	Super::EndEffect();
1442 
1443 	if (Owner== NULL || Owner->player == NULL)
1444 		return;
1445 
1446 	Owner->player->cheats &= ~CF_BUDDHA;
1447 }
1448 
1449 // Scanner powerup ----------------------------------------------------------
1450 
1451 IMPLEMENT_CLASS (APowerScanner)
1452 
1453 // Time freezer powerup -----------------------------------------------------
1454 
IMPLEMENT_CLASS(APowerTimeFreezer)1455 IMPLEMENT_CLASS( APowerTimeFreezer)
1456 
1457 //===========================================================================
1458 //
1459 // APowerTimeFreezer :: InitEffect
1460 //
1461 //===========================================================================
1462 
1463 void APowerTimeFreezer::InitEffect()
1464 {
1465 	int freezemask;
1466 
1467 	Super::InitEffect();
1468 
1469 	if (Owner == NULL || Owner->player == NULL)
1470 		return;
1471 
1472 	// When this powerup is in effect, pause the music.
1473 	S_PauseSound(false, false);
1474 
1475 	// Give the player and his teammates the power to move when time is frozen.
1476 	freezemask = 1 << (Owner->player - players);
1477 	Owner->player->timefreezer |= freezemask;
1478 	for (int i = 0; i < MAXPLAYERS; i++)
1479 	{
1480 		if (playeringame[i] &&
1481 			players[i].mo != NULL &&
1482 			players[i].mo->IsTeammate(Owner)
1483 		   )
1484 		{
1485 			players[i].timefreezer |= freezemask;
1486 		}
1487 	}
1488 
1489 	// [RH] The effect ends one tic after the counter hits zero, so make
1490 	// sure we start at an odd count.
1491 	EffectTics += !(EffectTics & 1);
1492 	if ((EffectTics & 1) == 0)
1493 	{
1494 		EffectTics++;
1495 	}
1496 	// Make sure the effect starts and ends on an even tic.
1497 	if ((level.time & 1) == 0)
1498 	{
1499 		level.flags2 |= LEVEL2_FROZEN;
1500 	}
1501 	else
1502 	{
1503 		// Compensate for skipped tic, but beware of overflow.
1504 		if(EffectTics < INT_MAX)
1505 			EffectTics++;
1506 	}
1507 }
1508 
1509 //===========================================================================
1510 //
1511 // APowerTimeFreezer :: DoEffect
1512 //
1513 //===========================================================================
1514 
DoEffect()1515 void APowerTimeFreezer::DoEffect()
1516 {
1517 	Super::DoEffect();
1518 	// [RH] Do not change LEVEL_FROZEN on odd tics, or the Revenant's tracer
1519 	// will get thrown off.
1520 	// [ED850] Don't change it if the player is predicted either.
1521 	if (level.time & 1 || (Owner != NULL && Owner->player != NULL && Owner->player->cheats & CF_PREDICTING))
1522 	{
1523 		return;
1524 	}
1525 	// [RH] The "blinking" can't check against EffectTics exactly or it will
1526 	// never happen, because InitEffect ensures that EffectTics will always
1527 	// be odd when level.time is even.
1528 	if ( EffectTics > 4*32
1529 		|| (( EffectTics > 3*32 && EffectTics <= 4*32 ) && ((EffectTics + 1) & 15) != 0 )
1530 		|| (( EffectTics > 2*32 && EffectTics <= 3*32 ) && ((EffectTics + 1) & 7) != 0 )
1531 		|| (( EffectTics >   32 && EffectTics <= 2*32 ) && ((EffectTics + 1) & 3) != 0 )
1532 		|| (( EffectTics >    0 && EffectTics <= 1*32 ) && ((EffectTics + 1) & 1) != 0 ))
1533 		level.flags2 |= LEVEL2_FROZEN;
1534 	else
1535 		level.flags2 &= ~LEVEL2_FROZEN;
1536 }
1537 
1538 //===========================================================================
1539 //
1540 // APowerTimeFreezer :: EndEffect
1541 //
1542 //===========================================================================
1543 
EndEffect()1544 void APowerTimeFreezer::EndEffect()
1545 {
1546 	int	i;
1547 
1548 	Super::EndEffect();
1549 
1550 	// If there is an owner, remove the timefreeze flag corresponding to
1551 	// her from all players.
1552 	if (Owner != NULL && Owner->player != NULL)
1553 	{
1554 		int freezemask = ~(1 << (Owner->player - players));
1555 		for (i = 0; i < MAXPLAYERS; ++i)
1556 		{
1557 			players[i].timefreezer &= freezemask;
1558 		}
1559 	}
1560 
1561 	// Are there any players who still have timefreezer bits set?
1562 	for (i = 0; i < MAXPLAYERS; ++i)
1563 	{
1564 		if (playeringame[i] && players[i].timefreezer != 0)
1565 		{
1566 			break;
1567 		}
1568 	}
1569 
1570 	if (i == MAXPLAYERS)
1571 	{
1572 		// No, so allow other actors to move about freely once again.
1573 		level.flags2 &= ~LEVEL2_FROZEN;
1574 
1575 		// Also, turn the music back on.
1576 		S_ResumeSound(false);
1577 	}
1578 }
1579 
1580 // Damage powerup ------------------------------------------------------
1581 
IMPLEMENT_CLASS(APowerDamage)1582 IMPLEMENT_CLASS(APowerDamage)
1583 
1584 //===========================================================================
1585 //
1586 // APowerDamage :: InitEffect
1587 //
1588 //===========================================================================
1589 
1590 void APowerDamage::InitEffect( )
1591 {
1592 	Super::InitEffect();
1593 
1594 	// Use sound channel 5 to avoid interference with other actions.
1595 	if (Owner != NULL) S_Sound(Owner, 5, SeeSound, 1.0f, ATTN_NONE);
1596 }
1597 
1598 //===========================================================================
1599 //
1600 // APowerDamage :: EndEffect
1601 //
1602 //===========================================================================
1603 
EndEffect()1604 void APowerDamage::EndEffect( )
1605 {
1606 	Super::EndEffect();
1607 	// Use sound channel 5 to avoid interference with other actions.
1608 	if (Owner != NULL) S_Sound(Owner, 5, DeathSound, 1.0f, ATTN_NONE);
1609 }
1610 
1611 //===========================================================================
1612 //
1613 // APowerDamage :: ModifyDamage
1614 //
1615 //===========================================================================
1616 
ModifyDamage(int damage,FName damageType,int & newdamage,bool passive)1617 void APowerDamage::ModifyDamage(int damage, FName damageType, int &newdamage, bool passive)
1618 {
1619 	static const fixed_t def = 4*FRACUNIT;
1620 	if (!passive && damage > 0)
1621 	{
1622 		const fixed_t * pdf = NULL;
1623 		DmgFactors * df = GetClass()->ActorInfo->DamageFactors;
1624 		if (df != NULL && df->CountUsed() != 0)
1625 		{
1626 			pdf = df->CheckFactor(damageType);
1627 		}
1628 		else
1629 		{
1630 			pdf = &def;
1631 		}
1632 		if (pdf != NULL)
1633 		{
1634 			damage = newdamage = FixedMul(damage, *pdf);
1635 			if (*pdf > 0 && damage == 0) damage = newdamage = 1;	// don't allow zero damage as result of an underflow
1636 			if (Owner != NULL && *pdf > FRACUNIT) S_Sound(Owner, 5, ActiveSound, 1.0f, ATTN_NONE);
1637 		}
1638 	}
1639 	if (Inventory != NULL) Inventory->ModifyDamage(damage, damageType, newdamage, passive);
1640 }
1641 
1642 // Quarter damage powerup ------------------------------------------------------
1643 
IMPLEMENT_CLASS(APowerProtection)1644 IMPLEMENT_CLASS(APowerProtection)
1645 
1646 #define PROTECTION_FLAGS3	(MF3_NORADIUSDMG | MF3_DONTMORPH | MF3_DONTSQUASH | MF3_DONTBLAST | MF3_NOTELEOTHER)
1647 #define PROTECTION_FLAGS5	(MF5_NOPAIN | MF5_DONTRIP)
1648 
1649 //===========================================================================
1650 //
1651 // APowerProtection :: InitEffect
1652 //
1653 //===========================================================================
1654 
1655 void APowerProtection::InitEffect( )
1656 {
1657 	Super::InitEffect();
1658 
1659 	if (Owner != NULL)
1660 	{
1661 		S_Sound(Owner, CHAN_AUTO, SeeSound, 1.0f, ATTN_NONE);
1662 
1663 		// Transfer various protection flags if owner does not already have them.
1664 		// If the owner already has the flag, clear it from the powerup.
1665 		// If the powerup still has a flag set, add it to the owner.
1666 		flags3 &= ~(Owner->flags3 & PROTECTION_FLAGS3);
1667 		Owner->flags3 |= flags3 & PROTECTION_FLAGS3;
1668 
1669 		flags5 &= ~(Owner->flags5 & PROTECTION_FLAGS5);
1670 		Owner->flags5 |= flags5 & PROTECTION_FLAGS5;
1671 	}
1672 }
1673 
1674 //===========================================================================
1675 //
1676 // APowerProtection :: EndEffect
1677 //
1678 //===========================================================================
1679 
EndEffect()1680 void APowerProtection::EndEffect( )
1681 {
1682 	Super::EndEffect();
1683 	if (Owner != NULL)
1684 	{
1685 		S_Sound(Owner, CHAN_AUTO, DeathSound, 1.0f, ATTN_NONE);
1686 		Owner->flags3 &= ~(flags3 & PROTECTION_FLAGS3);
1687 		Owner->flags5 &= ~(flags5 & PROTECTION_FLAGS5);
1688 	}
1689 }
1690 
1691 //===========================================================================
1692 //
1693 // APowerProtection :: AbsorbDamage
1694 //
1695 //===========================================================================
1696 
ModifyDamage(int damage,FName damageType,int & newdamage,bool passive)1697 void APowerProtection::ModifyDamage(int damage, FName damageType, int &newdamage, bool passive)
1698 {
1699 	static const fixed_t def = FRACUNIT/4;
1700 	if (passive && damage > 0)
1701 	{
1702 		const fixed_t *pdf = NULL;
1703 		DmgFactors *df = GetClass()->ActorInfo->DamageFactors;
1704 		if (df != NULL && df->CountUsed() != 0)
1705 		{
1706 			pdf = df->CheckFactor(damageType);
1707 		}
1708 		else pdf = &def;
1709 
1710 		if (pdf != NULL)
1711 		{
1712 			damage = newdamage = FixedMul(damage, *pdf);
1713 			if (Owner != NULL && *pdf < FRACUNIT) S_Sound(Owner, CHAN_AUTO, ActiveSound, 1.0f, ATTN_NONE);
1714 		}
1715 	}
1716 	if (Inventory != NULL)
1717 	{
1718 		Inventory->ModifyDamage(damage, damageType, newdamage, passive);
1719 	}
1720 }
1721 
1722 // Drain rune -------------------------------------------------------
1723 
IMPLEMENT_CLASS(APowerDrain)1724 IMPLEMENT_CLASS(APowerDrain)
1725 
1726 //===========================================================================
1727 //
1728 // ARuneDrain :: InitEffect
1729 //
1730 //===========================================================================
1731 
1732 void APowerDrain::InitEffect( )
1733 {
1734 	Super::InitEffect();
1735 
1736 	if (Owner== NULL || Owner->player == NULL)
1737 		return;
1738 
1739 	// Give the player the power to drain life from opponents when he damages them.
1740 	Owner->player->cheats |= CF_DRAIN;
1741 }
1742 
1743 //===========================================================================
1744 //
1745 // ARuneDrain :: EndEffect
1746 //
1747 //===========================================================================
1748 
EndEffect()1749 void APowerDrain::EndEffect( )
1750 {
1751 	Super::EndEffect();
1752 
1753 	// Nothing to do if there's no owner.
1754 	if (Owner != NULL && Owner->player != NULL)
1755 	{
1756 		// Take away the drain power.
1757 		Owner->player->cheats &= ~CF_DRAIN;
1758 	}
1759 }
1760 
1761 
1762 // Regeneration rune -------------------------------------------------------
1763 
IMPLEMENT_CLASS(APowerRegeneration)1764 IMPLEMENT_CLASS(APowerRegeneration)
1765 
1766 //===========================================================================
1767 //
1768 // APowerRegeneration :: DoEffect
1769 //
1770 //===========================================================================
1771 
1772 void APowerRegeneration::DoEffect()
1773 {
1774 	Super::DoEffect();
1775 	if (Owner != NULL && Owner->health > 0 && (level.time & 31) == 0)
1776 	{
1777 		if (P_GiveBody(Owner, Strength/FRACUNIT))
1778 		{
1779 			S_Sound(Owner, CHAN_ITEM, "*regenerate", 1, ATTN_NORM );
1780 		}
1781 	}
1782 }
1783 
1784 // High jump rune -------------------------------------------------------
1785 
IMPLEMENT_CLASS(APowerHighJump)1786 IMPLEMENT_CLASS(APowerHighJump)
1787 
1788 //===========================================================================
1789 //
1790 // ARuneHighJump :: InitEffect
1791 //
1792 //===========================================================================
1793 
1794 void APowerHighJump::InitEffect( )
1795 {
1796 	Super::InitEffect();
1797 
1798 	if (Owner== NULL || Owner->player == NULL)
1799 		return;
1800 
1801 	// Give the player the power to jump much higher.
1802 	Owner->player->cheats |= CF_HIGHJUMP;
1803 }
1804 
1805 //===========================================================================
1806 //
1807 // ARuneHighJump :: EndEffect
1808 //
1809 //===========================================================================
1810 
EndEffect()1811 void APowerHighJump::EndEffect( )
1812 {
1813 	Super::EndEffect();
1814 	// Nothing to do if there's no owner.
1815 	if (Owner != NULL && Owner->player != NULL)
1816 	{
1817 		// Take away the high jump power.
1818 		Owner->player->cheats &= ~CF_HIGHJUMP;
1819 	}
1820 }
1821 
1822 // Double firing speed rune ---------------------------------------------
1823 
IMPLEMENT_CLASS(APowerDoubleFiringSpeed)1824 IMPLEMENT_CLASS(APowerDoubleFiringSpeed)
1825 
1826 //===========================================================================
1827 //
1828 // APowerDoubleFiringSpeed :: InitEffect
1829 //
1830 //===========================================================================
1831 
1832 void APowerDoubleFiringSpeed::InitEffect( )
1833 {
1834 	Super::InitEffect();
1835 
1836 	if (Owner== NULL || Owner->player == NULL)
1837 		return;
1838 
1839 	// Give the player the power to shoot twice as fast.
1840 	Owner->player->cheats |= CF_DOUBLEFIRINGSPEED;
1841 }
1842 
1843 //===========================================================================
1844 //
1845 // APowerDoubleFiringSpeed :: EndEffect
1846 //
1847 //===========================================================================
1848 
EndEffect()1849 void APowerDoubleFiringSpeed::EndEffect( )
1850 {
1851 	Super::EndEffect();
1852 	// Nothing to do if there's no owner.
1853 	if (Owner != NULL && Owner->player != NULL)
1854 	{
1855 		// Take away the shooting twice as fast power.
1856 		Owner->player->cheats &= ~CF_DOUBLEFIRINGSPEED;
1857 	}
1858 }
1859 
1860 // Morph powerup ------------------------------------------------------
1861 
IMPLEMENT_CLASS(APowerMorph)1862 IMPLEMENT_CLASS(APowerMorph)
1863 
1864 //===========================================================================
1865 //
1866 // APowerMorph :: Serialize
1867 //
1868 //===========================================================================
1869 
1870 void APowerMorph::Serialize (FArchive &arc)
1871 {
1872 	Super::Serialize (arc);
1873 	arc << PlayerClass << MorphStyle << MorphFlash << UnMorphFlash;
1874 	arc << Player;
1875 }
1876 
1877 //===========================================================================
1878 //
1879 // APowerMorph :: InitEffect
1880 //
1881 //===========================================================================
1882 
InitEffect()1883 void APowerMorph::InitEffect( )
1884 {
1885 	Super::InitEffect();
1886 
1887 	if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None)
1888 	{
1889 		player_t *realplayer = Owner->player;	// Remember the identity of the player
1890 		const PClass *morph_flash = PClass::FindClass (MorphFlash);
1891 		const PClass *unmorph_flash = PClass::FindClass (UnMorphFlash);
1892 		const PClass *player_class = PClass::FindClass (PlayerClass);
1893 		if (P_MorphPlayer(realplayer, realplayer, player_class, -1/*INDEFINITELY*/, MorphStyle, morph_flash, unmorph_flash))
1894 		{
1895 			Owner = realplayer->mo;				// Replace the new owner in our owner; safe because we are not attached to anything yet
1896 			ItemFlags |= IF_CREATECOPYMOVED;	// Let the caller know the "real" owner has changed (to the morphed actor)
1897 			Player = realplayer;				// Store the player identity (morphing clears the unmorphed actor's "player" field)
1898 		}
1899 		else // morph failed - give the caller an opportunity to fail the pickup completely
1900 		{
1901 			ItemFlags |= IF_INITEFFECTFAILED;	// Let the caller know that the activation failed (can fail the pickup if appropriate)
1902 		}
1903 	}
1904 }
1905 
1906 //===========================================================================
1907 //
1908 // APowerMorph :: EndEffect
1909 //
1910 //===========================================================================
1911 
EndEffect()1912 void APowerMorph::EndEffect( )
1913 {
1914 	Super::EndEffect();
1915 
1916 	// Abort if owner already destroyed
1917 	if (Owner == NULL)
1918 	{
1919 		assert(Player == NULL);
1920 		return;
1921 	}
1922 
1923 	// Abort if owner already unmorphed
1924 	if (Player == NULL)
1925 	{
1926 		return;
1927 	}
1928 
1929 	// Abort if owner is dead; their Die() method will
1930 	// take care of any required unmorphing on death.
1931 	if (Player->health <= 0)
1932 	{
1933 		return;
1934 	}
1935 
1936 	// Unmorph if possible
1937 	if (!bNoCallUndoMorph)
1938 	{
1939 		int savedMorphTics = Player->morphTics;
1940 		P_UndoPlayerMorph (Player, Player, 0, !!(Player->MorphStyle & MORPH_UNDOALWAYS));
1941 
1942 		// Abort if unmorph failed; in that case,
1943 		// set the usual retry timer and return.
1944 		if (Player != NULL && Player->morphTics)
1945 		{
1946 			// Transfer retry timeout
1947 			// to the powerup's timer.
1948 			EffectTics = Player->morphTics;
1949 			// Reload negative morph tics;
1950 			// use actual value; it may
1951 			// be in use for animation.
1952 			Player->morphTics = savedMorphTics;
1953 			// Try again some time later
1954 			return;
1955 		}
1956 	}
1957 	// Unmorph suceeded
1958 	Player = NULL;
1959 }
1960 
1961 // Infinite Ammo Powerup -----------------------------------------------------
1962 
IMPLEMENT_CLASS(APowerInfiniteAmmo)1963 IMPLEMENT_CLASS(APowerInfiniteAmmo)
1964 
1965 //===========================================================================
1966 //
1967 // APowerInfiniteAmmo :: InitEffect
1968 //
1969 //===========================================================================
1970 
1971 void APowerInfiniteAmmo::InitEffect( )
1972 {
1973 	Super::InitEffect();
1974 
1975 	if (Owner== NULL || Owner->player == NULL)
1976 		return;
1977 
1978 	// Give the player infinite ammo
1979 	Owner->player->cheats |= CF_INFINITEAMMO;
1980 }
1981 
1982 //===========================================================================
1983 //
1984 // APowerInfiniteAmmo :: EndEffect
1985 //
1986 //===========================================================================
1987 
EndEffect()1988 void APowerInfiniteAmmo::EndEffect( )
1989 {
1990 	Super::EndEffect();
1991 
1992 	// Nothing to do if there's no owner.
1993 	if (Owner != NULL && Owner->player != NULL)
1994 	{
1995 		// Take away the limitless ammo
1996 		Owner->player->cheats &= ~CF_INFINITEAMMO;
1997 	}
1998 }
1999 
2000