ref: e3260fcecfc83f51e83e96e470c4dfbeacfe64d3
dir: /po_man.c/
//************************************************************************** //** //** PO_MAN.C : Heretic 2 : Raven Software, Corp. //** //** $Revision: 575 $ //** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $ //** //************************************************************************** // HEADER FILES ------------------------------------------------------------ #include "h2stdinc.h" #include "h2def.h" #include "p_local.h" #include "r_local.h" // MACROS ------------------------------------------------------------------ #define PO_MAXPOLYSEGS 64 // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- boolean PO_MovePolyobj(int num, int x, int y); boolean PO_RotatePolyobj(int num, angle_t angle); void PO_Init(int lump); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static polyobj_t *GetPolyobj(int polyNum); static int GetPolyobjMirror(int poly); static void ThrustMobj(mobj_t *mobj, seg_t *seg, polyobj_t *po); static void UpdateSegBBox(seg_t *seg); static void RotatePt(int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY); static void UnLinkPolyobj(polyobj_t *po); static void LinkPolyobj(polyobj_t *po); static boolean CheckMobjBlocking(seg_t *seg, polyobj_t *po); static void InitBlockMap(void); static void IterFindPolySegs(int x, int y, seg_t **segList); static void SpawnPolyobj(int idx, int tag, boolean crush); static void TranslateToStartSpot(int tag, int originX, int originY); // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern seg_t *segs; // PUBLIC DATA DEFINITIONS ------------------------------------------------- polyblock_t **PolyBlockMap; polyobj_t *polyobjs; // list of all poly-objects on the level int po_NumPolyobjs; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static int PolySegCount; static fixed_t PolyStartX; static fixed_t PolyStartY; // CODE -------------------------------------------------------------------- // ===== Polyobj Event Code ===== //========================================================================== // // T_RotatePoly // //========================================================================== void T_RotatePoly(polyevent_t *pe) { int absSpeed; polyobj_t *poly; if (PO_RotatePolyobj(pe->polyobj, pe->speed)) { absSpeed = abs(pe->speed); if (pe->dist == -1) { // perpetual polyobj return; } pe->dist -= absSpeed; if (pe->dist <= 0) { poly = GetPolyobj(pe->polyobj); if (poly->specialdata == pe) { poly->specialdata = NULL; } SN_StopSequence((mobj_t *)&poly->startSpot); P_PolyobjFinished(poly->tag); P_RemoveThinker(&pe->thinker); } if (pe->dist < absSpeed) { pe->speed = pe->dist*(pe->speed < 0 ? -1 : 1); } } } //========================================================================== // // EV_RotatePoly // //========================================================================== boolean EV_RotatePoly(line_t*, byte *args, int direction, boolean overRide) { int mirror; int polyNum; polyevent_t *pe; polyobj_t *poly; polyNum = args[0]; if ((poly = GetPolyobj(polyNum))) { if (poly->specialdata && !overRide) { // poly is already moving return false; } } else { I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); } pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL); P_AddThinker(&pe->thinker); pe->thinker.function = T_RotatePoly; pe->polyobj = polyNum; if (args[2]) { if (args[2] == 255) { pe->dist = -1; } else { pe->dist = args[2]*(ANGLE_90/64); // Angle } } else { pe->dist = ANGLE_MAX-1; } pe->speed = (args[1]*direction*(ANGLE_90/64))>>3; poly->specialdata = pe; SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); while ((mirror = GetPolyobjMirror(polyNum))) { poly = GetPolyobj(mirror); if (poly && poly->specialdata && !overRide) { // mirroring poly is already in motion break; } pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL); P_AddThinker(&pe->thinker); pe->thinker.function = T_RotatePoly; poly->specialdata = pe; pe->polyobj = mirror; if (args[2]) { if (args[2] == 255) { pe->dist = -1; } else { pe->dist = args[2]*(ANGLE_90/64); // Angle } } else { pe->dist = ANGLE_MAX-1; } if ((poly = GetPolyobj(polyNum))) { poly->specialdata = pe; } else { I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum); } direction = -direction; pe->speed = (args[1]*direction*(ANGLE_90/64))>>3; polyNum = mirror; SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } return true; } //========================================================================== // // T_MovePoly // //========================================================================== void T_MovePoly(polyevent_t *pe) { int absSpeed; polyobj_t *poly; if (PO_MovePolyobj(pe->polyobj, pe->xSpeed, pe->ySpeed)) { absSpeed = abs(pe->speed); pe->dist -= absSpeed; if (pe->dist <= 0) { poly = GetPolyobj(pe->polyobj); if (poly->specialdata == pe) { poly->specialdata = NULL; } SN_StopSequence((mobj_t *)&poly->startSpot); P_PolyobjFinished(poly->tag); P_RemoveThinker(&pe->thinker); } if (pe->dist < absSpeed) { pe->speed = pe->dist*(pe->speed < 0 ? -1 : 1); pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]); pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]); } } } //========================================================================== // // EV_MovePoly // //========================================================================== boolean EV_MovePoly(line_t*, byte *args, boolean timesEight, boolean overRide) { int mirror; int polyNum; polyevent_t *pe; polyobj_t *poly; angle_t an; polyNum = args[0]; if ((poly = GetPolyobj(polyNum))) { if (poly->specialdata && !overRide) { // poly is already moving return false; } } else { I_Error("EV_MovePoly: Invalid polyobj num: %d\n", polyNum); } pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL); P_AddThinker(&pe->thinker); pe->thinker.function = T_MovePoly; pe->polyobj = polyNum; if (timesEight) { pe->dist = args[3]*8*FRACUNIT; } else { pe->dist = args[3]*FRACUNIT; // Distance } pe->speed = args[1]*(FRACUNIT/8); poly->specialdata = pe; an = args[2]*(ANGLE_90/64); pe->angle = an>>ANGLETOFINESHIFT; pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]); pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]); SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); while ((mirror = GetPolyobjMirror(polyNum))) { poly = GetPolyobj(mirror); if (poly && poly->specialdata && !overRide) { // mirroring poly is already in motion break; } pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL); P_AddThinker(&pe->thinker); pe->thinker.function = T_MovePoly; pe->polyobj = mirror; poly->specialdata = pe; if (timesEight) { pe->dist = args[3]*8*FRACUNIT; } else { pe->dist = args[3]*FRACUNIT; // Distance } pe->speed = args[1]*(FRACUNIT/8); an = an + ANGLE_180; // reverse the angle pe->angle = an>>ANGLETOFINESHIFT; pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]); pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]); polyNum = mirror; SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } return true; } //========================================================================== // // T_PolyDoor // //========================================================================== void T_PolyDoor(polydoor_t *pd) { int absSpeed; polyobj_t *poly; if (pd->tics) { if (!--pd->tics) { poly = GetPolyobj(pd->polyobj); SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } return; } switch (pd->type) { case PODOOR_SLIDE: if (PO_MovePolyobj(pd->polyobj, pd->xSpeed, pd->ySpeed)) { absSpeed = abs(pd->speed); pd->dist -= absSpeed; if (pd->dist <= 0) { poly = GetPolyobj(pd->polyobj); SN_StopSequence((mobj_t *)&poly->startSpot); if (!pd->close) { pd->dist = pd->totalDist; pd->close = true; pd->tics = pd->waitTics; pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT) - pd->direction; pd->xSpeed = -pd->xSpeed; pd->ySpeed = -pd->ySpeed; } else { if (poly->specialdata == pd) { poly->specialdata = NULL; } P_PolyobjFinished(poly->tag); P_RemoveThinker(&pd->thinker); } } } else { poly = GetPolyobj(pd->polyobj); if (poly->crush || !pd->close) { // continue moving if the poly is a crusher, or is opening return; } else { // open back up pd->dist = pd->totalDist-pd->dist; pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT) - pd->direction; pd->xSpeed = -pd->xSpeed; pd->ySpeed = -pd->ySpeed; pd->close = false; SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } } break; case PODOOR_SWING: if (PO_RotatePolyobj(pd->polyobj, pd->speed)) { absSpeed = abs(pd->speed); if (pd->dist == -1) { // perpetual polyobj return; } pd->dist -= absSpeed; if (pd->dist <= 0) { poly = GetPolyobj(pd->polyobj); SN_StopSequence((mobj_t *)&poly->startSpot); if (!pd->close) { pd->dist = pd->totalDist; pd->close = true; pd->tics = pd->waitTics; pd->speed = -pd->speed; } else { if (poly->specialdata == pd) { poly->specialdata = NULL; } P_PolyobjFinished(poly->tag); P_RemoveThinker(&pd->thinker); } } } else { poly = GetPolyobj(pd->polyobj); if (poly->crush || !pd->close) { // continue moving if the poly is a crusher, or is opening return; } else { // open back up and rewait pd->dist = pd->totalDist-pd->dist; pd->speed = -pd->speed; pd->close = false; SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } } break; default: break; } } //========================================================================== // // EV_OpenPolyDoor // //========================================================================== boolean EV_OpenPolyDoor(line_t*, byte *args, podoortype_t type) { int mirror; int polyNum; polydoor_t *pd; polyobj_t *poly; angle_t an = 0; polyNum = args[0]; if ((poly = GetPolyobj(polyNum))) { if (poly->specialdata) { // poly is already moving return false; } } else { I_Error("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum); } pd = (polydoor_t *) Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, NULL); memset(pd, 0, sizeof(polydoor_t)); P_AddThinker(&pd->thinker); pd->thinker.function = T_PolyDoor; pd->type = type; pd->polyobj = polyNum; if (type == PODOOR_SLIDE) { pd->waitTics = args[4]; pd->speed = args[1]*(FRACUNIT/8); pd->totalDist = args[3]*FRACUNIT; // Distance pd->dist = pd->totalDist; an = args[2]*(ANGLE_90/64); pd->direction = an>>ANGLETOFINESHIFT; pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]); pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]); SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } else if (type == PODOOR_SWING) { pd->waitTics = args[3]; pd->direction = 1; // ADD: PODOOR_SWINGL, PODOOR_SWINGR pd->speed = (args[1]*pd->direction*(ANGLE_90/64))>>3; pd->totalDist = args[2]*(ANGLE_90/64); pd->dist = pd->totalDist; SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } poly->specialdata = pd; while ((mirror = GetPolyobjMirror(polyNum))) { poly = GetPolyobj(mirror); if (poly && poly->specialdata) { // mirroring poly is already in motion break; } pd = (polydoor_t *) Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, NULL); memset(pd, 0, sizeof(polydoor_t)); P_AddThinker(&pd->thinker); pd->thinker.function = T_PolyDoor; pd->polyobj = mirror; pd->type = type; poly->specialdata = pd; if (type == PODOOR_SLIDE) { pd->waitTics = args[4]; pd->speed = args[1]*(FRACUNIT/8); pd->totalDist = args[3]*FRACUNIT; // Distance pd->dist = pd->totalDist; an = an+ANGLE_180; // reverse the angle pd->direction = an>>ANGLETOFINESHIFT; pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]); pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]); SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } else if (type == PODOOR_SWING) { pd->waitTics = args[3]; pd->direction = -1; // ADD: same as above pd->speed = (args[1]*pd->direction*(ANGLE_90/64))>>3; pd->totalDist = args[2]*(ANGLE_90/64); pd->dist = pd->totalDist; SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType); } polyNum = mirror; } return true; } // ===== Higher Level Poly Interface code ===== //========================================================================== // // GetPolyobj // //========================================================================== static polyobj_t *GetPolyobj(int polyNum) { int i; for (i = 0; i < po_NumPolyobjs; i++) { if (polyobjs[i].tag == polyNum) { return &polyobjs[i]; } } return NULL; } //========================================================================== // // GetPolyobjMirror // //========================================================================== static int GetPolyobjMirror(int poly) { int i; for (i = 0; i < po_NumPolyobjs; i++) { if (polyobjs[i].tag == poly) { return ((*polyobjs[i].segs)->linedef->arg2); } } return 0; } //========================================================================== // // ThrustMobj // //========================================================================== static void ThrustMobj(mobj_t *mobj, seg_t *seg, polyobj_t *po) { int thrustAngle; int thrustX; int thrustY; polyevent_t *pe; int force; if (!(mobj->flags&MF_SHOOTABLE) && !mobj->player) { return; } thrustAngle = (seg->angle - ANGLE_90)>>ANGLETOFINESHIFT; pe = (polyevent_t *) po->specialdata; if (pe) { if (pe->thinker.function == T_RotatePoly) { force = pe->speed>>8; } else { force = pe->speed>>3; } if (force < FRACUNIT) { force = FRACUNIT; } else if (force > 4*FRACUNIT) { force = 4*FRACUNIT; } } else { force = FRACUNIT; } thrustX = FixedMul(force, finecosine[thrustAngle]); thrustY = FixedMul(force, finesine[thrustAngle]); mobj->momx += thrustX; mobj->momy += thrustY; if (po->crush) { if (!P_CheckPosition(mobj, mobj->x + thrustX, mobj->y + thrustY)) { P_DamageMobj(mobj, NULL, NULL, 3); } } } //========================================================================== // // UpdateSegBBox // //========================================================================== static void UpdateSegBBox(seg_t *seg) { line_t *line; line = seg->linedef; if (seg->v1->x < seg->v2->x) { line->bbox[BOXLEFT] = seg->v1->x; line->bbox[BOXRIGHT] = seg->v2->x; } else { line->bbox[BOXLEFT] = seg->v2->x; line->bbox[BOXRIGHT] = seg->v1->x; } if (seg->v1->y < seg->v2->y) { line->bbox[BOXBOTTOM] = seg->v1->y; line->bbox[BOXTOP] = seg->v2->y; } else { line->bbox[BOXBOTTOM] = seg->v2->y; line->bbox[BOXTOP] = seg->v1->y; } // Update the line's slopetype line->dx = line->v2->x - line->v1->x; line->dy = line->v2->y - line->v1->y; if (!line->dx) { line->slopetype = ST_VERTICAL; } else if (!line->dy) { line->slopetype = ST_HORIZONTAL; } else { if (FixedDiv(line->dy, line->dx) > 0) { line->slopetype = ST_POSITIVE; } else { line->slopetype = ST_NEGATIVE; } } } //========================================================================== // // PO_MovePolyobj // //========================================================================== boolean PO_MovePolyobj(int num, int x, int y) { int count; seg_t **segList; seg_t **veryTempSeg; polyobj_t *po; vertex_t *prevPts; boolean blocked; if (!(po = GetPolyobj(num))) { I_Error("PO_MovePolyobj: Invalid polyobj number: %d\n", num); } UnLinkPolyobj(po); segList = po->segs; prevPts = po->prevPts; blocked = false; validcount++; for (count = po->numsegs; count; count--, segList++, prevPts++) { if ((*segList)->linedef->validcount != validcount) { (*segList)->linedef->bbox[BOXTOP] += y; (*segList)->linedef->bbox[BOXBOTTOM] += y; (*segList)->linedef->bbox[BOXLEFT] += x; (*segList)->linedef->bbox[BOXRIGHT] += x; (*segList)->linedef->validcount = validcount; } for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++) { if ((*veryTempSeg)->v1 == (*segList)->v1) { break; } } if (veryTempSeg == segList) { (*segList)->v1->x += x; (*segList)->v1->y += y; } (*prevPts).x += x; // previous points are unique for each seg (*prevPts).y += y; } segList = po->segs; for (count = po->numsegs; count; count--, segList++) { if (CheckMobjBlocking(*segList, po)) { blocked = true; } } if (blocked) { count = po->numsegs; segList = po->segs; prevPts = po->prevPts; validcount++; while (count--) { if ((*segList)->linedef->validcount != validcount) { (*segList)->linedef->bbox[BOXTOP] -= y; (*segList)->linedef->bbox[BOXBOTTOM] -= y; (*segList)->linedef->bbox[BOXLEFT] -= x; (*segList)->linedef->bbox[BOXRIGHT] -= x; (*segList)->linedef->validcount = validcount; } for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++) { if ((*veryTempSeg)->v1 == (*segList)->v1) { break; } } if (veryTempSeg == segList) { (*segList)->v1->x -= x; (*segList)->v1->y -= y; } (*prevPts).x -= x; (*prevPts).y -= y; segList++; prevPts++; } LinkPolyobj(po); return false; } po->startSpot.x += x; po->startSpot.y += y; LinkPolyobj(po); return true; } //========================================================================== // // RotatePt // //========================================================================== static void RotatePt(int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY) { fixed_t xtr, ytr; fixed_t gxt, gyt; xtr = *x; ytr = *y; gxt = FixedMul(xtr, finecosine[an]); gyt = FixedMul(ytr, finesine[an]); *x = (gxt - gyt) + startSpotX; gxt = FixedMul(xtr, finesine[an]); gyt = FixedMul(ytr, finecosine[an]); *y = (gyt + gxt) + startSpotY; } //========================================================================== // // PO_RotatePolyobj // //========================================================================== boolean PO_RotatePolyobj(int num, angle_t angle) { int count; seg_t **segList; vertex_t *originalPts; vertex_t *prevPts; int an; polyobj_t *po; boolean blocked; if (!(po = GetPolyobj(num))) { I_Error("PO_RotatePolyobj: Invalid polyobj number: %d\n", num); } an = (po->angle + angle)>>ANGLETOFINESHIFT; UnLinkPolyobj(po); segList = po->segs; originalPts = po->originalPts; prevPts = po->prevPts; for (count = po->numsegs; count; count--, segList++, originalPts++, prevPts++) { prevPts->x = (*segList)->v1->x; prevPts->y = (*segList)->v1->y; (*segList)->v1->x = originalPts->x; (*segList)->v1->y = originalPts->y; RotatePt(an, &(*segList)->v1->x, &(*segList)->v1->y, po->startSpot.x, po->startSpot.y); } segList = po->segs; blocked = false; validcount++; for (count = po->numsegs; count; count--, segList++) { if (CheckMobjBlocking(*segList, po)) { blocked = true; } if ((*segList)->linedef->validcount != validcount) { UpdateSegBBox(*segList); (*segList)->linedef->validcount = validcount; } (*segList)->angle += angle; } if (blocked) { segList = po->segs; prevPts = po->prevPts; for (count = po->numsegs; count; count--, segList++, prevPts++) { (*segList)->v1->x = prevPts->x; (*segList)->v1->y = prevPts->y; } segList = po->segs; validcount++; for (count = po->numsegs; count; count--, segList++, prevPts++) { if ((*segList)->linedef->validcount != validcount) { UpdateSegBBox(*segList); (*segList)->linedef->validcount = validcount; } (*segList)->angle -= angle; } LinkPolyobj(po); return false; } po->angle += angle; LinkPolyobj(po); return true; } //========================================================================== // // UnLinkPolyobj // //========================================================================== static void UnLinkPolyobj(polyobj_t *po) { polyblock_t *link; int i, j; int idx; // remove the polyobj from each blockmap section for (j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++) { idx = j * bmapwidth; for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++) { if (i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight) { link = PolyBlockMap[idx + i]; while (link != NULL && link->polyobj != po) { link = link->next; } if (link == NULL) { // polyobj not located in the link cell continue; } link->polyobj = NULL; } } } } //========================================================================== // // LinkPolyobj // //========================================================================== static void LinkPolyobj(polyobj_t *po) { int leftX, rightX; int topY, bottomY; seg_t **tempSeg; polyblock_t **link; polyblock_t *tempLink; int i, j; // calculate the polyobj bbox tempSeg = po->segs; rightX = leftX = (*tempSeg)->v1->x; topY = bottomY = (*tempSeg)->v1->y; for (i = 0; i < po->numsegs; i++, tempSeg++) { if ((*tempSeg)->v1->x > rightX) { rightX = (*tempSeg)->v1->x; } if ((*tempSeg)->v1->x < leftX) { leftX = (*tempSeg)->v1->x; } if ((*tempSeg)->v1->y > topY) { topY = (*tempSeg)->v1->y; } if ((*tempSeg)->v1->y < bottomY) { bottomY = (*tempSeg)->v1->y; } } po->bbox[BOXRIGHT] = (rightX - bmaporgx)>>MAPBLOCKSHIFT; po->bbox[BOXLEFT] = (leftX - bmaporgx)>>MAPBLOCKSHIFT; po->bbox[BOXTOP] = (topY - bmaporgy)>>MAPBLOCKSHIFT; po->bbox[BOXBOTTOM] = (bottomY - bmaporgy)>>MAPBLOCKSHIFT; // add the polyobj to each blockmap section for (j = po->bbox[BOXBOTTOM]*bmapwidth; j <= po->bbox[BOXTOP]*bmapwidth; j += bmapwidth) { for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++) { if (i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth) { link = &PolyBlockMap[j + i]; if (!(*link)) { // Create a new link at the current block cell *link = (polyblock_t *) Z_Malloc(sizeof(polyblock_t), PU_LEVEL, NULL); (*link)->next = NULL; (*link)->prev = NULL; (*link)->polyobj = po; continue; } else { tempLink = *link; while (tempLink->next != NULL && tempLink->polyobj != NULL) { tempLink = tempLink->next; } } if (tempLink->polyobj == NULL) { tempLink->polyobj = po; continue; } else { tempLink->next = (polyblock_t *) Z_Malloc(sizeof(polyblock_t), PU_LEVEL, NULL); tempLink->next->next = NULL; tempLink->next->prev = tempLink; tempLink->next->polyobj = po; } } // else, don't link the polyobj, since it's off the map } } } //========================================================================== // // CheckMobjBlocking // //========================================================================== static boolean CheckMobjBlocking(seg_t *seg, polyobj_t *po) { mobj_t *mobj; int i, j; int left, right, top, bottom; int tmbbox[4]; line_t *ld; boolean blocked; ld = seg->linedef; top = (ld->bbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; bottom = (ld->bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; left = (ld->bbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; right = (ld->bbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; blocked = false; bottom = bottom < 0 ? 0 : bottom; bottom = bottom >= bmapheight ? bmapheight - 1 : bottom; top = top < 0 ? 0 : top; top = top >= bmapheight ? bmapheight - 1 : top; left = left < 0 ? 0 : left; left = left >= bmapwidth ? bmapwidth - 1 : left; right = right < 0 ? 0 : right; right = right >= bmapwidth ? bmapwidth - 1 : right; for (j = bottom*bmapwidth; j <= top*bmapwidth; j += bmapwidth) { for (i = left; i <= right; i++) { for (mobj = blocklinks[j+i]; mobj; mobj = mobj->bnext) { if (mobj->flags&MF_SOLID || mobj->player) { tmbbox[BOXTOP] = mobj->y + mobj->radius; tmbbox[BOXBOTTOM] = mobj->y - mobj->radius; tmbbox[BOXLEFT] = mobj->x - mobj->radius; tmbbox[BOXRIGHT] = mobj->x + mobj->radius; if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) { continue; } if (P_BoxOnLineSide(tmbbox, ld) != -1) { continue; } ThrustMobj(mobj, seg, po); blocked = true; } } } } return blocked; } //========================================================================== // // InitBlockMap // //========================================================================== static void InitBlockMap(void) { int i; int j; seg_t **segList; // int area; int leftX, rightX; int topY, bottomY; PolyBlockMap = (polyblock_t **) Z_Malloc(bmapwidth*bmapheight*sizeof(polyblock_t *), PU_LEVEL, NULL); memset(PolyBlockMap, 0, bmapwidth*bmapheight*sizeof(polyblock_t *)); for (i = 0; i < po_NumPolyobjs; i++) { LinkPolyobj(&polyobjs[i]); // calculate a rough area // right now, working like shit...gotta fix this... segList = polyobjs[i].segs; leftX = rightX = (*segList)->v1->x; topY = bottomY = (*segList)->v1->y; for (j = 0; j < polyobjs[i].numsegs; j++, segList++) { if ((*segList)->v1->x < leftX) { leftX = (*segList)->v1->x; } if ((*segList)->v1->x > rightX) { rightX = (*segList)->v1->x; } if ((*segList)->v1->y < bottomY) { bottomY = (*segList)->v1->y; } if ((*segList)->v1->y > topY) { topY = (*segList)->v1->y; } } // area = ((rightX>>FRACBITS) - (leftX>>FRACBITS)) * ((topY>>FRACBITS) - (bottomY>>FRACBITS)); // fprintf(stdaux, "Area of Polyobj[%d]: %d\n", polyobjs[i].tag, area); // fprintf(stdaux, "\t[%d]\n[%d]\t\t[%d]\n\t[%d]\n", // topY>>FRACBITS, leftX>>FRACBITS, // rightX>>FRACBITS, bottomY>>FRACBITS); } } //========================================================================== // // IterFindPolySegs // // Passing NULL for segList will cause IterFindPolySegs to // count the number of segs in the polyobj //========================================================================== static void IterFindPolySegs(int x, int y, seg_t **segList) { int i; if (x == PolyStartX && y == PolyStartY) { return; } for (i = 0; i < numsegs; i++) { if (segs[i].v1->x == x && segs[i].v1->y == y) { if (!segList) { PolySegCount++; } else { *segList++ = &segs[i]; } IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, segList); return; } } I_Error("IterFindPolySegs: Non-closed Polyobj located.\n"); } //========================================================================== // // SpawnPolyobj // //========================================================================== static void SpawnPolyobj(int idx, int tag, boolean crush) { int i; int j; int psIndex; int psIndexOld; seg_t *polySegList[PO_MAXPOLYSEGS]; for (i = 0; i < numsegs; i++) { if (segs[i].linedef->special == PO_LINE_START && segs[i].linedef->arg1 == tag) { if (polyobjs[idx].segs) { I_Error("SpawnPolyobj: Polyobj %d already spawned.\n", tag); } segs[i].linedef->special = 0; segs[i].linedef->arg1 = 0; PolySegCount = 1; PolyStartX = segs[i].v1->x; PolyStartY = segs[i].v1->y; IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, NULL); polyobjs[idx].numsegs = PolySegCount; polyobjs[idx].segs = (seg_t **) Z_Malloc(PolySegCount*sizeof(seg_t *), PU_LEVEL, NULL); *(polyobjs[idx].segs) = &segs[i]; // insert the first seg IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, polyobjs[idx].segs + 1); polyobjs[idx].crush = crush; polyobjs[idx].tag = tag; polyobjs[idx].seqType = segs[i].linedef->arg3; if (polyobjs[idx].seqType < 0 || polyobjs[idx].seqType >= SEQTYPE_NUMSEQ) { polyobjs[idx].seqType = 0; } break; } } if (!polyobjs[idx].segs) { // didn't find a polyobj through PO_LINE_START psIndex = 0; polyobjs[idx].numsegs = 0; for (j = 1; j < PO_MAXPOLYSEGS; j++) { psIndexOld = psIndex; for (i = 0; i < numsegs; i++) { if (segs[i].linedef->special == PO_LINE_EXPLICIT && segs[i].linedef->arg1 == tag) { if (!segs[i].linedef->arg2) { I_Error("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n", j + 1, tag); } if (segs[i].linedef->arg2 == j) { polySegList[psIndex] = &segs[i]; polyobjs[idx].numsegs++; psIndex++; if (psIndex > PO_MAXPOLYSEGS) { I_Error("SpawnPolyobj: psIndex > PO_MAXPOLYSEGS\n"); } } } } // Clear out any specials for these segs...we cannot clear them out // in the above loop, since we aren't guaranteed one seg per // linedef. for (i = 0; i < numsegs; i++) { if (segs[i].linedef->special == PO_LINE_EXPLICIT && segs[i].linedef->arg1 == tag && segs[i].linedef->arg2 == j) { segs[i].linedef->special = 0; segs[i].linedef->arg1 = 0; } } if (psIndex == psIndexOld) { // Check if an explicit line order has been skipped // A line has been skipped if there are any more explicit // lines with the current tag value for (i = 0; i < numsegs; i++) { if (segs[i].linedef->special == PO_LINE_EXPLICIT && segs[i].linedef->arg1 == tag) { I_Error("SpawnPolyobj: Missing explicit line %d for poly %d\n", j, tag); } } } } if (polyobjs[idx].numsegs) { PolySegCount = polyobjs[idx].numsegs; // PolySegCount used globally polyobjs[idx].crush = crush; polyobjs[idx].tag = tag; polyobjs[idx].segs = (seg_t **) Z_Malloc(polyobjs[idx].numsegs*sizeof(seg_t *), PU_LEVEL, NULL); for (i = 0; i < polyobjs[idx].numsegs; i++) { polyobjs[idx].segs[i] = polySegList[i]; } polyobjs[idx].seqType = (*polyobjs[idx].segs)->linedef->arg4; } // Next, change the polyobjs first line to point to a mirror // if it exists (*polyobjs[idx].segs)->linedef->arg2 = (*polyobjs[idx].segs)->linedef->arg3; } } //========================================================================== // // TranslateToStartSpot // //========================================================================== static void TranslateToStartSpot(int tag, int originX, int originY) { seg_t **tempSeg; seg_t **veryTempSeg; vertex_t *tempPt; subsector_t *sub; polyobj_t *po; int deltaX; int deltaY; vertex_t avg; // used to find a polyobj's center, and hence subsector int i; po = NULL; for (i = 0; i < po_NumPolyobjs; i++) { if (polyobjs[i].tag == tag) { po = &polyobjs[i]; break; } } if (!po) { // didn't match the tag with a polyobj tag I_Error("TranslateToStartSpot: Unable to match polyobj tag: %d\n", tag); } if (po->segs == NULL) { I_Error("TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag); } po->originalPts = (vertex_t *) Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, NULL); po->prevPts = (vertex_t *) Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, NULL); deltaX = originX-po->startSpot.x; deltaY = originY-po->startSpot.y; tempSeg = po->segs; tempPt = po->originalPts; avg.x = 0; avg.y = 0; validcount++; for (i = 0; i < po->numsegs; i++, tempSeg++, tempPt++) { if ((*tempSeg)->linedef->validcount != validcount) { (*tempSeg)->linedef->bbox[BOXTOP] -= deltaY; (*tempSeg)->linedef->bbox[BOXBOTTOM] -= deltaY; (*tempSeg)->linedef->bbox[BOXLEFT] -= deltaX; (*tempSeg)->linedef->bbox[BOXRIGHT] -= deltaX; (*tempSeg)->linedef->validcount = validcount; } for (veryTempSeg = po->segs; veryTempSeg != tempSeg; veryTempSeg++) { if ((*veryTempSeg)->v1 == (*tempSeg)->v1) { break; } } if (veryTempSeg == tempSeg) { // the point hasn't been translated, yet (*tempSeg)->v1->x -= deltaX; (*tempSeg)->v1->y -= deltaY; } avg.x += (*tempSeg)->v1->x>>FRACBITS; avg.y += (*tempSeg)->v1->y>>FRACBITS; // the original Pts are based off the startSpot Pt, and are // unique to each seg, not each linedef tempPt->x = (*tempSeg)->v1->x - po->startSpot.x; tempPt->y = (*tempSeg)->v1->y - po->startSpot.y; } avg.x /= po->numsegs; avg.y /= po->numsegs; sub = R_PointInSubsector(avg.x<<FRACBITS, avg.y<<FRACBITS); if (sub->poly != NULL) { I_Error("PO_TranslateToStartSpot: Multiple polyobjs in a single subsector.\n"); } sub->poly = po; } //========================================================================== // // PO_Init // //========================================================================== void PO_Init(int lump) { void *data; int i; mapthing_t *mt; int numthings; int polyIndex; polyobjs = (polyobj_t *) Z_Malloc(po_NumPolyobjs*sizeof(polyobj_t), PU_LEVEL, NULL); memset(polyobjs, 0, po_NumPolyobjs*sizeof(polyobj_t)); data = W_CacheLumpNum(lump, PU_STATIC); numthings = W_LumpLength(lump)/sizeof(mapthing_t); mt = (mapthing_t *)data; polyIndex = 0; // index polyobj number // Find the startSpot points, and spawn each polyobj for (i = 0; i < numthings; i++, mt++) { mt->x = SHORT(mt->x); mt->y = SHORT(mt->y); mt->angle = SHORT(mt->angle); mt->type = SHORT(mt->type); // 3001 = no crush, 3002 = crushing if (mt->type == PO_SPAWN_TYPE || mt->type == PO_SPAWNCRUSH_TYPE) { // Polyobj StartSpot Pt. polyobjs[polyIndex].startSpot.x = mt->x<<FRACBITS; polyobjs[polyIndex].startSpot.y = mt->y<<FRACBITS; SpawnPolyobj(polyIndex, mt->angle, (mt->type == PO_SPAWNCRUSH_TYPE)); polyIndex++; } } mt = (mapthing_t *)data; for (i = 0; i < numthings; i++, mt++) { /* NOTE: we byte swapped the fields in the above loop, don't swap here again */ if (mt->type == PO_ANCHOR_TYPE) { // Polyobj Anchor Pt. TranslateToStartSpot(mt->angle, mt->x<<FRACBITS, mt->y<<FRACBITS); } } Z_Free (data); // check for a startspot without an anchor point for (i = 0; i < po_NumPolyobjs; i++) { if (!polyobjs[i].originalPts) { I_Error("PO_Init: StartSpot located without an Anchor point: %d\n", polyobjs[i].tag); } } InitBlockMap(); } //========================================================================== // // PO_Busy // //========================================================================== boolean PO_Busy(int polyobj) { polyobj_t *poly; poly = GetPolyobj(polyobj); if (!poly->specialdata) { return false; } else { return true; } }