1252 lines
35 KiB
Plaintext
1252 lines
35 KiB
Plaintext
#using scripts\codescripts\struct;
|
|
|
|
#using scripts\shared\hud_util_shared;
|
|
#using scripts\shared\system_shared;
|
|
#using scripts\shared\flag_shared;
|
|
|
|
|
|
|
|
#namespace doors;
|
|
|
|
|
|
|
|
|
|
class cDoor
|
|
{
|
|
var m_s_bundle; // Bundle with info regarding the door.
|
|
var m_str_targetname;
|
|
var m_str_target;
|
|
var m_str_script_flag;
|
|
|
|
var m_e_door; // Door Ent
|
|
|
|
var m_e_trigger; // Trigger Ent
|
|
var m_e_trigger_player; // Player who opens the door
|
|
var m_n_trigger_height;
|
|
|
|
var m_n_hack_pct; // percentage of the current hack completed.
|
|
var m_b_hacking; // true if hacking is currently taking place.
|
|
|
|
var m_e_hint_trigger;
|
|
|
|
var m_v_open_pos; // Door open and close positions (for slide doors)
|
|
var m_v_close_pos;
|
|
|
|
var m_n_door_connect_paths; // Does door connect paths?
|
|
|
|
var m_b_is_open; // Is the door open?
|
|
|
|
// Overrides that can be set in script
|
|
var m_override_swing_angle;
|
|
|
|
var m_door_open_delay_time; // Ability to delat the door opening
|
|
|
|
constructor()
|
|
{
|
|
m_n_trigger_height = 80; // Default trigger height
|
|
m_override_swing_angle = undefined;
|
|
m_door_open_delay_time = 0;
|
|
m_e_trigger_player = undefined;
|
|
}
|
|
|
|
destructor()
|
|
{
|
|
if( IsDefined(m_e_trigger) )
|
|
{
|
|
m_e_trigger delete();
|
|
}
|
|
}
|
|
|
|
function init_xmodel( str_xmodel, connect_paths, v_origin, v_angles )
|
|
{
|
|
if( !IsDefined(str_xmodel) )
|
|
{
|
|
str_xmodel = "script_origin";
|
|
//ASSERTMSG( "No model found in Door Script Bundle" );
|
|
//return;
|
|
}
|
|
|
|
m_e_door = spawn( "script_model", v_origin, 1 );
|
|
m_e_door setModel( str_xmodel );
|
|
m_e_door.angles = v_angles;
|
|
|
|
if(connect_paths)
|
|
{
|
|
m_e_door DisconnectPaths();
|
|
}
|
|
}
|
|
|
|
function get_hack_pos()
|
|
{
|
|
v_trigger_offset = m_s_bundle.v_trigger_offset;
|
|
|
|
v_pos = calculate_offset_position( m_e_door.origin, m_e_door.angles, v_trigger_offset );
|
|
v_pos = ( v_pos[0], v_pos[1], v_pos[2]+50 ); // Its a look at trigger, so move the base of the trigger off the ground
|
|
|
|
if ( IsDefined( m_str_target ) )
|
|
{
|
|
e_target = GetEnt( m_str_target, "targetname" );
|
|
if ( IsDefined( e_target ) )
|
|
{
|
|
return e_target.origin;
|
|
}
|
|
}
|
|
|
|
return v_pos;
|
|
}
|
|
|
|
function get_hack_angles()
|
|
{
|
|
v_angles = m_e_door.angles;
|
|
|
|
if ( IsDefined( m_str_target ) )
|
|
{
|
|
e_target = GetEnt( m_str_target, "targetname" );
|
|
if ( IsDefined( e_target ) )
|
|
{
|
|
return e_target.angles;
|
|
}
|
|
}
|
|
|
|
return v_angles;
|
|
}
|
|
|
|
function init_hint_trigger()
|
|
{
|
|
// Only certain types of doors have this trigger.
|
|
//
|
|
if ( m_s_bundle.door_unlock_method == "default" && !( isdefined( m_s_bundle.door_trigger_at_target ) && m_s_bundle.door_trigger_at_target ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Keys don't use a hint trigger.
|
|
//
|
|
if ( m_s_bundle.door_unlock_method == "key" )
|
|
{
|
|
return;
|
|
}
|
|
|
|
v_offset = m_s_bundle.v_trigger_offset;
|
|
n_radius = m_s_bundle.door_trigger_radius;
|
|
|
|
v_pos = calculate_offset_position( m_e_door.origin, m_e_door.angles, v_offset );
|
|
|
|
// Its a look at trigger, so move the base of the trigger off the ground
|
|
v_pos = ( v_pos[0], v_pos[1], v_pos[2]+50 );
|
|
|
|
e_trig = spawn( "trigger_radius_use", v_pos, 0, n_radius, m_n_trigger_height );
|
|
e_trig TriggerIgnoreTeam();
|
|
|
|
e_trig SetVisibleToAll();
|
|
e_trig SetTeamForTrigger( "none" );
|
|
e_trig UseTriggerRequireLookAt();
|
|
|
|
e_trig SetCursorHint( "HINT_NOICON" );
|
|
|
|
m_e_hint_trigger = e_trig;
|
|
|
|
thread process_hint_trigger_message();
|
|
}
|
|
|
|
function lock()
|
|
{
|
|
self flag::set( "locked" );
|
|
update_use_message();
|
|
}
|
|
|
|
function unlock()
|
|
{
|
|
self flag::clear( "locked" );
|
|
}
|
|
|
|
function delete_door()
|
|
{
|
|
m_e_door delete();
|
|
m_e_door = undefined;
|
|
|
|
if( IsDefined(m_e_trigger) )
|
|
{
|
|
m_e_trigger delete();
|
|
m_e_trigger = undefined;
|
|
}
|
|
}
|
|
|
|
function open()
|
|
{
|
|
self flag::set( "open" );
|
|
}
|
|
|
|
function close_internal()
|
|
{
|
|
self flag::clear( "open" );
|
|
set_script_flags( false );
|
|
|
|
self flag::set( "animating" );
|
|
|
|
if( ( isdefined( m_s_bundle.b_loop_sound ) && m_s_bundle.b_loop_sound ) )
|
|
{
|
|
m_e_door playsound( m_s_bundle.door_start_sound );
|
|
sndEnt = spawn( "script_origin", m_e_door.origin );
|
|
sndEnt linkto( m_e_door );
|
|
sndEnt playloopsound( m_s_bundle.door_loop_sound, 1 );
|
|
}
|
|
else if ( IsDefined(m_s_bundle.door_stop_sound) && m_s_bundle.door_stop_sound != "" )
|
|
{
|
|
m_e_door playsound( m_s_bundle.door_stop_sound );
|
|
}
|
|
|
|
// Close Door
|
|
if( m_s_bundle.door_open_method == "slide" )
|
|
{
|
|
m_e_door MoveTo( m_v_close_pos, m_s_bundle.door_open_time );
|
|
}
|
|
else if( m_s_bundle.door_open_method == "swing" )
|
|
{
|
|
angle = GetSwingAngle();
|
|
v_angle = ( m_e_door.angles[0], m_e_door.angles[1]-angle, m_e_door.angles[2] );
|
|
m_e_door RotateTo( v_angle, m_s_bundle.door_open_time );
|
|
}
|
|
// TODO: Animated - Closing
|
|
|
|
wait( m_s_bundle.door_open_time );
|
|
|
|
if( ( isdefined( m_n_door_connect_paths ) && m_n_door_connect_paths ) )
|
|
{
|
|
m_e_door DisconnectPaths();
|
|
}
|
|
|
|
if( ( isdefined( m_s_bundle.b_loop_sound ) && m_s_bundle.b_loop_sound ) )
|
|
{
|
|
sndEnt delete();
|
|
m_e_door playsound( m_s_bundle.door_stop_sound );
|
|
}
|
|
|
|
flag::clear( "animating" );
|
|
|
|
update_use_message();
|
|
}
|
|
|
|
function close()
|
|
{
|
|
self flag::clear( "open" );
|
|
}
|
|
|
|
function open_internal()
|
|
{
|
|
self flag::set( "animating" );
|
|
|
|
m_e_door notify( "door_opening" );
|
|
|
|
// Play the opening sound.
|
|
if ( IsDefined(m_s_bundle.door_start_sound) && m_s_bundle.door_start_sound != "" )
|
|
{
|
|
m_e_door playsound( m_s_bundle.door_start_sound );
|
|
}
|
|
|
|
// Play the looping door "open" sound.
|
|
if( ( isdefined( m_s_bundle.b_loop_sound ) && m_s_bundle.b_loop_sound ) )
|
|
{
|
|
sndEnt = spawn( "script_origin", m_e_door.origin );
|
|
sndEnt linkto( m_e_door );
|
|
sndEnt playloopsound( m_s_bundle.door_loop_sound, 1 );
|
|
}
|
|
|
|
if( m_s_bundle.door_open_method == "slide" )
|
|
{
|
|
m_e_door MoveTo( m_v_open_pos, m_s_bundle.door_open_time );
|
|
}
|
|
else if( m_s_bundle.door_open_method == "swing" )
|
|
{
|
|
angle = GetSwingAngle();
|
|
v_angle = ( m_e_door.angles[0], m_e_door.angles[1]+angle, m_e_door.angles[2] );
|
|
m_e_door RotateTo( v_angle, m_s_bundle.door_open_time );
|
|
}
|
|
|
|
if( ( isdefined( m_n_door_connect_paths ) && m_n_door_connect_paths ) )
|
|
{
|
|
m_e_door ConnectPaths();
|
|
}
|
|
|
|
wait( m_s_bundle.door_open_time );
|
|
|
|
if( ( isdefined( m_s_bundle.b_loop_sound ) && m_s_bundle.b_loop_sound ) )
|
|
{
|
|
sndEnt delete();
|
|
}
|
|
|
|
if ( IsDefined(m_s_bundle.door_stop_sound) && m_s_bundle.door_stop_sound != "" )
|
|
{
|
|
m_e_door playsound( m_s_bundle.door_stop_sound );
|
|
}
|
|
|
|
flag::clear( "animating" );
|
|
set_script_flags( true );
|
|
|
|
update_use_message();
|
|
}
|
|
|
|
function update_use_message()
|
|
{
|
|
if ( !( isdefined( m_s_bundle.door_use_trigger ) && m_s_bundle.door_use_trigger ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( self flag::get("open") )
|
|
{
|
|
if ( !( isdefined( m_s_bundle.door_closes ) && m_s_bundle.door_closes ) )
|
|
{
|
|
// m_e_trigger SetHintString( "" );
|
|
}
|
|
else
|
|
{
|
|
// m_e_trigger SetHintString( "Hold ^3[{+activate}]^7 to close door" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO - Localize the string, &"HINT_DOOR"
|
|
if( IsDefined(m_s_bundle.door_open_message) && (m_s_bundle.door_open_message != "") )
|
|
{
|
|
// m_e_trigger SetHintString( m_s_bundle.door_open_message );
|
|
}
|
|
else if (( isdefined( m_s_bundle.door_use_hold ) && m_s_bundle.door_use_hold ))
|
|
{
|
|
// m_e_trigger SetHintString( "Hold ^3[{+activate}]^7 to hold door open" );
|
|
}
|
|
else if (m_s_bundle.door_unlock_method == "key")
|
|
{
|
|
// m_e_trigger SetHintString( "Hold ^3[{+activate}]^7 to open door [cost: 1 key]" );
|
|
}
|
|
else if( self flag::get( "locked" ) )
|
|
{
|
|
// m_e_trigger SetHintString( &"SCRIPT_DOOR_LOCKED" );
|
|
}
|
|
else
|
|
{
|
|
// m_e_trigger SetHintString( "Hold ^3[{+activate}]^7 to open door" );
|
|
}
|
|
}
|
|
}
|
|
|
|
function run_lock_fx()
|
|
{
|
|
if ( !IsDefined(m_s_bundle.door_locked_fx) && !IsDefined(m_s_bundle.door_unlocked_fx) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
e_fx = undefined;
|
|
v_pos = get_hack_pos();
|
|
v_angles = get_hack_angles();
|
|
|
|
while ( true )
|
|
{
|
|
self flag::wait_till( "locked" );
|
|
|
|
if ( isdefined( e_fx ) )
|
|
{
|
|
e_fx delete();
|
|
e_fx = undefined;
|
|
}
|
|
|
|
if ( IsDefined(m_s_bundle.door_locked_fx) )
|
|
{
|
|
e_fx = Spawn( "script_model", v_pos );
|
|
e_fx SetModel( "tag_origin" );
|
|
e_fx.angles = v_angles;
|
|
PlayFXOnTag( m_s_bundle.door_locked_fx, e_fx, "tag_origin" );
|
|
}
|
|
|
|
self flag::wait_till_clear( "locked" );
|
|
|
|
if ( isdefined( e_fx ) )
|
|
{
|
|
e_fx delete();
|
|
e_fx = undefined;
|
|
}
|
|
|
|
if ( IsDefined(m_s_bundle.door_unlocked_fx) )
|
|
{
|
|
e_fx = Spawn( "script_model", v_pos );
|
|
e_fx SetModel( "tag_origin" );
|
|
e_fx.angles = v_angles;
|
|
PlayFXOnTag( m_s_bundle.door_unlocked_fx, e_fx, "tag_origin" );
|
|
}
|
|
}
|
|
}
|
|
|
|
function process_hint_trigger_message()
|
|
{
|
|
str_hint = "";
|
|
if ( ( isdefined( m_s_bundle.door_trigger_at_target ) && m_s_bundle.door_trigger_at_target ) )
|
|
{
|
|
str_hint = "This door is controlled elsewhere";
|
|
}
|
|
else if (m_s_bundle.door_unlock_method == "hack")
|
|
{
|
|
str_hint = "This door is electronically locked";
|
|
}
|
|
|
|
while ( true )
|
|
{
|
|
m_e_hint_trigger SetHintString(str_hint);
|
|
|
|
if ( ( isdefined( m_s_bundle.door_trigger_at_target ) && m_s_bundle.door_trigger_at_target ) )
|
|
{
|
|
self flag::wait_till( "open" );
|
|
}
|
|
else
|
|
{
|
|
self flag::wait_till_clear( "locked" );
|
|
}
|
|
|
|
m_e_hint_trigger SetHintString("");
|
|
|
|
if ( ( isdefined( m_s_bundle.door_trigger_at_target ) && m_s_bundle.door_trigger_at_target ) )
|
|
{
|
|
self flag::wait_till_clear( "open" );
|
|
}
|
|
else
|
|
{
|
|
self flag::wait_till( "locked" );
|
|
}
|
|
}
|
|
}
|
|
|
|
function init_trigger( v_offset, n_radius )
|
|
{
|
|
v_pos = calculate_offset_position( m_e_door.origin, m_e_door.angles, v_offset );
|
|
|
|
// Its a look at trigger, so move the base of the trigger off the ground
|
|
v_pos = ( v_pos[0], v_pos[1], v_pos[2]+50 );
|
|
|
|
if ( ( isdefined( m_s_bundle.door_trigger_at_target ) && m_s_bundle.door_trigger_at_target ) )
|
|
{
|
|
e_target = GetEnt( m_str_target, "targetname" );
|
|
if ( IsDefined( e_target ) )
|
|
{
|
|
v_pos = e_target.origin;
|
|
}
|
|
}
|
|
|
|
// Does the trigger need a USE prompt?
|
|
if( ( isdefined( m_s_bundle.door_use_trigger ) && m_s_bundle.door_use_trigger ) )
|
|
{
|
|
m_e_trigger = spawn( "trigger_radius_use", v_pos, 0, n_radius, m_n_trigger_height );
|
|
m_e_trigger TriggerIgnoreTeam();
|
|
|
|
m_e_trigger SetVisibleToAll();
|
|
m_e_trigger SetTeamForTrigger( "none" );
|
|
m_e_trigger UseTriggerRequireLookAt();
|
|
|
|
m_e_trigger SetCursorHint( "HINT_NOICON" );
|
|
}
|
|
else
|
|
{
|
|
m_e_trigger = spawn( "trigger_radius", v_pos, 0, n_radius, m_n_trigger_height );
|
|
}
|
|
}
|
|
|
|
function set_script_flags( b_set )
|
|
{
|
|
if ( IsDefined( m_str_script_flag ) )
|
|
{
|
|
a_flags = StrTok(m_str_script_flag, ",");
|
|
foreach( str_flag in a_flags )
|
|
{
|
|
if ( b_set )
|
|
{
|
|
level flag::set(str_flag);
|
|
}
|
|
else
|
|
{
|
|
level flag::clear(str_flag);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function init_movement( n_slide_up, n_slide_amount )
|
|
{
|
|
if( m_s_bundle.door_open_method == "slide" )
|
|
{
|
|
// Setup the open and close offsets
|
|
if( n_slide_up )
|
|
{
|
|
v_offset = ( 0, 0, n_slide_amount );
|
|
}
|
|
else
|
|
{
|
|
v_offset = ( n_slide_amount, 0, 0 );
|
|
}
|
|
|
|
m_v_open_pos = calculate_offset_position( m_e_door.origin, m_e_door.angles, v_offset );
|
|
m_v_close_pos = m_e_door.origin;
|
|
}
|
|
}
|
|
|
|
function set_door_paths( n_door_connect_paths )
|
|
{
|
|
m_n_door_connect_paths = n_door_connect_paths;
|
|
}
|
|
|
|
// TODO (Slone): There's no reason to pass these variables in. The info is available via the bundle.
|
|
//
|
|
function calculate_offset_position( v_origin, v_angles, v_offset )
|
|
{
|
|
v_pos = v_origin;
|
|
|
|
if( v_offset[0] )
|
|
{
|
|
v_side = anglestoforward( v_angles ); // X Axis = Forward
|
|
v_pos = v_pos + (v_offset[0] * v_side);
|
|
}
|
|
if( v_offset[1] )
|
|
{
|
|
v_dir = anglestoright( v_angles );
|
|
v_pos = v_pos + (v_offset[1] * v_dir);
|
|
}
|
|
if( v_offset[2] )
|
|
{
|
|
v_up = anglestoup( v_angles );
|
|
v_pos = v_pos + (v_offset[2] * v_up);
|
|
}
|
|
|
|
return( v_pos );
|
|
}
|
|
|
|
// Override the doors swing angle
|
|
function set_swing_angle( angle )
|
|
{
|
|
m_override_swing_angle = angle;
|
|
}
|
|
|
|
function GetSwingAngle()
|
|
{
|
|
if( IsDefined(m_override_swing_angle) )
|
|
{
|
|
angle = m_override_swing_angle;
|
|
}
|
|
else
|
|
{
|
|
angle = m_s_bundle.door_swing_angle;
|
|
}
|
|
return( angle );
|
|
}
|
|
|
|
function SetDoorOpenDelay( delay_time )
|
|
{
|
|
m_door_open_delay_time = delay_time;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////// Utility /////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
function autoexec __init__sytem__() { system::register("doors",&__init__,undefined,undefined); }
|
|
|
|
function __init__()
|
|
{
|
|
a_doors = struct::get_array( "scriptbundle_doors", "classname" ); // "_doors" auto generates from the TYPE field in the bundle
|
|
foreach ( s_instance in a_doors )
|
|
{
|
|
c_door = s_instance init();
|
|
if (isdefined(c_door) )
|
|
{
|
|
s_instance.c_door = c_door;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
// self = door bundle instance (The Script Script Instance, holds position, angles, targetname etc..)
|
|
function init()
|
|
{
|
|
if( !IsDefined(self.angles) )
|
|
{
|
|
self.angles = (0, 0 ,0 );
|
|
}
|
|
|
|
s_door_bundle = level.scriptbundles[ "doors" ][ self.scriptbundlename ];
|
|
|
|
return setup_door_scriptbundle( s_door_bundle, self );
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function setup_door_scriptbundle( s_door_bundle, s_door_instance )
|
|
{
|
|
c_door = new cDoor();
|
|
|
|
c_door flag::init( "locked", false );
|
|
c_door flag::init( "open", false );
|
|
c_door flag::init( "animating", false );
|
|
|
|
c_door.m_s_bundle = s_door_bundle;
|
|
c_door.m_str_targetname = s_door_instance.targetname;
|
|
c_door.m_str_target = s_door_instance.target;
|
|
c_door.m_str_script_flag = s_door_instance.script_flag;
|
|
|
|
//*************************
|
|
// Get the Door Bundle Data
|
|
//*************************
|
|
|
|
if ( c_door.m_s_bundle.door_unlock_method == "key" )
|
|
{
|
|
if ( IsDefined( c_door.m_s_bundle.door_key_model ) )
|
|
{
|
|
level.door_key_model = c_door.m_s_bundle.door_key_model;
|
|
}
|
|
|
|
if ( IsDefined( c_door.m_s_bundle.door_key_icon ) )
|
|
{
|
|
level.door_key_icon = c_door.m_s_bundle.door_key_icon;
|
|
}
|
|
|
|
if ( IsDefined( c_door.m_s_bundle.door_key_fx ) )
|
|
{
|
|
level.door_key_fx = c_door.m_s_bundle.door_key_fx;
|
|
}
|
|
}
|
|
|
|
if ( c_door.m_s_bundle.door_unlock_method == "hack" && !( isdefined( level.door_hack_precached ) && level.door_hack_precached ) )
|
|
{
|
|
level.door_hack_precached = true;
|
|
}
|
|
|
|
str_door_xmodel = c_door.m_s_bundle.model;
|
|
|
|
// Trigger Offset
|
|
if( IsDefined(c_door.m_s_bundle.door_triggerOffsetX) )
|
|
{
|
|
n_xOffset = c_door.m_s_bundle.door_triggerOffsetX;
|
|
}
|
|
else
|
|
{
|
|
n_xOffset = 0;
|
|
}
|
|
if( IsDefined(c_door.m_s_bundle.door_triggerOffsetY) )
|
|
{
|
|
n_yOffset = c_door.m_s_bundle.door_triggerOffsetY;
|
|
}
|
|
else
|
|
{
|
|
n_yOffset = 0;
|
|
}
|
|
if( IsDefined(c_door.m_s_bundle.door_triggerOffsetZ) )
|
|
{
|
|
n_zOffset = c_door.m_s_bundle.door_triggerOffsetZ;
|
|
}
|
|
else
|
|
{
|
|
n_zOffset = 0;
|
|
}
|
|
|
|
v_trigger_offset = ( n_xOffset, n_yOffset, n_zOffset );
|
|
c_door.m_s_bundle.v_trigger_offset = v_trigger_offset; // Store this for later use.
|
|
|
|
n_trigger_radius = c_door.m_s_bundle.door_trigger_radius;
|
|
if( ( isdefined( c_door.m_s_bundle.door_slide_horizontal ) && c_door.m_s_bundle.door_slide_horizontal ) )
|
|
{
|
|
n_slide_up = 0;
|
|
}
|
|
else
|
|
{
|
|
n_slide_up = 1;
|
|
}
|
|
n_open_time = c_door.m_s_bundle.door_open_time;
|
|
n_slide_amount = c_door.m_s_bundle.door_slide_open_units;
|
|
|
|
if( !IsDefined(c_door.m_s_bundle.door_swing_angle) )
|
|
{
|
|
c_door.m_s_bundle.door_swing_angle = 0;
|
|
}
|
|
|
|
if( ( isdefined( c_door.m_s_bundle.door_closes ) && c_door.m_s_bundle.door_closes ) )
|
|
{
|
|
n_door_closes = 1;
|
|
}
|
|
else
|
|
{
|
|
n_door_closes = 0;
|
|
}
|
|
|
|
if( ( isdefined( c_door.m_s_bundle.door_connect_paths ) && c_door.m_s_bundle.door_connect_paths ) )
|
|
{
|
|
n_door_connect_paths = 1;
|
|
}
|
|
else
|
|
{
|
|
n_door_connect_paths = 0;
|
|
}
|
|
|
|
if ( ( isdefined( c_door.m_s_bundle.door_start_open ) && c_door.m_s_bundle.door_start_open ) )
|
|
{
|
|
c_door flag::set( "open" );
|
|
}
|
|
|
|
if ( IsDefined( c_door.m_str_script_flag ) )
|
|
{
|
|
a_flags = StrTok(c_door.m_str_script_flag, ",");
|
|
foreach( str_flag in a_flags )
|
|
{
|
|
level flag::init( str_flag );
|
|
}
|
|
}
|
|
|
|
// Setup the Door
|
|
[[ c_door ]]->init_xmodel( str_door_xmodel, n_door_connect_paths, s_door_instance.origin, s_door_instance.angles);
|
|
|
|
// Setup the trigger - Just using radius triggers for now
|
|
[[ c_door ]]->init_trigger( v_trigger_offset, n_trigger_radius, c_door.m_s_bundle );
|
|
|
|
// Initialize the trigger to give hints regarding how to open the door.
|
|
//
|
|
[[ c_door ]]->init_hint_trigger();
|
|
|
|
// Initialize any fx associated with this door being (or not being) locked.
|
|
thread [[ c_door ]]->run_lock_fx();
|
|
|
|
// Setup door movement
|
|
[[ c_door ]]->init_movement( n_slide_up, n_slide_amount );
|
|
|
|
if ( !IsDefined(c_door.m_s_bundle.door_open_time) )
|
|
{
|
|
c_door.m_s_bundle.door_open_time = 0.4;
|
|
}
|
|
|
|
[[ c_door ]]->set_door_paths( n_door_connect_paths );
|
|
|
|
// Setup door sounds
|
|
c_door.m_s_bundle.b_loop_sound = IsDefined( c_door.m_s_bundle.door_loop_sound ) && c_door.m_s_bundle.door_loop_sound != "";
|
|
|
|
// Door update routine
|
|
level thread door_update( c_door );
|
|
|
|
return c_door;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
function door_open_update( c_door )
|
|
{
|
|
str_unlock_method = "default";
|
|
if ( IsDefined( c_door.m_s_bundle.door_unlock_method ) )
|
|
{
|
|
str_unlock_method = c_door.m_s_bundle.door_unlock_method;
|
|
}
|
|
|
|
b_auto_close = (( isdefined( c_door.m_s_bundle.door_closes ) && c_door.m_s_bundle.door_closes ) && !( isdefined( c_door.m_s_bundle.door_use_trigger ) && c_door.m_s_bundle.door_use_trigger ));
|
|
b_hold_open = ( isdefined( c_door.m_s_bundle.door_use_hold ) && c_door.m_s_bundle.door_use_hold );
|
|
b_manual_close = ( isdefined( c_door.m_s_bundle.door_use_trigger ) && c_door.m_s_bundle.door_use_trigger ) && ( isdefined( c_door.m_s_bundle.door_closes ) && c_door.m_s_bundle.door_closes );
|
|
|
|
// Wait for the player to hit the door trigger, unless it's already set to be open.
|
|
while ( true )
|
|
{
|
|
c_door.m_e_trigger waittill( "trigger", e_who );
|
|
c_door.m_e_trigger_player = e_who;
|
|
|
|
if ( !(c_door flag::get( "open" )) )
|
|
{
|
|
if ( !(c_door flag::get( "locked" ) ))
|
|
{
|
|
if ( b_hold_open || b_auto_close )
|
|
{
|
|
[[c_door]]->open();
|
|
|
|
if ( b_hold_open )
|
|
{
|
|
e_who player_freeze_in_place( true );
|
|
e_who DisableWeapons();
|
|
e_who DisableOffhandWeapons();
|
|
}
|
|
|
|
door_wait_until_clear( c_door, e_who );
|
|
[[c_door]]->close();
|
|
|
|
if ( b_hold_open )
|
|
{
|
|
{wait(.05);};
|
|
c_door flag::wait_till_clear( "animating" );
|
|
e_who player_freeze_in_place( false );
|
|
e_who EnableWeapons();
|
|
e_who EnableOffhandWeapons();
|
|
}
|
|
|
|
} else if ( str_unlock_method == "key" )
|
|
{
|
|
if ( e_who player_has_key( "door" ) )
|
|
{
|
|
e_who player_take_key( "door" );
|
|
[[c_door]]->open();
|
|
} else {
|
|
IPrintLnBold( "You need a key." );
|
|
}
|
|
} else {
|
|
[[c_door]]->open();
|
|
}
|
|
}
|
|
} else if ( b_manual_close )
|
|
{
|
|
[[c_door]]->close();
|
|
}
|
|
}
|
|
}
|
|
|
|
function door_update( c_door )
|
|
{
|
|
// c_door.m_e_trigger thread door_debug_line( c_door.m_e_trigger.origin );
|
|
|
|
str_unlock_method = "default";
|
|
if ( IsDefined( c_door.m_s_bundle.door_unlock_method ) )
|
|
{
|
|
str_unlock_method = c_door.m_s_bundle.door_unlock_method;
|
|
}
|
|
|
|
// "Key" doors aren't *really* unlocked.
|
|
if ( ( isdefined( c_door.m_s_bundle.door_locked ) && c_door.m_s_bundle.door_locked ) && str_unlock_method != "key" )
|
|
{
|
|
c_door flag::set( "locked" );
|
|
|
|
if (IsDefined(c_door.m_str_targetname))
|
|
{
|
|
thread door_update_lock_scripted( c_door );
|
|
}
|
|
}
|
|
|
|
thread door_open_update( c_door );
|
|
|
|
[[c_door]]->update_use_message();
|
|
|
|
while( 1 )
|
|
{
|
|
// Wait for the door to unlock.
|
|
//
|
|
if( c_door flag::get( "locked" ) )
|
|
{
|
|
c_door flag::wait_till_clear( "locked" );
|
|
}
|
|
|
|
c_door flag::wait_till( "open" );
|
|
|
|
// Check for a delay opening the door
|
|
if( c_door.m_door_open_delay_time > 0 )
|
|
{
|
|
c_door.m_e_door notify( "door_waiting_to_open", c_door.m_e_trigger_player );
|
|
wait( c_door.m_door_open_delay_time );
|
|
}
|
|
|
|
[[c_door]]->open_internal();
|
|
|
|
c_door flag::wait_till_clear( "open" );
|
|
|
|
[[c_door]]->close_internal();
|
|
|
|
// If the door stays open, tidyup and exit
|
|
if( !( isdefined( c_door.m_s_bundle.door_closes ) && c_door.m_s_bundle.door_closes ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
{wait(.05);};
|
|
}
|
|
|
|
// Cleanup
|
|
c_door.m_e_trigger delete();
|
|
c_door.m_e_trigger = undefined;
|
|
}
|
|
|
|
function door_update_lock_scripted( c_door )
|
|
{
|
|
door_str = c_door.m_str_targetname;
|
|
c_door.m_e_trigger.targetname = (door_str + "_trig");
|
|
|
|
while ( true )
|
|
{
|
|
c_door.m_e_trigger waittill( "unlocked" );
|
|
[[c_door]]->unlock();
|
|
}
|
|
}
|
|
|
|
function player_freeze_in_place( b_do_freeze )
|
|
{
|
|
if ( !b_do_freeze )
|
|
{
|
|
if ( IsDefined(self.freeze_origin) )
|
|
{
|
|
self Unlink();
|
|
self.freeze_origin Delete();
|
|
self.freeze_origin = undefined;
|
|
}
|
|
} else {
|
|
if ( !IsDefined(self.freeze_origin) )
|
|
{
|
|
self.freeze_origin = Spawn( "script_model", self.origin );
|
|
self.freeze_origin SetModel( "tag_origin" );
|
|
self.freeze_origin.angles = self.angles;
|
|
self PlayerLinkToDelta(self.freeze_origin, "tag_origin", 1.0, 45.0, 45.0, 45.0, 45.0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Waits for a trigger to be clear of all ENTS for X time
|
|
//*****************************************************************************
|
|
|
|
// self = trigger
|
|
function trigger_wait_until_clear( c_door )
|
|
{
|
|
self endon( "death" );
|
|
|
|
last_trigger_time = gettime();
|
|
self.ents_in_trigger = true;
|
|
|
|
str_kill_trigger_notify = "trigger_now_clear";
|
|
self thread trigger_check_for_ents_touching( str_kill_trigger_notify );
|
|
|
|
while( 1 )
|
|
{
|
|
time = gettime();
|
|
|
|
// If there are still ents in the trigger, reset the time counter
|
|
if( self.ents_in_trigger == true )
|
|
{
|
|
self.ents_in_trigger = false;
|
|
last_trigger_time = time;
|
|
}
|
|
|
|
// Have we waited long enough for all ents to the
|
|
dt = ( time - last_trigger_time ) / 1000;
|
|
if( dt >= 0.3 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
{wait(.05);};
|
|
}
|
|
|
|
self notify( str_kill_trigger_notify );
|
|
}
|
|
|
|
// Waits until the user releases the X button, or until they leave the area.
|
|
//
|
|
// self == interaction trigger
|
|
//
|
|
function door_wait_until_user_release( c_door, e_triggerer, str_kill_on_door_notify )
|
|
{
|
|
if ( IsDefined( str_kill_on_door_notify ) )
|
|
{
|
|
c_door endon( str_kill_on_door_notify );
|
|
}
|
|
|
|
// Brief grace period.
|
|
wait 0.25;
|
|
|
|
max_dist_sq = c_door.m_s_bundle.door_trigger_radius * c_door.m_s_bundle.door_trigger_radius;
|
|
b_pressed = true;
|
|
n_dist = 0.0;
|
|
|
|
do {
|
|
{wait(.05);};
|
|
b_pressed = e_triggerer UseButtonPressed();
|
|
n_dist = DistanceSquared(e_triggerer.origin, self.origin);
|
|
}
|
|
while ( b_pressed && n_dist < max_dist_sq );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Waits for door to be clear of all ENTS for X time
|
|
//*****************************************************************************
|
|
function door_wait_until_clear( c_door, e_triggerer )
|
|
{
|
|
e_trigger = c_door.m_e_trigger;
|
|
e_temp_trigger = undefined;
|
|
|
|
// If the trigger is not at the door, we need to create a trigger at the door
|
|
// for temporary purposes.
|
|
if ( ( isdefined( c_door.m_s_bundle.door_trigger_at_target ) && c_door.m_s_bundle.door_trigger_at_target ) )
|
|
{
|
|
e_door = c_door.m_e_door;
|
|
v_trigger_offset = c_door.m_s_bundle.v_trigger_offset;
|
|
v_pos = [[c_door]]->calculate_offset_position( e_door.origin, e_door.angles, v_trigger_offset );
|
|
n_radius = c_door.m_s_bundle.door_trigger_radius;
|
|
n_height = c_door.m_n_trigger_height;
|
|
|
|
// Spawn a trigger
|
|
e_temp_trigger = spawn( "trigger_radius", v_pos, 0, n_radius, n_height );
|
|
e_trigger = e_temp_trigger;
|
|
}
|
|
|
|
// Player must hold down the button to keep the door open.
|
|
if ( IsPlayer( e_triggerer ) && ( isdefined( c_door.m_s_bundle.door_use_hold ) && c_door.m_s_bundle.door_use_hold ) )
|
|
{
|
|
c_door.m_e_trigger door_wait_until_user_release( c_door, e_triggerer );
|
|
}
|
|
|
|
// Wait for trigger to be clear of any entity
|
|
e_trigger trigger_wait_until_clear( c_door );
|
|
|
|
if ( IsDefined( e_temp_trigger ) )
|
|
{
|
|
e_temp_trigger Delete();
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
// Waits for a trigger to be free of all ents
|
|
//*****************************************************************************
|
|
|
|
// self = trigger
|
|
function trigger_check_for_ents_touching( str_kill_trigger_notify )
|
|
{
|
|
self endon( "death" );
|
|
self endon( str_kill_trigger_notify );
|
|
|
|
while( 1 )
|
|
{
|
|
self waittill( "trigger", e_who );
|
|
self.ents_in_trigger = true;
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//*****************************************************************************
|
|
|
|
// self = door trigger
|
|
function door_debug_line( v_origin )
|
|
{
|
|
self endon( "death" );
|
|
|
|
while( 1 )
|
|
{
|
|
v_start = v_origin;
|
|
v_end = v_start + ( 0, 0, 1000 );
|
|
v_col = ( 0, 0, 1 );
|
|
|
|
/#
|
|
line( v_start, v_end, (0,0,1) );
|
|
#/
|
|
|
|
wait( 0.1 );
|
|
}
|
|
}
|
|
|
|
function player_has_key( str_key_type )
|
|
{
|
|
if ( !IsDefined( self.collectible_keys ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( !IsDefined( self.collectible_keys[str_key_type] ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return self.collectible_keys[str_key_type].num_keys > 0;
|
|
}
|
|
|
|
function player_take_key( str_key_type )
|
|
{
|
|
if (!player_has_key( str_key_type ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self.collectible_keys[str_key_type].num_keys--;
|
|
if ( self.collectible_keys[str_key_type].num_keys <= 0 && IsDefined( self.collectible_keys[str_key_type].hudelem ) )
|
|
{
|
|
self.collectible_keys[str_key_type].hudelem Destroy();
|
|
self.collectible_keys[str_key_type].hudelem = undefined;
|
|
}
|
|
}
|
|
|
|
function rotate_key_forever()
|
|
{
|
|
self endon( "death" );
|
|
while ( true )
|
|
{
|
|
self RotateYaw( 180, 3.0 );
|
|
wait 2.5;
|
|
}
|
|
}
|
|
|
|
function key_process_timeout( n_timeout_sec, e_trigger, e_model )
|
|
{
|
|
e_trigger endon( "death" );
|
|
|
|
const blinking_time = 5.0;
|
|
if ( n_timeout_sec < blinking_time )
|
|
{
|
|
n_timeout_sec = blinking_time + 1.0;
|
|
}
|
|
|
|
wait n_timeout_sec - blinking_time;
|
|
|
|
n_stepsize = 0.5;
|
|
b_on = true;
|
|
for ( f = 0.0; f < blinking_time; f += n_stepsize )
|
|
{
|
|
if ( b_on )
|
|
{
|
|
e_model Hide();
|
|
} else {
|
|
e_model Show();
|
|
}
|
|
b_on = !b_on;
|
|
wait n_stepsize;
|
|
|
|
// Blinking gets faster over time.
|
|
if ( n_stepsize > 0.15 )
|
|
{
|
|
n_stepsize *= 0.9;
|
|
}
|
|
}
|
|
|
|
level notify( "key_drop_timeout" );
|
|
|
|
e_model Delete();
|
|
e_trigger Delete();
|
|
}
|
|
|
|
function give_ai_key_internal( n_timeout_sec, str_key_type )
|
|
{
|
|
v_pos = self.origin;
|
|
|
|
e_model = spawn("script_model", v_pos + (0,0,80) );
|
|
e_model.angles = (10,0,10);
|
|
e_model SetModel( level.door_key_model );
|
|
|
|
if ( IsDefined( level.door_key_fx ) )
|
|
{
|
|
PlayFXOnTag( level.door_key_fx, e_model, "tag_origin" );
|
|
}
|
|
|
|
while( IsAlive( self ) )
|
|
{
|
|
e_model MoveTo( self.origin + (0,0,80), 0.2 );
|
|
e_model RotateYaw( 30, 0.2 );
|
|
wait 0.1;
|
|
}
|
|
|
|
e_model MoveZ( -60, 1.0 );
|
|
wait 1.0;
|
|
|
|
e_model thread rotate_key_forever();
|
|
|
|
e_trigger = spawn( "trigger_radius", e_model.origin, 0, 25.0, 100.0 );
|
|
|
|
if ( isdefined( n_timeout_sec ) )
|
|
{
|
|
level thread key_process_timeout( n_timeout_sec, e_trigger, e_model );
|
|
}
|
|
|
|
e_trigger endon( "death" );
|
|
|
|
while ( true )
|
|
{
|
|
e_trigger waittill( "trigger", e_who );
|
|
if ( IsPlayer( e_who ) )
|
|
{
|
|
e_who give_player_key( str_key_type );
|
|
break;
|
|
}
|
|
}
|
|
|
|
e_model Delete();
|
|
e_trigger Delete();
|
|
}
|
|
|
|
function give_ai_key( n_timeout_sec = undefined, str_key_type = "door" )
|
|
{
|
|
assert( isdefined( level.door_key_model ), "Attempting to give ai a key, but no key model is associated with any door in this level." );
|
|
|
|
self thread give_ai_key_internal( n_timeout_sec, str_key_type );
|
|
}
|
|
|
|
function give_player_key( str_key_type = "door" )
|
|
{
|
|
assert( isdefined( level.door_key_icon ), "Attempting to give player a key, but no key icon is associated with any door in this level." );
|
|
|
|
if ( !IsDefined( self.collectible_keys ) )
|
|
{
|
|
self.collectible_keys = [];
|
|
}
|
|
|
|
if ( !IsDefined( self.collectible_keys[str_key_type] ) )
|
|
{
|
|
self.collectible_keys[str_key_type] = SpawnStruct();
|
|
self.collectible_keys[str_key_type].num_keys = 0;
|
|
self.collectible_keys[str_key_type].type = str_key_type;
|
|
}
|
|
|
|
hudelem = self.collectible_keys[str_key_type].hudelem;
|
|
if ( !isdefined( hudelem ) )
|
|
{
|
|
hudelem = newclienthudelem( self );
|
|
}
|
|
|
|
hudelem.alignX = "right";
|
|
hudelem.alignY = "bottom";
|
|
hudelem.horzAlign = "right";
|
|
hudelem.vertAlign = "bottom";
|
|
hudelem.hidewheninmenu = true;
|
|
hudelem.hideWhenInDemo = true;
|
|
hudelem.y = -75;
|
|
hudelem.x = -25;
|
|
|
|
hudelem SetShader( level.door_key_icon, 16, 16 );
|
|
|
|
self.collectible_keys[str_key_type].hudelem = hudelem;
|
|
|
|
self.collectible_keys[str_key_type].num_keys++;
|
|
}
|
|
|
|
function unlock_all( b_do_open = true )
|
|
{
|
|
a_s_inst_list = struct::get_array( "scriptbundle_doors", "classname" );
|
|
foreach( s_inst in a_s_inst_list )
|
|
{
|
|
c_door = s_inst.c_door;
|
|
if ( isdefined( c_door ) )
|
|
{
|
|
[[c_door]]->unlock();
|
|
|
|
if ( b_do_open )
|
|
{
|
|
[[c_door]]->open();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function unlock( str_name, str_name_type = "targetname", b_do_open = true )
|
|
{
|
|
a_s_inst_list = struct::get_array( str_name, str_name_type );
|
|
foreach( s_inst in a_s_inst_list )
|
|
{
|
|
if ( isdefined( s_inst.c_door ) )
|
|
{
|
|
[[s_inst.c_door]]->unlock();
|
|
|
|
if ( b_do_open )
|
|
{
|
|
[[s_inst.c_door]]->open();
|
|
}
|
|
}
|
|
}
|
|
}
|