shithub: choc

ref: bbb39c2906ab01b75e7959a0d07560a4a56c459a
dir: /src/strife/p_doors.c/

View raw version
// Emacs style mode select   -*- C++ -*- 
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005 Simon Howard
//
// 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: Door animation code (opening/closing)
//
//-----------------------------------------------------------------------------



#include "z_zone.h"
#include "doomdef.h"
#include "deh_main.h"
#include "p_local.h"

#include "s_sound.h"


// State.
#include "doomstat.h"
#include "r_state.h"

// Data.
#include "dstrings.h"
#include "sounds.h"


//
// VERTICAL DOORS
//

//
// T_VerticalDoor
//
void T_VerticalDoor(vldoor_t* door)
{
    result_e res1;
    result_e res2;

    switch(door->direction)
    {
    case 0:
        // WAITING
        if (!--door->topcountdown)
        {
            switch(door->type)
            {
            case blazeRaise:
                door->direction = -1; // time to go back down
                S_StartSound(&door->sector->soundorg, sfx_bdcls);
                break;

            case normal:
                door->direction = -1; // time to go back down
                // villsa [STRIFE] closesound added
                S_StartSound(&door->sector->soundorg, door->closesound);
                break;

                // villsa [STRIFE]
            case shopClose:
                door->direction = 1;
                door->speed = (2*FRACUNIT);
                S_StartSound(&door->sector->soundorg, door->opensound);
                break;

            case close30ThenOpen:
                door->direction = 1;

                // villsa [STRIFE] opensound added
                S_StartSound(&door->sector->soundorg, door->opensound);
                break;

            default:
                break;
            }
        }
        break;

    case 2:
        //  INITIAL WAIT
        if (!--door->topcountdown)
        {
            switch(door->type)
            {
            case raiseIn5Mins:
                door->direction = 1;
                door->type = normal;

                // villsa [STRIFE] opensound added
                S_StartSound(&door->sector->soundorg, door->opensound);
                break;

            default:
                break;
            }
        }
        break;

        // villsa [STRIFE]
    case -2:
        // SPLIT
        res1 = T_MovePlane(door->sector, door->speed, door->topheight, 0, 1, 1);
        res2 = T_MovePlane(door->sector, door->speed, door->topwait, 0, 0, -1);

        if(res1 == pastdest && res2 == pastdest)
        {
            door->sector->specialdata = NULL;
            P_RemoveThinker(&door->thinker);  // unlink and free
        }

        break;

    case -1:
        // DOWN
        res1 = T_MovePlane(door->sector, door->speed, door->sector->floorheight, false, 1, door->direction);
        if(res1 == pastdest)
        {
            switch(door->type)
            {
            case normal:
            case close:
            case blazeRaise:
            case blazeClose:
                door->sector->specialdata = NULL;
                P_RemoveThinker (&door->thinker);  // unlink and free
                // villsa [STRIFE] no sounds
                break;

            case close30ThenOpen:
                door->direction = 0;
                door->topcountdown = TICRATE*30;
                break;

                // villsa [STRIFE]
            case shopClose:
                door->direction = 0;
                door->topcountdown = TICRATE*120;
                break;

            default:
                break;
            }
        }
        else if(res1 == crushed)
        {
            switch(door->type)
            {
            case blazeClose:
            case close:		// DO NOT GO BACK UP!
            case shopClose:     // villsa [STRIFE]
                break;

            default:
                door->direction = 1;
                // villsa [STRIFE] opensound added
                S_StartSound(&door->sector->soundorg, door->opensound);
                break;
            }
        }
        break;

    case 1:
        // UP
        res1 = T_MovePlane(door->sector,
            door->speed,
            door->topheight,
            false,1,door->direction);

        if(res1 == pastdest)
        {
            switch(door->type)
            {
            case blazeRaise:
            case normal:
                door->direction = 0; // wait at top
                door->topcountdown = door->topwait;
                break;

            case close30ThenOpen:
            case blazeOpen:
            case open:
            case shopClose:     // villsa [STRIFE]
                door->sector->specialdata = NULL;
                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 = DEH_String(PD_BLUEO);
	    S_StartSound(NULL,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 = DEH_String(PD_REDO);
	    S_StartSound(NULL,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 = DEH_String(PD_YELLOWO);
	    S_StartSound(NULL,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 = &sectors[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;
        R_SoundNumForDoor(door);    // villsa [STRIFE] set door sounds

        switch(type)
        {
            // villsa [STRIFE] new door type
        case splitOpen:
            door->direction = -2;
            door->topheight = P_FindLowestCeilingSurrounding(sec);
            door->topheight -= 4*FRACUNIT;
            door->speed = FRACUNIT;
            // yes, it using topwait to get the floor height
            door->topwait = P_FindLowestFloorSurrounding(sec);
            if(door->topheight == sec->ceilingheight)
                continue;

            S_StartSound(&sec->soundorg, door->opensound);
            break;

            // villsa [STRIFE] new door type
        case splitRaiseNearest:
            door->direction = -2;
            door->topheight = P_FindLowestCeilingSurrounding(sec);
            door->topheight -= 4*FRACUNIT;
            door->speed = FRACUNIT;
            // yes, it using topwait to get the floor height
            door->topwait = P_FindHighestFloorSurrounding(sec);
            if(door->topheight == sec->ceilingheight)
                continue;

            S_StartSound(&sec->soundorg, door->opensound);
            break;

        case blazeClose:
        case shopClose:     // villsa [STRIFE]
            door->topheight = P_FindLowestCeilingSurrounding(sec);
            door->topheight -= 4*FRACUNIT;
            door->direction = -1;
            door->speed = VDOORSPEED * 4;
            S_StartSound(&door->sector->soundorg, sfx_bdcls);
            break;

        case close:
            door->topheight = P_FindLowestCeilingSurrounding(sec);
            door->topheight -= 4*FRACUNIT;
            door->direction = -1;

            // villsa [STRIFE] set door sounds
            S_StartSound(&door->sector->soundorg, door->opensound);
            break;

        case close30ThenOpen:
            door->topheight = sec->ceilingheight;
            door->direction = -1;

            // villsa [STRIFE] set door sounds
            S_StartSound(&door->sector->soundorg, door->closesound);
            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(&door->sector->soundorg, sfx_bdopn);
            break;

        case normal:
        case open:
            door->direction = 1;
            door->topheight = P_FindLowestCeilingSurrounding(sec);
            door->topheight -= 4*FRACUNIT;

            if(door->topheight != sec->ceilingheight)
                S_StartSound(&door->sector->soundorg, door->opensound);
            break;

        default:
            break;
        }

    }
    return rtn;
}

//
// EV_ClearForceFields
//
// villsa [STRIFE] new function
//
int EV_ClearForceFields(line_t* line)
{
    int         secnum;
    int         rtn;
    sector_t*   sec;
    int         i;
    line_t*     secline;

    secnum = -1;
    rtn = 0;

    while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
    {
        sec = &sectors[secnum];
        rtn = 1;

        line->special = 0;

        if(!sec->linecount)
            return;

        for(i = 0; i < sec->linecount; i++)
        {
            secline = sec->lines[i];
            if(!(secline->flags & ML_TWOSIDED))
                continue;
            if(secline->special != 148)
                continue;

            secline->flags &= ~ML_BLOCKING;
            secline->special = 0;
            sides[secline->sidenum[0]].midtexture = 0;
            sides[secline->sidenum[1]].midtexture = 0;
        }
    }
}


//
// 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 = DEH_String(PD_BLUEK);
	    S_StartSound(NULL,sfx_oof);
	    return;
	}
	break;
	
      case 27: // Yellow Lock
      case 34:
	if ( !player )
	    return;
	
	if (!player->cards[it_yellowcard] &&
	    !player->cards[it_yellowskull])
	{
	    player->message = DEH_String(PD_YELLOWK);
	    S_StartSound(NULL,sfx_oof);
	    return;
	}
	break;
	
      case 28: // Red Lock
      case 33:
	if ( !player )
	    return;
	
	if (!player->cards[it_redcard] && !player->cards[it_redskull])
	{
	    player->message = DEH_String(PD_REDK);
	    S_StartSound(NULL,sfx_oof);
	    return;
	}
	break;
    }*/
	
    // if the sector has an active thinker, use it
    sec = sides[ line->sidenum[side^1]] .sector;
    secnum = 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

                // When is a door not a door?
                // In Vanilla, door->direction is set, even though
                // "specialdata" might not actually point at a door.

                if (door->thinker.function.acp1 == (actionf_p1) T_VerticalDoor)
                {
                    door->direction = -1;	// start going down immediately
                }
                else if (door->thinker.function.acp1 == (actionf_p1) T_PlatRaise)
                {
                    // Erm, this is a plat, not a door.
                    // This notably causes a problem in ep1-0500.lmp where
                    // a plat and a door are cross-referenced; the door
                    // doesn't open on 64-bit.
                    // The direction field in vldoor_t corresponds to the wait
                    // field in plat_t.  Let's set that to -1 instead.

                    plat_t *plat;

                    plat = (plat_t *) door;
                    plat->wait = -1;
                }
                else
                {
                    // This isn't a door OR a plat.  Now we're in trouble.

                    fprintf(stderr, "EV_VerticalDoor: Tried to close "
                                    "something that wasn't a door.\n");

                    // Try closing it anyway. At least it will work on 32-bit
                    // machines.

                    door->direction = -1;
                }
	    }
	    return;
	}
    }
	
    // for proper sound
    switch(line->special)
    {
      case 117:	// BLAZING DOOR RAISE
      case 118:	// BLAZING DOOR OPEN
	S_StartSound(&sec->soundorg,sfx_bdopn);
	break;
	
      case 1:	// NORMAL DOOR SOUND
      case 31:
	S_StartSound(&sec->soundorg,sfx_swish); // villsa [STRIFE] TODO - fix sounds
	break;
	
      default:	// LOCKED DOOR SOUND
	S_StartSound(&sec->soundorg,sfx_swish); // villsa [STRIFE] TODO - fix sounds
	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 = normal;
	break;
	
      case 31:
      case 32:
      case 33:
      case 34:
	door->type = 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 = normal;
    door->speed = VDOORSPEED;
    door->topcountdown = 30 * TICRATE;
}

//
// 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 * TICRATE;
}


