From 0df2cb80cf03d7259746834220d209b306a8c503 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 4 Sep 2008 23:15:36 +0000 Subject: Add GPLed Heretic/Hexen source. Subversion-branch: /branches/raven-branch Subversion-revision: 1195 --- src/hexen/po_man.c | 1482 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1482 insertions(+) create mode 100644 src/hexen/po_man.c (limited to 'src/hexen/po_man.c') diff --git a/src/hexen/po_man.c b/src/hexen/po_man.c new file mode 100644 index 00000000..6e0883ff --- /dev/null +++ b/src/hexen/po_man.c @@ -0,0 +1,1482 @@ + +//************************************************************************** +//** +//** PO_MAN.C : Heretic 2 : Raven Software, Corp. +//** +//** $RCSfile: po_man.c,v $ +//** $Revision: 1.22 $ +//** $Date: 95/09/28 18:20:56 $ +//** $Author: cjr $ +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#include "h2def.h" +#include "p_local.h" +#include "r_local.h" + +// MACROS ------------------------------------------------------------------ + +#define PO_MAXPOLYSEGS 64 + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL 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 index, 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 *line, 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 = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0); + 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 = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0); + 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 *line, 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 = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0); + 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 = Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, 0); + 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 *line, byte *args, podoortype_t type) +{ + int mirror; + int polyNum; + polydoor_t *pd; + polyobj_t *poly; + angle_t an; + + 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 = Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, 0); + 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 = Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, 0); + 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 = 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 trx, try; + fixed_t gxt, gyt; + + trx = *x; + try = *y; + + gxt = FixedMul(trx, finecosine[an]); + gyt = FixedMul(try, finesine[an]); + *x = (gxt-gyt)+startSpotX; + + gxt = FixedMul(trx, finesine[an]); + gyt = FixedMul(try, 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 index; + + // remove the polyobj from each blockmap section + for(j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++) + { + index = j*bmapwidth; + for(i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++) + { + if(i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight) + { + link = PolyBlockMap[index+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 = Z_Malloc(sizeof(polyblock_t), PU_LEVEL, 0); + (*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 = Z_Malloc(sizeof(polyblock_t), + PU_LEVEL, 0); + 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 = Z_Malloc(bmapwidth*bmapheight*sizeof(polyblock_t *), + PU_LEVEL, 0); + 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 index, 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[index].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[index].numsegs = PolySegCount; + polyobjs[index].segs = Z_Malloc(PolySegCount*sizeof(seg_t *), + PU_LEVEL, 0); + *(polyobjs[index].segs) = &segs[i]; // insert the first seg + IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, + polyobjs[index].segs+1); + polyobjs[index].crush = crush; + polyobjs[index].tag = tag; + polyobjs[index].seqType = segs[i].linedef->arg3; + if(polyobjs[index].seqType < 0 + || polyobjs[index].seqType >= SEQTYPE_NUMSEQ) + { + polyobjs[index].seqType = 0; + } + break; + } + } + if(!polyobjs[index].segs) + { // didn't find a polyobj through PO_LINE_START + psIndex = 0; + polyobjs[index].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[index].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[index].numsegs) + { + PolySegCount = polyobjs[index].numsegs; // PolySegCount used globally + polyobjs[index].crush = crush; + polyobjs[index].tag = tag; + polyobjs[index].segs = Z_Malloc(polyobjs[index].numsegs + *sizeof(seg_t *), PU_LEVEL, 0); + for(i = 0; i < polyobjs[index].numsegs; i++) + { + polyobjs[index].segs[i] = polySegList[i]; + } + polyobjs[index].seqType = (*polyobjs[index].segs)->linedef->arg4; + } + // Next, change the polyobjs first line to point to a mirror + // if it exists + (*polyobjs[index].segs)->linedef->arg2 = + (*polyobjs[index].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 = Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, 0); + po->prevPts = Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, 0); + 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<poly != NULL) + { + I_Error("PO_TranslateToStartSpot: Multiple polyobjs in a single subsector.\n"); + } + sub->poly = po; +} + +//========================================================================== +// +// PO_Init +// +//========================================================================== + +void PO_Init(int lump) +{ + byte *data; + int i; + mapthing_t *mt; + int numthings; + int polyIndex; + + polyobjs = Z_Malloc(po_NumPolyobjs*sizeof(polyobj_t), PU_LEVEL, 0); + 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<y<angle, (mt->type == PO_SPAWNCRUSH_TYPE)); + polyIndex++; + } + } + mt = (mapthing_t *)data; + 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); + if(mt->type == PO_ANCHOR_TYPE) + { // Polyobj Anchor Pt. + TranslateToStartSpot(mt->angle, mt->x<y<specialdata) + { + return false; + } + else + { + return true; + } +} -- cgit v1.2.3