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 = §ors[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