// villsa [STRIFE] resurrected sliding doors
//

//
// villsa [STRIFE]
//
// Sliding door name information
//
static slidename_t slideFrameNames[MAXSLIDEDOORS] =
{
    // SIGLDR
    {
        "SIGLDR01",  // frame1
        "SIGLDR02",  // frame2
        "SIGLDR03",  // frame3
        "SIGLDR04",  // frame4
        "SIGLDR05",  // frame5
        "SIGLDR06",  // frame6
        "SIGLDR07",  // frame7
        "SIGLDR08"   // frame8
    },
    // DORSTN
    {
        "DORSTN01",  // frame1
        "DORSTN02",  // frame2
        "DORSTN03",  // frame3
        "DORSTN04",  // frame4
        "DORSTN05",  // frame5
        "DORSTN06",  // frame6
        "DORSTN07",  // frame7
        "DORSTN08"   // frame8
    },

    // DORQTR
    {
        "DORQTR01",  // frame1
        "DORQTR02",  // frame2
        "DORQTR03",  // frame3
        "DORQTR04",  // frame4
        "DORQTR05",  // frame5
        "DORQTR06",  // frame6
        "DORQTR07",  // frame7
        "DORQTR08"   // frame8
    },

    // DORCRG
    {
        "DORCRG01",  // frame1
        "DORCRG02",  // frame2
        "DORCRG03",  // frame3
        "DORCRG04",  // frame4
        "DORCRG05",  // frame5
        "DORCRG06",  // frame6
        "DORCRG07",  // frame7
        "DORCRG08"   // frame8
    },

    // DORCHN
    {
        "DORCHN01",  // frame1
        "DORCHN02",  // frame2
        "DORCHN03",  // frame3
        "DORCHN04",  // frame4
        "DORCHN05",  // frame5
        "DORCHN06",  // frame6
        "DORCHN07",  // frame7
        "DORCHN08"   // frame8
    },

    // DORIRS
    {
        "DORIRS01",  // frame1
        "DORIRS02",  // frame2
        "DORIRS03",  // frame3
        "DORIRS04",  // frame4
        "DORIRS05",  // frame5
        "DORIRS06",  // frame6
        "DORIRS07",  // frame7
        "DORIRS08"   // frame8
    },

    // DORALN
    {
        "DORALN01",  // frame1
        "DORALN02",  // frame2
        "DORALN03",  // frame3
        "DORALN04",  // frame4
        "DORALN05",  // frame5
        "DORALN06",  // frame6
        "DORALN07",  // frame7
        "DORALN08"   // frame8
    },

    {"\0","\0","\0","\0","\0","\0","\0","\0"}
};

//
// villsa [STRIFE]
//
// Sliding door open sounds
//
static sfxenum_t slideOpenSounds[MAXSLIDEDOORS] =
{
    sfx_drlmto, sfx_drston, sfx_airlck, sfx_drsmto,
    sfx_drchno, sfx_airlck, sfx_airlck, sfx_None
};

//
// villsa [STRIFE]
//
// Sliding door close sounds
//
static sfxenum_t slideCloseSounds[MAXSLIDEDOORS] =
{
    sfx_drlmtc, sfx_drston, sfx_airlck, sfx_drsmtc,
    sfx_drchnc, sfx_airlck, sfx_airlck, sfx_None
};

slideframe_t slideFrames[MAXSLIDEDOORS];

//
// P_InitSlidingDoorFrames
//
// villsa [STRIFE] resurrected
//
void P_InitSlidingDoorFrames(void)
{
    int i;
    int f1;
    int f2;
    int f3;
    int f4;

    memset(slideFrames, 0, sizeof(slideframe_t) * MAXSLIDEDOORS);
	
    for(i = 0; i < MAXSLIDEDOORS; i++)
    {
	if(!slideFrameNames[i].frame1[0])
	    break;
			
	f1 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame1));
	f2 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame2));
	f3 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame3));
	f4 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame4));

	slideFrames[i].frames[0] = f1;
	slideFrames[i].frames[1] = f2;
	slideFrames[i].frames[2] = f3;
	slideFrames[i].frames[3] = f4;
		
	f1 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame5));
	f2 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame6));
	f3 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame7));
	f4 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame8));

	slideFrames[i].frames[4] = f1;
	slideFrames[i].frames[5] = f2;
	slideFrames[i].frames[6] = f3;
	slideFrames[i].frames[7] = f4;
    }
}


//
// P_FindSlidingDoorType
//
// Return index into "slideFrames" array
// for which door type to use
//
// villsa [STRIFE] resurrected
//
int P_FindSlidingDoorType(line_t* line)
{
    int i;
    int val;
	
    for(i = 0; i < MAXSLIDEDOORS-1; i++)
    {
        val = sides[line->sidenum[0]].toptexture;
	if(val == slideFrames[i].frames[0])
	    return i;
    }
	
    return -1;
}

//
// T_SlidingDoor
//
// villsa [STRIFE] resurrected
//
void T_SlidingDoor(slidedoor_t* door)
{
    sector_t* sec;

    sec = door->frontsector;

    switch(door->status)
    {
    case sd_opening:
        if(!door->timer--)
        {
            if(++door->frame == SNUMFRAMES)
            {
                // IF DOOR IS DONE OPENING...
                door->line1->flags &= ~ML_BLOCKING;
                door->line2->flags &= ~ML_BLOCKING;

                if(door->type == sdt_openOnly)
                {
                    door->frontsector->specialdata = NULL;
                    P_RemoveThinker (&door->thinker);
                    return;
                }

                door->timer = SDOORWAIT;
                door->status = sd_waiting;
            }
            else
            {
                // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME...
                door->timer = SWAITTICS;

                sides[door->line2->sidenum[0]].midtexture =
                    slideFrames[door->whichDoorIndex].frames[door->frame];

                sides[door->line2->sidenum[1]].midtexture =
                    slideFrames[door->whichDoorIndex].frames[door->frame];

                sides[door->line1->sidenum[0]].midtexture =
                    slideFrames[door->whichDoorIndex].frames[door->frame];

                sides[door->line1->sidenum[1]].midtexture =
                    slideFrames[door->whichDoorIndex].frames[door->frame];
            }
        }

        return;

    case sd_waiting:
        // IF DOOR IS DONE WAITING...
        if(!door->timer--)
        {
            fixed_t speed;
            fixed_t cheight;

            sec = door->frontsector;

            // CAN DOOR CLOSE?
            if(sec->thinglist != NULL)
            {
                door->timer = SDOORWAIT;
                return;
            }
            else
            {

                cheight = sec->ceilingheight;
                speed = cheight - sec->floorheight - (10*FRACUNIT);

                // something blocking it?
                if(T_MovePlane(sec, speed, sec->floorheight, 0, 1, -1) == crushed)
                {
                    door->timer = SDOORWAIT;
                    return;
                }
                else
                {
                    // Instantly move plane
                    T_MovePlane(sec, (128*FRACUNIT), cheight, 0, 1, 1);

                    // turn line blocking back on
                    door->line1->flags |= ML_BLOCKING;
                    door->line2->flags |= ML_BLOCKING;

                    // play close sound
                    S_StartSound(&sec->soundorg, slideCloseSounds[door->whichDoorIndex]);

                    door->status = sd_closing;
                    door->timer = SWAITTICS;
                }
            }
        }

        return;

    case sd_closing:
        if (!door->timer--)
        {
            if(--door->frame < 0)
            {
                // IF DOOR IS DONE CLOSING...
                T_MovePlane(sec, (128*FRACUNIT), sec->floorheight, 0, 1, -1);
                door->frontsector->specialdata = NULL;
                P_RemoveThinker (&door->thinker);
                return;
            }
            else
            {
                // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME...
                door->timer = SWAITTICS;

                sides[door->line2->sidenum[0]].midtexture =
                    slideFrames[door->whichDoorIndex].frames[door->frame];

                sides[door->line2->sidenum[1]].midtexture =
                    slideFrames[door->whichDoorIndex].frames[door->frame];

                sides[door->line1->sidenum[0]].midtexture =
                    slideFrames[door->whichDoorIndex].frames[door->frame];

                sides[door->line1->sidenum[1]].midtexture =
                    slideFrames[door->whichDoorIndex].frames[door->frame];
            }
        }

        return;
    }
}

