1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 //	Implements special effects:
17 //	Texture animation, height or lighting changes
18 //	 according to adjacent sectors, respective
19 //	 utility functions, etc.
20 //	Line Tag handling. Line and Sector triggers.
21 //
22 
23 
24 #include <stdlib.h>
25 
26 #include "doomdef.h"
27 #include "doomstat.h"
28 
29 #include "deh_main.h"
30 #include "i_system.h"
31 #include "z_zone.h"
32 #include "m_argv.h"
33 #include "m_misc.h"
34 #include "m_random.h"
35 #include "w_wad.h"
36 
37 #include "r_local.h"
38 #include "p_local.h"
39 
40 #include "g_game.h"
41 
42 #include "s_sound.h"
43 
44 // State.
45 #include "r_state.h"
46 
47 // Data.
48 #include "sounds.h"
49 
50 
51 //
52 // Animating textures and planes
53 // There is another anim_t used in wi_stuff, unrelated.
54 //
55 typedef struct
56 {
57     boolean	istexture;
58     int		picnum;
59     int		basepic;
60     int		numpics;
61     int		speed;
62 
63 } anim_t;
64 
65 //
66 //      source animation definition
67 //
68 typedef struct
69 {
70     int 	istexture;	// if false, it is a flat
71     char	endname[9];
72     char	startname[9];
73     int		speed;
74 } animdef_t;
75 
76 
77 
78 #define MAXANIMS                32
79 
80 extern anim_t	anims[MAXANIMS];
81 extern anim_t*	lastanim;
82 
83 //
84 // P_InitPicAnims
85 //
86 
87 // Floor/ceiling animation sequences,
88 //  defined by first and last frame,
89 //  i.e. the flat (64x64 tile) name to
90 //  be used.
91 // The full animation sequence is given
92 //  using all the flats between the start
93 //  and end entry, in the order found in
94 //  the WAD file.
95 //
96 animdef_t		animdefs[] =
97 {
98     {false,	"NUKAGE3",	"NUKAGE1",	8},
99     {false,	"FWATER4",	"FWATER1",	8},
100     {false,	"SWATER4",	"SWATER1", 	8},
101     {false,	"LAVA4",	"LAVA1",	8},
102     {false,	"BLOOD3",	"BLOOD1",	8},
103 
104     // DOOM II flat animations.
105     {false,	"RROCK08",	"RROCK05",	8},
106     {false,	"SLIME04",	"SLIME01",	8},
107     {false,	"SLIME08",	"SLIME05",	8},
108     {false,	"SLIME12",	"SLIME09",	8},
109 
110     {true,	"BLODGR4",	"BLODGR1",	8},
111     {true,	"SLADRIP3",	"SLADRIP1",	8},
112 
113     {true,	"BLODRIP4",	"BLODRIP1",	8},
114     {true,	"FIREWALL",	"FIREWALA",	8},
115     {true,	"GSTFONT3",	"GSTFONT1",	8},
116     {true,	"FIRELAVA",	"FIRELAV3",	8},
117     {true,	"FIREMAG3",	"FIREMAG1",	8},
118     {true,	"FIREBLU2",	"FIREBLU1",	8},
119     {true,	"ROCKRED3",	"ROCKRED1",	8},
120 
121     {true,	"BFALL4",	"BFALL1",	8},
122     {true,	"SFALL4",	"SFALL1",	8},
123     {true,	"WFALL4",	"WFALL1",	8},
124     {true,	"DBRAIN4",	"DBRAIN1",	8},
125 
126     {-1,        "",             "",             0},
127 };
128 
129 anim_t		anims[MAXANIMS];
130 anim_t*		lastanim;
131 
132 
133 //
134 //      Animating line specials
135 //
136 #define MAXLINEANIMS            64
137 
138 extern  short	numlinespecials;
139 extern  line_t*	linespeciallist[MAXLINEANIMS];
140 
141 
142 
P_InitPicAnims(void)143 void P_InitPicAnims (void)
144 {
145     int		i;
146 
147 
148     //	Init animation
149     lastanim = anims;
150     for (i=0 ; animdefs[i].istexture != -1 ; i++)
151     {
152         char *startname, *endname;
153 
154         startname = DEH_String(animdefs[i].startname);
155         endname = DEH_String(animdefs[i].endname);
156 
157 	if (animdefs[i].istexture)
158 	{
159 	    // different episode ?
160 	    if (R_CheckTextureNumForName(startname) == -1)
161 		continue;
162 
163 	    lastanim->picnum = R_TextureNumForName(endname);
164 	    lastanim->basepic = R_TextureNumForName(startname);
165 	}
166 	else
167 	{
168 	    if (W_CheckNumForName(startname) == -1)
169 		continue;
170 
171 	    lastanim->picnum = R_FlatNumForName(endname);
172 	    lastanim->basepic = R_FlatNumForName(startname);
173 	}
174 
175 	lastanim->istexture = animdefs[i].istexture;
176 	lastanim->numpics = lastanim->picnum - lastanim->basepic + 1;
177 
178 	if (lastanim->numpics < 2)
179 	    I_Error ("P_InitPicAnims: bad cycle from %s to %s",
180 		     startname, endname);
181 
182 	lastanim->speed = animdefs[i].speed;
183 	lastanim++;
184     }
185 
186 }
187 
188 
189 
190 //
191 // UTILITIES
192 //
193 
194 
195 
196 //
197 // getSide()
198 // Will return a side_t*
199 //  given the number of the current sector,
200 //  the line number, and the side (0/1) that you want.
201 //
202 side_t*
getSide(int currentSector,int line,int side)203 getSide
204 ( int		currentSector,
205   int		line,
206   int		side )
207 {
208     return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
209 }
210 
211 
212 //
213 // getSector()
214 // Will return a sector_t*
215 //  given the number of the current sector,
216 //  the line number and the side (0/1) that you want.
217 //
218 sector_t*
getSector(int currentSector,int line,int side)219 getSector
220 ( int		currentSector,
221   int		line,
222   int		side )
223 {
224     return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
225 }
226 
227 
228 //
229 // twoSided()
230 // Given the sector number and the line number,
231 //  it will tell you whether the line is two-sided or not.
232 //
233 int
twoSided(int sector,int line)234 twoSided
235 ( int	sector,
236   int	line )
237 {
238     return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
239 }
240 
241 
242 
243 
244 //
245 // getNextSector()
246 // Return sector_t * of sector next to current.
247 // NULL if not two-sided line
248 //
249 sector_t*
getNextSector(line_t * line,sector_t * sec)250 getNextSector
251 ( line_t*	line,
252   sector_t*	sec )
253 {
254     if (!(line->flags & ML_TWOSIDED))
255 	return NULL;
256 
257     if (line->frontsector == sec)
258 	return line->backsector;
259 
260     return line->frontsector;
261 }
262 
263 
264 
265 //
266 // P_FindLowestFloorSurrounding()
267 // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
268 //
P_FindLowestFloorSurrounding(sector_t * sec)269 fixed_t	P_FindLowestFloorSurrounding(sector_t* sec)
270 {
271     int			i;
272     line_t*		check;
273     sector_t*		other;
274     fixed_t		floor = sec->floorheight;
275 
276     for (i=0 ;i < sec->linecount ; i++)
277     {
278 	check = sec->lines[i];
279 	other = getNextSector(check,sec);
280 
281 	if (!other)
282 	    continue;
283 
284 	if (other->floorheight < floor)
285 	    floor = other->floorheight;
286     }
287     return floor;
288 }
289 
290 
291 
292 //
293 // P_FindHighestFloorSurrounding()
294 // FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
295 //
P_FindHighestFloorSurrounding(sector_t * sec)296 fixed_t	P_FindHighestFloorSurrounding(sector_t *sec)
297 {
298     int			i;
299     line_t*		check;
300     sector_t*		other;
301     fixed_t		floor = -500*FRACUNIT;
302 
303     for (i=0 ;i < sec->linecount ; i++)
304     {
305 	check = sec->lines[i];
306 	other = getNextSector(check,sec);
307 
308 	if (!other)
309 	    continue;
310 
311 	if (other->floorheight > floor)
312 	    floor = other->floorheight;
313     }
314     return floor;
315 }
316 
317 
318 
319 //
320 // P_FindNextHighestFloor
321 // FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
322 // Note: this should be doable w/o a fixed array.
323 
324 // Thanks to entryway for the Vanilla overflow emulation.
325 
326 // 20 adjoining sectors max!
327 #define MAX_ADJOINING_SECTORS     20
328 
329 fixed_t
P_FindNextHighestFloor(sector_t * sec,int currentheight)330 P_FindNextHighestFloor
331 ( sector_t* sec,
332   int       currentheight )
333 {
334     int         i;
335     int         h;
336     int         min;
337     line_t*     check;
338     sector_t*   other;
339     fixed_t     height = currentheight;
340     fixed_t     heightlist[MAX_ADJOINING_SECTORS + 2];
341 
342     for (i=0, h=0; i < sec->linecount; i++)
343     {
344         check = sec->lines[i];
345         other = getNextSector(check,sec);
346 
347         if (!other)
348             continue;
349 
350         if (other->floorheight > height)
351         {
352             // Emulation of memory (stack) overflow
353             if (h == MAX_ADJOINING_SECTORS + 1)
354             {
355                 height = other->floorheight;
356             }
357             else if (h == MAX_ADJOINING_SECTORS + 2)
358             {
359                 // Fatal overflow: game crashes at 22 sectors
360                 I_Error("Sector with more than 22 adjoining sectors. "
361                         "Vanilla will crash here");
362             }
363 
364             heightlist[h++] = other->floorheight;
365         }
366     }
367 
368     // Find lowest height in list
369     if (!h)
370     {
371         return currentheight;
372     }
373 
374     min = heightlist[0];
375 
376     // Range checking?
377     for (i = 1; i < h; i++)
378     {
379         if (heightlist[i] < min)
380         {
381             min = heightlist[i];
382         }
383     }
384 
385     return min;
386 }
387 
388 //
389 // FIND LOWEST CEILING IN THE SURROUNDING SECTORS
390 //
391 fixed_t
P_FindLowestCeilingSurrounding(sector_t * sec)392 P_FindLowestCeilingSurrounding(sector_t* sec)
393 {
394     int			i;
395     line_t*		check;
396     sector_t*		other;
397     fixed_t		height = INT_MAX;
398 
399     for (i=0 ;i < sec->linecount ; i++)
400     {
401 	check = sec->lines[i];
402 	other = getNextSector(check,sec);
403 
404 	if (!other)
405 	    continue;
406 
407 	if (other->ceilingheight < height)
408 	    height = other->ceilingheight;
409     }
410     return height;
411 }
412 
413 
414 //
415 // FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
416 //
P_FindHighestCeilingSurrounding(sector_t * sec)417 fixed_t	P_FindHighestCeilingSurrounding(sector_t* sec)
418 {
419     int		i;
420     line_t*	check;
421     sector_t*	other;
422     fixed_t	height = 0;
423 
424     for (i=0 ;i < sec->linecount ; i++)
425     {
426 	check = sec->lines[i];
427 	other = getNextSector(check,sec);
428 
429 	if (!other)
430 	    continue;
431 
432 	if (other->ceilingheight > height)
433 	    height = other->ceilingheight;
434     }
435     return height;
436 }
437 
438 
439 
440 //
441 // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
442 //
443 int
P_FindSectorFromLineTag(line_t * line,int start)444 P_FindSectorFromLineTag
445 ( line_t*	line,
446   int		start )
447 {
448     int	i;
449 
450     for (i=start+1;i<numsectors;i++)
451 	if (sectors[i].tag == line->tag)
452 	    return i;
453 
454     return -1;
455 }
456 
457 
458 
459 
460 //
461 // Find minimum light from an adjacent sector
462 //
463 int
P_FindMinSurroundingLight(sector_t * sector,int max)464 P_FindMinSurroundingLight
465 ( sector_t*	sector,
466   int		max )
467 {
468     int		i;
469     int		min;
470     line_t*	line;
471     sector_t*	check;
472 
473     min = max;
474     for (i=0 ; i < sector->linecount ; i++)
475     {
476 	line = sector->lines[i];
477 	check = getNextSector(line,sector);
478 
479 	if (!check)
480 	    continue;
481 
482 	if (check->lightlevel < min)
483 	    min = check->lightlevel;
484     }
485     return min;
486 }
487 
488 
489 
490 //
491 // EVENTS
492 // Events are operations triggered by using, crossing,
493 // or shooting special lines, or by timed thinkers.
494 //
495 
496 //
497 // P_CrossSpecialLine - TRIGGER
498 // Called every time a thing origin is about
499 //  to cross a line with a non 0 special.
500 //
501 void
P_CrossSpecialLine(int linenum,int side,mobj_t * thing)502 P_CrossSpecialLine
503 ( int		linenum,
504   int		side,
505   mobj_t*	thing )
506 {
507     line_t*	line;
508     int		ok;
509 
510     line = &lines[linenum];
511 
512     //	Triggers that other things can activate
513     if (!thing->player)
514     {
515 	// Things that should NOT trigger specials...
516 	switch(thing->type)
517 	{
518 	  case MT_ROCKET:
519 	  case MT_PLASMA:
520 	  case MT_BFG:
521 	  case MT_TROOPSHOT:
522 	  case MT_HEADSHOT:
523 	  case MT_BRUISERSHOT:
524 	    return;
525 	    break;
526 
527 	  default: break;
528 	}
529 
530 	ok = 0;
531 	switch(line->special)
532 	{
533 	  case 39:	// TELEPORT TRIGGER
534 	  case 97:	// TELEPORT RETRIGGER
535 	  case 125:	// TELEPORT MONSTERONLY TRIGGER
536 	  case 126:	// TELEPORT MONSTERONLY RETRIGGER
537 	  case 4:	// RAISE DOOR
538 	  case 10:	// PLAT DOWN-WAIT-UP-STAY TRIGGER
539 	  case 88:	// PLAT DOWN-WAIT-UP-STAY RETRIGGER
540 	    ok = 1;
541 	    break;
542 	}
543 	if (!ok)
544 	    return;
545     }
546 
547 
548     // Note: could use some const's here.
549     switch (line->special)
550     {
551 	// TRIGGERS.
552 	// All from here to RETRIGGERS.
553       case 2:
554 	// Open Door
555 	EV_DoDoor(line,vld_open);
556 	line->special = 0;
557 	break;
558 
559       case 3:
560 	// Close Door
561 	EV_DoDoor(line,vld_close);
562 	line->special = 0;
563 	break;
564 
565       case 4:
566 	// Raise Door
567 	EV_DoDoor(line,vld_normal);
568 	line->special = 0;
569 	break;
570 
571       case 5:
572 	// Raise Floor
573 	EV_DoFloor(line,raiseFloor);
574 	line->special = 0;
575 	break;
576 
577       case 6:
578 	// Fast Ceiling Crush & Raise
579 	EV_DoCeiling(line,fastCrushAndRaise);
580 	line->special = 0;
581 	break;
582 
583       case 8:
584 	// Build Stairs
585 	EV_BuildStairs(line,build8);
586 	line->special = 0;
587 	break;
588 
589       case 10:
590 	// PlatDownWaitUp
591 	EV_DoPlat(line,downWaitUpStay,0);
592 	line->special = 0;
593 	break;
594 
595       case 12:
596 	// Light Turn On - brightest near
597 	EV_LightTurnOn(line,0);
598 	line->special = 0;
599 	break;
600 
601       case 13:
602 	// Light Turn On 255
603 	EV_LightTurnOn(line,255);
604 	line->special = 0;
605 	break;
606 
607       case 16:
608 	// Close Door 30
609 	EV_DoDoor(line,vld_close30ThenOpen);
610 	line->special = 0;
611 	break;
612 
613       case 17:
614 	// Start Light Strobing
615 	EV_StartLightStrobing(line);
616 	line->special = 0;
617 	break;
618 
619       case 19:
620 	// Lower Floor
621 	EV_DoFloor(line,lowerFloor);
622 	line->special = 0;
623 	break;
624 
625       case 22:
626 	// Raise floor to nearest height and change texture
627 	EV_DoPlat(line,raiseToNearestAndChange,0);
628 	line->special = 0;
629 	break;
630 
631       case 25:
632 	// Ceiling Crush and Raise
633 	EV_DoCeiling(line,crushAndRaise);
634 	line->special = 0;
635 	break;
636 
637       case 30:
638 	// Raise floor to shortest texture height
639 	//  on either side of lines.
640 	EV_DoFloor(line,raiseToTexture);
641 	line->special = 0;
642 	break;
643 
644       case 35:
645 	// Lights Very Dark
646 	EV_LightTurnOn(line,35);
647 	line->special = 0;
648 	break;
649 
650       case 36:
651 	// Lower Floor (TURBO)
652 	EV_DoFloor(line,turboLower);
653 	line->special = 0;
654 	break;
655 
656       case 37:
657 	// LowerAndChange
658 	EV_DoFloor(line,lowerAndChange);
659 	line->special = 0;
660 	break;
661 
662       case 38:
663 	// Lower Floor To Lowest
664 	EV_DoFloor( line, lowerFloorToLowest );
665 	line->special = 0;
666 	break;
667 
668       case 39:
669 	// TELEPORT!
670 	EV_Teleport( line, side, thing );
671 	line->special = 0;
672 	break;
673 
674       case 40:
675 	// RaiseCeilingLowerFloor
676 	EV_DoCeiling( line, raiseToHighest );
677 	EV_DoFloor( line, lowerFloorToLowest );
678 	line->special = 0;
679 	break;
680 
681       case 44:
682 	// Ceiling Crush
683 	EV_DoCeiling( line, lowerAndCrush );
684 	line->special = 0;
685 	break;
686 
687       case 52:
688 	// EXIT!
689 	G_ExitLevel ();
690 	break;
691 
692       case 53:
693 	// Perpetual Platform Raise
694 	EV_DoPlat(line,perpetualRaise,0);
695 	line->special = 0;
696 	break;
697 
698       case 54:
699 	// Platform Stop
700 	EV_StopPlat(line);
701 	line->special = 0;
702 	break;
703 
704       case 56:
705 	// Raise Floor Crush
706 	EV_DoFloor(line,raiseFloorCrush);
707 	line->special = 0;
708 	break;
709 
710       case 57:
711 	// Ceiling Crush Stop
712 	EV_CeilingCrushStop(line);
713 	line->special = 0;
714 	break;
715 
716       case 58:
717 	// Raise Floor 24
718 	EV_DoFloor(line,raiseFloor24);
719 	line->special = 0;
720 	break;
721 
722       case 59:
723 	// Raise Floor 24 And Change
724 	EV_DoFloor(line,raiseFloor24AndChange);
725 	line->special = 0;
726 	break;
727 
728       case 104:
729 	// Turn lights off in sector(tag)
730 	EV_TurnTagLightsOff(line);
731 	line->special = 0;
732 	break;
733 
734       case 108:
735 	// Blazing Door Raise (faster than TURBO!)
736 	EV_DoDoor (line,vld_blazeRaise);
737 	line->special = 0;
738 	break;
739 
740       case 109:
741 	// Blazing Door Open (faster than TURBO!)
742 	EV_DoDoor (line,vld_blazeOpen);
743 	line->special = 0;
744 	break;
745 
746       case 100:
747 	// Build Stairs Turbo 16
748 	EV_BuildStairs(line,turbo16);
749 	line->special = 0;
750 	break;
751 
752       case 110:
753 	// Blazing Door Close (faster than TURBO!)
754 	EV_DoDoor (line,vld_blazeClose);
755 	line->special = 0;
756 	break;
757 
758       case 119:
759 	// Raise floor to nearest surr. floor
760 	EV_DoFloor(line,raiseFloorToNearest);
761 	line->special = 0;
762 	break;
763 
764       case 121:
765 	// Blazing PlatDownWaitUpStay
766 	EV_DoPlat(line,blazeDWUS,0);
767 	line->special = 0;
768 	break;
769 
770       case 124:
771 	// Secret EXIT
772 	G_SecretExitLevel ();
773 	break;
774 
775       case 125:
776 	// TELEPORT MonsterONLY
777 	if (!thing->player)
778 	{
779 	    EV_Teleport( line, side, thing );
780 	    line->special = 0;
781 	}
782 	break;
783 
784       case 130:
785 	// Raise Floor Turbo
786 	EV_DoFloor(line,raiseFloorTurbo);
787 	line->special = 0;
788 	break;
789 
790       case 141:
791 	// Silent Ceiling Crush & Raise
792 	EV_DoCeiling(line,silentCrushAndRaise);
793 	line->special = 0;
794 	break;
795 
796 	// RETRIGGERS.  All from here till end.
797       case 72:
798 	// Ceiling Crush
799 	EV_DoCeiling( line, lowerAndCrush );
800 	break;
801 
802       case 73:
803 	// Ceiling Crush and Raise
804 	EV_DoCeiling(line,crushAndRaise);
805 	break;
806 
807       case 74:
808 	// Ceiling Crush Stop
809 	EV_CeilingCrushStop(line);
810 	break;
811 
812       case 75:
813 	// Close Door
814 	EV_DoDoor(line,vld_close);
815 	break;
816 
817       case 76:
818 	// Close Door 30
819 	EV_DoDoor(line,vld_close30ThenOpen);
820 	break;
821 
822       case 77:
823 	// Fast Ceiling Crush & Raise
824 	EV_DoCeiling(line,fastCrushAndRaise);
825 	break;
826 
827       case 79:
828 	// Lights Very Dark
829 	EV_LightTurnOn(line,35);
830 	break;
831 
832       case 80:
833 	// Light Turn On - brightest near
834 	EV_LightTurnOn(line,0);
835 	break;
836 
837       case 81:
838 	// Light Turn On 255
839 	EV_LightTurnOn(line,255);
840 	break;
841 
842       case 82:
843 	// Lower Floor To Lowest
844 	EV_DoFloor( line, lowerFloorToLowest );
845 	break;
846 
847       case 83:
848 	// Lower Floor
849 	EV_DoFloor(line,lowerFloor);
850 	break;
851 
852       case 84:
853 	// LowerAndChange
854 	EV_DoFloor(line,lowerAndChange);
855 	break;
856 
857       case 86:
858 	// Open Door
859 	EV_DoDoor(line,vld_open);
860 	break;
861 
862       case 87:
863 	// Perpetual Platform Raise
864 	EV_DoPlat(line,perpetualRaise,0);
865 	break;
866 
867       case 88:
868 	// PlatDownWaitUp
869 	EV_DoPlat(line,downWaitUpStay,0);
870 	break;
871 
872       case 89:
873 	// Platform Stop
874 	EV_StopPlat(line);
875 	break;
876 
877       case 90:
878 	// Raise Door
879 	EV_DoDoor(line,vld_normal);
880 	break;
881 
882       case 91:
883 	// Raise Floor
884 	EV_DoFloor(line,raiseFloor);
885 	break;
886 
887       case 92:
888 	// Raise Floor 24
889 	EV_DoFloor(line,raiseFloor24);
890 	break;
891 
892       case 93:
893 	// Raise Floor 24 And Change
894 	EV_DoFloor(line,raiseFloor24AndChange);
895 	break;
896 
897       case 94:
898 	// Raise Floor Crush
899 	EV_DoFloor(line,raiseFloorCrush);
900 	break;
901 
902       case 95:
903 	// Raise floor to nearest height
904 	// and change texture.
905 	EV_DoPlat(line,raiseToNearestAndChange,0);
906 	break;
907 
908       case 96:
909 	// Raise floor to shortest texture height
910 	// on either side of lines.
911 	EV_DoFloor(line,raiseToTexture);
912 	break;
913 
914       case 97:
915 	// TELEPORT!
916 	EV_Teleport( line, side, thing );
917 	break;
918 
919       case 98:
920 	// Lower Floor (TURBO)
921 	EV_DoFloor(line,turboLower);
922 	break;
923 
924       case 105:
925 	// Blazing Door Raise (faster than TURBO!)
926 	EV_DoDoor (line,vld_blazeRaise);
927 	break;
928 
929       case 106:
930 	// Blazing Door Open (faster than TURBO!)
931 	EV_DoDoor (line,vld_blazeOpen);
932 	break;
933 
934       case 107:
935 	// Blazing Door Close (faster than TURBO!)
936 	EV_DoDoor (line,vld_blazeClose);
937 	break;
938 
939       case 120:
940 	// Blazing PlatDownWaitUpStay.
941 	EV_DoPlat(line,blazeDWUS,0);
942 	break;
943 
944       case 126:
945 	// TELEPORT MonsterONLY.
946 	if (!thing->player)
947 	    EV_Teleport( line, side, thing );
948 	break;
949 
950       case 128:
951 	// Raise To Nearest Floor
952 	EV_DoFloor(line,raiseFloorToNearest);
953 	break;
954 
955       case 129:
956 	// Raise Floor Turbo
957 	EV_DoFloor(line,raiseFloorTurbo);
958 	break;
959     }
960 }
961 
962 
963 
964 //
965 // P_ShootSpecialLine - IMPACT SPECIALS
966 // Called when a thing shoots a special line.
967 //
968 void
P_ShootSpecialLine(mobj_t * thing,line_t * line)969 P_ShootSpecialLine
970 ( mobj_t*	thing,
971   line_t*	line )
972 {
973     int		ok;
974 
975     //	Impacts that other things can activate.
976     if (!thing->player)
977     {
978 	ok = 0;
979 	switch(line->special)
980 	{
981 	  case 46:
982 	    // OPEN DOOR IMPACT
983 	    ok = 1;
984 	    break;
985 	}
986 	if (!ok)
987 	    return;
988     }
989 
990     switch(line->special)
991     {
992       case 24:
993 	// RAISE FLOOR
994 	EV_DoFloor(line,raiseFloor);
995 	P_ChangeSwitchTexture(line,0);
996 	break;
997 
998       case 46:
999 	// OPEN DOOR
1000 	EV_DoDoor(line,vld_open);
1001 	P_ChangeSwitchTexture(line,1);
1002 	break;
1003 
1004       case 47:
1005 	// RAISE FLOOR NEAR AND CHANGE
1006 	EV_DoPlat(line,raiseToNearestAndChange,0);
1007 	P_ChangeSwitchTexture(line,0);
1008 	break;
1009     }
1010 }
1011 
1012 
1013 
1014 //
1015 // P_PlayerInSpecialSector
1016 // Called every tic frame
1017 //  that the player origin is in a special sector
1018 //
P_PlayerInSpecialSector(player_t * player)1019 void P_PlayerInSpecialSector (player_t* player)
1020 {
1021     sector_t*	sector;
1022 
1023     sector = player->mo->subsector->sector;
1024 
1025     // Falling, not all the way down yet?
1026     if (player->mo->z != sector->floorheight)
1027 	return;
1028 
1029     // Has hitten ground.
1030     switch (sector->special)
1031     {
1032       case 5:
1033 	// HELLSLIME DAMAGE
1034 	if (!player->powers[pw_ironfeet])
1035 	    if (!(leveltime&0x1f))
1036 		P_DamageMobj (player->mo, NULL, NULL, 10);
1037 	break;
1038 
1039       case 7:
1040 	// NUKAGE DAMAGE
1041 	if (!player->powers[pw_ironfeet])
1042 	    if (!(leveltime&0x1f))
1043 		P_DamageMobj (player->mo, NULL, NULL, 5);
1044 	break;
1045 
1046       case 16:
1047 	// SUPER HELLSLIME DAMAGE
1048       case 4:
1049 	// STROBE HURT
1050 	if (!player->powers[pw_ironfeet]
1051 	    || (P_Random()<5) )
1052 	{
1053 	    if (!(leveltime&0x1f))
1054 		P_DamageMobj (player->mo, NULL, NULL, 20);
1055 	}
1056 	break;
1057 
1058       case 9:
1059 	// SECRET SECTOR
1060 	player->secretcount++;
1061 	sector->special = 0;
1062 	break;
1063 
1064       case 11:
1065 	// EXIT SUPER DAMAGE! (for E1M8 finale)
1066 	player->cheats &= ~CF_GODMODE;
1067 
1068 	if (!(leveltime&0x1f))
1069 	    P_DamageMobj (player->mo, NULL, NULL, 20);
1070 
1071 	if (player->health <= 10)
1072 	    G_ExitLevel();
1073 	break;
1074 
1075       default:
1076 	I_Error ("P_PlayerInSpecialSector: "
1077 		 "unknown special %i",
1078 		 sector->special);
1079 	break;
1080     };
1081 }
1082 
1083 
1084 
1085 
1086 //
1087 // P_UpdateSpecials
1088 // Animate planes, scroll walls, etc.
1089 //
1090 boolean		levelTimer;
1091 int		levelTimeCount;
1092 
P_UpdateSpecials(void)1093 void P_UpdateSpecials (void)
1094 {
1095     anim_t*	anim;
1096     int		pic;
1097     int		i;
1098     line_t*	line;
1099 
1100 
1101     //	LEVEL TIMER
1102     if (levelTimer == true)
1103     {
1104 	levelTimeCount--;
1105 	if (!levelTimeCount)
1106 	    G_ExitLevel();
1107     }
1108 
1109     //	ANIMATE FLATS AND TEXTURES GLOBALLY
1110     for (anim = anims ; anim < lastanim ; anim++)
1111     {
1112 	for (i=anim->basepic ; i<anim->basepic+anim->numpics ; i++)
1113 	{
1114 	    pic = anim->basepic + ( (leveltime/anim->speed + i)%anim->numpics );
1115 	    if (anim->istexture)
1116 		texturetranslation[i] = pic;
1117 	    else
1118 		flattranslation[i] = pic;
1119 	}
1120     }
1121 
1122 
1123     //	ANIMATE LINE SPECIALS
1124     for (i = 0; i < numlinespecials; i++)
1125     {
1126 	line = linespeciallist[i];
1127 	switch(line->special)
1128 	{
1129 	  case 48:
1130 	    // EFFECT FIRSTCOL SCROLL +
1131 	    sides[line->sidenum[0]].textureoffset += FRACUNIT;
1132 	    break;
1133 	}
1134     }
1135 
1136 
1137     //	DO BUTTONS
1138     for (i = 0; i < MAXBUTTONS; i++)
1139 	if (buttonlist[i].btimer)
1140 	{
1141 	    buttonlist[i].btimer--;
1142 	    if (!buttonlist[i].btimer)
1143 	    {
1144 		switch(buttonlist[i].where)
1145 		{
1146 		  case top:
1147 		    sides[buttonlist[i].line->sidenum[0]].toptexture =
1148 			buttonlist[i].btexture;
1149 		    break;
1150 
1151 		  case middle:
1152 		    sides[buttonlist[i].line->sidenum[0]].midtexture =
1153 			buttonlist[i].btexture;
1154 		    break;
1155 
1156 		  case bottom:
1157 		    sides[buttonlist[i].line->sidenum[0]].bottomtexture =
1158 			buttonlist[i].btexture;
1159 		    break;
1160 		}
1161 		S_StartSound(&buttonlist[i].soundorg,sfx_swtchn);
1162 		memset(&buttonlist[i],0,sizeof(button_t));
1163 	    }
1164 	}
1165 }
1166 
1167 
1168 //
1169 // Donut overrun emulation
1170 //
1171 // Derived from the code from PrBoom+.  Thanks go to Andrey Budko (entryway)
1172 // as usual :-)
1173 //
1174 
1175 #define DONUT_FLOORHEIGHT_DEFAULT 0x00000000
1176 #define DONUT_FLOORPIC_DEFAULT 0x16
1177 
DonutOverrun(fixed_t * s3_floorheight,short * s3_floorpic,line_t * line,sector_t * pillar_sector)1178 static void DonutOverrun(fixed_t *s3_floorheight, short *s3_floorpic,
1179                          line_t *line, sector_t *pillar_sector)
1180 {
1181     static int first = 1;
1182     static int tmp_s3_floorheight;
1183     static int tmp_s3_floorpic;
1184 
1185     extern int numflats;
1186 
1187     if (first)
1188     {
1189         int p;
1190 
1191         // This is the first time we have had an overrun.
1192         first = 0;
1193 
1194         // Default values
1195         tmp_s3_floorheight = DONUT_FLOORHEIGHT_DEFAULT;
1196         tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT;
1197 
1198         //!
1199         // @category compat
1200         // @arg <x> <y>
1201         //
1202         // Use the specified magic values when emulating behavior caused
1203         // by memory overruns from improperly constructed donuts.
1204         // In Vanilla Doom this can differ depending on the operating
1205         // system.  The default (if this option is not specified) is to
1206         // emulate the behavior when running under Windows 98.
1207 
1208         p = M_CheckParmWithArgs("-donut", 2);
1209 
1210         if (p > 0)
1211         {
1212             // Dump of needed memory: (fixed_t)0000:0000 and (short)0000:0008
1213             //
1214             // C:\>debug
1215             // -d 0:0
1216             //
1217             // DOS 6.22:
1218             // 0000:0000    (57 92 19 00) F4 06 70 00-(16 00)
1219             // DOS 7.1:
1220             // 0000:0000    (9E 0F C9 00) 65 04 70 00-(16 00)
1221             // Win98:
1222             // 0000:0000    (00 00 00 00) 65 04 70 00-(16 00)
1223             // DOSBox under XP:
1224             // 0000:0000    (00 00 00 F1) ?? ?? ?? 00-(07 00)
1225 
1226             M_StrToInt(myargv[p + 1], &tmp_s3_floorheight);
1227             M_StrToInt(myargv[p + 2], &tmp_s3_floorpic);
1228 
1229             if (tmp_s3_floorpic >= numflats)
1230             {
1231                 fprintf(stderr,
1232                         "DonutOverrun: The second parameter for \"-donut\" "
1233                         "switch should be greater than 0 and less than number "
1234                         "of flats (%d). Using default value (%d) instead. \n",
1235                         numflats, DONUT_FLOORPIC_DEFAULT);
1236                 tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT;
1237             }
1238         }
1239     }
1240 
1241     /*
1242     fprintf(stderr,
1243             "Linedef: %d; Sector: %d; "
1244             "New floor height: %d; New floor pic: %d\n",
1245             line->iLineID, pillar_sector->iSectorID,
1246             tmp_s3_floorheight >> 16, tmp_s3_floorpic);
1247      */
1248 
1249     *s3_floorheight = (fixed_t) tmp_s3_floorheight;
1250     *s3_floorpic = (short) tmp_s3_floorpic;
1251 }
1252 
1253 
1254 //
1255 // Special Stuff that can not be categorized
1256 //
EV_DoDonut(line_t * line)1257 int EV_DoDonut(line_t*	line)
1258 {
1259     sector_t*		s1;
1260     sector_t*		s2;
1261     sector_t*		s3;
1262     int			secnum;
1263     int			rtn;
1264     int			i;
1265     floormove_t*	floor;
1266     fixed_t s3_floorheight;
1267     short s3_floorpic;
1268 
1269     secnum = -1;
1270     rtn = 0;
1271     while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
1272     {
1273 	s1 = &sectors[secnum];
1274 
1275 	// ALREADY MOVING?  IF SO, KEEP GOING...
1276 	if (s1->specialdata)
1277 	    continue;
1278 
1279 	rtn = 1;
1280 	s2 = getNextSector(s1->lines[0],s1);
1281 
1282         // Vanilla Doom does not check if the linedef is one sided.  The
1283         // game does not crash, but reads invalid memory and causes the
1284         // sector floor to move "down" to some unknown height.
1285         // DOSbox prints a warning about an invalid memory access.
1286         //
1287         // I'm not sure exactly what invalid memory is being read.  This
1288         // isn't something that should be done, anyway.
1289         // Just print a warning and return.
1290 
1291         if (s2 == NULL)
1292         {
1293             fprintf(stderr,
1294                     "EV_DoDonut: linedef had no second sidedef! "
1295                     "Unexpected behavior may occur in Vanilla Doom. \n");
1296 	    break;
1297         }
1298 
1299 	for (i = 0; i < s2->linecount; i++)
1300 	{
1301 	    s3 = s2->lines[i]->backsector;
1302 
1303 	    if (s3 == s1)
1304 		continue;
1305 
1306             if (s3 == NULL)
1307             {
1308                 // e6y
1309                 // s3 is NULL, so
1310                 // s3->floorheight is an int at 0000:0000
1311                 // s3->floorpic is a short at 0000:0008
1312                 // Trying to emulate
1313 
1314                 fprintf(stderr,
1315                         "EV_DoDonut: WARNING: emulating buffer overrun due to "
1316                         "NULL back sector. "
1317                         "Unexpected behavior may occur in Vanilla Doom.\n");
1318 
1319                 DonutOverrun(&s3_floorheight, &s3_floorpic, line, s1);
1320             }
1321             else
1322             {
1323                 s3_floorheight = s3->floorheight;
1324                 s3_floorpic = s3->floorpic;
1325             }
1326 
1327 	    //	Spawn rising slime
1328 	    floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
1329 	    P_AddThinker (&floor->thinker);
1330 	    s2->specialdata = floor;
1331 	    floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
1332 	    floor->type = donutRaise;
1333 	    floor->crush = false;
1334 	    floor->direction = 1;
1335 	    floor->sector = s2;
1336 	    floor->speed = FLOORSPEED / 2;
1337 	    floor->texture = s3_floorpic;
1338 	    floor->newspecial = 0;
1339 	    floor->floordestheight = s3_floorheight;
1340 
1341 	    //	Spawn lowering donut-hole
1342 	    floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
1343 	    P_AddThinker (&floor->thinker);
1344 	    s1->specialdata = floor;
1345 	    floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
1346 	    floor->type = lowerFloor;
1347 	    floor->crush = false;
1348 	    floor->direction = -1;
1349 	    floor->sector = s1;
1350 	    floor->speed = FLOORSPEED / 2;
1351 	    floor->floordestheight = s3_floorheight;
1352 	    break;
1353 	}
1354     }
1355     return rtn;
1356 }
1357 
1358 
1359 
1360 //
1361 // SPECIAL SPAWNING
1362 //
1363 
1364 //
1365 // P_SpawnSpecials
1366 // After the map has been loaded, scan for specials
1367 //  that spawn thinkers
1368 //
1369 short		numlinespecials;
1370 line_t*		linespeciallist[MAXLINEANIMS];
1371 
1372 
1373 // Parses command line parameters.
P_SpawnSpecials(void)1374 void P_SpawnSpecials (void)
1375 {
1376     sector_t*	sector;
1377     int		i;
1378 
1379     // See if -TIMER was specified.
1380 
1381     if (timelimit > 0 && deathmatch)
1382     {
1383         levelTimer = true;
1384         levelTimeCount = timelimit * 60 * TICRATE;
1385     }
1386     else
1387     {
1388 	levelTimer = false;
1389     }
1390 
1391     //	Init special SECTORs.
1392     sector = sectors;
1393     for (i=0 ; i<numsectors ; i++, sector++)
1394     {
1395 	if (!sector->special)
1396 	    continue;
1397 
1398 	switch (sector->special)
1399 	{
1400 	  case 1:
1401 	    // FLICKERING LIGHTS
1402 	    P_SpawnLightFlash (sector);
1403 	    break;
1404 
1405 	  case 2:
1406 	    // STROBE FAST
1407 	    P_SpawnStrobeFlash(sector,FASTDARK,0);
1408 	    break;
1409 
1410 	  case 3:
1411 	    // STROBE SLOW
1412 	    P_SpawnStrobeFlash(sector,SLOWDARK,0);
1413 	    break;
1414 
1415 	  case 4:
1416 	    // STROBE FAST/DEATH SLIME
1417 	    P_SpawnStrobeFlash(sector,FASTDARK,0);
1418 	    sector->special = 4;
1419 	    break;
1420 
1421 	  case 8:
1422 	    // GLOWING LIGHT
1423 	    P_SpawnGlowingLight(sector);
1424 	    break;
1425 	  case 9:
1426 	    // SECRET SECTOR
1427 	    totalsecret++;
1428 	    break;
1429 
1430 	  case 10:
1431 	    // DOOR CLOSE IN 30 SECONDS
1432 	    P_SpawnDoorCloseIn30 (sector);
1433 	    break;
1434 
1435 	  case 12:
1436 	    // SYNC STROBE SLOW
1437 	    P_SpawnStrobeFlash (sector, SLOWDARK, 1);
1438 	    break;
1439 
1440 	  case 13:
1441 	    // SYNC STROBE FAST
1442 	    P_SpawnStrobeFlash (sector, FASTDARK, 1);
1443 	    break;
1444 
1445 	  case 14:
1446 	    // DOOR RAISE IN 5 MINUTES
1447 	    P_SpawnDoorRaiseIn5Mins (sector, i);
1448 	    break;
1449 
1450 	  case 17:
1451 	    P_SpawnFireFlicker(sector);
1452 	    break;
1453 	}
1454     }
1455 
1456 
1457     //	Init line EFFECTs
1458     numlinespecials = 0;
1459     for (i = 0;i < numlines; i++)
1460     {
1461 	switch(lines[i].special)
1462 	{
1463 	  case 48:
1464             if (numlinespecials >= MAXLINEANIMS)
1465             {
1466                 I_Error("Too many scrolling wall linedefs! "
1467                         "(Vanilla limit is 64)");
1468             }
1469 	    // EFFECT FIRSTCOL SCROLL+
1470 	    linespeciallist[numlinespecials] = &lines[i];
1471 	    numlinespecials++;
1472 	    break;
1473 	}
1474     }
1475 
1476 
1477     //	Init other misc stuff
1478     for (i = 0;i < MAXCEILINGS;i++)
1479 	activeceilings[i] = NULL;
1480 
1481     for (i = 0;i < MAXPLATS;i++)
1482 	activeplats[i] = NULL;
1483 
1484     for (i = 0;i < MAXBUTTONS;i++)
1485 	memset(&buttonlist[i],0,sizeof(button_t));
1486 
1487     // UNUSED: no horizonal sliders.
1488     //	P_InitSlidingDoorFrames();
1489 }
1490