1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2000 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *  Generalized linedef type handlers
31  *  Floors, Ceilings, Doors, Locked Doors, Lifts, Stairs, Crushers
32  *
33  *-----------------------------------------------------------------------------*/
34 
35 #include "doomstat.h" //jff 6/19/98 for demo_compatibility
36 #include "r_main.h"
37 #include "p_spec.h"
38 #include "p_tick.h"
39 #include "m_random.h"
40 #include "s_sound.h"
41 #include "sounds.h"
42 #include "e6y.h"
43 
44 //////////////////////////////////////////////////////////
45 //
46 // Generalized Linedef Type handlers
47 //
48 //////////////////////////////////////////////////////////
49 
50 //
51 // EV_DoGenFloor()
52 //
53 // Handle generalized floor types
54 //
55 // Passed the line activating the generalized floor function
56 // Returns true if a thinker is created
57 //
58 // jff 02/04/98 Added this routine (and file) to handle generalized
59 // floor movers using bit fields in the line special type.
60 //
EV_DoGenFloor(line_t * line)61 int EV_DoGenFloor
62 ( line_t*       line )
63 {
64   int                   secnum;
65   int                   rtn;
66   dboolean               manual;
67   sector_t*             sec;
68   floormove_t*          floor;
69   unsigned              value = (unsigned)line->special - GenFloorBase;
70 
71   // parse the bit fields in the line's special type
72 
73   int Crsh = (value & FloorCrush) >> FloorCrushShift;
74   int ChgT = (value & FloorChange) >> FloorChangeShift;
75   int Targ = (value & FloorTarget) >> FloorTargetShift;
76   int Dirn = (value & FloorDirection) >> FloorDirectionShift;
77   int ChgM = (value & FloorModel) >> FloorModelShift;
78   int Sped = (value & FloorSpeed) >> FloorSpeedShift;
79   int Trig = (value & TriggerType) >> TriggerTypeShift;
80 
81   rtn = 0;
82 
83   if (ProcessNoTagLines(line, &sec, &secnum)) {if (zerotag_manual) {manual = true; goto manual_floor;} else {return rtn;}};//e6y
84   // check if a manual trigger, if so do just the sector on the backside
85   manual = false;
86   if (Trig==PushOnce || Trig==PushMany)
87   {
88     if (!(sec = line->backsector))
89       return rtn;
90     secnum = sec->iSectorID;
91     manual = true;
92     goto manual_floor;
93   }
94 
95   secnum = -1;
96   // if not manual do all sectors tagged the same as the line
97   while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
98   {
99     sec = &sectors[secnum];
100 
101 manual_floor:
102     // Do not start another function if floor already moving
103     if (P_SectorActive(floor_special,sec))
104     {
105       if (!manual)
106         continue;
107       else
108         return rtn;
109     }
110 
111     // new floor thinker
112     rtn = 1;
113     floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
114     memset(floor, 0, sizeof(*floor));
115     P_AddThinker (&floor->thinker);
116     sec->floordata = floor;
117     floor->thinker.function = T_MoveFloor;
118     floor->crush = Crsh;
119     floor->direction = Dirn? 1 : -1;
120     floor->sector = sec;
121     floor->texture = sec->floorpic;
122     floor->newspecial = sec->special;
123     //jff 3/14/98 transfer old special field too
124     floor->oldspecial = sec->oldspecial;
125     floor->type = genFloor;
126 
127     // set the speed of motion
128     switch (Sped)
129     {
130       case SpeedSlow:
131         floor->speed = FLOORSPEED;
132         break;
133       case SpeedNormal:
134         floor->speed = FLOORSPEED*2;
135         break;
136       case SpeedFast:
137         floor->speed = FLOORSPEED*4;
138         break;
139       case SpeedTurbo:
140         floor->speed = FLOORSPEED*8;
141         break;
142       default:
143         break;
144     }
145 
146     // set the destination height
147     switch(Targ)
148     {
149       case FtoHnF:
150         floor->floordestheight = P_FindHighestFloorSurrounding(sec);
151         break;
152       case FtoLnF:
153         floor->floordestheight = P_FindLowestFloorSurrounding(sec);
154         break;
155       case FtoNnF:
156         floor->floordestheight = Dirn?
157           P_FindNextHighestFloor(sec,sec->floorheight) :
158           P_FindNextLowestFloor(sec,sec->floorheight);
159         break;
160       case FtoLnC:
161         floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
162         break;
163       case FtoC:
164         floor->floordestheight = sec->ceilingheight;
165         break;
166       case FbyST:
167         floor->floordestheight = (floor->sector->floorheight>>FRACBITS) +
168           floor->direction * (P_FindShortestTextureAround(secnum)>>FRACBITS);
169         if (floor->floordestheight>32000)  //jff 3/13/98 prevent overflow
170           floor->floordestheight=32000;    // wraparound in floor height
171         if (floor->floordestheight<-32000)
172           floor->floordestheight=-32000;
173         floor->floordestheight<<=FRACBITS;
174         break;
175       case Fby24:
176         floor->floordestheight = floor->sector->floorheight +
177           floor->direction * 24*FRACUNIT;
178         break;
179       case Fby32:
180         floor->floordestheight = floor->sector->floorheight +
181           floor->direction * 32*FRACUNIT;
182         break;
183       default:
184         break;
185     }
186 
187     // set texture/type change properties
188     if (ChgT)   // if a texture change is indicated
189     {
190       if (ChgM) // if a numeric model change
191       {
192         sector_t *sec;
193 
194         //jff 5/23/98 find model with ceiling at target height if target
195         //is a ceiling type
196         sec = (Targ==FtoLnC || Targ==FtoC)?
197           P_FindModelCeilingSector(floor->floordestheight,secnum) :
198           P_FindModelFloorSector(floor->floordestheight,secnum);
199         if (sec)
200         {
201           floor->texture = sec->floorpic;
202           switch(ChgT)
203           {
204             case FChgZero:  // zero type
205               floor->newspecial = 0;
206               //jff 3/14/98 change old field too
207               floor->oldspecial = 0;
208               floor->type = genFloorChg0;
209               break;
210             case FChgTyp:   // copy type
211               floor->newspecial = sec->special;
212               //jff 3/14/98 change old field too
213               floor->oldspecial = sec->oldspecial;
214               floor->type = genFloorChgT;
215               break;
216             case FChgTxt:   // leave type be
217               floor->type = genFloorChg;
218               break;
219             default:
220               break;
221           }
222         }
223       }
224       else     // else if a trigger model change
225       {
226         floor->texture = line->frontsector->floorpic;
227         switch (ChgT)
228         {
229           case FChgZero:    // zero type
230             floor->newspecial = 0;
231             //jff 3/14/98 change old field too
232             floor->oldspecial = 0;
233             floor->type = genFloorChg0;
234             break;
235           case FChgTyp:     // copy type
236             floor->newspecial = line->frontsector->special;
237             //jff 3/14/98 change old field too
238             floor->oldspecial = line->frontsector->oldspecial;
239             floor->type = genFloorChgT;
240             break;
241           case FChgTxt:     // leave type be
242             floor->type = genFloorChg;
243           default:
244             break;
245         }
246       }
247     }
248     if (manual) return rtn;
249   }
250   return rtn;
251 }
252 
253 
254 //
255 // EV_DoGenCeiling()
256 //
257 // Handle generalized ceiling types
258 //
259 // Passed the linedef activating the ceiling function
260 // Returns true if a thinker created
261 //
262 // jff 02/04/98 Added this routine (and file) to handle generalized
263 // floor movers using bit fields in the line special type.
264 //
EV_DoGenCeiling(line_t * line)265 int EV_DoGenCeiling
266 ( line_t*       line )
267 {
268   int                   secnum;
269   int                   rtn;
270   dboolean               manual;
271   fixed_t               targheight;
272   sector_t*             sec;
273   ceiling_t*            ceiling;
274   unsigned              value = (unsigned)line->special - GenCeilingBase;
275 
276   // parse the bit fields in the line's special type
277 
278   int Crsh = (value & CeilingCrush) >> CeilingCrushShift;
279   int ChgT = (value & CeilingChange) >> CeilingChangeShift;
280   int Targ = (value & CeilingTarget) >> CeilingTargetShift;
281   int Dirn = (value & CeilingDirection) >> CeilingDirectionShift;
282   int ChgM = (value & CeilingModel) >> CeilingModelShift;
283   int Sped = (value & CeilingSpeed) >> CeilingSpeedShift;
284   int Trig = (value & TriggerType) >> TriggerTypeShift;
285 
286   rtn = 0;
287 
288   if (ProcessNoTagLines(line, &sec, &secnum)) {if (zerotag_manual) {manual = true; goto manual_ceiling;} else {return rtn;}};//e6y
289   // check if a manual trigger, if so do just the sector on the backside
290   manual = false;
291   if (Trig==PushOnce || Trig==PushMany)
292   {
293     if (!(sec = line->backsector))
294       return rtn;
295     secnum = sec->iSectorID;
296     manual = true;
297     goto manual_ceiling;
298   }
299 
300   secnum = -1;
301   // if not manual do all sectors tagged the same as the line
302   while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
303   {
304     sec = &sectors[secnum];
305 
306 manual_ceiling:
307     // Do not start another function if ceiling already moving
308     if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
309     {
310       if (!manual)
311         continue;
312       else
313         return rtn;
314     }
315 
316     // new ceiling thinker
317     rtn = 1;
318     ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
319     memset(ceiling, 0, sizeof(*ceiling));
320     P_AddThinker (&ceiling->thinker);
321     sec->ceilingdata = ceiling; //jff 2/22/98
322     ceiling->thinker.function = T_MoveCeiling;
323     ceiling->crush = Crsh;
324     ceiling->direction = Dirn? 1 : -1;
325     ceiling->sector = sec;
326     ceiling->texture = sec->ceilingpic;
327     ceiling->newspecial = sec->special;
328     //jff 3/14/98 change old field too
329     ceiling->oldspecial = sec->oldspecial;
330     ceiling->tag = sec->tag;
331     ceiling->type = genCeiling;
332 
333     // set speed of motion
334     switch (Sped)
335     {
336       case SpeedSlow:
337         ceiling->speed = CEILSPEED;
338         break;
339       case SpeedNormal:
340         ceiling->speed = CEILSPEED*2;
341         break;
342       case SpeedFast:
343         ceiling->speed = CEILSPEED*4;
344         break;
345       case SpeedTurbo:
346         ceiling->speed = CEILSPEED*8;
347         break;
348       default:
349         break;
350     }
351 
352     // set destination target height
353     targheight = sec->ceilingheight;
354     switch(Targ)
355     {
356       case CtoHnC:
357         targheight = P_FindHighestCeilingSurrounding(sec);
358         break;
359       case CtoLnC:
360         targheight = P_FindLowestCeilingSurrounding(sec);
361         break;
362       case CtoNnC:
363         targheight = Dirn?
364           P_FindNextHighestCeiling(sec,sec->ceilingheight) :
365           P_FindNextLowestCeiling(sec,sec->ceilingheight);
366         break;
367       case CtoHnF:
368         targheight = P_FindHighestFloorSurrounding(sec);
369         break;
370       case CtoF:
371         targheight = sec->floorheight;
372         break;
373       case CbyST:
374         targheight = (ceiling->sector->ceilingheight>>FRACBITS) +
375           ceiling->direction * (P_FindShortestUpperAround(secnum)>>FRACBITS);
376         if (targheight>32000)  //jff 3/13/98 prevent overflow
377           targheight=32000;    // wraparound in ceiling height
378         if (targheight<-32000)
379           targheight=-32000;
380         targheight<<=FRACBITS;
381         break;
382       case Cby24:
383         targheight = ceiling->sector->ceilingheight +
384           ceiling->direction * 24*FRACUNIT;
385         break;
386       case Cby32:
387         targheight = ceiling->sector->ceilingheight +
388           ceiling->direction * 32*FRACUNIT;
389         break;
390       default:
391         break;
392     }
393     if (Dirn) ceiling->topheight = targheight;
394     else ceiling->bottomheight = targheight;
395 
396     // set texture/type change properties
397     if (ChgT)     // if a texture change is indicated
398     {
399       if (ChgM)   // if a numeric model change
400       {
401         sector_t *sec;
402 
403         //jff 5/23/98 find model with floor at target height if target
404         //is a floor type
405         sec = (Targ==CtoHnF || Targ==CtoF)?
406           P_FindModelFloorSector(targheight,secnum) :
407           P_FindModelCeilingSector(targheight,secnum);
408         if (sec)
409         {
410           ceiling->texture = sec->ceilingpic;
411           switch (ChgT)
412           {
413             case CChgZero:  // type is zeroed
414               ceiling->newspecial = 0;
415               //jff 3/14/98 change old field too
416               ceiling->oldspecial = 0;
417               ceiling->type = genCeilingChg0;
418               break;
419             case CChgTyp:   // type is copied
420               ceiling->newspecial = sec->special;
421               //jff 3/14/98 change old field too
422               ceiling->oldspecial = sec->oldspecial;
423               ceiling->type = genCeilingChgT;
424               break;
425             case CChgTxt:   // type is left alone
426               ceiling->type = genCeilingChg;
427               break;
428             default:
429               break;
430           }
431         }
432       }
433       else        // else if a trigger model change
434       {
435         ceiling->texture = line->frontsector->ceilingpic;
436         switch (ChgT)
437         {
438           case CChgZero:    // type is zeroed
439             ceiling->newspecial = 0;
440             //jff 3/14/98 change old field too
441             ceiling->oldspecial = 0;
442             ceiling->type = genCeilingChg0;
443             break;
444           case CChgTyp:     // type is copied
445             ceiling->newspecial = line->frontsector->special;
446             //jff 3/14/98 change old field too
447             ceiling->oldspecial = line->frontsector->oldspecial;
448             ceiling->type = genCeilingChgT;
449             break;
450           case CChgTxt:     // type is left alone
451             ceiling->type = genCeilingChg;
452             break;
453           default:
454             break;
455         }
456       }
457     }
458     P_AddActiveCeiling(ceiling);  // add this ceiling to the active list
459     if (manual) return rtn;
460   }
461   return rtn;
462 }
463 
464 //
465 // EV_DoGenLift()
466 //
467 // Handle generalized lift types
468 //
469 // Passed the linedef activating the lift
470 // Returns true if a thinker is created
471 //
EV_DoGenLift(line_t * line)472 int EV_DoGenLift
473 ( line_t*       line )
474 {
475   plat_t*         plat;
476   int             secnum;
477   int             rtn;
478   dboolean         manual;
479   sector_t*       sec;
480   unsigned        value = (unsigned)line->special - GenLiftBase;
481 
482   // parse the bit fields in the line's special type
483 
484   int Targ = (value & LiftTarget) >> LiftTargetShift;
485   int Dely = (value & LiftDelay) >> LiftDelayShift;
486   int Sped = (value & LiftSpeed) >> LiftSpeedShift;
487   int Trig = (value & TriggerType) >> TriggerTypeShift;
488 
489   secnum = -1;
490   rtn = 0;
491 
492   // Activate all <type> plats that are in_stasis
493 
494   if (Targ==LnF2HnF)
495     P_ActivateInStasis(line->tag);
496 
497   if (ProcessNoTagLines(line, &sec, &secnum)) {if (zerotag_manual) {manual = true; goto manual_lift;} else {return rtn;}};//e6y
498   // check if a manual trigger, if so do just the sector on the backside
499   manual = false;
500   if (Trig==PushOnce || Trig==PushMany)
501   {
502     if (!(sec = line->backsector))
503       return rtn;
504     secnum = sec->iSectorID;
505     manual = true;
506     goto manual_lift;
507   }
508 
509   // if not manual do all sectors tagged the same as the line
510   while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
511   {
512     sec = &sectors[secnum];
513 
514 manual_lift:
515     // Do not start another function if floor already moving
516     if (P_SectorActive(floor_special,sec))
517     {
518       if (!manual)
519         continue;
520       else
521         return rtn;
522     }
523 
524     // Setup the plat thinker
525     rtn = 1;
526     plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0);
527     memset(plat, 0, sizeof(*plat));
528     P_AddThinker(&plat->thinker);
529 
530     plat->sector = sec;
531     plat->sector->floordata = plat;
532     plat->thinker.function = T_PlatRaise;
533     plat->crush = false;
534     plat->tag = line->tag;
535 
536     plat->type = genLift;
537     plat->high = sec->floorheight;
538     plat->status = down;
539 
540     // setup the target destination height
541     switch(Targ)
542     {
543       case F2LnF:
544         plat->low = P_FindLowestFloorSurrounding(sec);
545         if (plat->low > sec->floorheight)
546           plat->low = sec->floorheight;
547         break;
548       case F2NnF:
549         plat->low = P_FindNextLowestFloor(sec,sec->floorheight);
550         break;
551       case F2LnC:
552         plat->low = P_FindLowestCeilingSurrounding(sec);
553         if (plat->low > sec->floorheight)
554           plat->low = sec->floorheight;
555         break;
556       case LnF2HnF:
557         plat->type = genPerpetual;
558         plat->low = P_FindLowestFloorSurrounding(sec);
559         if (plat->low > sec->floorheight)
560           plat->low = sec->floorheight;
561         plat->high = P_FindHighestFloorSurrounding(sec);
562         if (plat->high < sec->floorheight)
563           plat->high = sec->floorheight;
564         plat->status = P_Random(pr_genlift)&1;
565         break;
566       default:
567         break;
568     }
569 
570     // setup the speed of motion
571     switch(Sped)
572     {
573       case SpeedSlow:
574         plat->speed = PLATSPEED * 2;
575         break;
576       case SpeedNormal:
577         plat->speed = PLATSPEED * 4;
578         break;
579       case SpeedFast:
580         plat->speed = PLATSPEED * 8;
581         break;
582       case SpeedTurbo:
583         plat->speed = PLATSPEED * 16;
584         break;
585       default:
586         break;
587     }
588 
589     // setup the delay time before the floor returns
590     switch(Dely)
591     {
592       case 0:
593         plat->wait = 1*35;
594         break;
595       case 1:
596         plat->wait = PLATWAIT*35;
597         break;
598       case 2:
599         plat->wait = 5*35;
600         break;
601       case 3:
602         plat->wait = 10*35;
603         break;
604     }
605 
606     S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart);
607     P_AddActivePlat(plat); // add this plat to the list of active plats
608 
609     if (manual)
610       return rtn;
611   }
612   return rtn;
613 }
614 
615 //
616 // EV_DoGenStairs()
617 //
618 // Handle generalized stair building
619 //
620 // Passed the linedef activating the stairs
621 // Returns true if a thinker is created
622 //
EV_DoGenStairs(line_t * line)623 int EV_DoGenStairs
624 ( line_t*       line )
625 {
626   int                   secnum;
627   int                   osecnum; //jff 3/4/98 preserve loop index
628   int                   height;
629   int                   i;
630   int                   newsecnum;
631   int                   texture;
632   int                   ok;
633   int                   rtn;
634   dboolean               manual;
635 
636   sector_t*             sec;
637   sector_t*             tsec;
638 
639   floormove_t*  floor;
640 
641   fixed_t               stairsize;
642   fixed_t               speed;
643 
644   unsigned              value = (unsigned)line->special - GenStairsBase;
645 
646   // parse the bit fields in the line's special type
647 
648   int Igno = (value & StairIgnore) >> StairIgnoreShift;
649   int Dirn = (value & StairDirection) >> StairDirectionShift;
650   int Step = (value & StairStep) >> StairStepShift;
651   int Sped = (value & StairSpeed) >> StairSpeedShift;
652   int Trig = (value & TriggerType) >> TriggerTypeShift;
653 
654   rtn = 0;
655 
656   if (ProcessNoTagLines(line, &sec, &secnum)) {if (zerotag_manual) {manual = true; goto manual_stair;} else {return rtn;}};//e6y
657   // check if a manual trigger, if so do just the sector on the backside
658   manual = false;
659   if (Trig==PushOnce || Trig==PushMany)
660   {
661     if (!(sec = line->backsector))
662       return rtn;
663     secnum = sec->iSectorID;
664     manual = true;
665     goto manual_stair;
666   }
667 
668   secnum = -1;
669   // if not manual do all sectors tagged the same as the line
670   while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
671   {
672     sec = &sectors[secnum];
673 
674 manual_stair:
675     //Do not start another function if floor already moving
676     //jff 2/26/98 add special lockout condition to wait for entire
677     //staircase to build before retriggering
678     if (P_SectorActive(floor_special,sec) || sec->stairlock)
679     {
680       if (!manual)
681         continue;
682       else
683         return rtn;
684     }
685 
686     // new floor thinker
687     rtn = 1;
688     floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
689     memset(floor, 0, sizeof(*floor));
690     P_AddThinker (&floor->thinker);
691     sec->floordata = floor;
692     floor->thinker.function = T_MoveFloor;
693     floor->direction = Dirn? 1 : -1;
694     floor->sector = sec;
695 
696     // setup speed of stair building
697     switch(Sped)
698       {
699       default:
700       case SpeedSlow:
701         floor->speed = FLOORSPEED/4;
702         break;
703       case SpeedNormal:
704         floor->speed = FLOORSPEED/2;
705         break;
706       case SpeedFast:
707         floor->speed = FLOORSPEED*2;
708         break;
709       case SpeedTurbo:
710         floor->speed = FLOORSPEED*4;
711         break;
712       }
713 
714     // setup stepsize for stairs
715     switch(Step)
716     {
717       default:
718       case 0:
719         stairsize = 4*FRACUNIT;
720         break;
721       case 1:
722         stairsize = 8*FRACUNIT;
723         break;
724       case 2:
725         stairsize = 16*FRACUNIT;
726         break;
727       case 3:
728         stairsize = 24*FRACUNIT;
729         break;
730     }
731 
732     speed = floor->speed;
733     height = sec->floorheight + floor->direction * stairsize;
734     floor->floordestheight = height;
735     texture = sec->floorpic;
736     floor->crush = false;
737     floor->type = genBuildStair; // jff 3/31/98 do not leave uninited
738 
739     sec->stairlock = -2;         // jff 2/26/98 set up lock on current sector
740     sec->nextsec = -1;
741     sec->prevsec = -1;
742 
743     osecnum = secnum;            //jff 3/4/98 preserve loop index
744     // Find next sector to raise
745     // 1.     Find 2-sided line with same sector side[0]
746     // 2.     Other side is the next sector to raise
747     do
748     {
749       ok = 0;
750       for (i = 0;i < sec->linecount;i++)
751       {
752         if ( !((sec->lines[i])->backsector) )
753           continue;
754 
755         tsec = (sec->lines[i])->frontsector;
756         newsecnum = tsec->iSectorID;
757 
758         if (secnum != newsecnum)
759           continue;
760 
761         tsec = (sec->lines[i])->backsector;
762         newsecnum = tsec->iSectorID;
763 
764         if (!Igno && tsec->floorpic != texture)
765           continue;
766 
767         /* jff 6/19/98 prevent double stepsize */
768         if (compatibility_level < boom_202_compatibility)
769           height += floor->direction * stairsize;
770 
771         //jff 2/26/98 special lockout condition for retriggering
772         if (P_SectorActive(floor_special,tsec) || tsec->stairlock)
773           continue;
774 
775         /* jff 6/19/98 increase height AFTER continue */
776         if (compatibility_level >= boom_202_compatibility)
777           height += floor->direction * stairsize;
778 
779         // jff 2/26/98
780         // link the stair chain in both directions
781         // lock the stair sector until building complete
782         sec->nextsec = newsecnum; // link step to next
783         tsec->prevsec = secnum;   // link next back
784         tsec->nextsec = -1;       // set next forward link as end
785         tsec->stairlock = -2;     // lock the step
786 
787         sec = tsec;
788         secnum = newsecnum;
789         floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
790 
791         memset(floor, 0, sizeof(*floor));
792         P_AddThinker (&floor->thinker);
793 
794         sec->floordata = floor;
795         floor->thinker.function = T_MoveFloor;
796         floor->direction = Dirn? 1 : -1;
797         floor->sector = sec;
798         floor->speed = speed;
799         floor->floordestheight = height;
800         floor->crush = false;
801         floor->type = genBuildStair; // jff 3/31/98 do not leave uninited
802 
803         ok = 1;
804         break;
805       }
806     } while(ok);
807       if (manual)
808         return rtn;
809       secnum = osecnum; //jff 3/4/98 restore old loop index
810   }
811   // retriggerable generalized stairs build up or down alternately
812   if (rtn)
813     line->special ^= StairDirection; // alternate dir on succ activations
814   return rtn;
815 }
816 
817 //
818 // EV_DoGenCrusher()
819 //
820 // Handle generalized crusher types
821 //
822 // Passed the linedef activating the crusher
823 // Returns true if a thinker created
824 //
EV_DoGenCrusher(line_t * line)825 int EV_DoGenCrusher
826 ( line_t*       line )
827 {
828   int                   secnum;
829   int                   rtn;
830   dboolean               manual;
831   sector_t*             sec;
832   ceiling_t*            ceiling;
833   unsigned              value = (unsigned)line->special - GenCrusherBase;
834 
835   // parse the bit fields in the line's special type
836 
837   int Slnt = (value & CrusherSilent) >> CrusherSilentShift;
838   int Sped = (value & CrusherSpeed) >> CrusherSpeedShift;
839   int Trig = (value & TriggerType) >> TriggerTypeShift;
840 
841   //jff 2/22/98  Reactivate in-stasis ceilings...for certain types.
842   //jff 4/5/98 return if activated
843   rtn = P_ActivateInStasisCeiling(line);
844 
845   if (ProcessNoTagLines(line, &sec, &secnum)) {if (zerotag_manual) {manual = true; goto manual_crusher;} else {return rtn;}};//e6y
846   // check if a manual trigger, if so do just the sector on the backside
847   manual = false;
848   if (Trig==PushOnce || Trig==PushMany)
849   {
850     if (!(sec = line->backsector))
851       return rtn;
852     secnum = sec->iSectorID;
853     manual = true;
854     goto manual_crusher;
855   }
856 
857   secnum = -1;
858   // if not manual do all sectors tagged the same as the line
859   while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
860   {
861     sec = &sectors[secnum];
862 
863 manual_crusher:
864     // Do not start another function if ceiling already moving
865     if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
866     {
867       if (!manual)
868         continue;
869       else
870         return rtn;
871     }
872 
873     // new ceiling thinker
874     rtn = 1;
875     ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
876     memset(ceiling, 0, sizeof(*ceiling));
877     P_AddThinker (&ceiling->thinker);
878     sec->ceilingdata = ceiling; //jff 2/22/98
879     ceiling->thinker.function = T_MoveCeiling;
880     ceiling->crush = true;
881     ceiling->direction = -1;
882     ceiling->sector = sec;
883     ceiling->texture = sec->ceilingpic;
884     ceiling->newspecial = sec->special;
885     ceiling->tag = sec->tag;
886     ceiling->type = Slnt? genSilentCrusher : genCrusher;
887     ceiling->topheight = sec->ceilingheight;
888     ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
889 
890     // setup ceiling motion speed
891     switch (Sped)
892     {
893       case SpeedSlow:
894         ceiling->speed = CEILSPEED;
895         break;
896       case SpeedNormal:
897         ceiling->speed = CEILSPEED*2;
898         break;
899       case SpeedFast:
900         ceiling->speed = CEILSPEED*4;
901         break;
902       case SpeedTurbo:
903         ceiling->speed = CEILSPEED*8;
904         break;
905       default:
906         break;
907     }
908     ceiling->oldspeed=ceiling->speed;
909 
910     P_AddActiveCeiling(ceiling);  // add to list of active ceilings
911     if (manual) return rtn;
912   }
913   return rtn;
914 }
915 
916 //
917 // EV_DoGenLockedDoor()
918 //
919 // Handle generalized locked door types
920 //
921 // Passed the linedef activating the generalized locked door
922 // Returns true if a thinker created
923 //
EV_DoGenLockedDoor(line_t * line)924 int EV_DoGenLockedDoor
925 ( line_t* line )
926 {
927   int   secnum,rtn;
928   sector_t* sec;
929   vldoor_t* door;
930   dboolean manual;
931   unsigned  value = (unsigned)line->special - GenLockedBase;
932 
933   // parse the bit fields in the line's special type
934 
935   int Kind = (value & LockedKind) >> LockedKindShift;
936   int Sped = (value & LockedSpeed) >> LockedSpeedShift;
937   int Trig = (value & TriggerType) >> TriggerTypeShift;
938 
939   rtn = 0;
940 
941   if (ProcessNoTagLines(line, &sec, &secnum)) {if (zerotag_manual) {manual = true; goto manual_locked;} else {return rtn;}};//e6y
942   // check if a manual trigger, if so do just the sector on the backside
943   manual = false;
944   if (Trig==PushOnce || Trig==PushMany)
945   {
946     if (!(sec = line->backsector))
947       return rtn;
948     secnum = sec->iSectorID;
949     manual = true;
950     goto manual_locked;
951   }
952 
953   secnum = -1;
954   rtn = 0;
955 
956   // if not manual do all sectors tagged the same as the line
957   while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
958   {
959     sec = &sectors[secnum];
960 manual_locked:
961     // Do not start another function if ceiling already moving
962     if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
963     {
964       if (!manual)
965         continue;
966       else
967         return rtn;
968     }
969 
970     // new door thinker
971     rtn = 1;
972     door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
973     memset(door, 0, sizeof(*door));
974     P_AddThinker (&door->thinker);
975     sec->ceilingdata = door; //jff 2/22/98
976 
977     door->thinker.function = T_VerticalDoor;
978     door->sector = sec;
979     door->topwait = VDOORWAIT;
980     door->line = line;
981     door->topheight = P_FindLowestCeilingSurrounding(sec);
982     door->topheight -= 4*FRACUNIT;
983     door->direction = 1;
984 
985     /* killough 10/98: implement gradual lighting */
986     door->lighttag = !comp[comp_doorlight] &&
987       (line->special&6) == 6 &&
988       line->special > GenLockedBase ? line->tag : 0;
989 
990     // setup speed of door motion
991     switch(Sped)
992     {
993       default:
994       case SpeedSlow:
995         door->type = Kind? genOpen : genRaise;
996         door->speed = VDOORSPEED;
997         break;
998       case SpeedNormal:
999         door->type = Kind? genOpen : genRaise;
1000         door->speed = VDOORSPEED*2;
1001         break;
1002       case SpeedFast:
1003         door->type = Kind? genBlazeOpen : genBlazeRaise;
1004         door->speed = VDOORSPEED*4;
1005         break;
1006       case SpeedTurbo:
1007         door->type = Kind? genBlazeOpen : genBlazeRaise;
1008         door->speed = VDOORSPEED*8;
1009 
1010         break;
1011     }
1012 
1013     // killough 4/15/98: fix generalized door opening sounds
1014     // (previously they always had the blazing door close sound)
1015 
1016     S_StartSound((mobj_t *)&door->sector->soundorg,   // killough 4/15/98
1017                  door->speed >= VDOORSPEED*4 ? sfx_bdopn : sfx_doropn);
1018 
1019     if (manual)
1020       return rtn;
1021   }
1022   return rtn;
1023 }
1024 
1025 //
1026 // EV_DoGenDoor()
1027 //
1028 // Handle generalized door types
1029 //
1030 // Passed the linedef activating the generalized door
1031 // Returns true if a thinker created
1032 //
EV_DoGenDoor(line_t * line)1033 int EV_DoGenDoor
1034 ( line_t* line )
1035 {
1036   int   secnum,rtn;
1037   sector_t* sec;
1038   dboolean   manual;
1039   vldoor_t* door;
1040   unsigned  value = (unsigned)line->special - GenDoorBase;
1041 
1042   // parse the bit fields in the line's special type
1043 
1044   int Dely = (value & DoorDelay) >> DoorDelayShift;
1045   int Kind = (value & DoorKind) >> DoorKindShift;
1046   int Sped = (value & DoorSpeed) >> DoorSpeedShift;
1047   int Trig = (value & TriggerType) >> TriggerTypeShift;
1048 
1049   rtn = 0;
1050 
1051   if (ProcessNoTagLines(line, &sec, &secnum)) {if (zerotag_manual) {manual = true; goto manual_door;} else {return rtn;}};//e6y
1052   // check if a manual trigger, if so do just the sector on the backside
1053   manual = false;
1054   if (Trig==PushOnce || Trig==PushMany)
1055   {
1056     if (!(sec = line->backsector))
1057       return rtn;
1058     secnum = sec->iSectorID;
1059     manual = true;
1060     goto manual_door;
1061   }
1062 
1063 
1064   secnum = -1;
1065   rtn = 0;
1066 
1067   // if not manual do all sectors tagged the same as the line
1068   while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
1069   {
1070     sec = &sectors[secnum];
1071 manual_door:
1072     // Do not start another function if ceiling already moving
1073     if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
1074     {
1075       if (!manual)
1076         continue;
1077       else
1078         return rtn;
1079     }
1080 
1081     // new door thinker
1082     rtn = 1;
1083     door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
1084     memset(door, 0, sizeof(*door));
1085     P_AddThinker (&door->thinker);
1086     sec->ceilingdata = door; //jff 2/22/98
1087 
1088     door->thinker.function = T_VerticalDoor;
1089     door->sector = sec;
1090     // setup delay for door remaining open/closed
1091     switch(Dely)
1092     {
1093       default:
1094       case 0:
1095         door->topwait = 35;
1096         break;
1097       case 1:
1098         door->topwait = VDOORWAIT;
1099         break;
1100       case 2:
1101         door->topwait = 2*VDOORWAIT;
1102         break;
1103       case 3:
1104         door->topwait = 7*VDOORWAIT;
1105         break;
1106     }
1107 
1108     // setup speed of door motion
1109     switch(Sped)
1110     {
1111       default:
1112       case SpeedSlow:
1113         door->speed = VDOORSPEED;
1114         break;
1115       case SpeedNormal:
1116         door->speed = VDOORSPEED*2;
1117         break;
1118       case SpeedFast:
1119         door->speed = VDOORSPEED*4;
1120         break;
1121       case SpeedTurbo:
1122         door->speed = VDOORSPEED*8;
1123         break;
1124     }
1125     door->line = line; // jff 1/31/98 remember line that triggered us
1126 
1127     /* killough 10/98: implement gradual lighting */
1128     door->lighttag = !comp[comp_doorlight] &&
1129       (line->special&6) == 6 &&
1130       line->special > GenLockedBase ? line->tag : 0;
1131 
1132     // set kind of door, whether it opens then close, opens, closes etc.
1133     // assign target heights accordingly
1134     switch(Kind)
1135     {
1136       case OdCDoor:
1137         door->direction = 1;
1138         door->topheight = P_FindLowestCeilingSurrounding(sec);
1139         door->topheight -= 4*FRACUNIT;
1140         if (door->topheight != sec->ceilingheight)
1141           S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn);
1142         door->type = Sped>=SpeedFast? genBlazeRaise : genRaise;
1143         break;
1144       case ODoor:
1145         door->direction = 1;
1146         door->topheight = P_FindLowestCeilingSurrounding(sec);
1147         door->topheight -= 4*FRACUNIT;
1148         if (door->topheight != sec->ceilingheight)
1149           S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn);
1150         door->type = Sped>=SpeedFast? genBlazeOpen : genOpen;
1151         break;
1152       case CdODoor:
1153         door->topheight = sec->ceilingheight;
1154         door->direction = -1;
1155         S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls);
1156         door->type = Sped>=SpeedFast? genBlazeCdO : genCdO;
1157         break;
1158       case CDoor:
1159         door->topheight = P_FindLowestCeilingSurrounding(sec);
1160         door->topheight -= 4*FRACUNIT;
1161         door->direction = -1;
1162         S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls);
1163         door->type = Sped>=SpeedFast? genBlazeClose : genClose;
1164         break;
1165       default:
1166         break;
1167     }
1168     if (manual)
1169       return rtn;
1170   }
1171   return rtn;
1172 }
1173