]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/p_floor.c
osezer patch 006
[theoddone33/hhexen.git] / base / p_floor.c
1
2 //**************************************************************************
3 //**
4 //** p_floor.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 #include "h2def.h"
14 #include "p_local.h"
15 #include "soundst.h"
16
17 extern fixed_t FloatBobOffsets[64];
18
19 //==================================================================
20 //==================================================================
21 //
22 //                                                              FLOORS
23 //
24 //==================================================================
25 //==================================================================
26
27 //==================================================================
28 //
29 //      Move a plane (floor or ceiling) and check for crushing
30 //
31 //==================================================================
32 result_e        T_MovePlane(sector_t *sector,fixed_t speed,
33                         fixed_t dest, int crush,int floorOrCeiling,int direction)
34 {
35         boolean flag;
36         fixed_t lastpos;
37
38         switch(floorOrCeiling)
39         {
40                 case 0:         // FLOOR
41                         switch(direction)
42                         {
43                                 case -1:        // DOWN
44                                         if (sector->floorheight - speed < dest)
45                                         {
46                                                 lastpos = sector->floorheight;
47                                                 sector->floorheight = dest;
48                                                 flag = P_ChangeSector(sector,crush);
49                                                 if (flag == true)
50                                                 {
51                                                         sector->floorheight =lastpos;
52                                                         P_ChangeSector(sector,crush);
53                                                         //return RES_CRUSHED;
54                                                 }
55                                                 return RES_PASTDEST;
56                                         }
57                                         else
58                                         {
59                                                 lastpos = sector->floorheight;
60                                                 sector->floorheight -= speed;
61                                                 flag = P_ChangeSector(sector,crush);
62                                                 if (flag == true)
63                                                 {
64                                                         sector->floorheight = lastpos;
65                                                         P_ChangeSector(sector,crush);
66                                                         return RES_CRUSHED;
67                                                 }
68                                         }
69                                         break;
70
71                                 case 1:         // UP
72                                         if (sector->floorheight + speed > dest)
73                                         {
74                                                 lastpos = sector->floorheight;
75                                                 sector->floorheight = dest;
76                                                 flag = P_ChangeSector(sector,crush);
77                                                 if (flag == true)
78                                                 {
79                                                         sector->floorheight = lastpos;
80                                                         P_ChangeSector(sector,crush);
81                                                         //return RES_CRUSHED;
82                                                 }
83                                                 return RES_PASTDEST;
84                                         }
85                                         else    // COULD GET CRUSHED
86                                         {
87                                                 lastpos = sector->floorheight;
88                                                 sector->floorheight += speed;
89                                                 flag = P_ChangeSector(sector,crush);
90                                                 if (flag == true)
91                                                 {
92                                                         //if (crush == true)
93                                                         //{
94                                                         //      return RES_CRUSHED;
95                                                         //}
96                                                         sector->floorheight = lastpos;
97                                                         P_ChangeSector(sector,crush);
98                                                         return RES_CRUSHED;
99                                                 }
100                                         }
101                                         break;
102                         }
103                         break;
104
105                 case 1:         // CEILING
106                         switch(direction)
107                         {
108                                 case -1:        // DOWN
109                                         if (sector->ceilingheight - speed < dest)
110                                         {
111                                                 lastpos = sector->ceilingheight;
112                                                 sector->ceilingheight = dest;
113                                                 flag = P_ChangeSector(sector,crush);
114                                                 if (flag == true)
115                                                 {
116                                                         sector->ceilingheight = lastpos;
117                                                         P_ChangeSector(sector,crush);
118                                                         //return RES_CRUSHED;
119                                                 }
120                                                 return RES_PASTDEST;
121                                         }
122                                         else    // COULD GET CRUSHED
123                                         {
124                                                 lastpos = sector->ceilingheight;
125                                                 sector->ceilingheight -= speed;
126                                                 flag = P_ChangeSector(sector,crush);
127                                                 if (flag == true)
128                                                 {
129                                                         //if (crush == true)
130                                                         //{
131                                                         //      return RES_CRUSHED;
132                                                         //}
133                                                         sector->ceilingheight = lastpos;
134                                                         P_ChangeSector(sector,crush);
135                                                         return RES_CRUSHED;
136                                                 }
137                                         }
138                                         break;
139
140                                 case 1:         // UP
141                                         if (sector->ceilingheight + speed > dest)
142                                         {
143                                                 lastpos = sector->ceilingheight;
144                                                 sector->ceilingheight = dest;
145                                                 flag = P_ChangeSector(sector,crush);
146                                                 if (flag == true)
147                                                 {
148                                                         sector->ceilingheight = lastpos;
149                                                         P_ChangeSector(sector,crush);
150                                                         //return RES_CRUSHED;
151                                                 }
152                                                 return RES_PASTDEST;
153                                         }
154                                         else
155                                         {
156                                                 lastpos = sector->ceilingheight;
157                                                 sector->ceilingheight += speed;
158                                                 flag = P_ChangeSector(sector,crush);
159                                                 #if 0
160                                                 if (flag == true)
161                                                 {
162                                                         sector->ceilingheight = lastpos;
163                                                         P_ChangeSector(sector,crush);
164                                                         return RES_CRUSHED;
165                                                 }
166                                                 #endif
167                                         }
168                                         break;
169                         }
170                         break;
171
172         }
173         return RES_OK;
174 }
175
176 //==================================================================
177 //
178 //      MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
179 //
180 //==================================================================
181 void T_MoveFloor(floormove_t *floor)
182 {
183         result_e        res;
184
185         if(floor->resetDelayCount)
186         {
187                 floor->resetDelayCount--;
188                 if(!floor->resetDelayCount)
189                 {
190                         floor->floordestheight = floor->resetHeight;
191                         floor->direction = -floor->direction;
192                         floor->resetDelay = 0;
193                         floor->delayCount = 0;
194                         floor->delayTotal = 0;
195                 }
196         }                                       
197         if(floor->delayCount)
198         {
199                 floor->delayCount--;
200                 if(!floor->delayCount && floor->textureChange)
201                 {
202                         floor->sector->floorpic += floor->textureChange;
203                 }
204                 return;
205         }
206
207         res = T_MovePlane(floor->sector,floor->speed,
208                         floor->floordestheight,floor->crush,0,floor->direction);
209
210         if(floor->type == FLEV_RAISEBUILDSTEP)
211         {
212                 if((floor->direction == 1 && floor->sector->floorheight >=
213                         floor->stairsDelayHeight) || (floor->direction == -1 &&
214                         floor->sector->floorheight <= floor->stairsDelayHeight))
215                 {
216                         floor->delayCount = floor->delayTotal;
217                         floor->stairsDelayHeight += floor->stairsDelayHeightDelta;
218                 }               
219         }
220         if (res == RES_PASTDEST)
221         {
222                 SN_StopSequence((mobj_t *)&floor->sector->soundorg);
223                 if(floor->delayTotal)
224                 {
225                         floor->delayTotal = 0;
226                 }
227                 if(floor->resetDelay)
228                 {
229 //                      floor->resetDelayCount = floor->resetDelay;
230 //                      floor->resetDelay = 0;
231                         return;
232                 }                       
233                 floor->sector->specialdata = NULL;
234                 /*
235                 if (floor->direction == 1)
236                         switch(floor->type)
237                         {
238                                 case donutRaise:
239                                         floor->sector->special = floor->newspecial;
240                                         floor->sector->floorpic = floor->texture;
241                                 default:
242                                         break;
243                         }
244                 else if (floor->direction == -1)
245                         switch(floor->type)
246                         {
247                                 case lowerAndChange:
248                                         floor->sector->special = floor->newspecial;
249                                         floor->sector->floorpic = floor->texture;
250                                 default:
251                                         break;
252                         }
253                 */
254                 if(floor->textureChange)
255                 {
256                         floor->sector->floorpic -= floor->textureChange;
257                 }
258                 P_TagFinished(floor->sector->tag);
259                 P_RemoveThinker(&floor->thinker);
260         }
261 }
262
263 //==================================================================
264 //
265 //      HANDLE FLOOR TYPES
266 //
267 //==================================================================
268 int EV_DoFloor(line_t *line, byte *args, floor_e floortype)
269 {
270         int                     secnum;
271         int                     rtn;
272         sector_t        *sec;
273         floormove_t     *floor=NULL;
274
275         secnum = -1;
276         rtn = 0;
277         while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
278         {
279                 sec = &sectors[secnum];
280
281                 //      ALREADY MOVING?  IF SO, KEEP GOING...
282                 if (sec->specialdata)
283                         continue;
284
285                 //
286                 //      new floor thinker
287                 //
288                 rtn = 1;
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;
295                 floor->crush = 0;
296                 floor->speed = args[1]*(FRACUNIT/8);
297                 if(floortype == FLEV_LOWERTIMES8INSTANT || 
298                         floortype == FLEV_RAISETIMES8INSTANT)
299                 {
300                         floor->speed = 2000<<FRACBITS;
301                 }
302                 switch(floortype)
303                 {
304                         case FLEV_LOWERFLOOR:
305                                 floor->direction = -1;
306                                 floor->sector = sec;
307                                 floor->floordestheight =
308                                         P_FindHighestFloorSurrounding(sec);
309                                 break;
310                         case FLEV_LOWERFLOORTOLOWEST:
311                                 floor->direction = -1;
312                                 floor->sector = sec;
313                                 floor->floordestheight =
314                                         P_FindLowestFloorSurrounding(sec);
315                                 break;
316                         case FLEV_LOWERFLOORBYVALUE:
317                                 floor->direction = -1;
318                                 floor->sector = sec;
319                                 floor->floordestheight = floor->sector->floorheight-
320                                         args[2]*FRACUNIT;
321                                 break;
322                         case FLEV_LOWERTIMES8INSTANT:
323                         case FLEV_LOWERBYVALUETIMES8:
324                                 floor->direction = -1;
325                                 floor->sector = sec;
326                                 floor->floordestheight = floor->sector->floorheight-
327                                         args[2]*FRACUNIT*8;
328                                 break;
329                         case FLEV_RAISEFLOORCRUSH:
330                                 floor->crush = args[2]; // arg[2] = crushing value
331                                 floor->direction = 1;
332                                 floor->sector = sec;
333                                 floor->floordestheight = sec->ceilingheight-8*FRACUNIT;
334                                 break;
335                         case FLEV_RAISEFLOOR:
336                                 floor->direction = 1;
337                                 floor->sector = sec;
338                                 floor->floordestheight =
339                                         P_FindLowestCeilingSurrounding(sec);
340                                 if (floor->floordestheight > sec->ceilingheight)
341                                         floor->floordestheight = sec->ceilingheight;
342                                 break;
343                         case FLEV_RAISEFLOORTONEAREST:
344                                 floor->direction = 1;
345                                 floor->sector = sec;
346                                 floor->floordestheight =
347                                         P_FindNextHighestFloor(sec,sec->floorheight);
348                                 break;
349                         case FLEV_RAISEFLOORBYVALUE:
350                                 floor->direction = 1;
351                                 floor->sector = sec;
352                                 floor->floordestheight = floor->sector->floorheight+
353                                         args[2]*FRACUNIT;
354                                 break;
355                         case FLEV_RAISETIMES8INSTANT:
356                         case FLEV_RAISEBYVALUETIMES8:
357                                 floor->direction = 1;
358                                 floor->sector = sec;
359                                 floor->floordestheight = floor->sector->floorheight+
360                                         args[2]*FRACUNIT*8;
361                                 break;
362                         case FLEV_MOVETOVALUETIMES8:
363                                 floor->sector = sec;
364                                 floor->floordestheight = args[2]*FRACUNIT*8;
365                                 if(args[3])
366                                 {
367                                         floor->floordestheight = -floor->floordestheight;
368                                 }
369                                 if(floor->floordestheight > floor->sector->floorheight)
370                                 {
371                                         floor->direction = 1;
372                                 }
373                                 else if(floor->floordestheight < floor->sector->floorheight)
374                                 {
375                                         floor->direction = -1;
376                                 }
377                                 else
378                                 { // already at lowest position
379                                         rtn = 0;
380                                 }
381                                 break;
382                         default:
383                                 rtn = 0;
384                                 break;
385                 }
386         }
387         if(rtn)
388         {
389                 SN_StartSequence((mobj_t *)&floor->sector->soundorg, 
390                         SEQ_PLATFORM+floor->sector->seqType);
391         }
392         return rtn;
393 }
394
395 //============================================================================
396 //
397 // EV_DoFloorAndCeiling
398 //
399 //============================================================================
400
401 int EV_DoFloorAndCeiling(line_t *line, byte *args, boolean raise)
402 {
403         boolean floor, ceiling;
404         int                     secnum;
405         sector_t        *sec;
406
407         if(raise)
408         {
409                 floor = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
410                 secnum = -1;
411                 while((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
412                 {
413                         sec = &sectors[secnum];
414                         sec->specialdata = NULL;
415                 }
416                 ceiling = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
417         }               
418         else 
419         {
420                 floor = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
421                 secnum = -1;
422                 while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
423                 {
424                         sec = &sectors[secnum];
425                         sec->specialdata = NULL;
426                 }
427                 ceiling = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
428         }
429         return (floor|ceiling);
430 }
431                         
432 // ===== Build Stairs Private Data =====
433
434 #define STAIR_SECTOR_TYPE       26
435 #define STAIR_QUEUE_SIZE        32
436
437 struct
438 {
439         sector_t *sector;
440         int type;
441         int height;
442 } StairQueue[STAIR_QUEUE_SIZE];
443
444 static int QueueHead;
445 static int QueueTail;
446
447 static int StepDelta;
448 static int Direction;
449 static int Speed;
450 static int Texture;
451 static int StartDelay;
452 static int StartDelayDelta;
453 static int TextureChange;
454 static int StartHeight;
455
456 //==========================================================================
457 //
458 // QueueStairSector
459 //
460 //==========================================================================
461
462 static void QueueStairSector(sector_t *sec, int type, int height)
463 {
464         if((QueueTail+1)%STAIR_QUEUE_SIZE == QueueHead)
465         {
466                 I_Error("BuildStairs:  Too many branches located.\n");
467         }
468         StairQueue[QueueTail].sector = sec;
469         StairQueue[QueueTail].type = type;
470         StairQueue[QueueTail].height = height;
471
472         QueueTail = (QueueTail+1)%STAIR_QUEUE_SIZE;
473 }
474
475 //==========================================================================
476 //
477 // DequeueStairSector
478 //
479 //==========================================================================
480
481 static sector_t *DequeueStairSector(int *type, int *height)
482 {
483         sector_t *sec;
484
485         if(QueueHead == QueueTail)
486         { // queue is empty
487                 return NULL;
488         }
489         *type = StairQueue[QueueHead].type;
490         *height = StairQueue[QueueHead].height;
491         sec = StairQueue[QueueHead].sector;
492         QueueHead = (QueueHead+1)%STAIR_QUEUE_SIZE;
493
494         return sec;
495 }
496
497 //==========================================================================
498 //
499 // ProcessStairSector
500 //
501 //==========================================================================
502
503 static void ProcessStairSector(sector_t *sec, int type, int height, 
504         stairs_e stairsType, int delay, int resetDelay)
505 {
506         int             i;
507         sector_t        *tsec;
508         floormove_t     *floor;
509
510         //
511         // new floor thinker
512         //
513         height += StepDelta;
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;
521         floor->sector = sec;
522         floor->floordestheight = height;
523         switch(stairsType)
524         {
525                 case STAIRS_NORMAL:
526                         floor->speed = Speed;
527                         if(delay)
528                         {
529                                 floor->delayTotal = delay;
530                                 floor->stairsDelayHeight = sec->floorheight+StepDelta;
531                                 floor->stairsDelayHeightDelta = StepDelta;
532                         }
533                         floor->resetDelay = resetDelay;
534                         floor->resetDelayCount = resetDelay;
535                         floor->resetHeight = sec->floorheight;
536                         break;
537                 case STAIRS_SYNC:
538                         floor->speed = FixedMul(Speed, FixedDiv(height-StartHeight,
539                                 StepDelta));
540                         floor->resetDelay = delay; //arg4
541                         floor->resetDelayCount = delay;
542                         floor->resetHeight = sec->floorheight;
543                         break;
544 /*
545                 case STAIRS_PHASED:
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;
552                         break;
553 */
554                 default:
555                         break;
556         }
557         SN_StartSequence((mobj_t *)&sec->soundorg, SEQ_PLATFORM+sec->seqType);
558         //
559         // Find next sector to raise
560         // Find nearby sector with sector special equal to type
561         //
562         for (i = 0; i < sec->linecount; i++)
563         {
564                 if(!((sec->lines[i])->flags&ML_TWOSIDED))
565                 {
566                         continue;
567                 }
568                 tsec = (sec->lines[i])->frontsector;
569                 if(tsec->special == type+STAIR_SECTOR_TYPE && !tsec->specialdata
570                         && tsec->floorpic == Texture && tsec->validcount != validcount)
571                 {
572                         QueueStairSector(tsec, type^1, height);
573                         tsec->validcount = validcount;
574                         //tsec->special = 0;
575                 }
576                 tsec = (sec->lines[i])->backsector;
577                 if(tsec->special == type+STAIR_SECTOR_TYPE && !tsec->specialdata
578                         && tsec->floorpic == Texture && tsec->validcount != validcount)
579                 {
580                         QueueStairSector(tsec, type^1, height);
581                         tsec->validcount = validcount;
582                         //tsec->special = 0;
583                 }
584         }
585 }
586
587 //==================================================================
588 //
589 //      BUILD A STAIRCASE!
590 //
591 // Direction is either positive or negative, denoting build stairs
592 //      up or down.
593 //==================================================================
594
595 int EV_BuildStairs(line_t *line, byte *args, int direction, 
596         stairs_e stairsType)
597 {
598         int secnum;
599         int height;
600         int     delay;
601         int resetDelay;
602         sector_t        *sec;
603         sector_t *qSec;
604         int type;
605
606         // Set global stairs variables
607         TextureChange = 0;
608         Direction = direction;
609         StepDelta = Direction*(args[2]*FRACUNIT);
610         Speed = args[1]*(FRACUNIT/8);
611         resetDelay = args[4];
612         delay = args[3];
613         if(stairsType == STAIRS_PHASED)
614         {
615                 StartDelayDelta = args[3];
616                 StartDelay = StartDelayDelta;
617                 resetDelay = StartDelayDelta;
618                 delay = 0;
619                 TextureChange = args[4];
620         }
621
622         secnum = -1;
623
624         validcount++; 
625         while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
626         {
627                 sec = &sectors[secnum];
628
629                 Texture = sec->floorpic;
630                 StartHeight = sec->floorheight;
631
632                 // ALREADY MOVING?  IF SO, KEEP GOING...
633                 if (sec->specialdata)
634                         continue;
635
636                 QueueStairSector(sec, 0, sec->floorheight);
637                 sec->special = 0;
638         }
639         while((qSec = DequeueStairSector(&type, &height)) != NULL)
640         {
641                 ProcessStairSector(qSec, type, height, stairsType, delay, resetDelay);
642         }
643         return(1);
644 }
645
646 //=========================================================================
647 //
648 // T_BuildPillar
649 //
650 //=========================================================================
651
652 void T_BuildPillar(pillar_t *pillar)
653 {
654         result_e        res1;
655         result_e res2;
656
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)
664         {
665                 pillar->sector->specialdata = NULL;
666                 SN_StopSequence((mobj_t *)&pillar->sector->soundorg);
667                 P_TagFinished(pillar->sector->tag);
668                 P_RemoveThinker(&pillar->thinker);
669         }
670 }
671
672 //=========================================================================
673 //
674 // EV_BuildPillar
675 //
676 //=========================================================================
677
678 int EV_BuildPillar(line_t *line, byte *args, boolean crush)
679 {
680         int secnum;
681         sector_t *sec;
682         pillar_t *pillar;
683         int newHeight;
684         int rtn;
685
686         rtn = 0;
687         secnum = -1;
688         while((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
689         {
690                 sec = &sectors[secnum];
691                 if(sec->specialdata)
692                         continue; // already moving
693                 if(sec->floorheight == sec->ceilingheight)
694                 { // pillar is already closed
695                         continue;
696                 }
697                 rtn = 1;
698                 if(!args[2])
699                 {
700                         newHeight = sec->floorheight+
701                                 ((sec->ceilingheight-sec->floorheight)/2);
702                 }
703                 else
704                 {
705                         newHeight = sec->floorheight+(args[2]<<FRACBITS);
706                 }
707
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;
713                 if(!args[2])
714                 {
715                         pillar->ceilingSpeed = pillar->floorSpeed = args[1]*(FRACUNIT/8);
716                 }
717                 else if(newHeight-sec->floorheight > sec->ceilingheight-newHeight)
718                 {
719                         pillar->floorSpeed = args[1]*(FRACUNIT/8);
720                         pillar->ceilingSpeed = FixedMul(sec->ceilingheight-newHeight,
721                                 FixedDiv(pillar->floorSpeed, newHeight-sec->floorheight));
722                 }
723                 else
724                 {
725                         pillar->ceilingSpeed = args[1]*(FRACUNIT/8);
726                         pillar->floorSpeed = FixedMul(newHeight-sec->floorheight,
727                                 FixedDiv(pillar->ceilingSpeed, sec->ceilingheight-newHeight));
728                 }
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);
735         }
736         return rtn;
737 }
738
739 //=========================================================================
740 //
741 // EV_OpenPillar
742 //
743 //=========================================================================
744
745 int EV_OpenPillar(line_t *line, byte *args)
746 {
747         int secnum;
748         sector_t *sec;
749         pillar_t *pillar;
750         int rtn;
751
752         rtn = 0;
753         secnum = -1;
754         while((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
755         {
756                 sec = &sectors[secnum];
757                 if(sec->specialdata)
758                         continue; // already moving
759                 if(sec->floorheight != sec->ceilingheight)
760                 { // pillar isn't closed
761                         continue;
762                 }
763                 rtn = 1;
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;
769                 if(!args[2])
770                 {
771                         pillar->floordest = P_FindLowestFloorSurrounding(sec);
772                 }
773                 else
774                 {
775                         pillar->floordest = sec->floorheight-(args[2]<<FRACBITS);
776                 }
777                 if(!args[3])
778                 {
779                         pillar->ceilingdest = P_FindHighestCeilingSurrounding(sec);
780                 }
781                 else
782                 {
783                         pillar->ceilingdest = sec->ceilingheight+(args[3]<<FRACBITS);
784                 }
785                 if(sec->floorheight-pillar->floordest >= pillar->ceilingdest-
786                         sec->ceilingheight)
787                 {
788                         pillar->floorSpeed = args[1]*(FRACUNIT/8);
789                         pillar->ceilingSpeed = FixedMul(sec->ceilingheight-
790                                 pillar->ceilingdest, FixedDiv(pillar->floorSpeed,
791                                 pillar->floordest-sec->floorheight));
792                 }
793                 else
794                 {
795                         pillar->ceilingSpeed = args[1]*(FRACUNIT/8);
796                         pillar->floorSpeed = FixedMul(pillar->floordest-sec->floorheight,
797                                 FixedDiv(pillar->ceilingSpeed, sec->ceilingheight-
798                                 pillar->ceilingdest));
799                 }
800                 pillar->direction = -1; // open the pillar
801                 SN_StartSequence((mobj_t *)&pillar->sector->soundorg, 
802                         SEQ_PLATFORM+pillar->sector->seqType);
803         }
804         return rtn;
805 }
806
807 //=========================================================================
808 //
809 // EV_FloorCrushStop
810 //
811 //=========================================================================
812
813 int EV_FloorCrushStop(line_t *line, byte *args)
814 {
815         thinker_t *think;
816         floormove_t *floor;
817         boolean rtn;
818
819         rtn = 0;
820         for(think = thinkercap.next; think != &thinkercap; think = think->next)
821         {
822                 if(think->function != T_MoveFloor)
823                 {
824                         continue;
825                 }
826                 floor = (floormove_t *)think;
827                 if(floor->type != FLEV_RAISEFLOORCRUSH)
828                 {
829                         continue;
830                 }
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);
836                 rtn = 1;
837         }       
838         return rtn;
839 }
840
841 //==========================================================================
842 //
843 // T_FloorWaggle
844 //
845 //==========================================================================
846
847 #define WGLSTATE_EXPAND 1
848 #define WGLSTATE_STABLE 2
849 #define WGLSTATE_REDUCE 3
850
851 void T_FloorWaggle(floorWaggle_t *waggle)
852 {
853         switch(waggle->state)
854         {
855                 case WGLSTATE_EXPAND:
856                         if((waggle->scale += waggle->scaleDelta)
857                                 >= waggle->targetScale)
858                         {
859                                 waggle->scale = waggle->targetScale;
860                                 waggle->state = WGLSTATE_STABLE;
861                         }
862                         break;
863                 case WGLSTATE_REDUCE:
864                         if((waggle->scale -= waggle->scaleDelta) <= 0)
865                         { // Remove
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);
871                                 return;
872                         }
873                         break;
874                 case WGLSTATE_STABLE:
875                         if(waggle->ticker != -1)
876                         {
877                                 if(!--waggle->ticker)
878                                 {
879                                         waggle->state = WGLSTATE_REDUCE;
880                                 }
881                         }
882                         break;
883         }
884         waggle->accumulator += waggle->accDelta;
885         waggle->sector->floorheight = waggle->originalHeight
886                 +FixedMul(FloatBobOffsets[(waggle->accumulator>>FRACBITS)&63],
887                 waggle->scale);
888         P_ChangeSector(waggle->sector, true);
889 }
890
891 //==========================================================================
892 //
893 // EV_StartFloorWaggle
894 //
895 //==========================================================================
896
897 boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset,
898         int timer)
899 {
900         int sectorIndex;
901         sector_t *sector;
902         floorWaggle_t *waggle;
903         boolean retCode;
904
905         retCode = false;
906         sectorIndex = -1;
907         while((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
908         {
909                 sector = &sectors[sectorIndex];
910                 if(sector->specialdata)
911                 { // Already busy with another thinker
912                         continue;
913                 }
914                 retCode = true;
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;
922                 waggle->scale = 0;
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);
929         }
930         return retCode;
931 }
932