boiii-scripts/shared/doors_shared.gsc
2023-04-13 17:30:38 +02:00

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();
}
}
}
}