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