Update the discussion of themeing in the manual, and put a note in the wps tags appen...
[kugel-rb.git] / apps / plugins / doom / p_floor.c
blobf4dbcd04f5cb5b95fdac6b28046a69c685a78c69
1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
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
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * 02111-1307, USA.
27 * DESCRIPTION:
28 * General plane mover and floor mover action routines
29 * Floor motion, pure changer types, raising stairs. donuts, elevators
31 *-----------------------------------------------------------------------------*/
33 #include "doomstat.h"
34 #include "r_main.h"
35 #include "p_map.h"
36 #include "p_spec.h"
37 #include "p_tick.h"
38 #include "s_sound.h"
39 #include "sounds.h"
41 #include "rockmacros.h"
43 ///////////////////////////////////////////////////////////////////////
45 // Plane (floor or ceiling), Floor motion and Elevator action routines
47 ///////////////////////////////////////////////////////////////////////
50 // T_MovePlane()
52 // Move a plane (floor or ceiling) and check for crushing. Called
53 // every tick by all actions that move floors or ceilings.
55 // Passed the sector to move a plane in, the speed to move it at,
56 // the dest height it is to achieve, whether it crushes obstacles,
57 // whether it moves a floor or ceiling, and the direction up or down
58 // to move.
60 // Returns a result_e:
61 // ok - plane moved normally, has not achieved destination yet
62 // pastdest - plane moved normally and is now at destination height
63 // crushed - plane encountered an obstacle, is holding until removed
65 result_e T_MovePlane
66 ( sector_t* sector,
67 fixed_t speed,
68 fixed_t dest,
69 boolean crush,
70 int floorOrCeiling,
71 int direction )
73 boolean flag;
74 fixed_t lastpos;
75 fixed_t destheight; //jff 02/04/98 used to keep floors/ceilings
76 // from moving thru each other
78 switch(floorOrCeiling)
80 case 0:
81 // Moving a floor
82 switch(direction)
84 case -1:
85 // Moving a floor down
86 if (sector->floorheight - speed < dest)
88 lastpos = sector->floorheight;
89 sector->floorheight = dest;
90 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
91 if (flag == true)
93 sector->floorheight =lastpos;
94 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
96 return pastdest;
98 else
100 lastpos = sector->floorheight;
101 sector->floorheight -= speed;
102 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
103 /* cph - make more compatible with original Doom, by
104 * reintroducing this code. This means floors can't lower
105 * if objects are stuck in the ceiling */
106 if ((flag == true) && comp[comp_floors]) {
107 sector->floorheight = lastpos;
108 P_ChangeSector(sector,crush);
109 return crushed;
112 break;
114 case 1:
115 // Moving a floor up
116 // jff 02/04/98 keep floor from moving thru ceilings
117 // jff 2/22/98 weaken check to demo_compatibility
118 destheight = (comp[comp_floors] || dest<sector->ceilingheight)?
119 dest : sector->ceilingheight;
120 if (sector->floorheight + speed > destheight)
122 lastpos = sector->floorheight;
123 sector->floorheight = destheight;
124 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
125 if (flag == true)
127 sector->floorheight = lastpos;
128 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
130 return pastdest;
132 else
134 // crushing is possible
135 lastpos = sector->floorheight;
136 sector->floorheight += speed;
137 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
138 if (flag == true)
140 /* jff 1/25/98 fix floor crusher */
141 if (comp[comp_floors]) {
142 if (crush == true)
143 return crushed;
145 sector->floorheight = lastpos;
146 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
147 return crushed;
150 break;
152 break;
154 case 1:
155 // moving a ceiling
156 switch(direction)
158 case -1:
159 // moving a ceiling down
160 // jff 02/04/98 keep ceiling from moving thru floors
161 // jff 2/22/98 weaken check to demo_compatibility
162 destheight = (comp[comp_floors] || dest>sector->floorheight)?
163 dest : sector->floorheight;
164 if (sector->ceilingheight - speed < destheight)
166 lastpos = sector->ceilingheight;
167 sector->ceilingheight = destheight;
168 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
170 if (flag == true)
172 sector->ceilingheight = lastpos;
173 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
175 return pastdest;
177 else
179 // crushing is possible
180 lastpos = sector->ceilingheight;
181 sector->ceilingheight -= speed;
182 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
184 if (flag == true)
186 if (crush == true)
187 return crushed;
188 sector->ceilingheight = lastpos;
189 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
190 return crushed;
193 break;
195 case 1:
196 // moving a ceiling up
197 if (sector->ceilingheight + speed > dest)
199 lastpos = sector->ceilingheight;
200 sector->ceilingheight = dest;
201 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
202 if (flag == true)
204 sector->ceilingheight = lastpos;
205 P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
207 return pastdest;
209 else
211 lastpos = sector->ceilingheight;
212 sector->ceilingheight += speed;
213 flag = P_CheckSector(sector,crush); //jff 3/19/98 use faster chk
215 break;
217 break;
219 return ok;
223 // T_MoveFloor()
225 // Move a floor to it's destination (up or down).
226 // Called once per tick for each moving floor.
228 // Passed a floormove_t structure that contains all pertinent info about the
229 // move. See P_SPEC.H for fields.
230 // No return.
232 // jff 02/08/98 all cases with labels beginning with gen added to support
233 // generalized line type behaviors.
234 void T_MoveFloor(floormove_t* floor)
236 result_e res;
238 res = T_MovePlane // move the floor
240 floor->sector,
241 floor->speed,
242 floor->floordestheight,
243 floor->crush,
245 floor->direction
248 if (!(leveltime&7)) // make the floormove sound
249 S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_stnmov);
251 if (res == pastdest) // if destination height is reached
253 if (floor->direction == 1) // going up
255 switch(floor->type) // handle texture/type changes
257 case donutRaise:
258 floor->sector->special = floor->newspecial;
259 floor->sector->floorpic = floor->texture;
260 break;
261 case genFloorChgT:
262 case genFloorChg0:
263 floor->sector->special = floor->newspecial;
264 //jff add to fix bug in special transfers from changes
265 floor->sector->oldspecial = floor->oldspecial;
266 //fall thru
267 case genFloorChg:
268 floor->sector->floorpic = floor->texture;
269 break;
270 default:
271 break;
274 else if (floor->direction == -1) // going down
276 switch(floor->type) // handle texture/type changes
278 case lowerAndChange:
279 floor->sector->special = floor->newspecial;
280 //jff add to fix bug in special transfers from changes
281 floor->sector->oldspecial = floor->oldspecial;
282 floor->sector->floorpic = floor->texture;
283 break;
284 case genFloorChgT:
285 case genFloorChg0:
286 floor->sector->special = floor->newspecial;
287 //jff add to fix bug in special transfers from changes
288 floor->sector->oldspecial = floor->oldspecial;
289 //fall thru
290 case genFloorChg:
291 floor->sector->floorpic = floor->texture;
292 break;
293 default:
294 break;
298 floor->sector->floordata = NULL; //jff 2/22/98
299 P_RemoveThinker(&floor->thinker);//remove this floor from list of movers
301 //jff 2/26/98 implement stair retrigger lockout while still building
302 // note this only applies to the retriggerable generalized stairs
304 if (floor->sector->stairlock==-2) // if this sector is stairlocked
306 sector_t *sec = floor->sector;
307 sec->stairlock=-1; // thinker done, promote lock to -1
309 while (sec->prevsec!=-1 && sectors[sec->prevsec].stairlock!=-2)
310 sec = &sectors[sec->prevsec]; // search for a non-done thinker
311 if (sec->prevsec==-1) // if all thinkers previous are done
313 sec = floor->sector; // search forward
314 while (sec->nextsec!=-1 && sectors[sec->nextsec].stairlock!=-2)
315 sec = &sectors[sec->nextsec];
316 if (sec->nextsec==-1) // if all thinkers ahead are done too
318 while (sec->prevsec!=-1) // clear all locks
320 sec->stairlock = 0;
321 sec = &sectors[sec->prevsec];
323 sec->stairlock = 0;
328 // make floor stop sound
329 S_StartSound((mobj_t *)&floor->sector->soundorg, sfx_pstop);
334 // T_MoveElevator()
336 // Move an elevator to it's destination (up or down)
337 // Called once per tick for each moving floor.
339 // Passed an elevator_t structure that contains all pertinent info about the
340 // move. See P_SPEC.H for fields.
341 // No return.
343 // jff 02/22/98 added to support parallel floor/ceiling motion
345 void T_MoveElevator(elevator_t* elevator)
347 result_e res;
349 if (elevator->direction<0) // moving down
351 res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor
353 elevator->sector,
354 elevator->speed,
355 elevator->ceilingdestheight,
357 1, // move floor
358 elevator->direction
360 if (res==ok || res==pastdest) // jff 4/7/98 don't move ceil if blocked
361 T_MovePlane
363 elevator->sector,
364 elevator->speed,
365 elevator->floordestheight,
367 0, // move ceiling
368 elevator->direction
371 else // up
373 res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor
375 elevator->sector,
376 elevator->speed,
377 elevator->floordestheight,
379 0, // move ceiling
380 elevator->direction
382 if (res==ok || res==pastdest) // jff 4/7/98 don't move floor if blocked
383 T_MovePlane
385 elevator->sector,
386 elevator->speed,
387 elevator->ceilingdestheight,
389 1, // move floor
390 elevator->direction
394 // make floor move sound
395 if (!(leveltime&7))
396 S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_stnmov);
398 if (res == pastdest) // if destination height acheived
400 elevator->sector->floordata = NULL; //jff 2/22/98
401 elevator->sector->ceilingdata = NULL; //jff 2/22/98
402 P_RemoveThinker(&elevator->thinker); // remove elevator from actives
404 // make floor stop sound
405 S_StartSound((mobj_t *)&elevator->sector->soundorg, sfx_pstop);
409 ///////////////////////////////////////////////////////////////////////
411 // Floor motion linedef handlers
413 ///////////////////////////////////////////////////////////////////////
416 // EV_DoFloor()
418 // Handle regular and extended floor types
420 // Passed the line that activated the floor and the type of floor motion
421 // Returns true if a thinker was created.
423 int EV_DoFloor
424 ( line_t* line,
425 floor_e floortype )
427 int secnum;
428 int rtn;
429 int i;
430 sector_t* sec;
431 floormove_t* floor;
433 secnum = -1;
434 rtn = 0;
435 // move all floors with the same tag as the linedef
436 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
438 sec = &sectors[secnum];
440 // Don't start a second thinker on the same floor
441 if (P_SectorActive(floor_special,sec)) //jff 2/23/98
442 continue;
444 // new floor thinker
445 rtn = 1;
446 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
447 P_AddThinker (&floor->thinker);
448 sec->floordata = floor; //jff 2/22/98
449 floor->thinker.function = T_MoveFloor;
450 floor->type = floortype;
451 floor->crush = false;
453 // setup the thinker according to the linedef type
454 switch(floortype)
456 case lowerFloor:
457 floor->direction = -1;
458 floor->sector = sec;
459 floor->speed = FLOORSPEED;
460 floor->floordestheight = P_FindHighestFloorSurrounding(sec);
461 break;
463 //jff 02/03/30 support lowering floor by 24 absolute
464 case lowerFloor24:
465 floor->direction = -1;
466 floor->sector = sec;
467 floor->speed = FLOORSPEED;
468 floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT;
469 break;
471 //jff 02/03/30 support lowering floor by 32 absolute (fast)
472 case lowerFloor32Turbo:
473 floor->direction = -1;
474 floor->sector = sec;
475 floor->speed = FLOORSPEED*4;
476 floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT;
477 break;
479 case lowerFloorToLowest:
480 floor->direction = -1;
481 floor->sector = sec;
482 floor->speed = FLOORSPEED;
483 floor->floordestheight = P_FindLowestFloorSurrounding(sec);
484 break;
486 //jff 02/03/30 support lowering floor to next lowest floor
487 case lowerFloorToNearest:
488 floor->direction = -1;
489 floor->sector = sec;
490 floor->speed = FLOORSPEED;
491 floor->floordestheight =
492 P_FindNextLowestFloor(sec,floor->sector->floorheight);
493 break;
495 case turboLower:
496 floor->direction = -1;
497 floor->sector = sec;
498 floor->speed = FLOORSPEED * 4;
499 floor->floordestheight = P_FindHighestFloorSurrounding(sec);
500 if (floor->floordestheight != sec->floorheight)
501 floor->floordestheight += 8*FRACUNIT;
502 break;
504 case raiseFloorCrush:
505 floor->crush = true;
506 case raiseFloor:
507 floor->direction = 1;
508 floor->sector = sec;
509 floor->speed = FLOORSPEED;
510 floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
511 if (floor->floordestheight > sec->ceilingheight)
512 floor->floordestheight = sec->ceilingheight;
513 floor->floordestheight -= (8*FRACUNIT)*(floortype == raiseFloorCrush);
514 break;
516 case raiseFloorTurbo:
517 floor->direction = 1;
518 floor->sector = sec;
519 floor->speed = FLOORSPEED*4;
520 floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight);
521 break;
523 case raiseFloorToNearest:
524 floor->direction = 1;
525 floor->sector = sec;
526 floor->speed = FLOORSPEED;
527 floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight);
528 break;
530 case raiseFloor24:
531 floor->direction = 1;
532 floor->sector = sec;
533 floor->speed = FLOORSPEED;
534 floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT;
535 break;
537 // jff 2/03/30 support straight raise by 32 (fast)
538 case raiseFloor32Turbo:
539 floor->direction = 1;
540 floor->sector = sec;
541 floor->speed = FLOORSPEED*4;
542 floor->floordestheight = floor->sector->floorheight + 32 * FRACUNIT;
543 break;
545 case raiseFloor512:
546 floor->direction = 1;
547 floor->sector = sec;
548 floor->speed = FLOORSPEED;
549 floor->floordestheight = floor->sector->floorheight + 512 * FRACUNIT;
550 break;
552 case raiseFloor24AndChange:
553 floor->direction = 1;
554 floor->sector = sec;
555 floor->speed = FLOORSPEED;
556 floor->floordestheight = floor->sector->floorheight + 24 * FRACUNIT;
557 sec->floorpic = line->frontsector->floorpic;
558 sec->special = line->frontsector->special;
559 //jff 3/14/98 transfer both old and new special
560 sec->oldspecial = line->frontsector->oldspecial;
561 break;
563 case raiseToTexture:
565 int minsize = INT_MAX;
566 side_t* side;
568 /* jff 3/13/98 no ovf */
569 if (!comp[comp_model]) minsize = 32000<<FRACBITS;
570 floor->direction = 1;
571 floor->sector = sec;
572 floor->speed = FLOORSPEED;
573 for (i = 0; i < sec->linecount; i++)
575 if (twoSided (secnum, i) )
577 side = getSide(secnum,i,0);
578 // jff 8/14/98 don't scan texture 0, its not real
579 if (side->bottomtexture > 0 ||
580 (comp[comp_model] && !side->bottomtexture))
581 if (textureheight[side->bottomtexture] < minsize)
582 minsize = textureheight[side->bottomtexture];
583 side = getSide(secnum,i,1);
584 // jff 8/14/98 don't scan texture 0, its not real
585 if (side->bottomtexture > 0 ||
586 (comp[comp_model] && !side->bottomtexture))
587 if (textureheight[side->bottomtexture] < minsize)
588 minsize = textureheight[side->bottomtexture];
591 if (comp[comp_model])
592 floor->floordestheight = floor->sector->floorheight + minsize;
593 else
595 floor->floordestheight =
596 (floor->sector->floorheight>>FRACBITS) + (minsize>>FRACBITS);
597 if (floor->floordestheight>32000)
598 floor->floordestheight = 32000; //jff 3/13/98 do not
599 floor->floordestheight<<=FRACBITS; // allow height overflow
602 break;
604 case lowerAndChange:
605 floor->direction = -1;
606 floor->sector = sec;
607 floor->speed = FLOORSPEED;
608 floor->floordestheight = P_FindLowestFloorSurrounding(sec);
609 floor->texture = sec->floorpic;
611 // jff 1/24/98 make sure floor->newspecial gets initialized
612 // in case no surrounding sector is at floordestheight
613 // --> should not affect compatibility <--
614 floor->newspecial = sec->special;
615 //jff 3/14/98 transfer both old and new special
616 floor->oldspecial = sec->oldspecial;
618 //jff 5/23/98 use model subroutine to unify fixes and handling
619 sec = P_FindModelFloorSector(floor->floordestheight,sec-sectors);
620 if (sec)
622 floor->texture = sec->floorpic;
623 floor->newspecial = sec->special;
624 //jff 3/14/98 transfer both old and new special
625 floor->oldspecial = sec->oldspecial;
627 break;
628 default:
629 break;
632 return rtn;
636 // EV_DoChange()
638 // Handle pure change types. These change floor texture and sector type
639 // by trigger or numeric model without moving the floor.
641 // The linedef causing the change and the type of change is passed
642 // Returns true if any sector changes
644 // jff 3/15/98 added to better support generalized sector types
646 int EV_DoChange
647 ( line_t* line,
648 change_e changetype )
650 int secnum;
651 int rtn;
652 sector_t* sec;
653 sector_t* secm;
655 secnum = -1;
656 rtn = 0;
657 // change all sectors with the same tag as the linedef
658 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
660 sec = &sectors[secnum];
662 rtn = 1;
664 // handle trigger or numeric change type
665 switch(changetype)
667 case trigChangeOnly:
668 sec->floorpic = line->frontsector->floorpic;
669 sec->special = line->frontsector->special;
670 sec->oldspecial = line->frontsector->oldspecial;
671 break;
672 case numChangeOnly:
673 secm = P_FindModelFloorSector(sec->floorheight,secnum);
674 if (secm) // if no model, no change
676 sec->floorpic = secm->floorpic;
677 sec->special = secm->special;
678 sec->oldspecial = secm->oldspecial;
680 break;
681 default:
682 break;
685 return rtn;
689 * EV_BuildStairs()
691 * Handles staircase building. A sequence of sectors chosen by algorithm
692 * rise at a speed indicated to a height that increases by the stepsize
693 * each step.
695 * Passed the linedef triggering the stairs and the type of stair rise
696 * Returns true if any thinkers are created
698 * cph 2001/09/21 - compatibility nightmares again
699 * There are three different ways this function has, during its history, stepped
700 * through all the stairs to be triggered by the single switch
701 * - original Doom used a linear P_FindSectorFromLineTag, but failed to preserve
702 * the index of the previous sector found, so instead it would restart its
703 * linear search from the last sector of the previous staircase
704 * - MBF/PrBoom with comp_stairs fail to emulate this, because their
705 * P_FindSectorFromLineTag is a chained hash table implementation. Instead they
706 * start following the hash chain from the last sector of the previous
707 * staircase, which will (probably) have the wrong tag, so they miss any further
708 * stairs
709 * - Boom fixed the bug, and MBF/PrBoom without comp_stairs work right
711 static inline int P_FindSectorFromLineTagWithLowerBound
712 (line_t* l, int start, int min)
714 /* Emulate original Doom's linear lower-bounded P_FindSectorFromLineTag
715 * as needed */
716 do {
717 start = P_FindSectorFromLineTag(l,start);
718 } while (start >= 0 && start <= min);
719 return start;
722 int EV_BuildStairs
723 ( line_t* line,
724 stair_e type )
726 /* cph 2001/09/22 - cleaned up this function to save my sanity. A separate
727 * outer loop index makes the logic much cleared, and local variables moved
728 * into the inner blocks helps too */
729 int ssec = -1;
730 int minssec = -1;
731 int rtn = 0;
733 // start a stair at each sector tagged the same as the linedef
734 while ((ssec = P_FindSectorFromLineTagWithLowerBound(line,ssec,minssec)) >= 0)
736 int secnum = ssec;
737 sector_t* sec = &sectors[secnum];
739 // don't start a stair if the first step's floor is already moving
740 if (!P_SectorActive(floor_special,sec)) { //jff 2/22/98
741 floormove_t* floor;
742 int texture, height;
743 fixed_t stairsize;
744 fixed_t speed;
745 int ok;
747 // create new floor thinker for first step
748 rtn = 1;
749 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
750 P_AddThinker (&floor->thinker);
751 sec->floordata = floor;
752 floor->thinker.function = T_MoveFloor;
753 floor->direction = 1;
754 floor->sector = sec;
755 floor->type = buildStair; //jff 3/31/98 do not leave uninited
757 // set up the speed and stepsize according to the stairs type
758 switch(type)
760 default: // killough -- prevent compiler warning
761 case build8:
762 speed = FLOORSPEED/4;
763 stairsize = 8*FRACUNIT;
764 if (!demo_compatibility)
765 floor->crush = false; //jff 2/27/98 fix uninitialized crush field
766 break;
767 case turbo16:
768 speed = FLOORSPEED*4;
769 stairsize = 16*FRACUNIT;
770 if (!demo_compatibility)
771 floor->crush = true; //jff 2/27/98 fix uninitialized crush field
772 break;
774 floor->speed = speed;
775 height = sec->floorheight + stairsize;
776 floor->floordestheight = height;
778 texture = sec->floorpic;
780 // Find next sector to raise
781 // 1. Find 2-sided line with same sector side[0] (lowest numbered)
782 // 2. Other side is the next sector to raise
783 // 3. Unless already moving, or different texture, then stop building
786 int i;
787 ok = 0;
789 for (i = 0;i < sec->linecount;i++)
791 sector_t* tsec = (sec->lines[i])->frontsector;
792 int newsecnum;
793 if ( !((sec->lines[i])->flags & ML_TWOSIDED) )
794 continue;
796 newsecnum = tsec-sectors;
798 if (secnum != newsecnum)
799 continue;
801 tsec = (sec->lines[i])->backsector;
802 if (!tsec) continue; //jff 5/7/98 if no backside, continue
803 newsecnum = tsec - sectors;
805 // if sector's floor is different texture, look for another
806 if (tsec->floorpic != texture)
807 continue;
809 /* jff 6/19/98 prevent double stepsize
810 * killough 10/98: intentionally left this way [MBF comment]
811 * cph 2001/02/06: stair bug fix should be controlled by comp_stairs,
812 * except if we're emulating MBF which perversly reverted the fix
814 if (comp[comp_stairs] || (compatibility_level == mbf_compatibility))
815 height += stairsize; // jff 6/28/98 change demo compatibility
817 // if sector's floor already moving, look for another
818 if (P_SectorActive(floor_special,tsec)) //jff 2/22/98
819 continue;
821 /* cph - see comment above - do this iff we didn't do so above */
822 if (!comp[comp_stairs] && (compatibility_level != mbf_compatibility))
823 height += stairsize;
825 sec = tsec;
826 secnum = newsecnum;
828 // create and initialize a thinker for the next step
829 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
830 P_AddThinker (&floor->thinker);
832 sec->floordata = floor; //jff 2/22/98
833 floor->thinker.function = T_MoveFloor;
834 floor->direction = 1;
835 floor->sector = sec;
836 floor->speed = speed;
837 floor->floordestheight = height;
838 floor->type = buildStair; //jff 3/31/98 do not leave uninited
839 //jff 2/27/98 fix uninitialized crush field
840 if (!demo_compatibility)
841 floor->crush = type==build8? false : true;
842 ok = 1;
843 break;
845 } while(ok); // continue until no next step is found
848 /* killough 10/98: compatibility option */
849 if (comp[comp_stairs]) {
850 /* cph 2001/09/22 - emulate buggy MBF comp_stairs for demos, with logic
851 * reversed since we now have a separate outer loop index.
852 * DEMOSYNC - what about boom_compatibility_compatibility?
854 if ((compatibility_level >= mbf_compatibility) && (compatibility_level <
855 prboom_3_compatibility)) ssec = secnum; /* Trash outer loop index */
856 else {
857 /* cph 2001/09/22 - now the correct comp_stairs - Doom used a linear
858 * search from the last secnum, so we set that as a minimum value and do
859 * a fresh tag search
861 ssec = -1; minssec = secnum;
865 return rtn;
869 // EV_DoDonut()
871 // Handle donut function: lower pillar, raise surrounding pool, both to height,
872 // texture and type of the sector surrounding the pool.
874 // Passed the linedef that triggered the donut
875 // Returns whether a thinker was created
877 int EV_DoDonut(line_t* line)
879 sector_t* s1;
880 sector_t* s2;
881 sector_t* s3;
882 int secnum;
883 int rtn;
884 int i;
885 floormove_t* floor;
887 secnum = -1;
888 rtn = 0;
889 // do function on all sectors with same tag as linedef
890 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
892 s1 = &sectors[secnum]; // s1 is pillar's sector
894 // do not start the donut if the pillar is already moving
895 if (P_SectorActive(floor_special,s1)) //jff 2/22/98
896 continue;
898 s2 = getNextSector(s1->lines[0],s1); // s2 is pool's sector
899 if (!s2) continue; // note lowest numbered line around
900 // pillar must be two-sided
902 /* do not start the donut if the pool is already moving
903 * cph - DEMOSYNC - was !compatibility */
904 if (!comp[comp_floors] && P_SectorActive(floor_special,s2))
905 continue; //jff 5/7/98
907 // find a two sided line around the pool whose other side isn't the pillar
908 for (i = 0;i < s2->linecount;i++)
910 //jff 3/29/98 use true two-sidedness, not the flag
911 // killough 4/5/98: changed demo_compatibility to compatibility
912 if (comp[comp_model])
914 if (!(s2->lines[i]->flags & ML_TWOSIDED) ||
915 (s2->lines[i]->backsector == s1))
916 continue;
918 else if (!s2->lines[i]->backsector || s2->lines[i]->backsector == s1)
919 continue;
921 rtn = 1; //jff 1/26/98 no donut action - no switch change on return
923 s3 = s2->lines[i]->backsector; // s3 is model sector for changes
925 // Spawn rising slime
926 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
927 P_AddThinker (&floor->thinker);
928 s2->floordata = floor; //jff 2/22/98
929 floor->thinker.function = T_MoveFloor;
930 floor->type = donutRaise;
931 floor->crush = false;
932 floor->direction = 1;
933 floor->sector = s2;
934 floor->speed = FLOORSPEED / 2;
935 floor->texture = s3->floorpic;
936 floor->newspecial = 0;
937 floor->floordestheight = s3->floorheight;
939 // Spawn lowering donut-hole pillar
940 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
941 P_AddThinker (&floor->thinker);
942 s1->floordata = floor; //jff 2/22/98
943 floor->thinker.function = T_MoveFloor;
944 floor->type = lowerFloor;
945 floor->crush = false;
946 floor->direction = -1;
947 floor->sector = s1;
948 floor->speed = FLOORSPEED / 2;
949 floor->floordestheight = s3->floorheight;
950 break;
953 return rtn;
957 // EV_DoElevator
959 // Handle elevator linedef types
961 // Passed the linedef that triggered the elevator and the elevator action
963 // jff 2/22/98 new type to move floor and ceiling in parallel
965 int EV_DoElevator
966 ( line_t* line,
967 elevator_e elevtype )
969 int secnum;
970 int rtn;
971 sector_t* sec;
972 elevator_t* elevator;
974 secnum = -1;
975 rtn = 0;
976 // act on all sectors with the same tag as the triggering linedef
977 while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
979 sec = &sectors[secnum];
981 // If either floor or ceiling is already activated, skip it
982 if (sec->floordata || sec->ceilingdata) //jff 2/22/98
983 continue;
985 // create and initialize new elevator thinker
986 rtn = 1;
987 elevator = Z_Malloc (sizeof(*elevator), PU_LEVSPEC, 0);
988 P_AddThinker (&elevator->thinker);
989 sec->floordata = elevator; //jff 2/22/98
990 sec->ceilingdata = elevator; //jff 2/22/98
991 elevator->thinker.function = T_MoveElevator;
992 elevator->type = elevtype;
994 // set up the fields according to the type of elevator action
995 switch(elevtype)
997 // elevator down to next floor
998 case elevateDown:
999 elevator->direction = -1;
1000 elevator->sector = sec;
1001 elevator->speed = ELEVATORSPEED;
1002 elevator->floordestheight =
1003 P_FindNextLowestFloor(sec,sec->floorheight);
1004 elevator->ceilingdestheight =
1005 elevator->floordestheight + sec->ceilingheight - sec->floorheight;
1006 break;
1008 // elevator up to next floor
1009 case elevateUp:
1010 elevator->direction = 1;
1011 elevator->sector = sec;
1012 elevator->speed = ELEVATORSPEED;
1013 elevator->floordestheight =
1014 P_FindNextHighestFloor(sec,sec->floorheight);
1015 elevator->ceilingdestheight =
1016 elevator->floordestheight + sec->ceilingheight - sec->floorheight;
1017 break;
1019 // elevator to floor height of activating switch's front sector
1020 case elevateCurrent:
1021 elevator->sector = sec;
1022 elevator->speed = ELEVATORSPEED;
1023 elevator->floordestheight = line->frontsector->floorheight;
1024 elevator->ceilingdestheight =
1025 elevator->floordestheight + sec->ceilingheight - sec->floorheight;
1026 elevator->direction =
1027 elevator->floordestheight>sec->floorheight? 1 : -1;
1028 break;
1030 default:
1031 break;
1034 return rtn;