// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id:$ // // Copyright (C) 1993-1996 by id Software, Inc. // // This source is available for distribution and/or modification // only under the terms of the DOOM Source Code License as // published by id Software. All rights reserved. // // The source is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License // for more details. // // $Log:$ // // DESCRIPTION: Door animation code (opening/closing) // //----------------------------------------------------------------------------- #include "doom_config.h" #include "z_zone.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" #include "doomstat.h" // State. #include "r_state.h" // State. #include "dstrings.h" // Data. #include "sounds.h" // Data. // // VERTICAL DOORS // // // T_VerticalDoor // void T_VerticalDoor(vldoor_t* door) { result_e res; switch (door->direction) { case 0: // WAITING if (!--door->topcountdown) { switch (door->type) { case blazeRaise: door->direction = -1; // time to go back down S_StartSound((mobj_t*)&door->sector->soundorg, sfx_bdcls); break; case door_normal: door->direction = -1; // time to go back down S_StartSound((mobj_t*)&door->sector->soundorg, sfx_dorcls); break; case close30ThenOpen: door->direction = 1; S_StartSound((mobj_t*)&door->sector->soundorg, sfx_doropn); break; default: break; } } break; case 2: // INITIAL WAIT if (!--door->topcountdown) { switch (door->type) { case raiseIn5Mins: door->direction = 1; door->type = door_normal; S_StartSound((mobj_t*)&door->sector->soundorg, sfx_doropn); break; default: break; } } break; case -1: // DOWN res = T_MovePlane(door->sector, door->speed, door->sector->floorheight, false, 1, door->direction); if (res == pastdest) { switch (door->type) { case blazeRaise: case blazeClose: door->sector->specialdata = 0; P_RemoveThinker(&door->thinker); // unlink and free S_StartSound((mobj_t*)&door->sector->soundorg, sfx_bdcls); break; case door_normal: case door_close: door->sector->specialdata = 0; P_RemoveThinker(&door->thinker); // unlink and free break; case close30ThenOpen: door->direction = 0; door->topcountdown = 35 * 30; break; default: break; } } else if (res == crushed) { switch (door->type) { case blazeClose: case door_close: // DO NOT GO BACK UP! break; default: door->direction = 1; S_StartSound((mobj_t*)&door->sector->soundorg, sfx_doropn); break; } } break; case 1: // UP res = T_MovePlane(door->sector, door->speed, door->topheight, false, 1, door->direction); if (res == pastdest) { switch (door->type) { case blazeRaise: case door_normal: door->direction = 0; // wait at top door->topcountdown = door->topwait; break; case close30ThenOpen: case blazeOpen: case door_open: door->sector->specialdata = 0; P_RemoveThinker(&door->thinker); // unlink and free break; default: break; } } break; } } // // EV_DoLockedDoor // Move a locked door up/down // int EV_DoLockedDoor(line_t* line, vldoor_e type, mobj_t* thing) { player_t* p; p = thing->player; if (!p) return 0; switch (line->special) { case 99: // Blue Lock case 133: if (!p) return 0; if (!p->cards[it_bluecard] && !p->cards[it_blueskull]) { p->message = PD_BLUEO; S_StartSound(0, sfx_oof); return 0; } break; case 134: // Red Lock case 135: if (!p) return 0; if (!p->cards[it_redcard] && !p->cards[it_redskull]) { p->message = PD_REDO; S_StartSound(0, sfx_oof); return 0; } break; case 136: // Yellow Lock case 137: if (!p) return 0; if (!p->cards[it_yellowcard] && !p->cards[it_yellowskull]) { p->message = PD_YELLOWO; S_StartSound(0, sfx_oof); return 0; } break; } return EV_DoDoor(line, type); } int EV_DoDoor(line_t* line, vldoor_e type) { int secnum, rtn; sector_t* sec; vldoor_t* door; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // new door thinker rtn = 1; door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->type = type; door->topwait = VDOORWAIT; door->speed = VDOORSPEED; switch (type) { case blazeClose: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; door->direction = -1; door->speed = VDOORSPEED * 4; S_StartSound((mobj_t*)&door->sector->soundorg, sfx_bdcls); break; case door_close: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; door->direction = -1; S_StartSound((mobj_t*)&door->sector->soundorg, sfx_dorcls); break; case close30ThenOpen: door->topheight = sec->ceilingheight; door->direction = -1; S_StartSound((mobj_t*)&door->sector->soundorg, sfx_dorcls); break; case blazeRaise: case blazeOpen: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; door->speed = VDOORSPEED * 4; if (door->topheight != sec->ceilingheight) S_StartSound((mobj_t*)&door->sector->soundorg, sfx_bdopn); break; case door_normal: case door_open: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; if (door->topheight != sec->ceilingheight) S_StartSound((mobj_t*)&door->sector->soundorg, sfx_doropn); break; default: break; } } return rtn; } // // EV_VerticalDoor : open a door manually, no tag value // void EV_VerticalDoor(line_t* line, mobj_t* thing) { player_t* player; int secnum; sector_t* sec; vldoor_t* door; int side; side = 0; // only front sides can be used // Check for locks player = thing->player; switch (line->special) { case 26: // Blue Lock case 32: if (!player) return; if (!player->cards[it_bluecard] && !player->cards[it_blueskull]) { player->message = PD_BLUEK; S_StartSound(0, sfx_oof); return; } break; case 27: // Yellow Lock case 34: if (!player) return; if (!player->cards[it_yellowcard] && !player->cards[it_yellowskull]) { player->message = PD_YELLOWK; S_StartSound(0, sfx_oof); return; } break; case 28: // Red Lock case 33: if (!player) return; if (!player->cards[it_redcard] && !player->cards[it_redskull]) { player->message = PD_REDK; S_StartSound(0, sfx_oof); return; } break; } // if the sector has an active thinker, use it sec = sides[line->sidenum[side ^ 1]].sector; secnum = (int)(sec - sectors); if (sec->specialdata) { door = sec->specialdata; switch (line->special) { case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s case 26: case 27: case 28: case 117: if (door->direction == -1) door->direction = 1; // go back up else { if (!thing->player) return; // JDC: bad guys never close doors door->direction = -1; // start going down immediately } return; } } // for proper sound switch (line->special) { case 117: // BLAZING DOOR RAISE case 118: // BLAZING DOOR OPEN S_StartSound((mobj_t*)&sec->soundorg, sfx_bdopn); break; case 1: // NORMAL DOOR SOUND case 31: S_StartSound((mobj_t*)&sec->soundorg, sfx_doropn); break; default: // LOCKED DOOR SOUND S_StartSound((mobj_t*)&sec->soundorg, sfx_doropn); break; } // new door thinker door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->direction = 1; door->speed = VDOORSPEED; door->topwait = VDOORWAIT; switch (line->special) { case 1: case 26: case 27: case 28: door->type = door_normal; break; case 31: case 32: case 33: case 34: door->type = door_open; line->special = 0; break; case 117: // blazing door raise door->type = blazeRaise; door->speed = VDOORSPEED * 4; break; case 118: // blazing door open door->type = blazeOpen; line->special = 0; door->speed = VDOORSPEED * 4; break; } // find the top and bottom of the movement range door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; } // // Spawn a door that closes after 30 seconds // void P_SpawnDoorCloseIn30(sector_t* sec) { vldoor_t* door; door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->direction = 0; door->type = door_normal; door->speed = VDOORSPEED; door->topcountdown = 30 * 35; } // // Spawn a door that opens after 5 minutes // void P_SpawnDoorRaiseIn5Mins(sector_t* sec, int secnum) { vldoor_t* door; door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; sec->special = 0; door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor; door->sector = sec; door->direction = 2; door->type = raiseIn5Mins; door->speed = VDOORSPEED; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; door->topwait = VDOORWAIT; door->topcountdown = 5 * 60 * 35; }