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