/* Emacs style mode select -*- C++ -*- *----------------------------------------------------------------------------- * * * PrBoom: a Doom port merged with LxDoom and LSDLDoom * based on BOOM, a modified and improved DOOM engine * Copyright (C) 1999 by * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman * Copyright (C) 1999-2000 by * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze * Copyright 2005, 2006 by * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * DESCRIPTION: * Generalized linedef type handlers * Floors, Ceilings, Doors, Locked Doors, Lifts, Stairs, Crushers * *-----------------------------------------------------------------------------*/ #include "doomstat.h" //jff 6/19/98 for demo_compatibility #include "r_main.h" #include "p_spec.h" #include "p_tick.h" #include "m_random.h" #include "s_sound.h" #include "sounds.h" ////////////////////////////////////////////////////////// // // Generalized Linedef Type handlers // ////////////////////////////////////////////////////////// // // EV_DoGenFloor() // // Handle generalized floor types // // Passed the line activating the generalized floor function // Returns true if a thinker is created // // jff 02/04/98 Added this routine (and file) to handle generalized // floor movers using bit fields in the line special type. // int EV_DoGenFloor ( line_t* line ) { int secnum; int rtn; boolean manual; sector_t* sec; floormove_t* floor; unsigned value = (unsigned)line->special - GenFloorBase; // parse the bit fields in the line's special type int Crsh = (value & FloorCrush) >> FloorCrushShift; int ChgT = (value & FloorChange) >> FloorChangeShift; int Targ = (value & FloorTarget) >> FloorTargetShift; int Dirn = (value & FloorDirection) >> FloorDirectionShift; int ChgM = (value & FloorModel) >> FloorModelShift; int Sped = (value & FloorSpeed) >> FloorSpeedShift; int Trig = (value & TriggerType) >> TriggerTypeShift; rtn = 0; // check if a manual trigger, if so do just the sector on the backside manual = false; if (Trig==PushOnce || Trig==PushMany) { if (!(sec = line->backsector)) return rtn; secnum = sec-sectors; manual = true; goto manual_floor; } secnum = -1; // if not manual do all sectors tagged the same as the line while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; manual_floor: // Do not start another function if floor already moving if (P_SectorActive(floor_special,sec)) { if (!manual) continue; else return rtn; } // new floor thinker rtn = 1; floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); memset(floor, 0, sizeof(*floor)); P_AddThinker (&floor->thinker); sec->floordata = floor; floor->thinker.function = T_MoveFloor; floor->crush = Crsh; floor->direction = Dirn? 1 : -1; floor->sector = sec; floor->texture = sec->floorpic; floor->newspecial = sec->special; //jff 3/14/98 transfer old special field too floor->oldspecial = sec->oldspecial; floor->type = genFloor; // set the speed of motion switch (Sped) { case SpeedSlow: floor->speed = FLOORSPEED; break; case SpeedNormal: floor->speed = FLOORSPEED*2; break; case SpeedFast: floor->speed = FLOORSPEED*4; break; case SpeedTurbo: floor->speed = FLOORSPEED*8; break; default: break; } // set the destination height switch(Targ) { case FtoHnF: floor->floordestheight = P_FindHighestFloorSurrounding(sec); break; case FtoLnF: floor->floordestheight = P_FindLowestFloorSurrounding(sec); break; case FtoNnF: floor->floordestheight = Dirn? P_FindNextHighestFloor(sec,sec->floorheight) : P_FindNextLowestFloor(sec,sec->floorheight); break; case FtoLnC: floor->floordestheight = P_FindLowestCeilingSurrounding(sec); break; case FtoC: floor->floordestheight = sec->ceilingheight; break; case FbyST: floor->floordestheight = (floor->sector->floorheight>>FRACBITS) + floor->direction * (P_FindShortestTextureAround(secnum)>>FRACBITS); if (floor->floordestheight>32000) //jff 3/13/98 prevent overflow floor->floordestheight=32000; // wraparound in floor height if (floor->floordestheight<-32000) floor->floordestheight=-32000; floor->floordestheight<<=FRACBITS; break; case Fby24: floor->floordestheight = floor->sector->floorheight + floor->direction * 24*FRACUNIT; break; case Fby32: floor->floordestheight = floor->sector->floorheight + floor->direction * 32*FRACUNIT; break; default: break; } // set texture/type change properties if (ChgT) // if a texture change is indicated { if (ChgM) // if a numeric model change { sector_t *sec; //jff 5/23/98 find model with ceiling at target height if target //is a ceiling type sec = (Targ==FtoLnC || Targ==FtoC)? P_FindModelCeilingSector(floor->floordestheight,secnum) : P_FindModelFloorSector(floor->floordestheight,secnum); if (sec) { floor->texture = sec->floorpic; switch(ChgT) { case FChgZero: // zero type floor->newspecial = 0; //jff 3/14/98 change old field too floor->oldspecial = 0; floor->type = genFloorChg0; break; case FChgTyp: // copy type floor->newspecial = sec->special; //jff 3/14/98 change old field too floor->oldspecial = sec->oldspecial; floor->type = genFloorChgT; break; case FChgTxt: // leave type be floor->type = genFloorChg; break; default: break; } } } else // else if a trigger model change { floor->texture = line->frontsector->floorpic; switch (ChgT) { case FChgZero: // zero type floor->newspecial = 0; //jff 3/14/98 change old field too floor->oldspecial = 0; floor->type = genFloorChg0; break; case FChgTyp: // copy type floor->newspecial = line->frontsector->special; //jff 3/14/98 change old field too floor->oldspecial = line->frontsector->oldspecial; floor->type = genFloorChgT; break; case FChgTxt: // leave type be floor->type = genFloorChg; default: break; } } } if (manual) return rtn; } return rtn; } // // EV_DoGenCeiling() // // Handle generalized ceiling types // // Passed the linedef activating the ceiling function // Returns true if a thinker created // // jff 02/04/98 Added this routine (and file) to handle generalized // floor movers using bit fields in the line special type. // int EV_DoGenCeiling ( line_t* line ) { int secnum; int rtn; boolean manual; fixed_t targheight; sector_t* sec; ceiling_t* ceiling; unsigned value = (unsigned)line->special - GenCeilingBase; // parse the bit fields in the line's special type int Crsh = (value & CeilingCrush) >> CeilingCrushShift; int ChgT = (value & CeilingChange) >> CeilingChangeShift; int Targ = (value & CeilingTarget) >> CeilingTargetShift; int Dirn = (value & CeilingDirection) >> CeilingDirectionShift; int ChgM = (value & CeilingModel) >> CeilingModelShift; int Sped = (value & CeilingSpeed) >> CeilingSpeedShift; int Trig = (value & TriggerType) >> TriggerTypeShift; rtn = 0; // check if a manual trigger, if so do just the sector on the backside manual = false; if (Trig==PushOnce || Trig==PushMany) { if (!(sec = line->backsector)) return rtn; secnum = sec-sectors; manual = true; goto manual_ceiling; } secnum = -1; // if not manual do all sectors tagged the same as the line while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; manual_ceiling: // Do not start another function if ceiling already moving if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 { if (!manual) continue; else return rtn; } // new ceiling thinker rtn = 1; ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); memset(ceiling, 0, sizeof(*ceiling)); P_AddThinker (&ceiling->thinker); sec->ceilingdata = ceiling; //jff 2/22/98 ceiling->thinker.function = T_MoveCeiling; ceiling->crush = Crsh; ceiling->direction = Dirn? 1 : -1; ceiling->sector = sec; ceiling->texture = sec->ceilingpic; ceiling->newspecial = sec->special; //jff 3/14/98 change old field too ceiling->oldspecial = sec->oldspecial; ceiling->tag = sec->tag; ceiling->type = genCeiling; // set speed of motion switch (Sped) { case SpeedSlow: ceiling->speed = CEILSPEED; break; case SpeedNormal: ceiling->speed = CEILSPEED*2; break; case SpeedFast: ceiling->speed = CEILSPEED*4; break; case SpeedTurbo: ceiling->speed = CEILSPEED*8; break; default: break; } // set destination target height targheight = sec->ceilingheight; switch(Targ) { case CtoHnC: targheight = P_FindHighestCeilingSurrounding(sec); break; case CtoLnC: targheight = P_FindLowestCeilingSurrounding(sec); break; case CtoNnC: targheight = Dirn? P_FindNextHighestCeiling(sec,sec->ceilingheight) : P_FindNextLowestCeiling(sec,sec->ceilingheight); break; case CtoHnF: targheight = P_FindHighestFloorSurrounding(sec); break; case CtoF: targheight = sec->floorheight; break; case CbyST: targheight = (ceiling->sector->ceilingheight>>FRACBITS) + ceiling->direction * (P_FindShortestUpperAround(secnum)>>FRACBITS); if (targheight>32000) //jff 3/13/98 prevent overflow targheight=32000; // wraparound in ceiling height if (targheight<-32000) targheight=-32000; targheight<<=FRACBITS; break; case Cby24: targheight = ceiling->sector->ceilingheight + ceiling->direction * 24*FRACUNIT; break; case Cby32: targheight = ceiling->sector->ceilingheight + ceiling->direction * 32*FRACUNIT; break; default: break; } if (Dirn) ceiling->topheight = targheight; else ceiling->bottomheight = targheight; // set texture/type change properties if (ChgT) // if a texture change is indicated { if (ChgM) // if a numeric model change { sector_t *sec; //jff 5/23/98 find model with floor at target height if target //is a floor type sec = (Targ==CtoHnF || Targ==CtoF)? P_FindModelFloorSector(targheight,secnum) : P_FindModelCeilingSector(targheight,secnum); if (sec) { ceiling->texture = sec->ceilingpic; switch (ChgT) { case CChgZero: // type is zeroed ceiling->newspecial = 0; //jff 3/14/98 change old field too ceiling->oldspecial = 0; ceiling->type = genCeilingChg0; break; case CChgTyp: // type is copied ceiling->newspecial = sec->special; //jff 3/14/98 change old field too ceiling->oldspecial = sec->oldspecial; ceiling->type = genCeilingChgT; break; case CChgTxt: // type is left alone ceiling->type = genCeilingChg; break; default: break; } } } else // else if a trigger model change { ceiling->texture = line->frontsector->ceilingpic; switch (ChgT) { case CChgZero: // type is zeroed ceiling->newspecial = 0; //jff 3/14/98 change old field too ceiling->oldspecial = 0; ceiling->type = genCeilingChg0; break; case CChgTyp: // type is copied ceiling->newspecial = line->frontsector->special; //jff 3/14/98 change old field too ceiling->oldspecial = line->frontsector->oldspecial; ceiling->type = genCeilingChgT; break; case CChgTxt: // type is left alone ceiling->type = genCeilingChg; break; default: break; } } } P_AddActiveCeiling(ceiling); // add this ceiling to the active list if (manual) return rtn; } return rtn; } // // EV_DoGenLift() // // Handle generalized lift types // // Passed the linedef activating the lift // Returns true if a thinker is created // int EV_DoGenLift ( line_t* line ) { plat_t* plat; int secnum; int rtn; boolean manual; sector_t* sec; unsigned value = (unsigned)line->special - GenLiftBase; // parse the bit fields in the line's special type int Targ = (value & LiftTarget) >> LiftTargetShift; int Dely = (value & LiftDelay) >> LiftDelayShift; int Sped = (value & LiftSpeed) >> LiftSpeedShift; int Trig = (value & TriggerType) >> TriggerTypeShift; secnum = -1; rtn = 0; // Activate all plats that are in_stasis if (Targ==LnF2HnF) P_ActivateInStasis(line->tag); // check if a manual trigger, if so do just the sector on the backside manual = false; if (Trig==PushOnce || Trig==PushMany) { if (!(sec = line->backsector)) return rtn; secnum = sec-sectors; manual = true; goto manual_lift; } // if not manual do all sectors tagged the same as the line while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; manual_lift: // Do not start another function if floor already moving if (P_SectorActive(floor_special,sec)) { if (!manual) continue; else return rtn; } // Setup the plat thinker rtn = 1; plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0); memset(plat, 0, sizeof(*plat)); P_AddThinker(&plat->thinker); plat->sector = sec; plat->sector->floordata = plat; plat->thinker.function = T_PlatRaise; plat->crush = false; plat->tag = line->tag; plat->type = genLift; plat->high = sec->floorheight; plat->status = down; // setup the target destination height switch(Targ) { case F2LnF: plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; break; case F2NnF: plat->low = P_FindNextLowestFloor(sec,sec->floorheight); break; case F2LnC: plat->low = P_FindLowestCeilingSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; break; case LnF2HnF: plat->type = genPerpetual; plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = P_FindHighestFloorSurrounding(sec); if (plat->high < sec->floorheight) plat->high = sec->floorheight; plat->status = P_Random(pr_genlift)&1; break; default: break; } // setup the speed of motion switch(Sped) { case SpeedSlow: plat->speed = PLATSPEED * 2; break; case SpeedNormal: plat->speed = PLATSPEED * 4; break; case SpeedFast: plat->speed = PLATSPEED * 8; break; case SpeedTurbo: plat->speed = PLATSPEED * 16; break; default: break; } // setup the delay time before the floor returns switch(Dely) { case 0: plat->wait = 1*35; break; case 1: plat->wait = PLATWAIT*35; break; case 2: plat->wait = 5*35; break; case 3: plat->wait = 10*35; break; } S_StartSound((mobj_t *)&sec->soundorg,sfx_pstart); P_AddActivePlat(plat); // add this plat to the list of active plats if (manual) return rtn; } return rtn; } // // EV_DoGenStairs() // // Handle generalized stair building // // Passed the linedef activating the stairs // Returns true if a thinker is created // int EV_DoGenStairs ( line_t* line ) { int secnum; int osecnum; //jff 3/4/98 preserve loop index int height; int i; int newsecnum; int texture; int ok; int rtn; boolean manual; sector_t* sec; sector_t* tsec; floormove_t* floor; fixed_t stairsize; fixed_t speed; unsigned value = (unsigned)line->special - GenStairsBase; // parse the bit fields in the line's special type int Igno = (value & StairIgnore) >> StairIgnoreShift; int Dirn = (value & StairDirection) >> StairDirectionShift; int Step = (value & StairStep) >> StairStepShift; int Sped = (value & StairSpeed) >> StairSpeedShift; int Trig = (value & TriggerType) >> TriggerTypeShift; rtn = 0; // check if a manual trigger, if so do just the sector on the backside manual = false; if (Trig==PushOnce || Trig==PushMany) { if (!(sec = line->backsector)) return rtn; secnum = sec-sectors; manual = true; goto manual_stair; } secnum = -1; // if not manual do all sectors tagged the same as the line while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; manual_stair: //Do not start another function if floor already moving //jff 2/26/98 add special lockout condition to wait for entire //staircase to build before retriggering if (P_SectorActive(floor_special,sec) || sec->stairlock) { if (!manual) continue; else return rtn; } // new floor thinker rtn = 1; floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); memset(floor, 0, sizeof(*floor)); P_AddThinker (&floor->thinker); sec->floordata = floor; floor->thinker.function = T_MoveFloor; floor->direction = Dirn? 1 : -1; floor->sector = sec; // setup speed of stair building switch(Sped) { default: case SpeedSlow: floor->speed = FLOORSPEED/4; break; case SpeedNormal: floor->speed = FLOORSPEED/2; break; case SpeedFast: floor->speed = FLOORSPEED*2; break; case SpeedTurbo: floor->speed = FLOORSPEED*4; break; } // setup stepsize for stairs switch(Step) { default: case 0: stairsize = 4*FRACUNIT; break; case 1: stairsize = 8*FRACUNIT; break; case 2: stairsize = 16*FRACUNIT; break; case 3: stairsize = 24*FRACUNIT; break; } speed = floor->speed; height = sec->floorheight + floor->direction * stairsize; floor->floordestheight = height; texture = sec->floorpic; floor->crush = false; floor->type = genBuildStair; // jff 3/31/98 do not leave uninited sec->stairlock = -2; // jff 2/26/98 set up lock on current sector sec->nextsec = -1; sec->prevsec = -1; osecnum = secnum; //jff 3/4/98 preserve loop index // Find next sector to raise // 1. Find 2-sided line with same sector side[0] // 2. Other side is the next sector to raise do { ok = 0; for (i = 0;i < sec->linecount;i++) { if ( !((sec->lines[i])->backsector) ) continue; tsec = (sec->lines[i])->frontsector; newsecnum = tsec-sectors; if (secnum != newsecnum) continue; tsec = (sec->lines[i])->backsector; newsecnum = tsec - sectors; if (!Igno && tsec->floorpic != texture) continue; /* jff 6/19/98 prevent double stepsize */ if (compatibility_level < boom_202_compatibility) height += floor->direction * stairsize; //jff 2/26/98 special lockout condition for retriggering if (P_SectorActive(floor_special,tsec) || tsec->stairlock) continue; /* jff 6/19/98 increase height AFTER continue */ if (compatibility_level >= boom_202_compatibility) height += floor->direction * stairsize; // jff 2/26/98 // link the stair chain in both directions // lock the stair sector until building complete sec->nextsec = newsecnum; // link step to next tsec->prevsec = secnum; // link next back tsec->nextsec = -1; // set next forward link as end tsec->stairlock = -2; // lock the step sec = tsec; secnum = newsecnum; floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); memset(floor, 0, sizeof(*floor)); P_AddThinker (&floor->thinker); sec->floordata = floor; floor->thinker.function = T_MoveFloor; floor->direction = Dirn? 1 : -1; floor->sector = sec; floor->speed = speed; floor->floordestheight = height; floor->crush = false; floor->type = genBuildStair; // jff 3/31/98 do not leave uninited ok = 1; break; } } while(ok); if (manual) return rtn; secnum = osecnum; //jff 3/4/98 restore old loop index } // retriggerable generalized stairs build up or down alternately if (rtn) line->special ^= StairDirection; // alternate dir on succ activations return rtn; } // // EV_DoGenCrusher() // // Handle generalized crusher types // // Passed the linedef activating the crusher // Returns true if a thinker created // int EV_DoGenCrusher ( line_t* line ) { int secnum; int rtn; boolean manual; sector_t* sec; ceiling_t* ceiling; unsigned value = (unsigned)line->special - GenCrusherBase; // parse the bit fields in the line's special type int Slnt = (value & CrusherSilent) >> CrusherSilentShift; int Sped = (value & CrusherSpeed) >> CrusherSpeedShift; int Trig = (value & TriggerType) >> TriggerTypeShift; //jff 2/22/98 Reactivate in-stasis ceilings...for certain types. //jff 4/5/98 return if activated rtn = P_ActivateInStasisCeiling(line); // check if a manual trigger, if so do just the sector on the backside manual = false; if (Trig==PushOnce || Trig==PushMany) { if (!(sec = line->backsector)) return rtn; secnum = sec-sectors; manual = true; goto manual_crusher; } secnum = -1; // if not manual do all sectors tagged the same as the line while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; manual_crusher: // Do not start another function if ceiling already moving if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 { if (!manual) continue; else return rtn; } // new ceiling thinker rtn = 1; ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0); memset(ceiling, 0, sizeof(*ceiling)); P_AddThinker (&ceiling->thinker); sec->ceilingdata = ceiling; //jff 2/22/98 ceiling->thinker.function = T_MoveCeiling; ceiling->crush = true; ceiling->direction = -1; ceiling->sector = sec; ceiling->texture = sec->ceilingpic; ceiling->newspecial = sec->special; ceiling->tag = sec->tag; ceiling->type = Slnt? genSilentCrusher : genCrusher; ceiling->topheight = sec->ceilingheight; ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); // setup ceiling motion speed switch (Sped) { case SpeedSlow: ceiling->speed = CEILSPEED; break; case SpeedNormal: ceiling->speed = CEILSPEED*2; break; case SpeedFast: ceiling->speed = CEILSPEED*4; break; case SpeedTurbo: ceiling->speed = CEILSPEED*8; break; default: break; } ceiling->oldspeed=ceiling->speed; P_AddActiveCeiling(ceiling); // add to list of active ceilings if (manual) return rtn; } return rtn; } // // EV_DoGenLockedDoor() // // Handle generalized locked door types // // Passed the linedef activating the generalized locked door // Returns true if a thinker created // int EV_DoGenLockedDoor ( line_t* line ) { int secnum,rtn; sector_t* sec; vldoor_t* door; boolean manual; unsigned value = (unsigned)line->special - GenLockedBase; // parse the bit fields in the line's special type int Kind = (value & LockedKind) >> LockedKindShift; int Sped = (value & LockedSpeed) >> LockedSpeedShift; int Trig = (value & TriggerType) >> TriggerTypeShift; rtn = 0; // check if a manual trigger, if so do just the sector on the backside manual = false; if (Trig==PushOnce || Trig==PushMany) { if (!(sec = line->backsector)) return rtn; secnum = sec-sectors; manual = true; goto manual_locked; } secnum = -1; rtn = 0; // if not manual do all sectors tagged the same as the line while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; manual_locked: // Do not start another function if ceiling already moving if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 { if (!manual) continue; else return rtn; } // new door thinker rtn = 1; door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); memset(door, 0, sizeof(*door)); P_AddThinker (&door->thinker); sec->ceilingdata = door; //jff 2/22/98 door->thinker.function = T_VerticalDoor; door->sector = sec; door->topwait = VDOORWAIT; door->line = line; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = 1; /* killough 10/98: implement gradual lighting */ door->lighttag = !comp[comp_doorlight] && (line->special&6) == 6 && line->special > GenLockedBase ? line->tag : 0; // setup speed of door motion switch(Sped) { default: case SpeedSlow: door->type = Kind? genOpen : genRaise; door->speed = VDOORSPEED; break; case SpeedNormal: door->type = Kind? genOpen : genRaise; door->speed = VDOORSPEED*2; break; case SpeedFast: door->type = Kind? genBlazeOpen : genBlazeRaise; door->speed = VDOORSPEED*4; break; case SpeedTurbo: door->type = Kind? genBlazeOpen : genBlazeRaise; door->speed = VDOORSPEED*8; break; } // killough 4/15/98: fix generalized door opening sounds // (previously they always had the blazing door close sound) S_StartSound((mobj_t *)&door->sector->soundorg, // killough 4/15/98 door->speed >= VDOORSPEED*4 ? sfx_bdopn : sfx_doropn); if (manual) return rtn; } return rtn; } // // EV_DoGenDoor() // // Handle generalized door types // // Passed the linedef activating the generalized door // Returns true if a thinker created // int EV_DoGenDoor ( line_t* line ) { int secnum,rtn; sector_t* sec; boolean manual; vldoor_t* door; unsigned value = (unsigned)line->special - GenDoorBase; // parse the bit fields in the line's special type int Dely = (value & DoorDelay) >> DoorDelayShift; int Kind = (value & DoorKind) >> DoorKindShift; int Sped = (value & DoorSpeed) >> DoorSpeedShift; int Trig = (value & TriggerType) >> TriggerTypeShift; rtn = 0; // check if a manual trigger, if so do just the sector on the backside manual = false; if (Trig==PushOnce || Trig==PushMany) { if (!(sec = line->backsector)) return rtn; secnum = sec-sectors; manual = true; goto manual_door; } secnum = -1; rtn = 0; // if not manual do all sectors tagged the same as the line while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; manual_door: // Do not start another function if ceiling already moving if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98 { if (!manual) continue; else return rtn; } // new door thinker rtn = 1; door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); memset(door, 0, sizeof(*door)); P_AddThinker (&door->thinker); sec->ceilingdata = door; //jff 2/22/98 door->thinker.function = T_VerticalDoor; door->sector = sec; // setup delay for door remaining open/closed switch(Dely) { default: case 0: door->topwait = 35; break; case 1: door->topwait = VDOORWAIT; break; case 2: door->topwait = 2*VDOORWAIT; break; case 3: door->topwait = 7*VDOORWAIT; break; } // setup speed of door motion switch(Sped) { default: case SpeedSlow: door->speed = VDOORSPEED; break; case SpeedNormal: door->speed = VDOORSPEED*2; break; case SpeedFast: door->speed = VDOORSPEED*4; break; case SpeedTurbo: door->speed = VDOORSPEED*8; break; } door->line = line; // jff 1/31/98 remember line that triggered us /* killough 10/98: implement gradual lighting */ door->lighttag = !comp[comp_doorlight] && (line->special&6) == 6 && line->special > GenLockedBase ? line->tag : 0; // set kind of door, whether it opens then close, opens, closes etc. // assign target heights accordingly switch(Kind) { case OdCDoor: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; if (door->topheight != sec->ceilingheight) S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn); door->type = Sped>=SpeedFast? genBlazeRaise : genRaise; break; case ODoor: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; if (door->topheight != sec->ceilingheight) S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast || comp[comp_sound] ? sfx_bdopn : sfx_doropn); door->type = Sped>=SpeedFast? genBlazeOpen : genOpen; break; case CdODoor: door->topheight = sec->ceilingheight; door->direction = -1; S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls); door->type = Sped>=SpeedFast? genBlazeCdO : genCdO; break; case CDoor: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = -1; S_StartSound((mobj_t *)&door->sector->soundorg,Sped>=SpeedFast && !comp[comp_sound] ? sfx_bdcls : sfx_dorcls); door->type = Sped>=SpeedFast? genBlazeClose : genClose; break; default: break; } if (manual) return rtn; } return rtn; }