ref: d88f201b76b8f1021e3b20fb487fcc3c49e6503b
dir: /p_floor.c/
//************************************************************************** //** //** p_floor.c : Heretic 2 : Raven Software, Corp. //** //** $Revision: 472 $ //** $Date: 2009-05-26 15:45:18 +0300 (Tue, 26 May 2009) $ //** //************************************************************************** #include "h2stdinc.h" #include "h2def.h" #include "p_local.h" #include "soundst.h" //================================================================== // // FLOORS // //================================================================== extern fixed_t FloatBobOffsets[64]; //================================================================== // // Move a plane (floor or ceiling) and check for crushing // //================================================================== result_e T_MovePlane(sector_t *sector,fixed_t speed, fixed_t dest, int crush, int floorOrCeiling, int direction) { boolean flag; fixed_t lastpos; switch (floorOrCeiling) { case 0: // FLOOR switch (direction) { case -1: // DOWN if (sector->floorheight - speed < dest) { lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector,crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector, crush); //return RES_CRUSHED; } return RES_PASTDEST; } else { lastpos = sector->floorheight; sector->floorheight -= speed; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector, crush); return RES_CRUSHED; } } break; case 1: // UP if (sector->floorheight + speed > dest) { lastpos = sector->floorheight; sector->floorheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->floorheight = lastpos; P_ChangeSector(sector, crush); //return RES_CRUSHED; } return RES_PASTDEST; } else // COULD GET CRUSHED { lastpos = sector->floorheight; sector->floorheight += speed; flag = P_ChangeSector(sector, crush); if (flag == true) { //if (crush == true) //{ // return RES_CRUSHED; //} sector->floorheight = lastpos; P_ChangeSector(sector, crush); return RES_CRUSHED; } } break; } break; /* END OF THE FLOOR CASE */ case 1: // CEILING switch (direction) { case -1: // DOWN if (sector->ceilingheight - speed < dest) { lastpos = sector->ceilingheight; sector->ceilingheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); //return RES_CRUSHED; } return RES_PASTDEST; } else // COULD GET CRUSHED { lastpos = sector->ceilingheight; sector->ceilingheight -= speed; flag = P_ChangeSector(sector, crush); if (flag == true) { //if (crush == true) //{ // return RES_CRUSHED; //} sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); return RES_CRUSHED; } } break; case 1: // UP if (sector->ceilingheight + speed > dest) { lastpos = sector->ceilingheight; sector->ceilingheight = dest; flag = P_ChangeSector(sector, crush); if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); //return RES_CRUSHED; } return RES_PASTDEST; } else { lastpos = sector->ceilingheight; USED(lastpos); sector->ceilingheight += speed; flag = P_ChangeSector(sector, crush); USED(flag); #if 0 if (flag == true) { sector->ceilingheight = lastpos; P_ChangeSector(sector, crush); return RES_CRUSHED; } #endif } break; } break; /* END OF THE CEILING CASE */ } return RES_OK; } //================================================================== // // MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN) // //================================================================== void T_MoveFloor(floormove_t *floor) { result_e res; if (floor->resetDelayCount) { floor->resetDelayCount--; if (!floor->resetDelayCount) { floor->floordestheight = floor->resetHeight; floor->direction = -floor->direction; floor->resetDelay = 0; floor->delayCount = 0; floor->delayTotal = 0; } } if (floor->delayCount) { floor->delayCount--; if (!floor->delayCount && floor->textureChange) { floor->sector->floorpic += floor->textureChange; } return; } res = T_MovePlane(floor->sector,floor->speed, floor->floordestheight, floor->crush, 0, floor->direction); if (floor->type == FLEV_RAISEBUILDSTEP) { if ((floor->direction == 1 && floor->sector->floorheight >= floor->stairsDelayHeight) || (floor->direction == -1 && floor->sector->floorheight <= floor->stairsDelayHeight)) { floor->delayCount = floor->delayTotal; floor->stairsDelayHeight += floor->stairsDelayHeightDelta; } } if (res == RES_PASTDEST) { SN_StopSequence((mobj_t *)(void *)&floor->sector->soundorg); if (floor->delayTotal) { floor->delayTotal = 0; } if (floor->resetDelay) { // floor->resetDelayCount = floor->resetDelay; // floor->resetDelay = 0; return; } floor->sector->specialdata = NULL; /* if (floor->direction == 1) { switch (floor->type) { case donutRaise: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } } else if (floor->direction == -1) { switch (floor->type) { case lowerAndChange: floor->sector->special = floor->newspecial; floor->sector->floorpic = floor->texture; default: break; } } */ if (floor->textureChange) { floor->sector->floorpic -= floor->textureChange; } P_TagFinished(floor->sector->tag); P_RemoveThinker(&floor->thinker); } } //================================================================== // // HANDLE FLOOR TYPES // //================================================================== int EV_DoFloor(line_t*, byte *args, floor_e floortype) { int secnum; int rtn; sector_t *sec; floormove_t *floor = NULL; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; // // new floor thinker // rtn = 1; floor = (floormove_t *) Z_Malloc (sizeof(*floor), PU_LEVSPEC, NULL); memset(floor, 0, sizeof(*floor)); P_AddThinker (&floor->thinker); sec->specialdata = floor; floor->thinker.function = T_MoveFloor; floor->type = floortype; floor->crush = 0; floor->speed = args[1]*(FRACUNIT/8); if (floortype == FLEV_LOWERTIMES8INSTANT || floortype == FLEV_RAISETIMES8INSTANT) { floor->speed = 2000<<FRACBITS; } switch (floortype) { case FLEV_LOWERFLOOR: floor->direction = -1; floor->sector = sec; floor->floordestheight = P_FindHighestFloorSurrounding(sec); break; case FLEV_LOWERFLOORTOLOWEST: floor->direction = -1; floor->sector = sec; floor->floordestheight = P_FindLowestFloorSurrounding(sec); break; case FLEV_LOWERFLOORBYVALUE: floor->direction = -1; floor->sector = sec; floor->floordestheight = floor->sector->floorheight - args[2]*FRACUNIT; break; case FLEV_LOWERTIMES8INSTANT: case FLEV_LOWERBYVALUETIMES8: floor->direction = -1; floor->sector = sec; floor->floordestheight = floor->sector->floorheight - args[2]*FRACUNIT*8; break; case FLEV_RAISEFLOORCRUSH: floor->crush = args[2]; // arg[2] = crushing value floor->direction = 1; floor->sector = sec; floor->floordestheight = sec->ceilingheight - 8*FRACUNIT; break; case FLEV_RAISEFLOOR: floor->direction = 1; floor->sector = sec; floor->floordestheight = P_FindLowestCeilingSurrounding(sec); if (floor->floordestheight > sec->ceilingheight) floor->floordestheight = sec->ceilingheight; break; case FLEV_RAISEFLOORTONEAREST: floor->direction = 1; floor->sector = sec; floor->floordestheight = P_FindNextHighestFloor(sec, sec->floorheight); break; case FLEV_RAISEFLOORBYVALUE: floor->direction = 1; floor->sector = sec; floor->floordestheight = floor->sector->floorheight + args[2]*FRACUNIT; break; case FLEV_RAISETIMES8INSTANT: case FLEV_RAISEBYVALUETIMES8: floor->direction = 1; floor->sector = sec; floor->floordestheight = floor->sector->floorheight + args[2]*FRACUNIT*8; break; case FLEV_MOVETOVALUETIMES8: floor->sector = sec; floor->floordestheight = args[2]*FRACUNIT*8; if (args[3]) { floor->floordestheight = -floor->floordestheight; } if (floor->floordestheight > floor->sector->floorheight) { floor->direction = 1; } else if (floor->floordestheight < floor->sector->floorheight) { floor->direction = -1; } else { // already at lowest position rtn = 0; } break; default: rtn = 0; break; } } if (rtn) { SN_StartSequence((mobj_t *)(void *)&floor->sector->soundorg, SEQ_PLATFORM + floor->sector->seqType); } return rtn; } //============================================================================ // // EV_DoFloorAndCeiling // //============================================================================ int EV_DoFloorAndCeiling(line_t *line, byte *args, boolean raise) { boolean floor, ceiling; int secnum; sector_t *sec; if (raise) { floor = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE); secnum = -1; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; sec->specialdata = NULL; } ceiling = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE); } else { floor = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE); secnum = -1; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; sec->specialdata = NULL; } ceiling = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE); } return (floor|ceiling); } // ===== Build Stairs Private Data ===== #define STAIR_SECTOR_TYPE 26 #define STAIR_QUEUE_SIZE 32 static struct { sector_t *sector; int type; int height; } StairQueue[STAIR_QUEUE_SIZE]; static int QueueHead; static int QueueTail; static int StepDelta; static int Direction; static int Speed; static int Texture; static int StartDelay; static int StartDelayDelta; static int TextureChange; static int StartHeight; //========================================================================== // // QueueStairSector // //========================================================================== static void QueueStairSector(sector_t *sec, int type, int height) { if ((QueueTail + 1) % STAIR_QUEUE_SIZE == QueueHead) { I_Error("BuildStairs: Too many branches located.\n"); } StairQueue[QueueTail].sector = sec; StairQueue[QueueTail].type = type; StairQueue[QueueTail].height = height; QueueTail = (QueueTail + 1) % STAIR_QUEUE_SIZE; } //========================================================================== // // DequeueStairSector // //========================================================================== static sector_t *DequeueStairSector(int *type, int *height) { sector_t *sec; if (QueueHead == QueueTail) { // queue is empty return NULL; } *type = StairQueue[QueueHead].type; *height = StairQueue[QueueHead].height; sec = StairQueue[QueueHead].sector; QueueHead = (QueueHead + 1) % STAIR_QUEUE_SIZE; return sec; } //========================================================================== // // ProcessStairSector // //========================================================================== static void ProcessStairSector(sector_t *sec, int type, int height, stairs_e stairsType, int delay, int resetDelay) { int i; sector_t *tsec; floormove_t *floor; // // new floor thinker // height += StepDelta; floor = (floormove_t *) Z_Malloc(sizeof(*floor), PU_LEVSPEC, NULL); memset(floor, 0, sizeof(*floor)); P_AddThinker(&floor->thinker); sec->specialdata = floor; floor->thinker.function = T_MoveFloor; floor->type = FLEV_RAISEBUILDSTEP; floor->direction = Direction; floor->sector = sec; floor->floordestheight = height; switch (stairsType) { case STAIRS_NORMAL: floor->speed = Speed; if (delay) { floor->delayTotal = delay; floor->stairsDelayHeight = sec->floorheight + StepDelta; floor->stairsDelayHeightDelta = StepDelta; } floor->resetDelay = resetDelay; floor->resetDelayCount = resetDelay; floor->resetHeight = sec->floorheight; break; case STAIRS_SYNC: floor->speed = FixedMul(Speed, FixedDiv(height - StartHeight, StepDelta)); floor->resetDelay = delay; //arg4 floor->resetDelayCount = delay; floor->resetHeight = sec->floorheight; break; /* case STAIRS_PHASED: floor->floordestheight = sec->floorheight + StepDelta; floor->speed = Speed; floor->delayCount = StartDelay; StartDelay += StartDelayDelta; floor->textureChange = TextureChange; floor->resetDelayCount = StartDelay; break; */ default: break; } SN_StartSequence((mobj_t *)(void *)&sec->soundorg, SEQ_PLATFORM + sec->seqType); // // Find next sector to raise // Find nearby sector with sector special equal to type // for (i = 0; i < sec->linecount; i++) { if (!((sec->lines[i])->flags & ML_TWOSIDED)) { continue; } tsec = (sec->lines[i])->frontsector; if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata && tsec->floorpic == Texture && tsec->validcount != validcount) { QueueStairSector(tsec, type^1, height); tsec->validcount = validcount; //tsec->special = 0; } tsec = (sec->lines[i])->backsector; if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata && tsec->floorpic == Texture && tsec->validcount != validcount) { QueueStairSector(tsec, type^1, height); tsec->validcount = validcount; //tsec->special = 0; } } } //================================================================== // // BUILD A STAIRCASE! // // Direction is either positive or negative, denoting build stairs // up or down. //================================================================== int EV_BuildStairs(line_t*, byte *args, int direction, stairs_e stairsType) { int secnum; int height; int delay; int resetDelay; sector_t *sec; sector_t *qSec; int type; // Set global stairs variables TextureChange = 0; Direction = direction; StepDelta = Direction*(args[2]*FRACUNIT); Speed = args[1]*(FRACUNIT/8); resetDelay = args[4]; delay = args[3]; if (stairsType == STAIRS_PHASED) { StartDelayDelta = args[3]; StartDelay = StartDelayDelta; resetDelay = StartDelayDelta; delay = 0; TextureChange = args[4]; } secnum = -1; validcount++; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; Texture = sec->floorpic; StartHeight = sec->floorheight; // ALREADY MOVING? IF SO, KEEP GOING... if (sec->specialdata) continue; QueueStairSector(sec, 0, sec->floorheight); sec->special = 0; } while ((qSec = DequeueStairSector(&type, &height)) != NULL) { ProcessStairSector(qSec, type, height, stairsType, delay, resetDelay); } return 1; } //========================================================================= // // T_BuildPillar // //========================================================================= void T_BuildPillar(pillar_t *pillar) { result_e res1; result_e res2; // First, raise the floor res1 = T_MovePlane(pillar->sector, pillar->floorSpeed, pillar->floordest, pillar->crush, 0, pillar->direction); // floorOrCeiling, direction // Then, lower the ceiling res2 = T_MovePlane(pillar->sector, pillar->ceilingSpeed, pillar->ceilingdest, pillar->crush, 1, -pillar->direction); if (res1 == RES_PASTDEST && res2 == RES_PASTDEST) { pillar->sector->specialdata = NULL; SN_StopSequence((mobj_t *)(void *)&pillar->sector->soundorg); P_TagFinished(pillar->sector->tag); P_RemoveThinker(&pillar->thinker); } } //========================================================================= // // EV_BuildPillar // //========================================================================= int EV_BuildPillar(line_t*, byte *args, boolean crush) { int secnum; sector_t *sec; pillar_t *pillar; int newHeight; int rtn; rtn = 0; secnum = -1; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // already moving if (sec->floorheight == sec->ceilingheight) { // pillar is already closed continue; } rtn = 1; if (!args[2]) { newHeight = sec->floorheight + ((sec->ceilingheight - sec->floorheight)/2); } else { newHeight = sec->floorheight + (args[2]<<FRACBITS); } pillar = (pillar_t *) Z_Malloc(sizeof(*pillar), PU_LEVSPEC, NULL); sec->specialdata = pillar; P_AddThinker(&pillar->thinker); pillar->thinker.function = T_BuildPillar; pillar->sector = sec; if (!args[2]) { pillar->ceilingSpeed = pillar->floorSpeed = args[1]*(FRACUNIT/8); } else if (newHeight-sec->floorheight > sec->ceilingheight - newHeight) { pillar->floorSpeed = args[1]*(FRACUNIT/8); pillar->ceilingSpeed = FixedMul(sec->ceilingheight - newHeight, FixedDiv(pillar->floorSpeed, newHeight - sec->floorheight)); } else { pillar->ceilingSpeed = args[1]*(FRACUNIT/8); pillar->floorSpeed = FixedMul(newHeight - sec->floorheight, FixedDiv(pillar->ceilingSpeed, sec->ceilingheight - newHeight)); } pillar->floordest = newHeight; pillar->ceilingdest = newHeight; pillar->direction = 1; pillar->crush = crush*args[3]; SN_StartSequence((mobj_t *)(void *)&pillar->sector->soundorg, SEQ_PLATFORM + pillar->sector->seqType); } return rtn; } //========================================================================= // // EV_OpenPillar // //========================================================================= int EV_OpenPillar(line_t*, byte *args) { int secnum; sector_t *sec; pillar_t *pillar; int rtn; rtn = 0; secnum = -1; while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // already moving if (sec->floorheight != sec->ceilingheight) { // pillar isn't closed continue; } rtn = 1; pillar = (pillar_t *) Z_Malloc(sizeof(*pillar), PU_LEVSPEC, NULL); sec->specialdata = pillar; P_AddThinker(&pillar->thinker); pillar->thinker.function = T_BuildPillar; pillar->sector = sec; if (!args[2]) { pillar->floordest = P_FindLowestFloorSurrounding(sec); } else { pillar->floordest = sec->floorheight - (args[2]<<FRACBITS); } if (!args[3]) { pillar->ceilingdest = P_FindHighestCeilingSurrounding(sec); } else { pillar->ceilingdest = sec->ceilingheight + (args[3]<<FRACBITS); } if (sec->floorheight - pillar->floordest >= pillar->ceilingdest - sec->ceilingheight) { pillar->floorSpeed = args[1]*(FRACUNIT/8); pillar->ceilingSpeed = FixedMul(sec->ceilingheight - pillar->ceilingdest, FixedDiv(pillar->floorSpeed, pillar->floordest - sec->floorheight)); } else { pillar->ceilingSpeed = args[1]*(FRACUNIT/8); pillar->floorSpeed = FixedMul(pillar->floordest - sec->floorheight, FixedDiv(pillar->ceilingSpeed, sec->ceilingheight - pillar->ceilingdest)); } pillar->direction = -1; // open the pillar SN_StartSequence((mobj_t *)(void *)&pillar->sector->soundorg, SEQ_PLATFORM + pillar->sector->seqType); } return rtn; } //========================================================================= // // EV_FloorCrushStop // //========================================================================= int EV_FloorCrushStop(line_t*, byte*) { thinker_t *think; floormove_t *floor; boolean rtn; rtn = 0; for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function != T_MoveFloor) { continue; } floor = (floormove_t *)think; if (floor->type != FLEV_RAISEFLOORCRUSH) { continue; } // Completely remove the crushing floor SN_StopSequence((mobj_t *)(void *)&floor->sector->soundorg); floor->sector->specialdata = NULL; P_TagFinished(floor->sector->tag); P_RemoveThinker(&floor->thinker); rtn = 1; } return rtn; } //========================================================================== // // T_FloorWaggle // //========================================================================== #define WGLSTATE_EXPAND 1 #define WGLSTATE_STABLE 2 #define WGLSTATE_REDUCE 3 void T_FloorWaggle(floorWaggle_t *waggle) { switch (waggle->state) { case WGLSTATE_EXPAND: if ((waggle->scale += waggle->scaleDelta) >= waggle->targetScale) { waggle->scale = waggle->targetScale; waggle->state = WGLSTATE_STABLE; } break; case WGLSTATE_REDUCE: if ((waggle->scale -= waggle->scaleDelta) <= 0) { // Remove waggle->sector->floorheight = waggle->originalHeight; P_ChangeSector(waggle->sector, true); waggle->sector->specialdata = NULL; P_TagFinished(waggle->sector->tag); P_RemoveThinker(&waggle->thinker); return; } break; case WGLSTATE_STABLE: if (waggle->ticker != -1) { if (!--waggle->ticker) { waggle->state = WGLSTATE_REDUCE; } } break; } waggle->accumulator += waggle->accDelta; waggle->sector->floorheight = waggle->originalHeight + FixedMul(FloatBobOffsets[(waggle->accumulator>>FRACBITS) & 63], waggle->scale); P_ChangeSector(waggle->sector, true); } //========================================================================== // // EV_StartFloorWaggle // //========================================================================== boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset, int timer) { int sectorIndex; sector_t *sector; floorWaggle_t *waggle; boolean retCode; retCode = false; sectorIndex = -1; while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0) { sector = §ors[sectorIndex]; if (sector->specialdata) { // Already busy with another thinker continue; } retCode = true; waggle = (floorWaggle_t *) Z_Malloc(sizeof(*waggle), PU_LEVSPEC, NULL); sector->specialdata = waggle; waggle->thinker.function = T_FloorWaggle; waggle->sector = sector; waggle->originalHeight = sector->floorheight; waggle->accumulator = offset*FRACUNIT; waggle->accDelta = speed<<10; waggle->scale = 0; waggle->targetScale = height<<10; waggle->scaleDelta = waggle->targetScale / (35 + ((3*35)*height)/255); waggle->ticker = timer ? timer*35 : -1; waggle->state = WGLSTATE_EXPAND; P_AddThinker(&waggle->thinker); } return retCode; }