mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-07 21:41:25 +00:00
15681d0588
dialogs. - Added Thing_Raise special that allows Arch-Vile like resurrections from scripts or DECORATE states. - Added a RadiusDamageFactor property for actors. This replaces the hard coded factor of 0.25 for Hexen's players. - Added new SpawnProjectile function to ACS. It's the same as Thing_Projectile2 but the projectile is specified by name, not spawn ID. - Added MAPINFO option to set the compatibility flags. If this is done these explicit settings will take precedence over the compatflags CVAR. SVN r164 (trunk)
871 lines
19 KiB
C++
871 lines
19 KiB
C++
// 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)
|
|
// [RH] Removed sliding door code and simplified for Hexen-ish specials
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "doomdef.h"
|
|
#include "p_local.h"
|
|
#include "s_sound.h"
|
|
#include "s_sndseq.h"
|
|
#include "doomstat.h"
|
|
#include "r_state.h"
|
|
#include "c_console.h"
|
|
#include "gi.h"
|
|
#include "a_keys.h"
|
|
#include "i_system.h"
|
|
#include "sc_man.h"
|
|
|
|
IMPLEMENT_CLASS (DDoor)
|
|
|
|
DDoor::DDoor ()
|
|
{
|
|
}
|
|
|
|
void DDoor::Serialize (FArchive &arc)
|
|
{
|
|
Super::Serialize (arc);
|
|
arc << m_Type
|
|
<< m_TopDist
|
|
<< m_BotSpot << m_BotDist << m_OldFloorDist
|
|
<< m_Speed
|
|
<< m_Direction
|
|
<< m_TopWait
|
|
<< m_TopCountdown
|
|
<< m_LightTag;
|
|
}
|
|
|
|
|
|
//
|
|
// VERTICAL DOORS
|
|
//
|
|
|
|
//
|
|
// T_VerticalDoor
|
|
//
|
|
void DDoor::Tick ()
|
|
{
|
|
EResult res;
|
|
|
|
if (m_Sector->floorplane.d != m_OldFloorDist)
|
|
{
|
|
if (!m_Sector->floordata || !m_Sector->floordata->IsKindOf(RUNTIME_CLASS(DPlat)) ||
|
|
!((DPlat*)m_Sector->floordata)->IsLift())
|
|
{
|
|
m_OldFloorDist = m_Sector->floorplane.d;
|
|
m_BotDist = m_Sector->ceilingplane.PointToDist (m_BotSpot,
|
|
m_Sector->floorplane.ZatPoint (m_BotSpot));
|
|
}
|
|
}
|
|
|
|
switch (m_Direction)
|
|
{
|
|
case 0:
|
|
// WAITING
|
|
if (!--m_TopCountdown)
|
|
{
|
|
switch (m_Type)
|
|
{
|
|
case doorRaise:
|
|
m_Direction = -1; // time to go back down
|
|
DoorSound (false);
|
|
break;
|
|
|
|
case doorCloseWaitOpen:
|
|
m_Direction = 1;
|
|
DoorSound (true);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
// INITIAL WAIT
|
|
if (!--m_TopCountdown)
|
|
{
|
|
switch (m_Type)
|
|
{
|
|
case doorRaiseIn5Mins:
|
|
m_Direction = 1;
|
|
m_Type = doorRaise;
|
|
DoorSound (true);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case -1:
|
|
// DOWN
|
|
res = MoveCeiling (m_Speed, m_BotDist, -1, m_Direction);
|
|
|
|
// killough 10/98: implement gradual lighting effects
|
|
if (m_LightTag != 0 && m_TopDist != -m_Sector->floorplane.d)
|
|
{
|
|
EV_LightTurnOnPartway (m_LightTag, FixedDiv (m_Sector->ceilingplane.d + m_Sector->floorplane.d,
|
|
m_TopDist + m_Sector->floorplane.d));
|
|
}
|
|
|
|
if (res == pastdest)
|
|
{
|
|
SN_StopSequence (m_Sector);
|
|
switch (m_Type)
|
|
{
|
|
case doorRaise:
|
|
case doorClose:
|
|
m_Sector->ceilingdata = NULL; //jff 2/22/98
|
|
stopinterpolation (INTERP_SectorCeiling, m_Sector);
|
|
Destroy (); // unlink and free
|
|
break;
|
|
|
|
case doorCloseWaitOpen:
|
|
m_Direction = 0;
|
|
m_TopCountdown = m_TopWait;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if (res == crushed)
|
|
{
|
|
switch (m_Type)
|
|
{
|
|
case doorClose: // DO NOT GO BACK UP!
|
|
break;
|
|
|
|
default:
|
|
m_Direction = 1;
|
|
DoorSound (true);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
// UP
|
|
res = MoveCeiling (m_Speed, m_TopDist, -1, m_Direction);
|
|
|
|
// killough 10/98: implement gradual lighting effects
|
|
if (m_LightTag != 0 && m_TopDist != -m_Sector->floorplane.d)
|
|
{
|
|
EV_LightTurnOnPartway (m_LightTag, FixedDiv (m_Sector->ceilingplane.d + m_Sector->floorplane.d,
|
|
m_TopDist + m_Sector->floorplane.d));
|
|
}
|
|
|
|
if (res == pastdest)
|
|
{
|
|
SN_StopSequence (m_Sector);
|
|
switch (m_Type)
|
|
{
|
|
case doorRaise:
|
|
m_Direction = 0; // wait at top
|
|
m_TopCountdown = m_TopWait;
|
|
break;
|
|
|
|
case doorCloseWaitOpen:
|
|
case doorOpen:
|
|
m_Sector->ceilingdata = NULL; //jff 2/22/98
|
|
stopinterpolation (INTERP_SectorCeiling, m_Sector);
|
|
Destroy (); // unlink and free
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// [RH] DoorSound: Plays door sound depending on direction and speed
|
|
void DDoor::DoorSound (bool raise) const
|
|
{
|
|
int choice;
|
|
|
|
// For multiple-selection sound sequences, the following choices are used:
|
|
// 0 Opening
|
|
// 1 Closing
|
|
// 2 Opening fast
|
|
// 3 Closing fast
|
|
|
|
choice = !raise;
|
|
|
|
if (m_Speed >= FRACUNIT*8)
|
|
{
|
|
choice += 2;
|
|
}
|
|
|
|
if (m_Sector->seqType >= 0)
|
|
{
|
|
SN_StartSequence (m_Sector, m_Sector->seqType, SEQ_DOOR, choice);
|
|
}
|
|
else
|
|
{
|
|
const char *snd;
|
|
|
|
switch (gameinfo.gametype)
|
|
{
|
|
default: /* Doom and Hexen */
|
|
snd = "DoorNormal";
|
|
break;
|
|
|
|
case GAME_Heretic:
|
|
snd = "HereticDoor";
|
|
break;
|
|
|
|
case GAME_Strife:
|
|
snd = "DoorSmallMetal";
|
|
|
|
// Search the front top textures of 2-sided lines on the door sector
|
|
// for a door sound to use.
|
|
for (int i = 0; i < m_Sector->linecount; ++i)
|
|
{
|
|
const char *texname;
|
|
line_t *line = m_Sector->lines[i];
|
|
|
|
if (line->backsector == NULL)
|
|
continue;
|
|
|
|
texname = TexMan[sides[line->sidenum[0]].toptexture]->Name;
|
|
if (texname[0] == 'D' && texname[1] == 'O' && texname[2] == 'R')
|
|
{
|
|
switch (texname[3])
|
|
{
|
|
case 'S':
|
|
snd = "DoorStone";
|
|
break;
|
|
|
|
case 'M':
|
|
if (texname[4] == 'L')
|
|
{
|
|
snd = "DoorLargeMetal";
|
|
}
|
|
break;
|
|
|
|
case 'W':
|
|
if (texname[4] == 'L')
|
|
{
|
|
snd = "DoorLargeWood";
|
|
}
|
|
else
|
|
{
|
|
snd = "DoorSmallWood";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
SN_StartSequence (m_Sector, snd, choice);
|
|
}
|
|
}
|
|
|
|
DDoor::DDoor (sector_t *sector)
|
|
: DMovingCeiling (sector)
|
|
{
|
|
}
|
|
|
|
// [RH] Merged EV_VerticalDoor and EV_DoLockedDoor into EV_DoDoor
|
|
// and made them more general to support the new specials.
|
|
|
|
// [RH] SpawnDoor: Helper function for EV_DoDoor
|
|
DDoor::DDoor (sector_t *sec, EVlDoor type, fixed_t speed, int delay, int lightTag)
|
|
: DMovingCeiling (sec),
|
|
m_Type (type), m_Speed (speed), m_TopWait (delay), m_LightTag (lightTag)
|
|
{
|
|
vertex_t *spot;
|
|
fixed_t height;
|
|
|
|
if (i_compatflags & COMPATF_NODOORLIGHT)
|
|
{
|
|
m_LightTag = 0;
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case doorClose:
|
|
m_Direction = -1;
|
|
height = sec->FindLowestCeilingSurrounding (&spot);
|
|
m_TopDist = sec->ceilingplane.PointToDist (spot, height - 4*FRACUNIT);
|
|
DoorSound (false);
|
|
break;
|
|
|
|
case doorOpen:
|
|
case doorRaise:
|
|
m_Direction = 1;
|
|
height = sec->FindLowestCeilingSurrounding (&spot);
|
|
m_TopDist = sec->ceilingplane.PointToDist (spot, height - 4*FRACUNIT);
|
|
if (m_TopDist != sec->ceilingplane.d)
|
|
DoorSound (true);
|
|
break;
|
|
|
|
case doorCloseWaitOpen:
|
|
m_TopDist = sec->ceilingplane.d;
|
|
m_Direction = -1;
|
|
DoorSound (false);
|
|
break;
|
|
|
|
case doorRaiseIn5Mins:
|
|
m_Direction = 2;
|
|
height = sec->FindLowestCeilingSurrounding (&spot);
|
|
m_TopDist = sec->ceilingplane.PointToDist (spot, height - 4*FRACUNIT);
|
|
m_TopCountdown = 5 * 60 * TICRATE;
|
|
break;
|
|
}
|
|
|
|
if (!m_Sector->floordata || !m_Sector->floordata->IsKindOf(RUNTIME_CLASS(DPlat)) ||
|
|
!((DPlat*)m_Sector->floordata)->IsLift())
|
|
{
|
|
height = sec->FindHighestFloorPoint (&m_BotSpot);
|
|
m_BotDist = sec->ceilingplane.PointToDist (m_BotSpot, height);
|
|
}
|
|
else
|
|
{
|
|
height = sec->FindLowestCeilingPoint(&m_BotSpot);
|
|
m_BotDist = sec->ceilingplane.PointToDist (m_BotSpot, height);
|
|
}
|
|
m_OldFloorDist = sec->floorplane.d;
|
|
}
|
|
|
|
bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing,
|
|
int tag, int speed, int delay, int lock, int lightTag)
|
|
{
|
|
bool rtn = false;
|
|
int secnum;
|
|
sector_t* sec;
|
|
|
|
if (lock != 0 && !P_CheckKeys (thing, lock, tag != 0))
|
|
return false;
|
|
|
|
if (tag == 0)
|
|
{ // [RH] manual door
|
|
if (!line)
|
|
return false;
|
|
|
|
// if the wrong side of door is pushed, give oof sound
|
|
if (line->sidenum[1] == NO_SIDE) // killough
|
|
{
|
|
S_Sound (thing, CHAN_VOICE, "*usefail", 1, ATTN_NORM);
|
|
return false;
|
|
}
|
|
|
|
// get the sector on the second side of activating linedef
|
|
sec = sides[line->sidenum[1]].sector;
|
|
secnum = sec-sectors;
|
|
|
|
// if door already has a thinker, use it
|
|
if (sec->ceilingdata)
|
|
{
|
|
if (sec->ceilingdata->IsKindOf (RUNTIME_CLASS(DDoor)))
|
|
{
|
|
DDoor *door = static_cast<DDoor *>(sec->ceilingdata);
|
|
|
|
// ONLY FOR "RAISE" DOORS, NOT "OPEN"s
|
|
if (door->m_Type == DDoor::doorRaise && type == DDoor::doorRaise)
|
|
{
|
|
if (door->m_Direction == -1)
|
|
{
|
|
door->m_Direction = 1; // go back up
|
|
door->DoorSound (true); // [RH] Make noise
|
|
}
|
|
else if (GET_SPAC(line->flags) != SPAC_PUSH)
|
|
// [RH] activate push doors don't go back down when you
|
|
// run into them (otherwise opening them would be
|
|
// a real pain).
|
|
{
|
|
if (!thing->player || thing->player->isbot)
|
|
return false; // JDC: bad guys never close doors
|
|
//Added by MC: Neither do bots.
|
|
|
|
door->m_Direction = -1; // start going down immediately
|
|
|
|
// [RH] If this sector doesn't have a specific sound
|
|
// attached to it, start the door close sequence.
|
|
// Otherwise, just let the current one continue.
|
|
if (sec->seqType == -1)
|
|
{
|
|
door->DoorSound (false);
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
if (new DDoor (sec, type, speed, delay, lightTag))
|
|
rtn = true;
|
|
}
|
|
else
|
|
{ // [RH] Remote door
|
|
|
|
secnum = -1;
|
|
while ((secnum = P_FindSectorFromTag (tag,secnum)) >= 0)
|
|
{
|
|
sec = §ors[secnum];
|
|
// if the ceiling already moving, don't start the door action
|
|
if (sec->ceilingdata)
|
|
continue;
|
|
|
|
if (new DDoor (sec, type, speed, delay, lightTag))
|
|
rtn = true;
|
|
}
|
|
|
|
}
|
|
return rtn;
|
|
}
|
|
|
|
|
|
//
|
|
// Spawn a door that closes after 30 seconds
|
|
//
|
|
void P_SpawnDoorCloseIn30 (sector_t *sec)
|
|
{
|
|
fixed_t height;
|
|
DDoor *door = new DDoor (sec);
|
|
|
|
sec->special = 0;
|
|
|
|
door->m_Sector = sec;
|
|
door->m_Direction = 0;
|
|
door->m_Type = DDoor::doorRaise;
|
|
door->m_Speed = FRACUNIT*2;
|
|
door->m_TopCountdown = 30 * TICRATE;
|
|
height = sec->FindHighestFloorPoint (&door->m_BotSpot);
|
|
door->m_BotDist = sec->ceilingplane.PointToDist (door->m_BotSpot, height);
|
|
door->m_OldFloorDist = sec->floorplane.d;
|
|
door->m_TopDist = sec->ceilingplane.d;
|
|
door->m_LightTag = 0;
|
|
}
|
|
|
|
//
|
|
// Spawn a door that opens after 5 minutes
|
|
//
|
|
void P_SpawnDoorRaiseIn5Mins (sector_t *sec)
|
|
{
|
|
sec->special = 0;
|
|
new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0);
|
|
}
|
|
|
|
// Strife's animated doors. Based on Doom's unused sliding doors, but slightly different.
|
|
|
|
class DeletingDoorArray : public TArray<FDoorAnimation>
|
|
{
|
|
public:
|
|
~DeletingDoorArray()
|
|
{
|
|
for(unsigned i=0;i<Size();i++)
|
|
{
|
|
FDoorAnimation *ani = &((*this)[i]);
|
|
if (ani->TextureFrames != NULL)
|
|
{
|
|
delete [] ani->TextureFrames;
|
|
ani->TextureFrames = NULL;
|
|
}
|
|
if (ani->OpenSound != NULL)
|
|
{
|
|
delete [] ani->OpenSound;
|
|
ani->OpenSound = NULL;
|
|
}
|
|
if (ani->CloseSound != NULL)
|
|
{
|
|
delete [] ani->CloseSound;
|
|
ani->CloseSound = NULL;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
DeletingDoorArray DoorAnimations;
|
|
|
|
// EV_SlidingDoor : slide a door horizontally
|
|
// (animate midtexture, then set noblocking line)
|
|
//
|
|
|
|
//
|
|
// Return index into "DoorAnimations" array for which door type to use
|
|
//
|
|
static int P_FindSlidingDoorType (int picnum)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < DoorAnimations.Size(); ++i)
|
|
{
|
|
if (picnum == DoorAnimations[i].BaseTexture)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool DAnimatedDoor::StartClosing ()
|
|
{
|
|
FDoorAnimation &ani = DoorAnimations[m_WhichDoorIndex];
|
|
|
|
// CAN DOOR CLOSE?
|
|
if (m_Sector->touching_thinglist != NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
fixed_t topdist = m_Sector->ceilingplane.d;
|
|
if (MoveCeiling (2048*FRACUNIT, m_BotDist, 0, -1) == crushed)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
MoveCeiling (2048*FRACUNIT, topdist, 1);
|
|
|
|
m_Line1->flags |= ML_BLOCKING;
|
|
m_Line2->flags |= ML_BLOCKING;
|
|
if (ani.CloseSound != NULL)
|
|
{
|
|
SN_StartSequence (m_Sector, ani.CloseSound, 1);
|
|
}
|
|
|
|
m_Status = Closing;
|
|
m_Timer = m_Speed;
|
|
return true;
|
|
}
|
|
|
|
void DAnimatedDoor::Tick ()
|
|
{
|
|
FDoorAnimation &ani = DoorAnimations[m_WhichDoorIndex];
|
|
|
|
switch (m_Status)
|
|
{
|
|
case Dead:
|
|
m_Sector->ceilingdata = NULL;
|
|
Destroy ();
|
|
break;
|
|
|
|
case Opening:
|
|
if (!m_Timer--)
|
|
{
|
|
if (++m_Frame >= ani.NumTextureFrames)
|
|
{
|
|
// IF DOOR IS DONE OPENING...
|
|
m_Line1->flags &= ~ML_BLOCKING;
|
|
m_Line2->flags &= ~ML_BLOCKING;
|
|
|
|
if (m_Delay == 0)
|
|
{
|
|
m_Sector->ceilingdata = NULL;
|
|
Destroy ();
|
|
break;
|
|
}
|
|
|
|
m_Timer = m_Delay;
|
|
m_Status = Waiting;
|
|
}
|
|
else
|
|
{
|
|
// IF DOOR NEEDS TO ANIMATE TO NEXT FRAME...
|
|
m_Timer = m_Speed;
|
|
|
|
sides[m_Line1->sidenum[0]].midtexture =
|
|
sides[m_Line1->sidenum[1]].midtexture =
|
|
sides[m_Line2->sidenum[0]].midtexture =
|
|
sides[m_Line2->sidenum[1]].midtexture =
|
|
ani.TextureFrames[m_Frame];
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Waiting:
|
|
// IF DOOR IS DONE WAITING...
|
|
if (!m_Timer--)
|
|
{
|
|
if (!StartClosing())
|
|
{
|
|
m_Timer = m_Delay;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Closing:
|
|
if (!m_Timer--)
|
|
{
|
|
if (--m_Frame < 0)
|
|
{
|
|
// IF DOOR IS DONE CLOSING...
|
|
MoveCeiling (2048*FRACUNIT, m_BotDist, -1);
|
|
m_Sector->ceilingdata = NULL;
|
|
Destroy ();
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// IF DOOR NEEDS TO ANIMATE TO NEXT FRAME...
|
|
m_Timer = m_Speed;
|
|
|
|
sides[m_Line1->sidenum[0]].midtexture =
|
|
sides[m_Line1->sidenum[1]].midtexture =
|
|
sides[m_Line2->sidenum[0]].midtexture =
|
|
sides[m_Line2->sidenum[1]].midtexture =
|
|
ani.TextureFrames[m_Frame];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
IMPLEMENT_CLASS (DAnimatedDoor)
|
|
|
|
DAnimatedDoor::DAnimatedDoor ()
|
|
{
|
|
}
|
|
|
|
DAnimatedDoor::DAnimatedDoor (sector_t *sec)
|
|
: DMovingCeiling (sec)
|
|
{
|
|
}
|
|
|
|
void DAnimatedDoor::Serialize (FArchive &arc)
|
|
{
|
|
Super::Serialize (arc);
|
|
arc << m_Line1 << m_Line2
|
|
<< m_Frame
|
|
<< m_Timer
|
|
<< m_BotDist
|
|
<< m_Status
|
|
<< m_Speed
|
|
<< m_Delay;
|
|
|
|
if (arc.IsStoring())
|
|
{
|
|
TexMan.WriteTexture (arc, DoorAnimations[m_WhichDoorIndex].BaseTexture);
|
|
}
|
|
else
|
|
{
|
|
int picnum = TexMan.ReadTexture (arc);
|
|
m_WhichDoorIndex = P_FindSlidingDoorType (picnum);
|
|
if (m_WhichDoorIndex == -1)
|
|
{ // Oh no! The door animation doesn't exist anymore!
|
|
m_WhichDoorIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay)
|
|
: DMovingCeiling (sec)
|
|
{
|
|
fixed_t topdist;
|
|
int picnum;
|
|
|
|
// The DMovingCeiling constructor automatically sets up an interpolation for us.
|
|
// Stop it, since the ceiling is moving instantly here.
|
|
stopinterpolation (INTERP_SectorCeiling, sec);
|
|
m_WhichDoorIndex = P_FindSlidingDoorType (sides[line->sidenum[0]].toptexture);
|
|
if (m_WhichDoorIndex < 0)
|
|
{
|
|
Printf ("EV_SlidingDoor: Textures are not defined for sliding door!");
|
|
m_Status = Dead;
|
|
return;
|
|
}
|
|
|
|
m_Line1 = line;
|
|
m_Line2 = line;
|
|
|
|
for (int i = 0; i < sec->linecount; ++i)
|
|
{
|
|
if (sec->lines[i] == line)
|
|
continue;
|
|
|
|
if (sides[sec->lines[i]->sidenum[0]].toptexture == sides[line->sidenum[0]].toptexture)
|
|
{
|
|
m_Line2 = sec->lines[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
picnum = sides[m_Line1->sidenum[0]].toptexture;
|
|
sides[m_Line1->sidenum[0]].midtexture = picnum;
|
|
sides[m_Line2->sidenum[0]].midtexture = picnum;
|
|
|
|
// don't forget texture scaling here!
|
|
FTexture *tex = TexMan[picnum];
|
|
topdist = tex ? (tex->GetHeight() * 8 / (tex->ScaleY ? tex->ScaleY : 8)) : 64;
|
|
//topdist = TexMan[picnum]->GetHeight(); // old non-scaling sensitive code!
|
|
|
|
topdist = m_Sector->ceilingplane.d - topdist * m_Sector->ceilingplane.c;
|
|
|
|
m_Status = Opening;
|
|
m_Speed = speed;
|
|
m_Delay = delay;
|
|
m_Timer = m_Speed;
|
|
m_Frame = 0;
|
|
m_Line1->flags |= ML_BLOCKING;
|
|
m_Line2->flags |= ML_BLOCKING;
|
|
m_BotDist = m_Sector->ceilingplane.d;
|
|
MoveCeiling (2048*FRACUNIT, topdist, 1);
|
|
if (DoorAnimations[m_WhichDoorIndex].OpenSound != NULL)
|
|
{
|
|
SN_StartSequence (m_Sector, DoorAnimations[m_WhichDoorIndex].OpenSound, 1);
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// EV_SlidingDoor
|
|
//
|
|
//============================================================================
|
|
|
|
bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay)
|
|
{
|
|
sector_t *sec;
|
|
int secnum;
|
|
bool rtn;
|
|
|
|
secnum = -1;
|
|
rtn = false;
|
|
|
|
if (tag == 0)
|
|
{
|
|
// Manual sliding door
|
|
sec = line->backsector;
|
|
|
|
// Make sure door isn't already being animated
|
|
if (sec->ceilingdata != NULL)
|
|
{
|
|
if (actor->player == NULL)
|
|
return false;
|
|
|
|
if (sec->ceilingdata->IsA (RUNTIME_CLASS(DAnimatedDoor)))
|
|
{
|
|
DAnimatedDoor *door = static_cast<DAnimatedDoor *> (sec->ceilingdata);
|
|
if (door->m_Status == DAnimatedDoor::Waiting)
|
|
{
|
|
return door->StartClosing();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
if (P_FindSlidingDoorType (sides[line->sidenum[0]].toptexture) >= 0)
|
|
{
|
|
new DAnimatedDoor (sec, line, speed, delay);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
|
|
{
|
|
sec = §ors[secnum];
|
|
if (sec->ceilingdata != NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (int i = 0; tag != 0 && i < sec->linecount; ++i)
|
|
{
|
|
line = sec->lines[i];
|
|
if (line->backsector == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
if (P_FindSlidingDoorType (sides[line->sidenum[0]].toptexture) >= 0)
|
|
{
|
|
rtn = true;
|
|
new DAnimatedDoor (sec, line, speed, delay);
|
|
}
|
|
}
|
|
}
|
|
return rtn;
|
|
}
|
|
|
|
void P_ParseAnimatedDoor()
|
|
{
|
|
const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny;
|
|
FDoorAnimation anim;
|
|
TArray<int> frames;
|
|
bool error = false;
|
|
int v;
|
|
|
|
SC_MustGetString();
|
|
anim.BaseTexture = TexMan.CheckForTexture (sc_String, FTexture::TEX_Wall, texflags);
|
|
anim.OpenSound = NULL;
|
|
anim.CloseSound = NULL;
|
|
|
|
if (anim.BaseTexture == -1)
|
|
{
|
|
error = true;
|
|
}
|
|
|
|
while (SC_GetString ())
|
|
{
|
|
if (SC_Compare ("opensound"))
|
|
{
|
|
SC_MustGetString ();
|
|
anim.OpenSound = copystring (sc_String);
|
|
}
|
|
else if (SC_Compare ("closesound"))
|
|
{
|
|
SC_MustGetString ();
|
|
anim.CloseSound = copystring (sc_String);
|
|
}
|
|
else if (SC_Compare ("pic"))
|
|
{
|
|
SC_MustGetString ();
|
|
if (IsNum (sc_String))
|
|
{
|
|
v = atoi(sc_String) + anim.BaseTexture -1;
|
|
}
|
|
else
|
|
{
|
|
v = TexMan.CheckForTexture (sc_String, FTexture::TEX_Wall, texflags);
|
|
if (v == -1 && anim.BaseTexture >= 0 && !error)
|
|
{
|
|
SC_ScriptError ("Unknown texture %s", sc_String);
|
|
}
|
|
frames.Push (v);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SC_UnGet ();
|
|
break;
|
|
}
|
|
}
|
|
if (!error)
|
|
{
|
|
anim.TextureFrames = new int[frames.Size()];
|
|
memcpy (anim.TextureFrames, &frames[0], sizeof(int) * frames.Size());
|
|
anim.NumTextureFrames = frames.Size();
|
|
DoorAnimations.Push (anim);
|
|
}
|
|
else
|
|
{
|
|
if (anim.OpenSound!=NULL) delete [] anim.OpenSound;
|
|
if (anim.CloseSound!=NULL) delete [] anim.CloseSound;
|
|
}
|
|
}
|