1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: po_man.cpp 4542 2014-02-09 17:39:42Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //	PO_MAN.C : Heretic 2 : Raven Software, Corp.
21 //
22 //-----------------------------------------------------------------------------
23 
24 // HEADER FILES ------------------------------------------------------------
25 
26 #include "doomdef.h"
27 #include "p_local.h"
28 #include "r_local.h"
29 #include "i_system.h"
30 #include "z_zone.h"
31 #include "w_wad.h"
32 #include "m_swap.h"
33 #include "m_bbox.h"
34 #include "tables.h"
35 #include "s_sndseq.h"
36 
37 // MACROS ------------------------------------------------------------------
38 
39 #define PO_MAXPOLYSEGS 64
40 
41 // TYPES -------------------------------------------------------------------
42 
43 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
44 
45 BOOL PO_MovePolyobj (int num, int x, int y);
46 BOOL PO_RotatePolyobj (int num, angle_t angle);
47 void PO_Init (void);
48 
49 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
50 
51 static polyobj_t *GetPolyobj (int polyNum);
52 static int GetPolyobjMirror (int poly);
53 static void UpdateSegBBox (seg_t *seg);
54 static void RotatePt (int an, fixed_t *x, fixed_t *y, fixed_t startSpotX,
55 	fixed_t startSpotY);
56 static void UnLinkPolyobj (polyobj_t *po);
57 static void LinkPolyobj (polyobj_t *po);
58 static BOOL CheckMobjBlocking (seg_t *seg, polyobj_t *po);
59 static void InitBlockMap (void);
60 static void IterFindPolySegs (int x, int y, seg_t **segList);
61 static void SpawnPolyobj (int index, int tag, BOOL crush);
62 static void TranslateToStartSpot (int tag, int originX, int originY);
63 static void DoMovePolyobj (polyobj_t *po, int x, int y);
64 
65 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
66 
67 extern seg_t *segs;
68 
69 // PUBLIC DATA DEFINITIONS -------------------------------------------------
70 
71 polyblock_t **PolyBlockMap;
72 polyobj_t *polyobjs; // list of all poly-objects on the level
73 int po_NumPolyobjs;
74 polyspawns_t *polyspawns; // [RH] Let P_SpawnMapThings() find our thingies for us
75 
76 // PRIVATE DATA DEFINITIONS ------------------------------------------------
77 
78 static int PolySegCount;
79 static fixed_t PolyStartX;
80 static fixed_t PolyStartY;
81 
82 // CODE --------------------------------------------------------------------
83 
IMPLEMENT_SERIAL(DPolyAction,DThinker)84 IMPLEMENT_SERIAL (DPolyAction, DThinker)
85 IMPLEMENT_SERIAL (DRotatePoly, DPolyAction)
86 IMPLEMENT_SERIAL (DMovePoly, DPolyAction)
87 IMPLEMENT_SERIAL (DPolyDoor, DMovePoly)
88 
89 DPolyAction::DPolyAction ()
90 {
91 }
92 
Serialize(FArchive & arc)93 void DPolyAction::Serialize (FArchive &arc)
94 {
95 	Super::Serialize (arc);
96 	if (arc.IsStoring ())
97 		arc << m_PolyObj << m_Speed << m_Dist;
98 	else
99 		arc >> m_PolyObj >> m_Speed >> m_Dist;
100 }
101 
DPolyAction(int polyNum)102 DPolyAction::DPolyAction (int polyNum)
103 {
104 	m_PolyObj = polyNum;
105 	m_Speed = 0;
106 	m_Dist = 0;
107 }
108 
DRotatePoly()109 DRotatePoly::DRotatePoly ()
110 {
111 }
112 
Serialize(FArchive & arc)113 void DRotatePoly::Serialize (FArchive &arc)
114 {
115 	Super::Serialize (arc);
116 }
117 
DRotatePoly(int polyNum)118 DRotatePoly::DRotatePoly (int polyNum)
119 	: Super (polyNum)
120 {
121 }
122 
DMovePoly()123 DMovePoly::DMovePoly ()
124 {
125 }
126 
Serialize(FArchive & arc)127 void DMovePoly::Serialize (FArchive &arc)
128 {
129 	Super::Serialize (arc);
130 	if (arc.IsStoring ())
131 		arc << m_Angle << m_xSpeed << m_ySpeed;
132 	else
133 		arc >> m_Angle >> m_xSpeed >> m_ySpeed;
134 }
135 
DMovePoly(int polyNum)136 DMovePoly::DMovePoly (int polyNum)
137 	: Super (polyNum)
138 {
139 	m_Angle = 0;
140 	m_xSpeed = 0;
141 	m_ySpeed = 0;
142 }
143 
DPolyDoor()144 DPolyDoor::DPolyDoor ()
145 {
146 }
147 
Serialize(FArchive & arc)148 void DPolyDoor::Serialize (FArchive &arc)
149 {
150 	Super::Serialize (arc);
151 	if (arc.IsStoring ())
152 		arc << m_Direction << m_TotalDist << m_Tics << m_WaitTics << m_Type << m_Close;
153 	else
154 		arc >> m_Direction >> m_TotalDist >> m_Tics >> m_WaitTics >> m_Type >> m_Close;
155 }
156 
DPolyDoor(int polyNum,podoortype_t type)157 DPolyDoor::DPolyDoor (int polyNum, podoortype_t type)
158 	: Super (polyNum)
159 {
160 	m_Type = type;
161 	m_Direction = 0;
162 	m_TotalDist = 0;
163 	m_Tics = 0;
164 	m_WaitTics = 0;
165 	m_Close = false;
166 }
167 
168 // ===== Polyobj Event Code =====
169 
170 
171 //
172 // T_RotatePoly
173 //
RunThink()174 void DRotatePoly::RunThink ()
175 {
176 	if (PO_RotatePolyobj (m_PolyObj, m_Speed))
177 	{
178 		int absSpeed = abs (m_Speed);
179 
180 		if (m_Dist == -1)
181 		{ // perpetual polyobj
182 			return;
183 		}
184 		m_Dist -= absSpeed;
185 		if (m_Dist <= 0)
186 		{
187 			polyobj_t *poly = GetPolyobj (m_PolyObj);
188 			if (poly->specialdata == this)
189 			{
190 				poly->specialdata = NULL;
191 			}
192 			SN_StopSequence (poly);
193 			Destroy ();
194 		}
195 		else if (m_Dist < absSpeed)
196 		{
197 			m_Speed = m_Dist * (m_Speed < 0 ? -1 : 1);
198 		}
199 	}
200 }
201 
202 //
203 // EV_RotatePoly
204 //
EV_RotatePoly(line_t * line,int polyNum,int speed,int byteAngle,int direction,BOOL overRide)205 BOOL EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle,
206 					int direction, BOOL overRide)
207 {
208 	int mirror;
209 	DRotatePoly *pe;
210 	polyobj_t *poly;
211 
212 	if ( (poly = GetPolyobj(polyNum)) )
213 	{
214 		if (poly->specialdata && !overRide)
215 		{ // poly is already moving
216 			return false;
217 		}
218 	}
219 	else
220 	{
221 		I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
222 	}
223 	pe = new DRotatePoly (polyNum);
224 	if (byteAngle)
225 	{
226 		if (byteAngle == 255)
227 		{
228 			pe->m_Dist = ~0;
229 		}
230 		else
231 		{
232 			pe->m_Dist = byteAngle*(ANG90/64); // Angle
233 		}
234 	}
235 	else
236 	{
237 		pe->m_Dist = ANG360-1;
238 	}
239 	pe->m_Speed = (speed*direction*(ANG90/64))>>3;
240 	poly->specialdata = pe;
241 	SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
242 
243 	while ( (mirror = GetPolyobjMirror( polyNum)) )
244 	{
245 		poly = GetPolyobj(mirror);
246 		if (poly && poly->specialdata && !overRide)
247 		{ // mirroring poly is already in motion
248 			break;
249 		}
250 		pe = new DRotatePoly (mirror);
251 		poly->specialdata = pe;
252 		if (byteAngle)
253 		{
254 			if (byteAngle == 255)
255 			{
256 				pe->m_Dist = ~0;
257 			}
258 			else
259 			{
260 				pe->m_Dist = byteAngle*(ANG90/64); // Angle
261 			}
262 		}
263 		else
264 		{
265 			pe->m_Dist = ANG360-1;
266 		}
267 		if( (poly = GetPolyobj(polyNum)) )
268 		{
269 			poly->specialdata = pe;
270 		}
271 		else
272 		{
273 			I_Error ("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
274 		}
275 		direction = -direction;
276 		pe->m_Speed = (speed*direction*(ANG90/64))>>3;
277 		polyNum = mirror;
278 		SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
279 	}
280 	return true;
281 }
282 
283 //
284 // T_MovePoly
285 //
RunThink()286 void DMovePoly::RunThink ()
287 {
288 	polyobj_t *poly;
289 
290 	if (PO_MovePolyobj (m_PolyObj, m_xSpeed, m_ySpeed))
291 	{
292 		int absSpeed = abs (m_Speed);
293 		m_Dist -= absSpeed;
294 		if (m_Dist <= 0)
295 		{
296 			poly = GetPolyobj (m_PolyObj);
297 			if (poly->specialdata == this)
298 			{
299 				poly->specialdata = NULL;
300 			}
301 			SN_StopSequence (poly);
302 			Destroy ();
303 		}
304 		else if (m_Dist < absSpeed)
305 		{
306 			m_Speed = m_Dist * (m_Speed < 0 ? -1 : 1);
307 			m_xSpeed = FixedMul (m_Speed, finecosine[m_Angle]);
308 			m_ySpeed = FixedMul (m_Speed, finesine[m_Angle]);
309 		}
310 	}
311 }
312 
313 //
314 // EV_MovePoly
315 //
EV_MovePoly(line_t * line,int polyNum,int speed,angle_t angle,fixed_t dist,BOOL overRide)316 BOOL EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle,
317 				  fixed_t dist, BOOL overRide)
318 {
319 	int mirror;
320 	DMovePoly *pe;
321 	polyobj_t *poly;
322 	angle_t an;
323 
324 	if ( (poly = GetPolyobj(polyNum)) )
325 	{
326 		if (poly->specialdata && !overRide)
327 		{ // poly is already moving
328 			return false;
329 		}
330 	}
331 	else
332 	{
333 		I_Error("EV_MovePoly: Invalid polyobj num: %d\n", polyNum);
334 	}
335 	pe = new DMovePoly (polyNum);
336 	pe->m_Dist = dist; // Distance
337 	pe->m_Speed = speed;
338 	poly->specialdata = pe;
339 
340 	an = angle;
341 
342 	pe->m_Angle = an>>ANGLETOFINESHIFT;
343 	pe->m_xSpeed = FixedMul (pe->m_Speed, finecosine[pe->m_Angle]);
344 	pe->m_ySpeed = FixedMul (pe->m_Speed, finesine[pe->m_Angle]);
345 	SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
346 
347 	while ( (mirror = GetPolyobjMirror(polyNum)) )
348 	{
349 		poly = GetPolyobj(mirror);
350 		if (poly && poly->specialdata && !overRide)
351 		{ // mirroring poly is already in motion
352 			break;
353 		}
354 		pe = new DMovePoly (mirror);
355 		poly->specialdata = pe;
356 		pe->m_Dist = dist; // Distance
357 		pe->m_Speed = speed;
358 		an = an+ANG180; // reverse the angle
359 		pe->m_Angle = an>>ANGLETOFINESHIFT;
360 		pe->m_xSpeed = FixedMul (pe->m_Speed, finecosine[pe->m_Angle]);
361 		pe->m_ySpeed = FixedMul (pe->m_Speed, finesine[pe->m_Angle]);
362 		polyNum = mirror;
363 		SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
364 	}
365 	return true;
366 }
367 
368 
369 //
370 // T_PolyDoor
371 //
RunThink()372 void DPolyDoor::RunThink ()
373 {
374 	int absSpeed;
375 	polyobj_t *poly;
376 
377 	if (m_Tics)
378 	{
379 		if (!--m_Tics)
380 		{
381 			poly = GetPolyobj (m_PolyObj);
382 			SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
383 		}
384 		return;
385 	}
386 	switch (m_Type)
387 	{
388 	case PODOOR_SLIDE:
389 		if (m_Dist <= 0 || PO_MovePolyobj (m_PolyObj, m_xSpeed, m_ySpeed))
390 		{
391 			absSpeed = abs (m_Speed);
392 			m_Dist -= absSpeed;
393 			if (m_Dist <= 0)
394 			{
395 				poly = GetPolyobj (m_PolyObj);
396 				SN_StopSequence (poly);
397 				if (!m_Close)
398 				{
399 					m_Dist = m_TotalDist;
400 					m_Close = true;
401 					m_Tics = m_WaitTics;
402 					m_Direction = (ANG360>>ANGLETOFINESHIFT)-
403 						m_Direction;
404 					m_xSpeed = -m_xSpeed;
405 					m_ySpeed = -m_ySpeed;
406 				}
407 				else
408 				{
409 					if (poly->specialdata == this)
410 					{
411 						poly->specialdata = NULL;
412 					}
413 					Destroy ();
414 				}
415 			}
416 		}
417 		else
418 		{
419 			poly = GetPolyobj (m_PolyObj);
420 			if (poly->crush || !m_Close)
421 			{ // continue moving if the poly is a crusher, or is opening
422 				return;
423 			}
424 			else
425 			{ // open back up
426 				m_Dist = m_TotalDist - m_Dist;
427 				m_Direction = (ANG360>>ANGLETOFINESHIFT)-
428 					m_Direction;
429 				m_xSpeed = -m_xSpeed;
430 				m_ySpeed = -m_ySpeed;
431 				m_Close = false;
432 				SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
433 			}
434 		}
435 		break;
436 	case PODOOR_SWING:
437 		if (PO_RotatePolyobj (m_PolyObj, m_Speed))
438 		{
439 			absSpeed = abs (m_Speed);
440 			if (m_Dist == -1)
441 			{ // perpetual polyobj
442 				return;
443 			}
444 			m_Dist -= absSpeed;
445 			if (m_Dist <= 0)
446 			{
447 				poly = GetPolyobj (m_PolyObj);
448 				SN_StopSequence (poly);
449 				if (!m_Close)
450 				{
451 					m_Dist = m_TotalDist;
452 					m_Close = true;
453 					m_Tics = m_WaitTics;
454 					m_Speed = -m_Speed;
455 				}
456 				else
457 				{
458 					if (poly->specialdata == this)
459 					{
460 						poly->specialdata = NULL;
461 					}
462 					Destroy ();
463 				}
464 			}
465 		}
466 		else
467 		{
468 			poly = GetPolyobj (m_PolyObj);
469 			if(poly->crush || !m_Close)
470 			{ // continue moving if the poly is a crusher, or is opening
471 				return;
472 			}
473 			else
474 			{ // open back up and rewait
475 				m_Dist = m_TotalDist - m_Dist;
476 				m_Speed = -m_Speed;
477 				m_Close = false;
478 				SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
479 			}
480 		}
481 		break;
482 	default:
483 		break;
484 	}
485 }
486 
487 //
488 // EV_OpenPolyDoor
489 //
EV_OpenPolyDoor(line_t * line,int polyNum,int speed,angle_t angle,int delay,int distance,podoortype_t type)490 BOOL EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle,
491 					  int delay, int distance, podoortype_t type)
492 {
493 	int mirror;
494 	DPolyDoor *pd;
495 	polyobj_t *poly;
496 
497 	if( (poly = GetPolyobj(polyNum)) )
498 	{
499 		if (poly->specialdata)
500 		{ // poly is already moving
501 			return false;
502 		}
503 	}
504 	else
505 	{
506 		I_Error("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum);
507 	}
508 	pd = new DPolyDoor (polyNum, type);
509 	if (type == PODOOR_SLIDE)
510 	{
511 		pd->m_WaitTics = delay;
512 		pd->m_Speed = speed;
513 		pd->m_Dist = pd->m_TotalDist = distance; // Distance
514 		pd->m_Direction = angle >> ANGLETOFINESHIFT;
515 		pd->m_xSpeed = FixedMul (pd->m_Speed, finecosine[pd->m_Direction]);
516 		pd->m_ySpeed = FixedMul (pd->m_Speed, finesine[pd->m_Direction]);
517 		SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
518 	}
519 	else if (type == PODOOR_SWING)
520 	{
521 		pd->m_WaitTics = delay;
522 		pd->m_Direction = 1; // ADD:  PODO'OR_SWINGL, PODOOR_SWINGR
523 		pd->m_Speed = (speed*pd->m_Direction*(ANG90/64))>>3;
524 		pd->m_Dist = pd->m_TotalDist = angle;
525 		SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
526 	}
527 
528 	poly->specialdata = pd;
529 
530 	while ( (mirror = GetPolyobjMirror (polyNum)) )
531 	{
532 		poly = GetPolyobj (mirror);
533 		if (poly && poly->specialdata)
534 		{ // mirroring poly is already in motion
535 			break;
536 		}
537 		pd = new DPolyDoor (mirror, type);
538 		poly->specialdata = pd;
539 		if (type == PODOOR_SLIDE)
540 		{
541 			pd->m_WaitTics = delay;
542 			pd->m_Speed = speed;
543 			pd->m_Dist = pd->m_TotalDist = distance; // Distance
544 			pd->m_Direction = (angle + ANG180) >> ANGLETOFINESHIFT; // reverse the angle
545 			pd->m_xSpeed = FixedMul (pd->m_Speed, finecosine[pd->m_Direction]);
546 			pd->m_ySpeed = FixedMul (pd->m_Speed, finesine[pd->m_Direction]);
547 			SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
548 		}
549 		else if (type == PODOOR_SWING)
550 		{
551 			pd->m_WaitTics = delay;
552 			pd->m_Direction = -1; // ADD:  same as above
553 			pd->m_Speed = (speed*pd->m_Direction*(ANG90/64))>>3;
554 			pd->m_Dist = pd->m_TotalDist = angle;
555 			SN_StartSequence (poly, poly->seqType, SEQ_DOOR);
556 		}
557 		polyNum = mirror;
558 	}
559 	return true;
560 }
561 
562 // ===== Higher Level Poly Interface code =====
563 
564 
565 //
566 // GetPolyobj
567 //
GetPolyobj(int polyNum)568 static polyobj_t *GetPolyobj (int polyNum)
569 {
570 	int i;
571 
572 	for (i = 0; i < po_NumPolyobjs; i++)
573 	{
574 		if (polyobjs[i].tag == polyNum)
575 		{
576 			return &polyobjs[i];
577 		}
578 	}
579 	return NULL;
580 }
581 
582 //
583 // GetPolyobjMirror
584 //
GetPolyobjMirror(int poly)585 static int GetPolyobjMirror(int poly)
586 {
587 	int i;
588 
589 	for (i = 0; i < po_NumPolyobjs; i++)
590 	{
591 		if (polyobjs[i].tag == poly)
592 		{
593 			return (*polyobjs[i].segs)->linedef->args[1];
594 		}
595 	}
596 	return 0;
597 }
598 
599 //
600 // ThrustMobj
601 //
ThrustMobj(AActor * actor,seg_t * seg,polyobj_t * po)602 void ThrustMobj (AActor *actor, seg_t *seg, polyobj_t *po)
603 {
604 	int thrustAngle;
605 	int thrustX;
606 	int thrustY;
607 	DPolyAction *pe;
608 
609 	int force;
610 
611 	if (!(actor->flags&MF_SHOOTABLE) && !actor->player)
612 	{
613 		return;
614 	}
615 	thrustAngle = (seg->angle-ANG90)>>ANGLETOFINESHIFT;
616 
617 	pe = static_cast<DPolyAction *>(po->specialdata);
618 	if (pe)
619 	{
620 		if (pe->IsKindOf (RUNTIME_CLASS (DRotatePoly)))
621 		{
622 			force = pe->m_Speed >> 8;
623 		}
624 		else
625 		{
626 			force = pe->m_Speed >> 3;
627 		}
628 		if (force < FRACUNIT)
629 		{
630 			force = FRACUNIT;
631 		}
632 		else if (force > 4*FRACUNIT)
633 		{
634 			force = 4*FRACUNIT;
635 		}
636 	}
637 	else
638 	{
639 		force = FRACUNIT;
640 	}
641 
642 	thrustX = FixedMul (force, finecosine[thrustAngle]);
643 	thrustY = FixedMul (force, finesine[thrustAngle]);
644 	actor->momx += thrustX;
645 	actor->momy += thrustY;
646 	if (po->crush)
647 	{
648 		if (!P_CheckPosition (actor, actor->x + thrustX, actor->y + thrustY))
649 		{
650 			P_DamageMobj (actor, NULL, NULL, 3, MOD_CRUSH);
651 		}
652 	}
653 }
654 
655 
656 //
657 // UpdateSegBBox
658 //
UpdateSegBBox(seg_t * seg)659 static void UpdateSegBBox (seg_t *seg)
660 {
661 	line_t *line;
662 
663 	line = seg->linedef;
664 
665 	if (seg->v1->x < seg->v2->x)
666 	{
667 		line->bbox[BOXLEFT] = seg->v1->x;
668 		line->bbox[BOXRIGHT] = seg->v2->x;
669 	}
670 	else
671 	{
672 		line->bbox[BOXLEFT] = seg->v2->x;
673 		line->bbox[BOXRIGHT] = seg->v1->x;
674 	}
675 	if (seg->v1->y < seg->v2->y)
676 	{
677 		line->bbox[BOXBOTTOM] = seg->v1->y;
678 		line->bbox[BOXTOP] = seg->v2->y;
679 	}
680 	else
681 	{
682 		line->bbox[BOXBOTTOM] = seg->v2->y;
683 		line->bbox[BOXTOP] = seg->v1->y;
684 	}
685 
686 	// Update the line's slopetype
687 	line->dx = line->v2->x - line->v1->x;
688 	line->dy = line->v2->y - line->v1->y;
689 	if (!line->dx)
690 	{
691 		line->slopetype = ST_VERTICAL;
692 	}
693 	else if (!line->dy)
694 	{
695 		line->slopetype = ST_HORIZONTAL;
696 	}
697 	else
698 	{
699 		if (FixedDiv(line->dy, line->dx) > 0)
700 		{
701 			line->slopetype = ST_POSITIVE;
702 		}
703 		else
704 		{
705 			line->slopetype = ST_NEGATIVE;
706 		}
707 	}
708 }
709 
710 
711 //
712 // PO_MovePolyobj
713 //
PO_MovePolyobj(int num,int x,int y)714 BOOL PO_MovePolyobj (int num, int x, int y)
715 {
716 	int count;
717 	seg_t **segList;
718 	polyobj_t *po;
719 	bool blocked;
720 
721 	if (!(po = GetPolyobj (num)))
722 	{
723 		I_Error ("PO_MovePolyobj: Invalid polyobj number: %d\n", num);
724 	}
725 
726 	UnLinkPolyobj (po);
727 	DoMovePolyobj (po, x, y);
728 
729 	segList = po->segs;
730 	blocked = false;
731 	for (count = po->numsegs; count; count--, segList++)
732 	{
733 		if (CheckMobjBlocking(*segList, po))
734 		{
735 			blocked = true;
736 			break;
737 		}
738 	}
739 	if (blocked)
740 	{
741 		DoMovePolyobj (po, -x, -y);
742 		LinkPolyobj(po);
743 		return false;
744 	}
745 	po->startSpot[0] += x;
746 	po->startSpot[1] += y;
747 	LinkPolyobj (po);
748 	return true;
749 }
750 
751 //
752 // DoMovePolyobj
753 //
DoMovePolyobj(polyobj_t * po,int x,int y)754 void DoMovePolyobj (polyobj_t *po, int x, int y)
755 {
756 	int count;
757 	seg_t **segList;
758 	seg_t **veryTempSeg;
759 	vertex_t *prevPts;
760 
761 	segList = po->segs;
762 	prevPts = po->prevPts;
763 
764 	validcount++;
765 	for (count = po->numsegs; count; count--, segList++, prevPts++)
766 	{
767 		line_t *linedef = (*segList)->linedef;
768 		if (linedef->validcount != validcount)
769 		{
770 			linedef->bbox[BOXTOP] += y;
771 			linedef->bbox[BOXBOTTOM] += y;
772 			linedef->bbox[BOXLEFT] += x;
773 			linedef->bbox[BOXRIGHT] += x;
774 			//if (linedef->sidenum[0] != -1)
775 			//	ADecal::MoveChain (sides[linedef->sidenum[0]].BoundActors, x, y);
776 			//if (linedef->sidenum[1] != -1)
777 			//	ADecal::MoveChain (sides[linedef->sidenum[1]].BoundActors, x, y);
778 			linedef->validcount = validcount;
779 		}
780 		for (veryTempSeg = po->segs; veryTempSeg != segList;
781 			veryTempSeg++)
782 		{
783 			if ((*veryTempSeg)->v1 == (*segList)->v1)
784 			{
785 				break;
786 			}
787 		}
788 		if (veryTempSeg == segList)
789 		{
790 			(*segList)->v1->x += x;
791 			(*segList)->v1->y += y;
792 		}
793 		(*prevPts).x += x; // previous points are unique for each seg
794 		(*prevPts).y += y;
795 	}
796 }
797 
798 //
799 // RotatePt
800 //
RotatePt(int an,fixed_t * x,fixed_t * y,fixed_t startSpotX,fixed_t startSpotY)801 static void RotatePt (int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY)
802 {
803 	fixed_t tr_x, tr_y;
804 	fixed_t gxt, gyt;
805 
806 	tr_x = *x;
807 	tr_y = *y;
808 
809 	gxt = FixedMul(tr_x, finecosine[an]);
810 	gyt = FixedMul(tr_y, finesine[an]);
811 	*x = (gxt-gyt)+startSpotX;
812 
813 	gxt = FixedMul(tr_x, finesine[an]);
814 	gyt = FixedMul(tr_y, finecosine[an]);
815 	*y = (gyt+gxt)+startSpotY;
816 }
817 
818 //
819 // PO_RotatePolyobj
820 //
PO_RotatePolyobj(int num,angle_t angle)821 BOOL PO_RotatePolyobj (int num, angle_t angle)
822 {
823 	int count;
824 	seg_t **segList;
825 	vertex_t *originalPts;
826 	vertex_t *prevPts;
827 	int an;
828 	polyobj_t *po;
829 	BOOL blocked;
830 
831 	if(!(po = GetPolyobj(num)))
832 	{
833 		I_Error("PO_RotatePolyobj: Invalid polyobj number: %d\n", num);
834 	}
835 	an = (po->angle+angle)>>ANGLETOFINESHIFT;
836 
837 	UnLinkPolyobj(po);
838 
839 	segList = po->segs;
840 	originalPts = po->originalPts;
841 	prevPts = po->prevPts;
842 
843 	for(count = po->numsegs; count; count--, segList++, originalPts++,
844 		prevPts++)
845 	{
846 		prevPts->x = (*segList)->v1->x;
847 		prevPts->y = (*segList)->v1->y;
848 		(*segList)->v1->x = originalPts->x;
849 		(*segList)->v1->y = originalPts->y;
850 		RotatePt (an, &(*segList)->v1->x, &(*segList)->v1->y, po->startSpot[0],
851 			po->startSpot[1]);
852 	}
853 	segList = po->segs;
854 	blocked = false;
855 	validcount++;
856 	for (count = po->numsegs; count; count--, segList++)
857 	{
858 		if (CheckMobjBlocking(*segList, po))
859 		{
860 			blocked = true;
861 		}
862 		if ((*segList)->linedef->validcount != validcount)
863 		{
864 			UpdateSegBBox(*segList);
865 			line_t *line = (*segList)->linedef;
866 			//if (line->sidenum[0] != -1)
867 			//	ADecal::FixForSide (&sides[line->sidenum[0]]);
868 			//if (line->sidenum[1] != -1)
869 			//	ADecal::FixForSide (&sides[line->sidenum[1]]);
870 			line->validcount = validcount;
871 		}
872 		(*segList)->angle += angle;
873 	}
874 	if (blocked)
875 	{
876 		segList = po->segs;
877 		prevPts = po->prevPts;
878 		for (count = po->numsegs; count; count--, segList++, prevPts++)
879 		{
880 			(*segList)->v1->x = prevPts->x;
881 			(*segList)->v1->y = prevPts->y;
882 		}
883 		segList = po->segs;
884 		validcount++;
885 		for (count = po->numsegs; count; count--, segList++, prevPts++)
886 		{
887 			if ((*segList)->linedef->validcount != validcount)
888 			{
889 				UpdateSegBBox(*segList);
890 				line_t *line = (*segList)->linedef;
891 				//if (line->sidenum[0] != -1)
892 				//	ADecal::FixForSide (&sides[line->sidenum[0]]);
893 				//if (line->sidenum[1] != -1)
894 				//	ADecal::FixForSide (&sides[line->sidenum[1]]);
895 				line->validcount = validcount;
896 			}
897 			(*segList)->angle -= angle;
898 		}
899 		LinkPolyobj(po);
900 		return false;
901 	}
902 	po->angle += angle;
903 	LinkPolyobj(po);
904 	return true;
905 }
906 
907 //
908 // UnLinkPolyobj
909 //
UnLinkPolyobj(polyobj_t * po)910 static void UnLinkPolyobj (polyobj_t *po)
911 {
912 	polyblock_t *link;
913 	int i, j;
914 	int index;
915 
916 	// remove the polyobj from each blockmap section
917 	for(j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++)
918 	{
919 		index = j*bmapwidth;
920 		for(i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
921 		{
922 			if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight)
923 			{
924 				link = PolyBlockMap[index+i];
925 				while(link != NULL && link->polyobj != po)
926 				{
927 					link = link->next;
928 				}
929 				if(link == NULL)
930 				{ // polyobj not located in the link cell
931 					continue;
932 				}
933 				link->polyobj = NULL;
934 			}
935 		}
936 	}
937 }
938 
939 //
940 // LinkPolyobj
941 //
LinkPolyobj(polyobj_t * po)942 static void LinkPolyobj (polyobj_t *po)
943 {
944 	int leftX, rightX;
945 	int topY, bottomY;
946 	seg_t **tempSeg;
947 	polyblock_t **link;
948 	polyblock_t *tempLink;
949 	int i, j;
950 
951 	// calculate the polyobj bbox
952 	tempSeg = po->segs;
953 	rightX = leftX = (*tempSeg)->v1->x;
954 	topY = bottomY = (*tempSeg)->v1->y;
955 
956 	for(i = 0; i < po->numsegs; i++, tempSeg++)
957 	{
958 		if((*tempSeg)->v1->x > rightX)
959 		{
960 			rightX = (*tempSeg)->v1->x;
961 		}
962 		if((*tempSeg)->v1->x < leftX)
963 		{
964 			leftX = (*tempSeg)->v1->x;
965 		}
966 		if((*tempSeg)->v1->y > topY)
967 		{
968 			topY = (*tempSeg)->v1->y;
969 		}
970 		if((*tempSeg)->v1->y < bottomY)
971 		{
972 			bottomY = (*tempSeg)->v1->y;
973 		}
974 	}
975 	po->bbox[BOXRIGHT] = (rightX-bmaporgx)>>MAPBLOCKSHIFT;
976 	po->bbox[BOXLEFT] = (leftX-bmaporgx)>>MAPBLOCKSHIFT;
977 	po->bbox[BOXTOP] = (topY-bmaporgy)>>MAPBLOCKSHIFT;
978 	po->bbox[BOXBOTTOM] = (bottomY-bmaporgy)>>MAPBLOCKSHIFT;
979 	// add the polyobj to each blockmap section
980 	for(j = po->bbox[BOXBOTTOM]*bmapwidth; j <= po->bbox[BOXTOP]*bmapwidth;
981 		j += bmapwidth)
982 	{
983 		for(i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
984 		{
985 			if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth)
986 			{
987 				link = &PolyBlockMap[j+i];
988 				if(!(*link))
989 				{ // Create a new link at the current block cell
990 					*link = (polyblock_t *)Z_Malloc(sizeof(polyblock_t), PU_LEVEL, 0);
991 					(*link)->next = NULL;
992 					(*link)->prev = NULL;
993 					(*link)->polyobj = po;
994 					continue;
995 				}
996 				else
997 				{
998 					tempLink = *link;
999 					while(tempLink->next != NULL && tempLink->polyobj != NULL)
1000 					{
1001 						tempLink = tempLink->next;
1002 					}
1003 				}
1004 				if(tempLink->polyobj == NULL)
1005 				{
1006 					tempLink->polyobj = po;
1007 					continue;
1008 				}
1009 				else
1010 				{
1011 					tempLink->next = (polyblock_t *)Z_Malloc (sizeof(polyblock_t),
1012 						PU_LEVEL, 0);
1013 					tempLink->next->next = NULL;
1014 					tempLink->next->prev = tempLink;
1015 					tempLink->next->polyobj = po;
1016 				}
1017 			}
1018 			// else, don't link the polyobj, since it's off the map
1019 		}
1020 	}
1021 }
1022 
1023 //
1024 // CheckMobjBlocking
1025 //
CheckMobjBlocking(seg_t * seg,polyobj_t * po)1026 static BOOL CheckMobjBlocking (seg_t *seg, polyobj_t *po)
1027 {
1028 	AActor *mobj;
1029 	int i, j;
1030 	int left, right, top, bottom;
1031 	fixed_t tmbbox[4];
1032 	line_t *ld;
1033 	BOOL blocked;
1034 
1035 	ld = seg->linedef;
1036 
1037 	top = (ld->bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
1038 	bottom = (ld->bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
1039 	left = (ld->bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
1040 	right = (ld->bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
1041 
1042 	blocked = false;
1043 
1044 	bottom = bottom < 0 ? 0 : bottom;
1045 	bottom = bottom >= bmapheight ? bmapheight-1 : bottom;
1046 	top = top < 0 ? 0 : top;
1047 	top = top >= bmapheight  ? bmapheight-1 : top;
1048 	left = left < 0 ? 0 : left;
1049 	left = left >= bmapwidth ? bmapwidth-1 : left;
1050 	right = right < 0 ? 0 : right;
1051 	right = right >= bmapwidth ?  bmapwidth-1 : right;
1052 
1053 	for (j = bottom*bmapwidth; j <= top*bmapwidth; j += bmapwidth)
1054 	{
1055 		for (i = left; i <= right; i++)
1056 		{
1057 			for (mobj = blocklinks[j+i]; mobj; mobj = mobj->bmapnode.Next(i, j/bmapwidth))
1058 			{
1059 				if ((mobj->flags&MF_SOLID) && !(mobj->flags&MF_NOCLIP))
1060 				{
1061 					tmbbox[BOXTOP] = mobj->y+mobj->radius;
1062 					tmbbox[BOXBOTTOM] = mobj->y-mobj->radius;
1063 					tmbbox[BOXLEFT] = mobj->x-mobj->radius;
1064 					tmbbox[BOXRIGHT] = mobj->x+mobj->radius;
1065 
1066 					if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
1067 						||      tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
1068 						||      tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
1069 						||      tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
1070 					{
1071 						continue;
1072 					}
1073 					if (P_BoxOnLineSide(tmbbox, ld) != -1)
1074 					{
1075 						continue;
1076 					}
1077 					ThrustMobj (mobj, seg, po);
1078 					blocked = true;
1079 				}
1080 			}
1081 		}
1082 	}
1083 	return blocked;
1084 }
1085 
1086 //
1087 // InitBlockMap
1088 //
InitBlockMap(void)1089 static void InitBlockMap (void)
1090 {
1091 	int i;
1092 
1093 	PolyBlockMap = (polyblock_t **)Z_Malloc (bmapwidth*bmapheight*sizeof(polyblock_t *),
1094 		PU_LEVEL, 0);
1095 	memset (PolyBlockMap, 0, bmapwidth*bmapheight*sizeof(polyblock_t *));
1096 
1097 	for (i = 0; i < po_NumPolyobjs; i++)
1098 	{
1099 		LinkPolyobj(&polyobjs[i]);
1100 	}
1101 }
1102 
1103 //
1104 // IterFindPolySegs
1105 //
1106 //              Passing NULL for segList will cause IterFindPolySegs to
1107 //      count the number of segs in the polyobj
IterFindPolySegs(int x,int y,seg_t ** segList)1108 static void IterFindPolySegs (int x, int y, seg_t **segList)
1109 {
1110 	int i;
1111 
1112 	if (x == PolyStartX && y == PolyStartY)
1113 	{
1114 		return;
1115 	}
1116 	for (i = 0; i < numsegs; i++)
1117 	{
1118 		if (segs[i].v1->x == x && segs[i].v1->y == y)
1119 		{
1120 			if(!segList)
1121 			{
1122 				PolySegCount++;
1123 			}
1124 			else
1125 			{
1126 				*segList++ = &segs[i];
1127 			}
1128 			IterFindPolySegs (segs[i].v2->x, segs[i].v2->y, segList);
1129 			return;
1130 		}
1131 	}
1132 	I_Error ("IterFindPolySegs: Non-closed Polyobj located.\n");
1133 }
1134 
1135 //
1136 // SpawnPolyobj
1137 //
SpawnPolyobj(int index,int tag,BOOL crush)1138 static void SpawnPolyobj (int index, int tag, BOOL crush)
1139 {
1140 	int i;
1141 	int j;
1142 	int psIndex;
1143 	int psIndexOld;
1144 	seg_t *polySegList[PO_MAXPOLYSEGS];
1145 
1146 	for (i = 0; i < numsegs; i++)
1147 	{
1148 		if (segs[i].linedef->special == PO_LINE_START &&
1149 			segs[i].linedef->args[0] == tag)
1150 		{
1151 			if (polyobjs[index].segs)
1152 			{
1153 				I_Error ("SpawnPolyobj: Polyobj %d already spawned.\n", tag);
1154 			}
1155 			segs[i].linedef->special = 0;
1156 			segs[i].linedef->args[0] = 0;
1157 			PolySegCount = 1;
1158 			PolyStartX = segs[i].v1->x;
1159 			PolyStartY = segs[i].v1->y;
1160 			IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, NULL);
1161 
1162 			polyobjs[index].numsegs = PolySegCount;
1163 			polyobjs[index].segs = (seg_t **)Z_Malloc (PolySegCount*sizeof(seg_t *),
1164 				PU_LEVEL, 0);
1165 			polyobjs[index].segs[0] = &segs[i]; // insert the first seg
1166 			IterFindPolySegs (segs[i].v2->x, segs[i].v2->y,
1167 				polyobjs[index].segs+1);
1168 			polyobjs[index].crush = crush;
1169 			polyobjs[index].tag = tag;
1170 			polyobjs[index].seqType = segs[i].linedef->args[2];
1171 			if (polyobjs[index].seqType < 0 || polyobjs[index].seqType > 63)
1172 			{
1173 				polyobjs[index].seqType = 0;
1174 			}
1175 			break;
1176 		}
1177 	}
1178 	if (!polyobjs[index].segs)
1179 	{ // didn't find a polyobj through PO_LINE_START
1180 		psIndex = 0;
1181 		polyobjs[index].numsegs = 0;
1182 		for (j = 1; j < PO_MAXPOLYSEGS; j++)
1183 		{
1184 			psIndexOld = psIndex;
1185 			for (i = 0; i < numsegs; i++)
1186 			{
1187 				if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
1188 					segs[i].linedef->args[0] == tag)
1189 				{
1190 					if (!segs[i].linedef->args[1])
1191 					{
1192 						I_Error ("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n",
1193 							j+1, tag);
1194 					}
1195 					if (segs[i].linedef->args[1] == j)
1196 					{
1197 						polySegList[psIndex] = &segs[i];
1198 						polyobjs[index].numsegs++;
1199 						psIndex++;
1200 						if (psIndex > PO_MAXPOLYSEGS)
1201 						{
1202 							I_Error ("SpawnPolyobj: psIndex > PO_MAXPOLYSEGS\n");
1203 						}
1204 					}
1205 				}
1206 			}
1207 			// Clear out any specials for these segs...we cannot clear them out
1208 			// 	in the above loop, since we aren't guaranteed one seg per
1209 			//		linedef.
1210 			for (i = 0; i < numsegs; i++)
1211 			{
1212 				if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
1213 					segs[i].linedef->args[0] == tag && segs[i].linedef->args[1] == j)
1214 				{
1215 					segs[i].linedef->special = 0;
1216 					segs[i].linedef->args[0] = 0;
1217 				}
1218 			}
1219 			if (psIndex == psIndexOld)
1220 			{ // Check if an explicit line order has been skipped
1221 				// A line has been skipped if there are any more explicit
1222 				// lines with the current tag value
1223 				for (i = 0; i < numsegs; i++)
1224 				{
1225 					if(segs[i].linedef->special == PO_LINE_EXPLICIT &&
1226 						segs[i].linedef->args[0] == tag)
1227 					{
1228 						I_Error ("SpawnPolyobj: Missing explicit line %d for poly %d\n",
1229 							j, tag);
1230 					}
1231 				}
1232 			}
1233 		}
1234 		if (polyobjs[index].numsegs)
1235 		{
1236 			PolySegCount = polyobjs[index].numsegs; // PolySegCount used globally
1237 			polyobjs[index].crush = crush;
1238 			polyobjs[index].tag = tag;
1239 			polyobjs[index].segs = (seg_t **)Z_Malloc (polyobjs[index].numsegs
1240 				*sizeof(seg_t *), PU_LEVEL, 0);
1241 			for (i = 0; i < polyobjs[index].numsegs; i++)
1242 			{
1243 				polyobjs[index].segs[i] = polySegList[i];
1244 			}
1245 			polyobjs[index].seqType = (*polyobjs[index].segs)->linedef->args[3];
1246 			// Next, change the polyobj's first line to point to a mirror
1247 			//		if it exists
1248 			(*polyobjs[index].segs)->linedef->args[1] =
1249 				(*polyobjs[index].segs)->linedef->args[2];
1250 		}
1251 		else
1252 			I_Error ("SpawnPolyobj: Poly %d does not exist\n", tag);
1253 	}
1254 }
1255 
1256 //
1257 // TranslateToStartSpot
1258 //
TranslateToStartSpot(int tag,int originX,int originY)1259 static void TranslateToStartSpot (int tag, int originX, int originY)
1260 {
1261 	seg_t **tempSeg;
1262 	seg_t **veryTempSeg;
1263 	vertex_t *tempPt;
1264 	subsector_t *sub;
1265 	polyobj_t *po;
1266 	int deltaX;
1267 	int deltaY;
1268 	vertex_t avg; // used to find a polyobj's center, and hence subsector
1269 	int i;
1270 
1271 	po = NULL;
1272 	for (i = 0; i < po_NumPolyobjs; i++)
1273 	{
1274 		if (polyobjs[i].tag == tag)
1275 		{
1276 			po = &polyobjs[i];
1277 			break;
1278 		}
1279 	}
1280 	if (po == NULL)
1281 	{ // didn't match the tag with a polyobj tag
1282 		I_Error("TranslateToStartSpot: Unable to match polyobj tag: %d\n",
1283 			tag);
1284 	}
1285 	if (po->segs == NULL)
1286 	{
1287 		I_Error ("TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag);
1288 	}
1289 	po->originalPts = (vertex_t *)Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, 0);
1290 	po->prevPts = (vertex_t *)Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, 0);
1291 	deltaX = originX-po->startSpot[0];
1292 	deltaY = originY-po->startSpot[1];
1293 
1294 	tempSeg = po->segs;
1295 	tempPt = po->originalPts;
1296 	avg.x = 0;
1297 	avg.y = 0;
1298 
1299 	validcount++;
1300 	for (i = 0; i < po->numsegs; i++, tempSeg++, tempPt++)
1301 	{
1302 		if ((*tempSeg)->linedef->validcount != validcount)
1303 		{
1304 			(*tempSeg)->linedef->bbox[BOXTOP] -= deltaY;
1305 			(*tempSeg)->linedef->bbox[BOXBOTTOM] -= deltaY;
1306 			(*tempSeg)->linedef->bbox[BOXLEFT] -= deltaX;
1307 			(*tempSeg)->linedef->bbox[BOXRIGHT] -= deltaX;
1308 			(*tempSeg)->linedef->validcount = validcount;
1309 		}
1310 		for (veryTempSeg = po->segs; veryTempSeg != tempSeg; veryTempSeg++)
1311 		{
1312 			if((*veryTempSeg)->v1 == (*tempSeg)->v1)
1313 			{
1314 				break;
1315 			}
1316 		}
1317 		if (veryTempSeg == tempSeg)
1318 		{ // the point hasn't been translated, yet
1319 			(*tempSeg)->v1->x -= deltaX;
1320 			(*tempSeg)->v1->y -= deltaY;
1321 		}
1322 		avg.x += (*tempSeg)->v1->x>>FRACBITS;
1323 		avg.y += (*tempSeg)->v1->y>>FRACBITS;
1324 		// the original Pts are based off the startSpot Pt, and are
1325 		// unique to each seg, not each linedef
1326 		tempPt->x = (*tempSeg)->v1->x-po->startSpot[0];
1327 		tempPt->y = (*tempSeg)->v1->y-po->startSpot[1];
1328 	}
1329 	avg.x /= po->numsegs;
1330 	avg.y /= po->numsegs;
1331 	sub = P_PointInSubsector (avg.x<<FRACBITS, avg.y<<FRACBITS);
1332 	if (sub->poly != NULL)
1333 	{
1334 		I_Error ("PO_TranslateToStartSpot: Multiple polyobjs in a single subsector.\n");
1335 	}
1336 	sub->poly = po;
1337 }
1338 
1339 //
1340 // PO_Init
1341 //
PO_Init(void)1342 void PO_Init (void)
1343 {
1344 	// [RH] Hexen found the polyobject-related things by reloading the map's
1345 	//		THINGS lump here and scanning through it. I have P_SpawnMapThing()
1346 	//		record those things instead, so that in here, we simply need to
1347 	//		look at the polyspawns list.
1348 	polyspawns_t *polyspawn, **prev;
1349 	int polyIndex;
1350 
1351 	polyobjs = (polyobj_t *)Z_Malloc (po_NumPolyobjs*sizeof(polyobj_t), PU_LEVEL, 0);
1352 	memset (polyobjs, 0, po_NumPolyobjs*sizeof(polyobj_t));
1353 
1354 	polyIndex = 0; // index polyobj number
1355 	// Find the startSpot points, and spawn each polyobj
1356 	for (polyspawn = polyspawns, prev = &polyspawns; polyspawn;)
1357 	{
1358 		// 9301 (3001) = no crush, 9302 (3002) = crushing
1359 		if (polyspawn->type == PO_SPAWN_TYPE || polyspawn->type == PO_SPAWNCRUSH_TYPE)
1360 		{ // Polyobj StartSpot Pt.
1361 			polyobjs[polyIndex].startSpot[0] = polyspawn->x;
1362 			polyobjs[polyIndex].startSpot[1] = polyspawn->y;
1363 			SpawnPolyobj(polyIndex, polyspawn->angle, (polyspawn->type == PO_SPAWNCRUSH_TYPE));
1364 			polyIndex++;
1365 			*prev = polyspawn->next;
1366 			delete polyspawn;
1367 			polyspawn = *prev;
1368 		} else {
1369 			prev = &polyspawn->next;
1370 			polyspawn = polyspawn->next;
1371 		}
1372 	}
1373 	for (polyspawn = polyspawns; polyspawn;)
1374 	{
1375 		polyspawns_t *next = polyspawn->next;
1376 		if (polyspawn->type == PO_ANCHOR_TYPE)
1377 		{ // Polyobj Anchor Pt.
1378 			TranslateToStartSpot (polyspawn->angle, polyspawn->x, polyspawn->y);
1379 		}
1380 		delete polyspawn;
1381 		polyspawn = next;
1382 	}
1383 	polyspawns = NULL;
1384 
1385 	// check for a startspot without an anchor point
1386 	for (polyIndex = 0; polyIndex < po_NumPolyobjs; polyIndex++)
1387 	{
1388 		if (!polyobjs[polyIndex].originalPts)
1389 		{
1390 			I_Error ("PO_Init: StartSpot located without an Anchor point: %d\n",
1391 				polyobjs[polyIndex].tag);
1392 		}
1393 	}
1394 	InitBlockMap();
1395 }
1396 
1397 //
1398 // PO_Busy
1399 //
PO_Busy(int polyobj)1400 BOOL PO_Busy (int polyobj)
1401 {
1402 	polyobj_t *poly;
1403 
1404 	poly = GetPolyobj (polyobj);
1405 	if (!poly->specialdata)
1406 	{
1407 		return false;
1408 	}
1409 	else
1410 	{
1411 		return true;
1412 	}
1413 }
1414 
1415 VERSION_CONTROL (po_man_cpp, "$Id: po_man.cpp 4542 2014-02-09 17:39:42Z dr_sean $")
1416