📄 doors.cpp
字号:
{
if ( max_health )
{
takedamage = DAMAGE_YES;
health = max_health;
}
// trigger all paired doors
door = ( Door * )G_GetEntity( nextdoor );
assert( door->isSubclassOf( Door ) );
while( door && ( door != this ) )
{
door->ProcessEvent( EV_Door_Close );
door = ( Door * )G_GetEntity( door->nextdoor );
assert( door->isSubclassOf( Door ) );
}
}
}
void Door::Open
(
Event *ev
)
{
Door *door;
Event *e;
Entity *other;
if ( ev->NumArgs() < 1 )
{
ev->Error( "No entity specified to open door. Door may open the wrong way." );
other = world;
}
else
{
other = ev->GetEntity( 1 );
}
if ( state == STATE_OPENING )
{
// already going up
return;
}
if ( state == STATE_OPEN )
{
// reset top wait time
if ( wait > 0 )
{
CancelEventsOfType( EV_Door_Close );
PostEvent( EV_Door_Close, wait );
}
return;
}
previous_state = state;
state = STATE_OPENING;
e = new Event( EV_Door_DoOpen );
e->AddEntity( other );
ProcessEvent( e );
if ( sound_move.length() > 1 )
{
ProcessEvent( EV_DoorSound );
sound( sound_move, 1, CHAN_VOICE + CHAN_NO_PHS_ADD, ATTN_NORM );
}
if ( master == this )
{
// trigger all paired doors
door = ( Door * )G_GetEntity( nextdoor );
assert( door->isSubclassOf( Door ) );
while( door && ( door != this ) )
{
e = new Event( EV_Door_Open );
e->AddEntity( other );
door->ProcessEvent( e );
door = ( Door * )G_GetEntity( door->nextdoor );
assert( door->isSubclassOf( Door ) );
}
SetAreaPortals( Target(), true );
}
}
void Door::DoorUse
(
Event *ev
)
{
Entity *other;
qboolean respond;
Event *e;
other = ev->GetEntity( 1 );
respond = ( ( ( respondto & TRIGGER_PLAYERS ) && other->isClient() ) ||
( ( respondto & TRIGGER_MONSTERS ) && other->isSubclassOf( Actor ) ) );
if ( !respond )
return;
// only allow use when not triggerd by other events
if ( health || ( spawnflags & ( DOOR_AUTO_OPEN | DOOR_TARGETED ) ) )
{
if ( other->isSubclassOf( Sentient ) && ( state == STATE_CLOSED ) )
{
if ( health )
{
gi.centerprintf ( other->edict, "jcx yv 20 string \"This door is jammed.\"" );
}
else if ( spawnflags & DOOR_TARGETED )
{
RandomGlobalSound( "door_triggered", 1, CHAN_VOICE + CHAN_NO_PHS_ADD, ATTN_NORM );
//gi.centerprintf ( other->edict, "jcx yv 20 string \"This door opens elsewhere.\"" );
}
}
return;
}
assert( master );
if ( !master )
{
// bulletproofing
master = this;
}
if ( master->state == STATE_CLOSED )
{
e = new Event( EV_Door_TryOpen );
e->AddEntity( other );
master->ProcessEvent( e );
}
else if ( master->state == STATE_OPEN )
{
e = new Event( EV_Door_Close );
e->AddEntity( other );
master->ProcessEvent( e );
}
}
void Door::DoorFire
(
Event *ev
)
{
Event *e;
Entity *other;
other = ev->GetEntity( 1 );
assert( master == this );
if ( master != this )
{
gi.error( "DoorFire: master != self" );
}
// no more messages
SetMessage( NULL );
// reset health in case we were damage triggered
health = max_health;
// will be reset upon return
takedamage = DAMAGE_NO;
if ( ( spawnflags & ( DOOR_TOGGLE | DOOR_START_OPEN ) ) && ( state == STATE_OPENING || state == STATE_OPEN ) )
{
spawnflags &= ~DOOR_START_OPEN;
ProcessEvent( EV_Door_Close );
}
else
{
e = new Event( EV_Door_Open );
e->AddEntity( other );
ProcessEvent( e );
}
}
void Door::DoorBlocked
(
Event *ev
)
{
Event *e;
Entity *other;
assert( master );
if ( ( master ) && ( master != this ) )
{
master->ProcessEvent( ev );
return;
}
if ( lastblocktime > level.time )
{
return;
}
lastblocktime = level.time + 0.3;
other = ev->GetEntity( 1 );
if ( dmg )
{
other->Damage( this, this, (int)dmg, worldorigin, vec_zero, vec_zero, 0, 0, MOD_CRUSH, -1, -1, 1.0f );
}
//
// if we killed him, lets keep on going
//
if ( other->health <= 0 )
{
return;
}
if ( state == STATE_OPENING || state == STATE_OPEN )
{
spawnflags &= ~DOOR_START_OPEN;
ProcessEvent( EV_Door_Close );
}
else
{
e = new Event( EV_Door_Open );
e->AddEntity( other );
ProcessEvent( e );
}
}
void Door::FieldTouched
(
Event *ev
)
{
Entity *other;
other = ev->GetEntity( 1 );
#ifdef SIN_DEMO
if ( ( state != STATE_OPEN ) && !( spawnflags & DOOR_AUTO_OPEN ) &&
( !other || !other->isSubclassOf( Actor ) ) )
#else
if ( ( state != STATE_OPEN ) && !( spawnflags & DOOR_AUTO_OPEN ) )
#endif
{
return;
}
TryOpen( ev );
}
qboolean Door::CanBeOpenedBy
(
Entity *ent
)
{
assert( master );
if ( ( master ) && ( master != this ) )
{
return master->CanBeOpenedBy( ent );
}
if ( !locked && !key.length() )
{
return true;
}
if ( ent && ent->isSubclassOf( Sentient ) && ( ( Sentient * )ent )->HasItem( key.c_str() ) )
{
return true;
}
return false;
}
void Door::TryOpen
(
Event *ev
)
{
Entity *other;
Event *event;
//FIXME
// hack so that doors aren't triggered by guys when game starts.
// have to fix delay that guys go through before setting up their threads
if ( level.time < 0.4 )
{
return;
}
other = ev->GetEntity( 1 );
assert( master );
if ( master && ( this != master ) )
{
event = new Event( EV_Door_TryOpen );
event->AddEntity( other );
master->ProcessEvent( event );
return;
}
if ( !other || ( other->health <= 0 ) )
{
return;
}
if ( locked )
{
if ( sound_locked.length() > 1 )
{
other->sound( sound_locked.c_str(), 1, CHAN_VOICE );
}
else if ( other->isSubclassOf( Player) )
{
other->RandomSound( "snd_locked", 1, CHAN_VOICE );
//gi.centerprintf ( other->edict, "jcx yv 20 string \"This door is locked.\"" );
}
// locked doors don't open for anyone
return;
}
if ( !CanBeOpenedBy( other ) )
{
Item *item;
ClassDef *cls;
if ( other->isClient() )
{
cls = getClass( key.c_str() );
if ( !cls )
{
gi.dprintf( "No item named '%s'\n", key.c_str() );
return;
}
item = ( Item * )cls->newInstance();
item->CancelEventsOfType( EV_Item_DropToFloor );
item->CancelEventsOfType( EV_Remove );
item->ProcessPendingEvents();
gi.centerprintf ( other->edict, "jcx yv 20 string \"You need this item:\" jcx yv -20 icon %d", item->GetIconIndex() );
delete item;
}
return;
}
// once we're opened by an item, we no longer need that item to open the door
key = "";
if ( Message().length() )
{
gi.centerprintf( other->edict, "jcx jcy string \"%s\"", Message().c_str() );
sound( sound_message, 1, CHAN_VOICE + CHAN_NO_PHS_ADD, ATTN_NORM );
}
event = new Event( EV_Door_Fire );
event->AddEntity( other );
ProcessEvent( event );
}
void Door::SpawnTriggerField
(
Vector fmins,
Vector fmaxs
)
{
TouchField *trig;
Vector min;
Vector max;
min = fmins - "60 60 8";
max = fmaxs + "60 60 8";
trig = new TouchField;
trig->Setup( this, EV_Door_TriggerFieldTouched, min, max, respondto );
trigger = trig->entnum;
}
EXPORT_FROM_DLL qboolean Door::DoorTouches
(
Door *e1
)
{
if ( e1->doormin.x > doormax.x )
{
return false;
}
if ( e1->doormin.y > doormax.y )
{
return false;
}
if ( e1->doormin.z > doormax.z )
{
return false;
}
if ( e1->doormax.x < doormin.x )
{
return false;
}
if ( e1->doormax.y < doormin.y )
{
return false;
}
if ( e1->doormax.z < doormin.z )
{
return false;
}
return true;
}
void Door::LinkDoors
(
Event *ev
)
{
Door *ent;
Door *next;
Vector cmins;
Vector cmaxs;
int t;
int i;
if ( nextdoor )
{
// already linked by another door
return;
}
// master doors own themselves
master = this;
if ( spawnflags & DOOR_DONT_LINK )
{
// don't want to link this door
nextdoor = entnum;
return;
}
cmins = absmin;
cmaxs = absmax;
ent = this;
for( t = entnum; t != 0; t = G_FindClass( t, getClassID() ) )
{
next = ( Door * )G_GetEntity( t );
if ( !ent->DoorTouches( next ) )
{
continue;
}
if ( next->nextdoor )
{
error( "cross connected doors. Targetname = %s entity %d", TargetName(), entnum );
}
ent->nextdoor = next->entnum;
ent = next;
for( i = 0; i < 3; i++ )
{
if ( ent->absmin[ i ] < cmins[ i ] )
{
cmins[ i ] = ent->absmin[ i ];
}
if ( ent->absmax[ i ] > cmaxs[ i ] )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -