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