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