2 //**************************************************************************
4 //** PO_MAN.C : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
13 // HEADER FILES ------------------------------------------------------------
19 // MACROS ------------------------------------------------------------------
21 #define PO_MAXPOLYSEGS 64
23 // TYPES -------------------------------------------------------------------
25 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
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);
31 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
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,
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);
47 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
51 // PUBLIC DATA DEFINITIONS -------------------------------------------------
53 polyblock_t **PolyBlockMap;
54 polyobj_t *polyobjs; // list of all poly-objects on the level
57 // PRIVATE DATA DEFINITIONS ------------------------------------------------
59 static int PolySegCount;
60 static fixed_t PolyStartX;
61 static fixed_t PolyStartY;
63 // CODE --------------------------------------------------------------------
65 // ===== Polyobj Event Code =====
67 //==========================================================================
71 //==========================================================================
73 void T_RotatePoly(polyevent_t *pe)
78 if(PO_RotatePolyobj(pe->polyobj, pe->speed))
80 absSpeed = abs(pe->speed);
83 { // perpetual polyobj
89 poly = GetPolyobj(pe->polyobj);
90 if(poly->specialdata == pe)
92 poly->specialdata = NULL;
94 SN_StopSequence((mobj_t *)&poly->startSpot);
95 P_PolyobjFinished(poly->tag);
96 P_RemoveThinker(&pe->thinker);
98 if(pe->dist < absSpeed)
100 pe->speed = pe->dist*(pe->speed < 0 ? -1 : 1);
105 //==========================================================================
109 //==========================================================================
111 boolean EV_RotatePoly(line_t *line, byte *args, int direction, boolean
120 if((poly = GetPolyobj(polyNum))) /* jim parens added for gcc */
122 if(poly->specialdata && !overRide)
123 { // poly is already moving
129 I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
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;
143 pe->dist = args[2]*(ANGLE_90/64); // Angle
148 pe->dist = ANGLE_MAX-1;
150 pe->speed = (args[1]*direction*(ANGLE_90/64))>>3;
151 poly->specialdata = pe;
152 SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
155 /* jim parens added for gcc */
156 while((mirror = GetPolyobjMirror(polyNum)))
158 poly = GetPolyobj(mirror);
159 if(poly && poly->specialdata && !overRide)
160 { // mirroring poly is already in motion
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;
176 pe->dist = args[2]*(ANGLE_90/64); // Angle
181 pe->dist = ANGLE_MAX-1;
183 if((poly = GetPolyobj(polyNum))) /* jim parens added for gcc */
185 poly->specialdata = pe;
189 I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
191 direction = -direction;
192 pe->speed = (args[1]*direction*(ANGLE_90/64))>>3;
194 SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
200 //==========================================================================
204 //==========================================================================
206 void T_MovePoly(polyevent_t *pe)
211 if(PO_MovePolyobj(pe->polyobj, pe->xSpeed, pe->ySpeed))
213 absSpeed = abs(pe->speed);
214 pe->dist -= absSpeed;
217 poly = GetPolyobj(pe->polyobj);
218 if(poly->specialdata == pe)
220 poly->specialdata = NULL;
222 SN_StopSequence((mobj_t *)&poly->startSpot);
223 P_PolyobjFinished(poly->tag);
224 P_RemoveThinker(&pe->thinker);
226 if(pe->dist < absSpeed)
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]);
235 //==========================================================================
239 //==========================================================================
241 boolean EV_MovePoly(line_t *line, byte *args, boolean timesEight, boolean
251 if((poly = GetPolyobj(polyNum))) /* jim parens added for gcc */
253 if(poly->specialdata && !overRide)
254 { // poly is already moving
260 I_Error("EV_MovePoly: Invalid polyobj num: %d\n", polyNum);
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;
268 pe->dist = args[3]*8*FRACUNIT;
272 pe->dist = args[3]*FRACUNIT; // Distance
274 pe->speed = args[1]*(FRACUNIT/8);
275 poly->specialdata = pe;
277 an = args[2]*(ANGLE_90/64);
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+
285 /* jim parens added for gcc */
286 while((mirror = GetPolyobjMirror(polyNum)))
288 poly = GetPolyobj(mirror);
289 if(poly && poly->specialdata && !overRide)
290 { // mirroring poly is already in motion
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;
300 pe->dist = args[3]*8*FRACUNIT;
304 pe->dist = args[3]*FRACUNIT; // Distance
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]);
312 SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
318 //==========================================================================
322 //==========================================================================
324 void T_PolyDoor(polydoor_t *pd)
333 poly = GetPolyobj(pd->polyobj);
334 SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE+
342 if(PO_MovePolyobj(pd->polyobj, pd->xSpeed, pd->ySpeed))
344 absSpeed = abs(pd->speed);
345 pd->dist -= absSpeed;
348 poly = GetPolyobj(pd->polyobj);
349 SN_StopSequence((mobj_t *)&poly->startSpot);
352 pd->dist = pd->totalDist;
354 pd->tics = pd->waitTics;
355 pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT)-
357 pd->xSpeed = -pd->xSpeed;
358 pd->ySpeed = -pd->ySpeed;
362 if(poly->specialdata == pd)
364 poly->specialdata = NULL;
366 P_PolyobjFinished(poly->tag);
367 P_RemoveThinker(&pd->thinker);
373 poly = GetPolyobj(pd->polyobj);
374 if(poly->crush || !pd->close)
375 { // continue moving if the poly is a crusher, or is opening
380 pd->dist = pd->totalDist-pd->dist;
381 pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT)-
383 pd->xSpeed = -pd->xSpeed;
384 pd->ySpeed = -pd->ySpeed;
386 SN_StartSequence((mobj_t *)&poly->startSpot,
387 SEQ_DOOR_STONE+poly->seqType);
392 if(PO_RotatePolyobj(pd->polyobj, pd->speed))
394 absSpeed = abs(pd->speed);
396 { // perpetual polyobj
399 pd->dist -= absSpeed;
402 poly = GetPolyobj(pd->polyobj);
403 SN_StopSequence((mobj_t *)&poly->startSpot);
406 pd->dist = pd->totalDist;
408 pd->tics = pd->waitTics;
409 pd->speed = -pd->speed;
413 if(poly->specialdata == pd)
415 poly->specialdata = NULL;
417 P_PolyobjFinished(poly->tag);
418 P_RemoveThinker(&pd->thinker);
424 poly = GetPolyobj(pd->polyobj);
425 if(poly->crush || !pd->close)
426 { // continue moving if the poly is a crusher, or is opening
430 { // open back up and rewait
431 pd->dist = pd->totalDist-pd->dist;
432 pd->speed = -pd->speed;
434 SN_StartSequence((mobj_t *)&poly->startSpot,
435 SEQ_DOOR_STONE+poly->seqType);
444 //==========================================================================
448 //==========================================================================
450 boolean EV_OpenPolyDoor(line_t *line, byte *args, podoortype_t type)
456 angle_t an = 0; /* jim added initialiser */
459 if((poly = GetPolyobj(polyNum))) /* jim parens added for gcc */
461 if(poly->specialdata)
462 { // poly is already moving
468 I_Error("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum);
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;
475 pd->polyobj = polyNum;
476 if(type == PODOOR_SLIDE)
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+
489 else if(type == PODOOR_SWING)
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+
500 poly->specialdata = pd;
502 /* jim parens added for gcc */
503 while((mirror = GetPolyobjMirror(polyNum)))
505 poly = GetPolyobj(mirror);
506 if(poly && poly->specialdata)
507 { // mirroring poly is already in motion
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;
516 poly->specialdata = pd;
517 if(type == PODOOR_SLIDE)
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+
530 else if(type == PODOOR_SWING)
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+
545 // ===== Higher Level Poly Interface code =====
547 //==========================================================================
551 //==========================================================================
553 static polyobj_t *GetPolyobj(int polyNum)
557 for(i = 0; i < po_NumPolyobjs; i++)
559 if(polyobjs[i].tag == polyNum)
567 //==========================================================================
571 //==========================================================================
573 static int GetPolyobjMirror(int poly)
577 for(i = 0; i < po_NumPolyobjs; i++)
579 if(polyobjs[i].tag == poly)
581 return((*polyobjs[i].segs)->linedef->arg2);
587 //==========================================================================
591 //==========================================================================
593 static void ThrustMobj(mobj_t *mobj, seg_t *seg, polyobj_t *po)
602 if(!(mobj->flags&MF_SHOOTABLE) && !mobj->player)
606 thrustAngle = (seg->angle-ANGLE_90)>>ANGLETOFINESHIFT;
608 pe = po->specialdata;
611 if(pe->thinker.function == T_RotatePoly)
613 force = pe->speed>>8;
617 force = pe->speed>>3;
623 else if(force > 4*FRACUNIT)
633 thrustX = FixedMul(force, finecosine[thrustAngle]);
634 thrustY = FixedMul(force, finesine[thrustAngle]);
635 mobj->momx += thrustX;
636 mobj->momy += thrustY;
639 if(!P_CheckPosition(mobj, mobj->x+thrustX, mobj->y+thrustY))
641 P_DamageMobj(mobj, NULL, NULL, 3);
646 //==========================================================================
650 //==========================================================================
652 static void UpdateSegBBox(seg_t *seg)
658 if(seg->v1->x < seg->v2->x)
660 line->bbox[BOXLEFT] = seg->v1->x;
661 line->bbox[BOXRIGHT] = seg->v2->x;
665 line->bbox[BOXLEFT] = seg->v2->x;
666 line->bbox[BOXRIGHT] = seg->v1->x;
668 if(seg->v1->y < seg->v2->y)
670 line->bbox[BOXBOTTOM] = seg->v1->y;
671 line->bbox[BOXTOP] = seg->v2->y;
675 line->bbox[BOXBOTTOM] = seg->v2->y;
676 line->bbox[BOXTOP] = seg->v1->y;
679 // Update the line's slopetype
680 line->dx = line->v2->x - line->v1->x;
681 line->dy = line->v2->y - line->v1->y;
684 line->slopetype = ST_VERTICAL;
688 line->slopetype = ST_HORIZONTAL;
692 if(FixedDiv(line->dy, line->dx) > 0)
694 line->slopetype = ST_POSITIVE;
698 line->slopetype = ST_NEGATIVE;
703 //==========================================================================
707 //==========================================================================
709 boolean PO_MovePolyobj(int num, int x, int y)
718 if(!(po = GetPolyobj(num)))
720 I_Error("PO_MovePolyobj: Invalid polyobj number: %d\n", num);
726 prevPts = po->prevPts;
730 for(count = po->numsegs; count; count--, segList++, prevPts++)
732 if((*segList)->linedef->validcount != validcount)
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;
740 for(veryTempSeg = po->segs; veryTempSeg != segList;
743 if((*veryTempSeg)->v1 == (*segList)->v1)
748 if(veryTempSeg == segList)
750 (*segList)->v1->x += x;
751 (*segList)->v1->y += y;
753 (*prevPts).x += x; // previous points are unique for each seg
757 for(count = po->numsegs; count; count--, segList++)
759 if(CheckMobjBlocking(*segList, po))
768 prevPts = po->prevPts;
772 if((*segList)->linedef->validcount != validcount)
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;
780 for(veryTempSeg = po->segs; veryTempSeg != segList;
783 if((*veryTempSeg)->v1 == (*segList)->v1)
788 if(veryTempSeg == segList)
790 (*segList)->v1->x -= x;
791 (*segList)->v1->y -= y;
801 po->startSpot.x += x;
802 po->startSpot.y += y;
807 //==========================================================================
811 //==========================================================================
813 static void RotatePt(int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY)
821 gxt = FixedMul(trx, finecosine[an]);
822 gyt = FixedMul(try, finesine[an]);
823 *x = (gxt-gyt)+startSpotX;
825 gxt = FixedMul(trx, finesine[an]);
826 gyt = FixedMul(try, finecosine[an]);
827 *y = (gyt+gxt)+startSpotY;
830 //==========================================================================
834 //==========================================================================
836 boolean PO_RotatePolyobj(int num, angle_t angle)
840 vertex_t *originalPts;
846 if(!(po = GetPolyobj(num)))
848 I_Error("PO_RotatePolyobj: Invalid polyobj number: %d\n", num);
850 an = (po->angle+angle)>>ANGLETOFINESHIFT;
855 originalPts = po->originalPts;
856 prevPts = po->prevPts;
858 for(count = po->numsegs; count; count--, segList++, originalPts++,
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,
871 for(count = po->numsegs; count; count--, segList++)
873 if(CheckMobjBlocking(*segList, po))
877 if((*segList)->linedef->validcount != validcount)
879 UpdateSegBBox(*segList);
880 (*segList)->linedef->validcount = validcount;
882 (*segList)->angle += angle;
887 prevPts = po->prevPts;
888 for(count = po->numsegs; count; count--, segList++, prevPts++)
890 (*segList)->v1->x = prevPts->x;
891 (*segList)->v1->y = prevPts->y;
895 for(count = po->numsegs; count; count--, segList++, prevPts++)
897 if((*segList)->linedef->validcount != validcount)
899 UpdateSegBBox(*segList);
900 (*segList)->linedef->validcount = validcount;
902 (*segList)->angle -= angle;
912 //==========================================================================
916 //==========================================================================
918 static void UnLinkPolyobj(polyobj_t *po)
924 // remove the polyobj from each blockmap section
925 for(j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++)
928 for(i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
930 if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight)
932 link = PolyBlockMap[index+i];
933 while(link != NULL && link->polyobj != po)
938 { // polyobj not located in the link cell
941 link->polyobj = NULL;
947 //==========================================================================
951 //==========================================================================
953 static void LinkPolyobj(polyobj_t *po)
959 polyblock_t *tempLink;
962 // calculate the polyobj bbox
964 rightX = leftX = (*tempSeg)->v1->x;
965 topY = bottomY = (*tempSeg)->v1->y;
967 for(i = 0; i < po->numsegs; i++, tempSeg++)
969 if((*tempSeg)->v1->x > rightX)
971 rightX = (*tempSeg)->v1->x;
973 if((*tempSeg)->v1->x < leftX)
975 leftX = (*tempSeg)->v1->x;
977 if((*tempSeg)->v1->y > topY)
979 topY = (*tempSeg)->v1->y;
981 if((*tempSeg)->v1->y < bottomY)
983 bottomY = (*tempSeg)->v1->y;
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;
994 for(i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
996 if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth)
998 link = &PolyBlockMap[j+i];
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;
1010 while(tempLink->next != NULL && tempLink->polyobj != NULL)
1012 tempLink = tempLink->next;
1015 if(tempLink->polyobj == NULL)
1017 tempLink->polyobj = po;
1022 tempLink->next = Z_Malloc(sizeof(polyblock_t),
1024 tempLink->next->next = NULL;
1025 tempLink->next->prev = tempLink;
1026 tempLink->next->polyobj = po;
1029 // else, don't link the polyobj, since it's off the map
1034 //==========================================================================
1036 // CheckMobjBlocking
1038 //==========================================================================
1040 static boolean CheckMobjBlocking(seg_t *seg, polyobj_t *po)
1044 int left, right, top, bottom;
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;
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;
1067 for(j = bottom*bmapwidth; j <= top*bmapwidth; j += bmapwidth)
1069 for(i = left; i <= right; i++)
1071 for(mobj = blocklinks[j+i]; mobj; mobj = mobj->bnext)
1073 if(mobj->flags&MF_SOLID || mobj->player)
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;
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])
1087 if(P_BoxOnLineSide(tmbbox, ld) != -1)
1091 ThrustMobj(mobj, seg, po);
1100 //==========================================================================
1104 //==========================================================================
1106 static void InitBlockMap(void)
1116 PolyBlockMap = Z_Malloc(bmapwidth*bmapheight*sizeof(polyblock_t *),
1118 memset(PolyBlockMap, 0, bmapwidth*bmapheight*sizeof(polyblock_t *));
1120 for(i = 0; i < po_NumPolyobjs; i++)
1122 LinkPolyobj(&polyobjs[i]);
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++)
1131 if((*segList)->v1->x < leftX)
1133 leftX = (*segList)->v1->x;
1135 if((*segList)->v1->x > rightX)
1137 rightX = (*segList)->v1->x;
1139 if((*segList)->v1->y < bottomY)
1141 bottomY = (*segList)->v1->y;
1143 if((*segList)->v1->y > topY)
1145 topY = (*segList)->v1->y;
1148 area = ((rightX>>FRACBITS)-(leftX>>FRACBITS))*
1149 ((topY>>FRACBITS)-(bottomY>>FRACBITS));
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,
1154 // rightX>>FRACBITS, bottomY>>FRACBITS);
1158 //==========================================================================
1162 // Passing NULL for segList will cause IterFindPolySegs to
1163 // count the number of segs in the polyobj
1164 //==========================================================================
1166 static void IterFindPolySegs(int x, int y, seg_t **segList)
1170 if(x == PolyStartX && y == PolyStartY)
1174 for(i = 0; i < numsegs; i++)
1176 if(segs[i].v1->x == x && segs[i].v1->y == y)
1184 *segList++ = &segs[i];
1186 IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, segList);
1190 I_Error("IterFindPolySegs: Non-closed Polyobj located.\n");
1194 //==========================================================================
1198 //==========================================================================
1200 static void SpawnPolyobj(int index, int tag, boolean crush)
1206 seg_t *polySegList[PO_MAXPOLYSEGS];
1208 for(i = 0; i < numsegs; i++)
1210 if(segs[i].linedef->special == PO_LINE_START &&
1211 segs[i].linedef->arg1 == tag)
1213 if(polyobjs[index].segs)
1215 I_Error("SpawnPolyobj: Polyobj %d already spawned.\n", tag);
1217 segs[i].linedef->special = 0;
1218 segs[i].linedef->arg1 = 0;
1220 PolyStartX = segs[i].v1->x;
1221 PolyStartY = segs[i].v1->y;
1222 IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, NULL);
1224 polyobjs[index].numsegs = PolySegCount;
1225 polyobjs[index].segs = Z_Malloc(PolySegCount*sizeof(seg_t *),
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)
1236 polyobjs[index].seqType = 0;
1241 if(!polyobjs[index].segs)
1242 { // didn't find a polyobj through PO_LINE_START
1244 polyobjs[index].numsegs = 0;
1245 for(j = 1; j < PO_MAXPOLYSEGS; j++)
1247 psIndexOld = psIndex;
1248 for (i = 0; i < numsegs; i++)
1250 if(segs[i].linedef->special == PO_LINE_EXPLICIT &&
1251 segs[i].linedef->arg1 == tag)
1253 if(!segs[i].linedef->arg2)
1255 I_Error("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n",
1258 if(segs[i].linedef->arg2 == j)
1260 polySegList[psIndex] = &segs[i];
1261 polyobjs[index].numsegs++;
1263 if(psIndex > PO_MAXPOLYSEGS)
1265 I_Error("SpawnPolyobj: psIndex > PO_MAXPOLYSEGS\n");
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
1273 for(i = 0; i < numsegs; i++)
1275 if(segs[i].linedef->special == PO_LINE_EXPLICIT &&
1276 segs[i].linedef->arg1 == tag && segs[i].linedef->arg2 == j)
1278 segs[i].linedef->special = 0;
1279 segs[i].linedef->arg1 = 0;
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++)
1288 if(segs[i].linedef->special == PO_LINE_EXPLICIT &&
1289 segs[i].linedef->arg1 == tag)
1291 I_Error("SpawnPolyobj: Missing explicit line %d for poly %d\n",
1297 if(polyobjs[index].numsegs)
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++)
1306 polyobjs[index].segs[i] = polySegList[i];
1308 polyobjs[index].seqType = (*polyobjs[index].segs)->linedef->arg4;
1310 // Next, change the polyobjs first line to point to a mirror
1312 (*polyobjs[index].segs)->linedef->arg2 =
1313 (*polyobjs[index].segs)->linedef->arg3;
1317 //==========================================================================
1319 // TranslateToStartSpot
1321 //==========================================================================
1323 static void TranslateToStartSpot(int tag, int originX, int originY)
1326 seg_t **veryTempSeg;
1332 vertex_t avg; // used to find a polyobj's center, and hence subsector
1336 for(i = 0; i < po_NumPolyobjs; i++)
1338 if(polyobjs[i].tag == tag)
1345 { // didn't match the tag with a polyobj tag
1346 I_Error("TranslateToStartSpot: Unable to match polyobj tag: %d\n",
1349 if(po->segs == NULL)
1351 I_Error("TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag);
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;
1359 tempPt = po->originalPts;
1364 for(i = 0; i < po->numsegs; i++, tempSeg++, tempPt++)
1366 if((*tempSeg)->linedef->validcount != validcount)
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;
1374 for(veryTempSeg = po->segs; veryTempSeg != tempSeg; veryTempSeg++)
1376 if((*veryTempSeg)->v1 == (*tempSeg)->v1)
1381 if(veryTempSeg == tempSeg)
1382 { // the point hasn't been translated, yet
1383 (*tempSeg)->v1->x -= deltaX;
1384 (*tempSeg)->v1->y -= deltaY;
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;
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)
1398 I_Error("PO_TranslateToStartSpot: Multiple polyobjs in a single subsector.\n");
1403 //==========================================================================
1407 //==========================================================================
1409 void PO_Init(int lump)
1417 polyobjs = Z_Malloc(po_NumPolyobjs*sizeof(polyobj_t), PU_LEVEL, 0);
1418 memset(polyobjs, 0, po_NumPolyobjs*sizeof(polyobj_t));
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++)
1427 mt->x = SHORT(mt->x);
1428 mt->y = SHORT(mt->y);
1429 mt->angle = SHORT(mt->angle);
1430 mt->type = SHORT(mt->type);
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));
1441 mt = (mapthing_t *)data;
1442 for (i = 0; i < numthings; i++, mt++)
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);
1454 // check for a startspot without an anchor point
1455 for(i = 0; i < po_NumPolyobjs; i++)
1457 if(!polyobjs[i].originalPts)
1459 I_Error("PO_Init: StartSpot located without an Anchor point: %d\n",
1466 //==========================================================================
1470 //==========================================================================
1472 boolean PO_Busy(int polyobj)
1476 poly = GetPolyobj(polyobj);
1477 if(!poly->specialdata)