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