1 
2 //**************************************************************************
3 //**
4 //** p_floor.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile: p_floor.c,v $
7 //** $Revision: 1.23 $
8 //** $Date: 95/10/06 16:53:19 $
9 //** $Author: paul $
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 //==================================================================
T_MovePlane(sector_t * sector,fixed_t speed,fixed_t dest,int crush,int floorOrCeiling,int direction)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 //==================================================================
T_MoveFloor(floormove_t * floor)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 //==================================================================
EV_DoFloor(line_t * line,byte * args,floor_e floortype)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 
EV_DoFloorAndCeiling(line_t * line,byte * args,boolean raise)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 
QueueStairSector(sector_t * sec,int type,int height)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 
DequeueStairSector(int * type,int * height)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 
ProcessStairSector(sector_t * sec,int type,int height,stairs_e stairsType,int delay,int resetDelay)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 
EV_BuildStairs(line_t * line,byte * args,int direction,stairs_e stairsType)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 
T_BuildPillar(pillar_t * pillar)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 
EV_BuildPillar(line_t * line,byte * args,boolean crush)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 
EV_OpenPillar(line_t * line,byte * args)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 
EV_FloorCrushStop(line_t * line,byte * args)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 
T_FloorWaggle(floorWaggle_t * waggle)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 
EV_StartFloorWaggle(int tag,int height,int speed,int offset,int timer)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