//
// EV_RemoteSlidingDoor
//
// villsa [STRIFE] new function
//
int EV_RemoteSlidingDoor(line_t* line, mobj_t* thing)
{
    int		    secnum;
    sector_t*       sec;
    slidedoor_t*    door;
    int             i;
    int             rtn;
    line_t*         secline;
	
    secnum = -1;
    rtn = 0;
    
    while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
    {
        sec = &sectors[secnum];
        if(sec->specialdata)
            continue;

        for(i = 0; i < 4; i++)
        {
            secline = sec->lines[i];

            if(P_FindSlidingDoorType(secline) < 0)
                continue;

            EV_SlidingDoor(secline, thing);
            rtn = 1;
        }
    }

    return rtn;
}


//
// EV_SlidingDoor
//
// villsa [STRIFE]
//
void EV_SlidingDoor(line_t* line, mobj_t* thing)
{
    sector_t*       sec;
    slidedoor_t*    door;
    int             i;
    line_t*         secline;

    // Make sure door isn't already being animated
    sec = sides[line->sidenum[1]].sector;
    door = NULL;
    if(sec->specialdata)
    {
        if (!thing->player)
            return;

        door = sec->specialdata;
        if(door->type == sdt_openAndClose)
        {
            if(door->status == sd_waiting)
            {
                door->status = sd_closing;
                door->timer = SWAITTICS;    // villsa [STRIFE]
            }
        }
        else
            return;
    }

    // Init sliding door vars
    if(!door)
    {
        door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
        P_AddThinker (&door->thinker);

        sec->specialdata = door;

        door->type = sdt_openAndClose;
        door->status = sd_opening;
        door->whichDoorIndex = P_FindSlidingDoorType(line);

        // villsa [STRIFE] different error message
        if(door->whichDoorIndex < 0)
            I_Error(DEH_String("EV_SlidingDoor: Textures are not defined for sliding door!"));

        sides[line->sidenum[0]].midtexture = sides[line->sidenum[0]].toptexture;

        // villsa [STRIFE]
        door->line1 = line;
        door->line2 = line;

        // villsa [STRIFE] this loop assumes that the sliding door is made up
        // of only four linedefs!
        for(i = 0; i < 4; i++)
        {
            secline = sec->lines[i];
            if(secline != line)
            {
                side_t* side1;
                side_t* side2;

                side1 = &sides[secline->sidenum[0]];
                side2 = &sides[line->sidenum[0]];

                if(side1->toptexture == side2->toptexture)
                    door->line2 = secline;
            }
        }

        door->thinker.function.acp1 = (actionf_p1)T_SlidingDoor;
        door->timer = SWAITTICS;
        door->frontsector = sec;
        door->frame = 0;

        // villsa [STRIFE] preset flags
        door->line1->flags |= ML_BLOCKING;
        door->line2->flags |= ML_BLOCKING;

        // villsa [STRIFE] set the closing sector
        T_MovePlane(
            door->frontsector,
            (128*FRACUNIT),
            P_FindLowestCeilingSurrounding(door->frontsector),
            0,
            1,
            1);

        // villsa [STRIFE] play open sound
        S_StartSound(&door->frontsector->soundorg, slideOpenSounds[door->whichDoorIndex]);
    }
}