2 //**************************************************************************
4 //** p_floor.c : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
17 extern fixed_t FloatBobOffsets[64];
19 //==================================================================
20 //==================================================================
24 //==================================================================
25 //==================================================================
27 //==================================================================
29 // Move a plane (floor or ceiling) and check for crushing
31 //==================================================================
32 result_e T_MovePlane(sector_t *sector,fixed_t speed,
33 fixed_t dest, int crush,int floorOrCeiling,int direction)
38 switch(floorOrCeiling)
44 if (sector->floorheight - speed < dest)
46 lastpos = sector->floorheight;
47 sector->floorheight = dest;
48 flag = P_ChangeSector(sector,crush);
51 sector->floorheight =lastpos;
52 P_ChangeSector(sector,crush);
59 lastpos = sector->floorheight;
60 sector->floorheight -= speed;
61 flag = P_ChangeSector(sector,crush);
64 sector->floorheight = lastpos;
65 P_ChangeSector(sector,crush);
72 if (sector->floorheight + speed > dest)
74 lastpos = sector->floorheight;
75 sector->floorheight = dest;
76 flag = P_ChangeSector(sector,crush);
79 sector->floorheight = lastpos;
80 P_ChangeSector(sector,crush);
85 else // COULD GET CRUSHED
87 lastpos = sector->floorheight;
88 sector->floorheight += speed;
89 flag = P_ChangeSector(sector,crush);
94 // return RES_CRUSHED;
96 sector->floorheight = lastpos;
97 P_ChangeSector(sector,crush);
109 if (sector->ceilingheight - speed < dest)
111 lastpos = sector->ceilingheight;
112 sector->ceilingheight = dest;
113 flag = P_ChangeSector(sector,crush);
116 sector->ceilingheight = lastpos;
117 P_ChangeSector(sector,crush);
118 //return RES_CRUSHED;
122 else // COULD GET CRUSHED
124 lastpos = sector->ceilingheight;
125 sector->ceilingheight -= speed;
126 flag = P_ChangeSector(sector,crush);
131 // return RES_CRUSHED;
133 sector->ceilingheight = lastpos;
134 P_ChangeSector(sector,crush);
141 if (sector->ceilingheight + speed > dest)
143 lastpos = sector->ceilingheight;
144 sector->ceilingheight = dest;
145 flag = P_ChangeSector(sector,crush);
148 sector->ceilingheight = lastpos;
149 P_ChangeSector(sector,crush);
150 //return RES_CRUSHED;
156 lastpos = sector->ceilingheight;
157 sector->ceilingheight += speed;
158 flag = P_ChangeSector(sector,crush);
162 sector->ceilingheight = lastpos;
163 P_ChangeSector(sector,crush);
176 //==================================================================
178 // MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
180 //==================================================================
181 void T_MoveFloor(floormove_t *floor)
185 if(floor->resetDelayCount)
187 floor->resetDelayCount--;
188 if(!floor->resetDelayCount)
190 floor->floordestheight = floor->resetHeight;
191 floor->direction = -floor->direction;
192 floor->resetDelay = 0;
193 floor->delayCount = 0;
194 floor->delayTotal = 0;
197 if(floor->delayCount)
200 if(!floor->delayCount && floor->textureChange)
202 floor->sector->floorpic += floor->textureChange;
207 res = T_MovePlane(floor->sector,floor->speed,
208 floor->floordestheight,floor->crush,0,floor->direction);
210 if(floor->type == FLEV_RAISEBUILDSTEP)
212 if((floor->direction == 1 && floor->sector->floorheight >=
213 floor->stairsDelayHeight) || (floor->direction == -1 &&
214 floor->sector->floorheight <= floor->stairsDelayHeight))
216 floor->delayCount = floor->delayTotal;
217 floor->stairsDelayHeight += floor->stairsDelayHeightDelta;
220 if (res == RES_PASTDEST)
222 SN_StopSequence((mobj_t *)&floor->sector->soundorg);
223 if(floor->delayTotal)
225 floor->delayTotal = 0;
227 if(floor->resetDelay)
229 // floor->resetDelayCount = floor->resetDelay;
230 // floor->resetDelay = 0;
233 floor->sector->specialdata = NULL;
235 if (floor->direction == 1)
239 floor->sector->special = floor->newspecial;
240 floor->sector->floorpic = floor->texture;
244 else if (floor->direction == -1)
248 floor->sector->special = floor->newspecial;
249 floor->sector->floorpic = floor->texture;
254 if(floor->textureChange)
256 floor->sector->floorpic -= floor->textureChange;
258 P_TagFinished(floor->sector->tag);
259 P_RemoveThinker(&floor->thinker);
263 //==================================================================
265 // HANDLE FLOOR TYPES
267 //==================================================================
268 int EV_DoFloor(line_t *line, byte *args, floor_e floortype)
273 floormove_t *floor=NULL;
277 while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
279 sec = §ors[secnum];
281 // ALREADY MOVING? IF SO, KEEP GOING...
282 if (sec->specialdata)
289 floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
290 memset(floor, 0, sizeof(*floor));
291 P_AddThinker (&floor->thinker);
292 sec->specialdata = floor;
293 floor->thinker.function = T_MoveFloor;
294 floor->type = floortype;
296 floor->speed = args[1]*(FRACUNIT/8);
297 if(floortype == FLEV_LOWERTIMES8INSTANT ||
298 floortype == FLEV_RAISETIMES8INSTANT)
300 floor->speed = 2000<<FRACBITS;
304 case FLEV_LOWERFLOOR:
305 floor->direction = -1;
307 floor->floordestheight =
308 P_FindHighestFloorSurrounding(sec);
310 case FLEV_LOWERFLOORTOLOWEST:
311 floor->direction = -1;
313 floor->floordestheight =
314 P_FindLowestFloorSurrounding(sec);
316 case FLEV_LOWERFLOORBYVALUE:
317 floor->direction = -1;
319 floor->floordestheight = floor->sector->floorheight-
322 case FLEV_LOWERTIMES8INSTANT:
323 case FLEV_LOWERBYVALUETIMES8:
324 floor->direction = -1;
326 floor->floordestheight = floor->sector->floorheight-
329 case FLEV_RAISEFLOORCRUSH:
330 floor->crush = args[2]; // arg[2] = crushing value
331 floor->direction = 1;
333 floor->floordestheight = sec->ceilingheight-8*FRACUNIT;
335 case FLEV_RAISEFLOOR:
336 floor->direction = 1;
338 floor->floordestheight =
339 P_FindLowestCeilingSurrounding(sec);
340 if (floor->floordestheight > sec->ceilingheight)
341 floor->floordestheight = sec->ceilingheight;
343 case FLEV_RAISEFLOORTONEAREST:
344 floor->direction = 1;
346 floor->floordestheight =
347 P_FindNextHighestFloor(sec,sec->floorheight);
349 case FLEV_RAISEFLOORBYVALUE:
350 floor->direction = 1;
352 floor->floordestheight = floor->sector->floorheight+
355 case FLEV_RAISETIMES8INSTANT:
356 case FLEV_RAISEBYVALUETIMES8:
357 floor->direction = 1;
359 floor->floordestheight = floor->sector->floorheight+
362 case FLEV_MOVETOVALUETIMES8:
364 floor->floordestheight = args[2]*FRACUNIT*8;
367 floor->floordestheight = -floor->floordestheight;
369 if(floor->floordestheight > floor->sector->floorheight)
371 floor->direction = 1;
373 else if(floor->floordestheight < floor->sector->floorheight)
375 floor->direction = -1;
378 { // already at lowest position
389 SN_StartSequence((mobj_t *)&floor->sector->soundorg,
390 SEQ_PLATFORM+floor->sector->seqType);
395 //============================================================================
397 // EV_DoFloorAndCeiling
399 //============================================================================
401 int EV_DoFloorAndCeiling(line_t *line, byte *args, boolean raise)
403 boolean floor, ceiling;
409 floor = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
411 while((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
413 sec = §ors[secnum];
414 sec->specialdata = NULL;
416 ceiling = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
420 floor = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
422 while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
424 sec = §ors[secnum];
425 sec->specialdata = NULL;
427 ceiling = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
429 return (floor|ceiling);
432 // ===== Build Stairs Private Data =====
434 #define STAIR_SECTOR_TYPE 26
435 #define STAIR_QUEUE_SIZE 32
442 } StairQueue[STAIR_QUEUE_SIZE];
444 static int QueueHead;
445 static int QueueTail;
447 static int StepDelta;
448 static int Direction;
451 static int StartDelay;
452 static int StartDelayDelta;
453 static int TextureChange;
454 static int StartHeight;
456 //==========================================================================
460 //==========================================================================
462 static void QueueStairSector(sector_t *sec, int type, int height)
464 if((QueueTail+1)%STAIR_QUEUE_SIZE == QueueHead)
466 I_Error("BuildStairs: Too many branches located.\n");
468 StairQueue[QueueTail].sector = sec;
469 StairQueue[QueueTail].type = type;
470 StairQueue[QueueTail].height = height;
472 QueueTail = (QueueTail+1)%STAIR_QUEUE_SIZE;
475 //==========================================================================
477 // DequeueStairSector
479 //==========================================================================
481 static sector_t *DequeueStairSector(int *type, int *height)
485 if(QueueHead == QueueTail)
489 *type = StairQueue[QueueHead].type;
490 *height = StairQueue[QueueHead].height;
491 sec = StairQueue[QueueHead].sector;
492 QueueHead = (QueueHead+1)%STAIR_QUEUE_SIZE;
497 //==========================================================================
499 // ProcessStairSector
501 //==========================================================================
503 static void ProcessStairSector(sector_t *sec, int type, int height,
504 stairs_e stairsType, int delay, int resetDelay)
514 floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
515 memset(floor, 0, sizeof(*floor));
516 P_AddThinker(&floor->thinker);
517 sec->specialdata = floor;
518 floor->thinker.function = T_MoveFloor;
519 floor->type = FLEV_RAISEBUILDSTEP;
520 floor->direction = Direction;
522 floor->floordestheight = height;
526 floor->speed = Speed;
529 floor->delayTotal = delay;
530 floor->stairsDelayHeight = sec->floorheight+StepDelta;
531 floor->stairsDelayHeightDelta = StepDelta;
533 floor->resetDelay = resetDelay;
534 floor->resetDelayCount = resetDelay;
535 floor->resetHeight = sec->floorheight;
538 floor->speed = FixedMul(Speed, FixedDiv(height-StartHeight,
540 floor->resetDelay = delay; //arg4
541 floor->resetDelayCount = delay;
542 floor->resetHeight = sec->floorheight;
546 floor->floordestheight = sec->floorheight+StepDelta;
547 floor->speed = Speed;
548 floor->delayCount = StartDelay;
549 StartDelay += StartDelayDelta;
550 floor->textureChange = TextureChange;
551 floor->resetDelayCount = StartDelay;
557 SN_StartSequence((mobj_t *)&sec->soundorg, SEQ_PLATFORM+sec->seqType);
559 // Find next sector to raise
560 // Find nearby sector with sector special equal to type
562 for (i = 0; i < sec->linecount; i++)
564 if(!((sec->lines[i])->flags&ML_TWOSIDED))
568 tsec = (sec->lines[i])->frontsector;
569 if(tsec->special == type+STAIR_SECTOR_TYPE && !tsec->specialdata
570 && tsec->floorpic == Texture && tsec->validcount != validcount)
572 QueueStairSector(tsec, type^1, height);
573 tsec->validcount = validcount;
576 tsec = (sec->lines[i])->backsector;
577 if(tsec->special == type+STAIR_SECTOR_TYPE && !tsec->specialdata
578 && tsec->floorpic == Texture && tsec->validcount != validcount)
580 QueueStairSector(tsec, type^1, height);
581 tsec->validcount = validcount;
587 //==================================================================
589 // BUILD A STAIRCASE!
591 // Direction is either positive or negative, denoting build stairs
593 //==================================================================
595 int EV_BuildStairs(line_t *line, byte *args, int direction,
606 // Set global stairs variables
608 Direction = direction;
609 StepDelta = Direction*(args[2]*FRACUNIT);
610 Speed = args[1]*(FRACUNIT/8);
611 resetDelay = args[4];
613 if(stairsType == STAIRS_PHASED)
615 StartDelayDelta = args[3];
616 StartDelay = StartDelayDelta;
617 resetDelay = StartDelayDelta;
619 TextureChange = args[4];
625 while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
627 sec = §ors[secnum];
629 Texture = sec->floorpic;
630 StartHeight = sec->floorheight;
632 // ALREADY MOVING? IF SO, KEEP GOING...
633 if (sec->specialdata)
636 QueueStairSector(sec, 0, sec->floorheight);
639 while((qSec = DequeueStairSector(&type, &height)) != NULL)
641 ProcessStairSector(qSec, type, height, stairsType, delay, resetDelay);
646 //=========================================================================
650 //=========================================================================
652 void T_BuildPillar(pillar_t *pillar)
657 // First, raise the floor
658 res1 = T_MovePlane(pillar->sector, pillar->floorSpeed, pillar->floordest,
659 pillar->crush, 0, pillar->direction); // floorOrCeiling, direction
660 // Then, lower the ceiling
661 res2 = T_MovePlane(pillar->sector, pillar->ceilingSpeed,
662 pillar->ceilingdest, pillar->crush, 1, -pillar->direction);
663 if (res1 == RES_PASTDEST && res2 == RES_PASTDEST)
665 pillar->sector->specialdata = NULL;
666 SN_StopSequence((mobj_t *)&pillar->sector->soundorg);
667 P_TagFinished(pillar->sector->tag);
668 P_RemoveThinker(&pillar->thinker);
672 //=========================================================================
676 //=========================================================================
678 int EV_BuildPillar(line_t *line, byte *args, boolean crush)
688 while((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
690 sec = §ors[secnum];
692 continue; // already moving
693 if(sec->floorheight == sec->ceilingheight)
694 { // pillar is already closed
700 newHeight = sec->floorheight+
701 ((sec->ceilingheight-sec->floorheight)/2);
705 newHeight = sec->floorheight+(args[2]<<FRACBITS);
708 pillar = Z_Malloc(sizeof(*pillar), PU_LEVSPEC, 0);
709 sec->specialdata = pillar;
710 P_AddThinker(&pillar->thinker);
711 pillar->thinker.function = T_BuildPillar;
712 pillar->sector = sec;
715 pillar->ceilingSpeed = pillar->floorSpeed = args[1]*(FRACUNIT/8);
717 else if(newHeight-sec->floorheight > sec->ceilingheight-newHeight)
719 pillar->floorSpeed = args[1]*(FRACUNIT/8);
720 pillar->ceilingSpeed = FixedMul(sec->ceilingheight-newHeight,
721 FixedDiv(pillar->floorSpeed, newHeight-sec->floorheight));
725 pillar->ceilingSpeed = args[1]*(FRACUNIT/8);
726 pillar->floorSpeed = FixedMul(newHeight-sec->floorheight,
727 FixedDiv(pillar->ceilingSpeed, sec->ceilingheight-newHeight));
729 pillar->floordest = newHeight;
730 pillar->ceilingdest = newHeight;
731 pillar->direction = 1;
732 pillar->crush = crush*args[3];
733 SN_StartSequence((mobj_t *)&pillar->sector->soundorg,
734 SEQ_PLATFORM+pillar->sector->seqType);
739 //=========================================================================
743 //=========================================================================
745 int EV_OpenPillar(line_t *line, byte *args)
754 while((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
756 sec = §ors[secnum];
758 continue; // already moving
759 if(sec->floorheight != sec->ceilingheight)
760 { // pillar isn't closed
764 pillar = Z_Malloc(sizeof(*pillar), PU_LEVSPEC, 0);
765 sec->specialdata = pillar;
766 P_AddThinker(&pillar->thinker);
767 pillar->thinker.function = T_BuildPillar;
768 pillar->sector = sec;
771 pillar->floordest = P_FindLowestFloorSurrounding(sec);
775 pillar->floordest = sec->floorheight-(args[2]<<FRACBITS);
779 pillar->ceilingdest = P_FindHighestCeilingSurrounding(sec);
783 pillar->ceilingdest = sec->ceilingheight+(args[3]<<FRACBITS);
785 if(sec->floorheight-pillar->floordest >= pillar->ceilingdest-
788 pillar->floorSpeed = args[1]*(FRACUNIT/8);
789 pillar->ceilingSpeed = FixedMul(sec->ceilingheight-
790 pillar->ceilingdest, FixedDiv(pillar->floorSpeed,
791 pillar->floordest-sec->floorheight));
795 pillar->ceilingSpeed = args[1]*(FRACUNIT/8);
796 pillar->floorSpeed = FixedMul(pillar->floordest-sec->floorheight,
797 FixedDiv(pillar->ceilingSpeed, sec->ceilingheight-
798 pillar->ceilingdest));
800 pillar->direction = -1; // open the pillar
801 SN_StartSequence((mobj_t *)&pillar->sector->soundorg,
802 SEQ_PLATFORM+pillar->sector->seqType);
807 //=========================================================================
811 //=========================================================================
813 int EV_FloorCrushStop(line_t *line, byte *args)
820 for(think = thinkercap.next; think != &thinkercap; think = think->next)
822 if(think->function != T_MoveFloor)
826 floor = (floormove_t *)think;
827 if(floor->type != FLEV_RAISEFLOORCRUSH)
831 // Completely remove the crushing floor
832 SN_StopSequence((mobj_t *)&floor->sector->soundorg);
833 floor->sector->specialdata = NULL;
834 P_TagFinished(floor->sector->tag);
835 P_RemoveThinker(&floor->thinker);
841 //==========================================================================
845 //==========================================================================
847 #define WGLSTATE_EXPAND 1
848 #define WGLSTATE_STABLE 2
849 #define WGLSTATE_REDUCE 3
851 void T_FloorWaggle(floorWaggle_t *waggle)
853 switch(waggle->state)
855 case WGLSTATE_EXPAND:
856 if((waggle->scale += waggle->scaleDelta)
857 >= waggle->targetScale)
859 waggle->scale = waggle->targetScale;
860 waggle->state = WGLSTATE_STABLE;
863 case WGLSTATE_REDUCE:
864 if((waggle->scale -= waggle->scaleDelta) <= 0)
866 waggle->sector->floorheight = waggle->originalHeight;
867 P_ChangeSector(waggle->sector, true);
868 waggle->sector->specialdata = NULL;
869 P_TagFinished(waggle->sector->tag);
870 P_RemoveThinker(&waggle->thinker);
874 case WGLSTATE_STABLE:
875 if(waggle->ticker != -1)
877 if(!--waggle->ticker)
879 waggle->state = WGLSTATE_REDUCE;
884 waggle->accumulator += waggle->accDelta;
885 waggle->sector->floorheight = waggle->originalHeight
886 +FixedMul(FloatBobOffsets[(waggle->accumulator>>FRACBITS)&63],
888 P_ChangeSector(waggle->sector, true);
891 //==========================================================================
893 // EV_StartFloorWaggle
895 //==========================================================================
897 boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset,
902 floorWaggle_t *waggle;
907 while((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
909 sector = §ors[sectorIndex];
910 if(sector->specialdata)
911 { // Already busy with another thinker
915 waggle = Z_Malloc(sizeof(*waggle), PU_LEVSPEC, 0);
916 sector->specialdata = waggle;
917 waggle->thinker.function = T_FloorWaggle;
918 waggle->sector = sector;
919 waggle->originalHeight = sector->floorheight;
920 waggle->accumulator = offset*FRACUNIT;
921 waggle->accDelta = speed<<10;
923 waggle->targetScale = height<<10;
924 waggle->scaleDelta = waggle->targetScale
925 /(35+((3*35)*height)/255);
926 waggle->ticker = timer ? timer*35 : -1;
927 waggle->state = WGLSTATE_EXPAND;
928 P_AddThinker(&waggle->thinker);