#using scripts\codescripts\struct; #using scripts\shared\array_shared; #using scripts\shared\flag_shared; #using scripts\shared\hud_util_shared; #using scripts\shared\spawner_shared; #using scripts\shared\system_shared; #using scripts\shared\util_shared; #namespace trigger; function autoexec __init__sytem__() { system::register("trigger",&__init__,undefined,undefined); } function __init__() { level.fog_trigger_current = undefined; level.trigger_hint_string = []; level.trigger_hint_func = []; if ( !isdefined( level.trigger_flags ) ) { init_flags(); } trigger_funcs = []; trigger_funcs[ "trigger_unlock" ] = &trigger_unlock; trigger_funcs[ "flag_set" ] = &flag_set_trigger; trigger_funcs[ "flag_clear" ] = &flag_clear_trigger; trigger_funcs[ "flag_set_touching" ] = &flag_set_touching; trigger_funcs[ "friendly_respawn_trigger" ] = &friendly_respawn_trigger; trigger_funcs[ "friendly_respawn_clear" ] = &friendly_respawn_clear; trigger_funcs[ "trigger_delete" ] = &trigger_turns_off; trigger_funcs[ "trigger_delete_on_touch" ] = &trigger_delete_on_touch; trigger_funcs[ "trigger_off" ] = &trigger_turns_off; trigger_funcs[ "delete_link_chain" ] = &delete_link_chain; trigger_funcs[ "no_crouch_or_prone" ] = &no_crouch_or_prone_think; trigger_funcs[ "no_prone" ] = &no_prone_think; trigger_funcs[ "flood_spawner" ] = &spawner::flood_trigger_think; trigger_funcs[ "trigger_spawner" ] = &trigger_spawner; trigger_funcs[ "trigger_hint" ] = &trigger_hint; trigger_funcs[ "exploder" ] = &trigger_exploder; foreach ( trig in get_all( "trigger_radius", "trigger_multiple", "trigger_once", "trigger_box" ) ) { if ( (isdefined(trig.spawnflags)&&((trig.spawnflags & 256) == 256)) ) { level thread trigger_look( trig ); } } foreach ( trig in get_all() ) { /# trig check_spawnflags(); #/ if ( trig.classname != "trigger_damage" ) { if ( trig.classname != "trigger_hurt" ) { if ( (isdefined(trig.spawnflags)&&((trig.spawnflags & 32) == 32)) ) { level thread trigger_spawner( trig ); } } } if ( ( trig.classname != "trigger_once" ) && is_trigger_once( trig ) ) { level thread trigger_once( trig ); } if ( isdefined( trig.script_flag_true ) ) { level thread script_flag_true_trigger( trig ); } if ( isdefined( trig.script_flag_set ) ) { level thread flag_set_trigger( trig, trig.script_flag_set ); } if ( isdefined( trig.script_flag_set_on_touching ) || isdefined( trig.script_flag_set_on_cleared ) ) { level thread script_flag_set_touching( trig ); } if ( isdefined( trig.script_flag_clear ) ) { level thread flag_clear_trigger( trig, trig.script_flag_clear ); } if ( isdefined( trig.script_flag_false ) ) { level thread script_flag_false_trigger( trig ); } if ( isdefined( trig.script_trigger_group ) ) { trig thread trigger_group(); } // MikeD( 06/26/07 ): Added script_notify, which will send out the value set to script_notify as a level notify once triggered if ( isdefined( trig.script_notify ) ) { level thread trigger_notify( trig, trig.script_notify ); } if ( isdefined( trig.script_fallback ) ) { level thread spawner::fallback_think( trig ); } if ( isdefined( trig.script_killspawner ) ) { level thread kill_spawner_trigger( trig ); } if ( isdefined( trig.targetname ) ) { // do targetname specific functions if ( isdefined( trigger_funcs[ trig.targetname ] ) ) { level thread [[ trigger_funcs[ trig.targetname ] ]]( trig ); } } } } function check_spawnflags() { if ( ( isdefined( self.script_trigger_allplayers ) && self.script_trigger_allplayers ) && ( (isdefined(self.spawnflags)&&((self.spawnflags & 1) == 1)) || (isdefined(self.spawnflags)&&((self.spawnflags & 2) == 2)) || (isdefined(self.spawnflags)&&((self.spawnflags & 4) == 4)) || (isdefined(self.spawnflags)&&((self.spawnflags & 8) == 8)) || (isdefined(self.spawnflags)&&((self.spawnflags & 16) == 16)) ) ) { //Assert( "Triggers using 'script_trigger_allplayers' are not compatible with other entity types. Please unset spawnflags for other types." ); // TODO: put this back in, just didn't want to check in an assert at the end of the day } } function trigger_unlock( trigger ) { // trigger unlocks unlock another trigger. When that trigger is hit, all unlocked triggers relock // trigger_unlocks with the same script_noteworthy relock the same triggers noteworthy = "not_set"; if( isdefined( trigger.script_noteworthy ) ) { noteworthy = trigger.script_noteworthy; } target_triggers = GetEntArray( trigger.target, "targetname" ); trigger thread trigger_unlock_death( trigger.target ); while ( true ) { array::run_all( target_triggers, &TriggerEnable, false ); trigger waittill( "trigger" ); array::run_all( target_triggers, &TriggerEnable, true ); wait_for_an_unlocked_trigger( target_triggers, noteworthy ); array::notify_all( target_triggers, "relock" ); } } function trigger_unlock_death( target ) { self waittill( "death" ); target_triggers = GetEntArray( target, "targetname" ); array::run_all( target_triggers, &TriggerEnable, false ); } function wait_for_an_unlocked_trigger( triggers, noteworthy ) { level endon( "unlocked_trigger_hit" + noteworthy ); ent = SpawnStruct(); for( i = 0; i < triggers.size; i++ ) { triggers[i] thread report_trigger( ent, noteworthy ); } ent waittill( "trigger" ); level notify( "unlocked_trigger_hit" + noteworthy ); } function report_trigger( ent, noteworthy ) { self endon( "relock" ); level endon( "unlocked_trigger_hit" + noteworthy ); self waittill( "trigger" ); ent notify( "trigger" ); } function get_trigger_look_target() { if ( isdefined( self.target ) ) { a_potential_targets = GetEntArray( self.target, "targetname" ); a_targets = []; foreach ( target in a_potential_targets ) { if ( ( target.classname === "script_origin" ) ) { if ( !isdefined( a_targets ) ) a_targets = []; else if ( !IsArray( a_targets ) ) a_targets = array( a_targets ); a_targets[a_targets.size]=target;; } } a_potential_target_structs = struct::get_array( self.target ); a_targets = ArrayCombine( a_targets, a_potential_target_structs, true, false ); if ( a_targets.size > 0 ) { Assert( a_targets.size == 1, "Look tigger at " + self.origin + " targets multiple origins/structs." ); e_target = a_targets[0]; } } if(!isdefined(e_target))e_target=self; return e_target; } function trigger_look( trigger ) { trigger endon( "death" ); e_target = trigger get_trigger_look_target(); if ( isdefined( trigger.script_flag ) && !isdefined( level.flag[trigger.script_flag] ) ) { level flag::init( trigger.script_flag, undefined, true ); } a_parameters = []; if ( isdefined( trigger.script_parameters ) ) { a_parameters = StrTok( trigger.script_parameters, ",; " ); } b_ads_check = IsInArray( a_parameters, "check_ads" ); while ( true ) { trigger waittill( "trigger", e_other ); if ( IsPlayer( e_other ) ) { while ( isdefined( e_other ) && e_other IsTouching( trigger ) ) { if ( e_other util::is_looking_at( e_target, trigger.script_dot, ( isdefined( trigger.script_trace ) && trigger.script_trace ) ) && ( !b_ads_check || !e_other util::is_ads() ) ) { trigger notify( "trigger_look", e_other ); if ( isdefined( trigger.script_flag ) ) { level flag::set( trigger.script_flag ); } } else { if ( isdefined( trigger.script_flag ) ) { level flag::clear( trigger.script_flag ); } } {wait(.05);}; } if ( isdefined( trigger.script_flag ) ) { level flag::clear( trigger.script_flag ); } } else { AssertMsg( "Look triggers only support players." ); } } } function trigger_spawner( trigger ) { a_spawners = GetSpawnerArray( trigger.target, "targetname" ); Assert( a_spawners.size > 0, "Triggers with flag TRIGGER_SPAWN at " + trigger.origin + " must target at least one spawner." ); trigger endon( "death" ); trigger wait_till(); foreach ( sp in a_spawners ) { if ( isdefined( sp ) ) { sp thread trigger_spawner_spawn(); } } } function trigger_spawner_spawn() { self endon( "death" ); self flag::script_flag_wait(); self util::script_delay(); self spawner::spawn(); } /@ "Name: trigger_notify()" "Summary: Sends out a level notify of the trigger's script_notify once triggered" "Module: Trigger" "CallOn: " "Example: trigger thread trigger_notify(); " "SPMP: singleplayer" @/ function trigger_notify( trigger, msg ) { trigger endon( "death" ); other = trigger wait_till(); if( isdefined( trigger.target ) ) { a_target_ents = GetEntArray( trigger.target, "targetname" ); foreach ( notify_ent in a_target_ents ) { notify_ent notify( msg, other ); } } level notify( msg, other ); } function flag_set_trigger( trigger, str_flag ) { trigger endon( "death" ); if(!isdefined(str_flag))str_flag=trigger.script_flag; if ( !level flag::exists( str_flag ) ) { level flag::init( str_flag, undefined, true ); } while ( true ) { trigger wait_till(); if ( isdefined( trigger.targetname ) && ( trigger.targetname == "flag_set" ) ) { // this is a "flag_set" trigger so support script_delay // generic triggers don't use script_dealy for flag setting because the // script_delay might be intended for something else trigger util::script_delay(); } level flag::set( str_flag ); } } function flag_clear_trigger( trigger, str_flag ) { trigger endon( "death" ); if(!isdefined(str_flag))str_flag=trigger.script_flag; if ( !level flag::exists( str_flag ) ) { level flag::init( str_flag, undefined, true ); } while ( true ) { trigger wait_till(); if ( isdefined( trigger.targetname ) && ( trigger.targetname == "flag_clear" ) ) { // this is a "level flag::clear" trigger so support script_delay // generic triggers don't use script_dealy for flag clearing because the // script_delay might be intended for something else trigger util::script_delay(); } level flag::clear( str_flag ); } } function add_tokens_to_trigger_flags( tokens ) { for( i = 0; i < tokens.size; i++ ) { flag = tokens[i]; if( !isdefined( level.trigger_flags[flag] ) ) { level.trigger_flags[flag] = []; } level.trigger_flags[flag][level.trigger_flags[flag].size] = self; } } function script_flag_false_trigger( trigger ) { // all of these flags must be false for the trigger to be enabled tokens = util::create_flags_and_return_tokens( trigger.script_flag_false ); trigger add_tokens_to_trigger_flags( tokens ); trigger update_based_on_flags(); } function script_flag_true_trigger( trigger ) { // all of these flags must be false for the trigger to be enabled tokens = util::create_flags_and_return_tokens( trigger.script_flag_true ); trigger add_tokens_to_trigger_flags( tokens ); trigger update_based_on_flags(); } function friendly_respawn_trigger( trigger ) { trigger endon( "death" ); spawners = GetEntArray( trigger.target, "targetname" ); assert( spawners.size == 1, "friendly_respawn_trigger targets multiple spawner with targetname " + trigger.target + ". Should target just 1 spawner." ); spawner = spawners[0]; assert( !isdefined( spawner.script_forcecolor ), "targeted spawner at " + spawner.origin + " should not have script_forcecolor set!" ); spawners = undefined; spawner endon( "death" ); while ( true ) { trigger waittill( "trigger" ); // SRS 12/20/2007: updated to allow for multiple color chains to be reinforced from different areas if( isdefined( trigger.script_forcecolor ) ) { level.respawn_spawners_specific[trigger.script_forcecolor] = spawner; } else { level.respawn_spawner = spawner; } level flag::set( "respawn_friendlies" ); wait( 0.5 ); } } function friendly_respawn_clear( trigger ) { trigger endon( "death" ); while ( true ) { trigger waittill( "trigger" ); level flag::clear( "respawn_friendlies" ); wait 0.5; } } function trigger_turns_off( trigger ) { trigger wait_till(); trigger TriggerEnable( false ); if( !isdefined( trigger.script_linkTo ) ) { return; } // also turn off all triggers this trigger links to tokens = Strtok( trigger.script_linkto, " " ); for( i = 0; i < tokens.size; i++ ) { array::run_all( GetEntArray( tokens[i], "script_linkname" ), &TriggerEnable, false ); } } function script_flag_set_touching( trigger ) { trigger endon( "death" ); if ( isdefined( trigger.script_flag_set_on_touching ) ) { level flag::init( trigger.script_flag_set_on_touching, undefined, true ); } if ( isdefined( trigger.script_flag_set_on_cleared ) ) { level flag::init( trigger.script_flag_set_on_cleared, undefined, true ); } trigger thread _detect_touched(); while ( true ) { trigger.script_touched = false; {wait(.05);}; waittillframeend; // wait for touched variable to update for this frame if ( !trigger.script_touched ) { // HACK: wait one more frame if it isn't touched - saw a strange issue where // the trigger thought it wasn't touched for a frame when another player joined // even though the first player was still standing in the trigger {wait(.05);}; waittillframeend; } if ( trigger.script_touched ) { if ( isdefined( trigger.script_flag_set_on_touching ) ) { level flag::set( trigger.script_flag_set_on_touching ); } if ( isdefined( trigger.script_flag_set_on_cleared ) ) { level flag::clear( trigger.script_flag_set_on_cleared ); } } else { if ( isdefined( trigger.script_flag_set_on_touching ) ) { level flag::clear( trigger.script_flag_set_on_touching ); } if ( isdefined( trigger.script_flag_set_on_cleared ) ) { level flag::set( trigger.script_flag_set_on_cleared ); } } } } function _detect_touched() { self endon( "death" ); while ( true ) { self waittill( "trigger" ); self.script_touched = true; } } function trigger_delete_on_touch( trigger ) { while ( true ) { trigger waittill( "trigger", other ); if( isdefined( other ) ) { // might've been removed before we got it other Delete(); } } } function flag_set_touching( trigger ) { str_flag = trigger.script_flag; if ( !isdefined( level.flag[ str_flag ] ) ) { level flag::init( str_flag, undefined, true ); } while ( true ) { trigger waittill( "trigger", other ); level flag::set( str_flag ); while ( IsAlive( other ) && other IsTouching( trigger ) && isdefined( trigger ) ) { wait( 0.25 ); } level flag::clear( str_flag ); } } function trigger_once( trig ) { trig endon( "death" ); if ( is_look_trigger( trig ) ) { trig waittill( "trigger_look" ); } else { trig waittill( "trigger" ); } waittillframeend; waittillframeend; if ( isdefined( trig ) ) { /# println( "" ); println( "*** trigger debug: deleting trigger with ent#: " + trig getentitynumber() + " at origin: " + trig.origin ); println( "" ); #/ trig Delete(); } } function trigger_hint( trigger ) { assert( isdefined( trigger.script_hint ), "Trigger_hint at " + trigger.origin + " has no .script_hint" ); trigger endon( "death" ); if ( !isdefined( level.displayed_hints ) ) { level.displayed_hints = []; } waittillframeend; // give level script a chance to set the hint string and optional boolean functions on this hint assert( isdefined( level.trigger_hint_string[ trigger.script_hint ] ), "Trigger_hint with hint " + trigger.script_hint + " had no hint string assigned to it. Define hint strings with util::add_hint_string()" ); trigger waittill( "trigger", other ); assert( IsPlayer( other ), "Tried to do a trigger_hint on a non player entity" ); if ( isdefined( level.displayed_hints[ trigger.script_hint ] ) ) { return; } level.displayed_hints[ trigger.script_hint ] = true; display_hint( trigger.script_hint ); } function trigger_exploder( trigger ) { trigger endon( "death" ); while (true) { trigger waittill( "trigger" ); if (isdefined(trigger.target )) { ActivateClientRadiantExploder( trigger.target ); } } } /@ "Name: display_hint( )" "Summary: Displays a hint created with add_hint_string." "Module: Utility" "MandatoryArg: : The hint reference created with add_hint_string." "Example: display_hint( "huzzah" )" "SPMP: singleplayer" @/ function display_hint( hint ) { if ( GetDvarString( "chaplincheat" ) == "1" ) { return; } // hint triggers have an optional function they can boolean off of to determine if the hint will occur // such as not doing the NVG hint if the player is using NVGs already if( isdefined( level.trigger_hint_func[ hint ] ) ) { if( [[ level.trigger_hint_func[ hint ] ]]() ) { return; } _hint_print( level.trigger_hint_string[ hint ], level.trigger_hint_func[ hint ] ); } else { _hint_print( level.trigger_hint_string[ hint ] ); } } function _hint_print( string, breakfunc ) { const MYFADEINTIME = 1.0; const MYFLASHTIME = 0.75; const MYALPHAHIGH = 0.95; const MYALPHALOW = 0.4; level flag::wait_till_clear( "global_hint_in_use" ); level flag::set( "global_hint_in_use" ); Hint = hud::createFontString( "objective", 2 ); //Hint.color = ( 1, 1, .5 ); //remove color so that color highlighting on PC can show up. Hint.alpha = 0.9; Hint.x = 0; Hint.y = -68; Hint.alignx = "center"; Hint.aligny = "middle"; Hint.horzAlign = "center"; Hint.vertAlign = "middle"; Hint.foreground = false; Hint.hidewhendead = true; Hint setText( string ); Hint.alpha = 0; Hint FadeOverTime( MYFADEINTIME ); Hint.alpha = MYALPHAHIGH; _hint_print_wait( MYFADEINTIME ); if ( isdefined( breakfunc ) ) { for ( ;; ) { Hint FadeOverTime( MYFLASHTIME ); Hint.alpha = MYALPHALOW; _hint_print_wait( MYFLASHTIME, breakfunc ); if ( [[ breakfunc ]]() ) { break; } Hint FadeOverTime( MYFLASHTIME ); Hint.alpha = MYALPHAHIGH; _hint_print_wait( MYFLASHTIME ); if ( [[ breakfunc ]]() ) { break; } } } else { for ( i = 0; i < 5; i++ ) { Hint FadeOverTime( MYFLASHTIME ); Hint.alpha = MYALPHALOW; _hint_print_wait( MYFLASHTIME ); Hint FadeOverTime( MYFLASHTIME ); Hint.alpha = MYALPHAHIGH; _hint_print_wait( MYFLASHTIME ); } } Hint Destroy(); level flag::clear( "global_hint_in_use" ); } function _hint_print_wait( length, breakfunc ) { if ( !isdefined( breakfunc ) ) { wait( length ); return; } timer = length * 20; for ( i = 0; i < timer; i++ ) { if ( [[ breakfunc ]]() ) { break; } {wait(.05);}; } } /@ "Name: get_all(type1, type2, type3, type4, type5, type6, type7, type8, type9)" "Summary: Gets all triggers on the map. If only want certain types, can specify those" "Module: Level" "CallOn: N/A" "OptionalArg: : Classname of Trigger to get." "Example: trigs = get_all();" "SPMP: singleplayer" @/ function get_all( type1, type2, type3, type4, type5, type6, type7, type8, type9 ) { if ( !isdefined( type1 ) ) { type1 = "trigger_damage"; type2 = "trigger_hurt"; type3 = "trigger_lookat"; type4 = "trigger_once"; type5 = "trigger_radius"; type6 = "trigger_use"; type7 = "trigger_use_touch"; type8 = "trigger_box"; type9 = "trigger_multiple"; type10 = "trigger_out_of_bounds"; } assert( _is_valid_trigger_type( type1 ) ); trigs = GetEntArray( type1, "classname" ); if ( isdefined( type2 ) ) { assert( _is_valid_trigger_type( type2 ) ); trigs = ArrayCombine( trigs, GetEntArray( type2, "classname" ), true, false ); } if ( isdefined( type3 ) ) { assert( _is_valid_trigger_type( type3 ) ); trigs = ArrayCombine( trigs, GetEntArray( type3, "classname" ), true, false ); } if ( isdefined( type4 ) ) { assert( _is_valid_trigger_type( type4 ) ); trigs = ArrayCombine( trigs, GetEntArray( type4, "classname" ), true, false ); } if ( isdefined( type5 ) ) { assert( _is_valid_trigger_type( type5 ) ); trigs = ArrayCombine( trigs, GetEntArray( type5, "classname" ), true, false ); } if ( isdefined( type6 ) ) { assert( _is_valid_trigger_type( type6 ) ); trigs = ArrayCombine( trigs, GetEntArray( type6, "classname" ), true, false ); } if ( isdefined( type7 ) ) { assert( _is_valid_trigger_type( type7 ) ); trigs = ArrayCombine( trigs, GetEntArray( type7, "classname" ), true, false ); } if ( isdefined( type8 ) ) { assert( _is_valid_trigger_type( type8 ) ); trigs = ArrayCombine( trigs, GetEntArray( type8, "classname" ), true, false ); } if ( isdefined( type9 ) ) { assert( _is_valid_trigger_type( type9 ) ); trigs = ArrayCombine( trigs, GetEntArray( type9, "classname" ), true, false ); } if ( isdefined( type10 ) ) { assert( _is_valid_trigger_type( type9 ) ); trigs = ArrayCombine( trigs, GetEntArray( type10, "classname" ), true, false ); } return trigs; } function _is_valid_trigger_type( type ) { switch ( type ) { case "trigger_damage": case "trigger_hurt": case "trigger_lookat": case "trigger_once": case "trigger_radius": case "trigger_use": case "trigger_use_touch": case "trigger_box": case "trigger_multiple": case "trigger_out_of_bounds": return true; break; default: return false; } } /@ function Name: wait_till( , str_key = "targetname", e_entity ) Summary: Waits until a trigger with the specified key / value is triggered. Returns the trigger and assigns the entity that triggered it to "trig.who". Module: Trigger MandatoryArg: str_name: Key value. OptionalArg: str_key: Key name on the trigger to use, example: "targetname" or "script_noteworthy". OptionalArg: e_entity: Wait for a specific entity to trigger the trigger. "OptionalArg: : Set to false to not assert if the trigger doesn't exist" function Example: wait_till( "player_in_building1, "script_noteworthy" ); SPMP: both @/ function wait_till( str_name, str_key = "targetname", e_entity, b_assert = true ) { if ( isdefined( str_name ) ) { triggers = GetEntArray( str_name, str_key ); if( ( SessionModeIsCampaignZombiesGame() ) ) { // sjakatdar ( 09/21/2015 ) - A temporary fix which should be removed in T8 branch. In campaign zombies, // players can double jump ahead and hit the trigger before trigger::wait_till is called, which can end up in this assert. //Assert( !b_assert || ( triggers.size > 0 ), "trigger not found: " + str_name + " key: " + str_key ); // Its better to just return true if the trigger is not found instead. if( triggers.size <= 0 ) return; } else { Assert( !b_assert || ( triggers.size > 0 ), "trigger not found: " + str_name + " key: " + str_key ); } if ( triggers.size > 0 ) { if ( triggers.size == 1 ) { trigger_hit = triggers[0]; trigger_hit _trigger_wait( e_entity ); } else { s_tracker = SpawnStruct(); array::thread_all( triggers,&_trigger_wait_think, s_tracker, e_entity ); s_tracker waittill( "trigger", e_other, trigger_hit ); trigger_hit.who = e_other; } return trigger_hit; } } else { if( ( SessionModeIsCampaignZombiesGame() ) ) { // sjakatdar ( 09/21/2015 ) - A temporary fix which should be removed in T8 branch. In campaign zombies, // players can double jump ahead and hit the trigger before trigger::wait_till is called, which can end up in script errors // Its better to just return true if the trigger is not found instead. if( !IsDefined( self ) ) return; } return _trigger_wait( e_entity ); } } function _trigger_wait( e_entity ) { self endon( "death" ); if ( isdefined( e_entity ) ) { e_entity endon( "death" ); } /# if ( is_look_trigger( self ) ) { Assert( !IsArray( e_entity ), "LOOK triggers can only wait on one entity." ); } else if ( self.classname === "trigger_damage" ) { Assert( !IsArray( e_entity ), "Damage triggers can only wait on one entity." ); } #/ while ( true ) { if ( is_look_trigger( self ) ) { self waittill( "trigger_look", e_other ); if ( isdefined( e_entity ) ) { if ( e_other !== e_entity ) { continue; } } } else if ( self.classname === "trigger_damage" ) { self waittill( "trigger", e_other ); if ( isdefined( e_entity ) ) { if ( e_other !== e_entity ) { continue; } } } else { self waittill( "trigger", e_other ); if ( isdefined( e_entity ) ) { if ( IsArray( e_entity ) ) { if ( !array::is_touching( e_entity, self ) ) { continue; } } else if ( !e_entity IsTouching( self ) && ( e_entity !== e_other ) ) { continue; } } } break; } self.who = e_other; return self; } function _trigger_wait_think( s_tracker, e_entity ) { self endon( "death" ); s_tracker endon( "trigger" ); e_other = _trigger_wait( e_entity ); s_tracker notify( "trigger", e_other, self ); } /@ "Name: use( , [str_key], [ent], [b_assert] )" "Summary: Activates a trigger with the specified key / value is triggered" "Module: Trigger" "CallOn: " "MandatoryArg: : Name of the key on this trigger. If name is not passed in, func will check against self" "OptionalArg: [str_key] : Key on the trigger to use, example: "targetname" or "script_noteworthy"" "OptionalArg: [ent] : Entity that the trigger is used by" "OptionalArg: [b_assert] : Set to false to not assert if the trigger doesn't exist" "Example: use( "player_in_building1, "targetname", enemy, false );" "SPMP: singleplayer" @/ function use( str_name, str_key = "targetname", ent, b_assert = true ) { if ( !isdefined( ent ) ) { ent = GetPlayers()[0]; } if ( isdefined( str_name ) ) { e_trig = GetEnt( str_name, str_key ); if( !isdefined( e_trig ) ) { if ( b_assert ) { AssertMsg( "trigger not found: " + str_name + " key: " + str_key ); } return; } } else { e_trig = self; str_name = self.targetname; } if( isdefined( ent ) ) { e_trig UseBy( ent ); } else { e_trig UseBy( e_trig ); } level notify( str_name, ent ); // TODO: brianb - do we need this? if ( is_look_trigger( e_trig ) ) { e_trig notify( "trigger_look", ent ); } return e_trig; } function set_flag_permissions( msg ) { // turns triggers on or off depending on if they have the proper flags set, based on their shift-g menu settings if ( !isdefined( level.trigger_flags ) || !isdefined( level.trigger_flags[ msg ] ) ) { return; } // cheaper to do the upkeep at this time rather than with endons and waittills on the individual triggers level.trigger_flags[ msg ] = array::remove_undefined( level.trigger_flags[ msg ] ); array::thread_all( level.trigger_flags[ msg ], &update_based_on_flags ); } function update_based_on_flags() { true_on = true; if ( isdefined( self.script_flag_true ) ) { true_on = false; tokens = util::create_flags_and_return_tokens( self.script_flag_true ); // stay off unless any of the flags are true for( i=0; i < tokens.size; i++ ) { if ( level flag::get( tokens[ i ] ) ) { true_on = true; break; } } } false_on = true; if ( isdefined( self.script_flag_false ) ) { tokens = util::create_flags_and_return_tokens( self.script_flag_false ); // stay off unless all flags are false for( i=0; i < tokens.size; i++ ) { if ( level flag::get( tokens[ i ] ) ) { false_on = false; break; } } } b_enable = true_on && false_on; self TriggerEnable( b_enable ); } function init_flags() { level.trigger_flags = []; } function is_look_trigger( trig ) { return ( isdefined( trig ) ? (isdefined(trig.spawnflags)&&((trig.spawnflags & 256) == 256)) && !( trig.classname === "trigger_damage" ) : false ); } function is_trigger_once( trig ) { return ( isdefined( trig ) ? (isdefined(trig.spawnflags)&&((trig.spawnflags & 1024) == 1024)) || ( ( self.classname === "trigger_once" ) ) : false ); } function wait_for_either( str_targetname1, str_targetname2 ) { ent = SpawnStruct(); array = []; array = ArrayCombine( array, GetEntArray( str_targetname1, "targetname" ), true, false ); array = ArrayCombine( array, GetEntArray( str_targetname2, "targetname" ), true, false ); for ( i = 0; i < array.size; i++ ) { ent thread _ent_waits_for_trigger( array[ i ] ); } ent waittill( "done", t_hit ); return t_hit; } function _ent_waits_for_trigger( trigger ) { trigger wait_till(); self notify( "done", trigger ); } /@ "Name: wait_or_timeout( n_time, str_name, str_key )" "Summary: Wait for a trigger to trigger or time passes." "MandatoryArg: n_time: the amount of time." "OptionalArg: str_name: name of the trigger." "OptionalArg: str_key: KVP key of the trigger." "Example: trigger::wait_or_timeout( 5, "my_trigger", "targetname" );" @/ function wait_or_timeout( n_time, str_name, str_key ) { if ( isdefined( n_time ) ) { __s = SpawnStruct(); __s endon( "timeout" ); __s util::delay_notify( n_time, "timeout" ); }; wait_till( str_name, str_key ); } /@ "Name: trigger_on_timeout( n_time, b_cancel_on_triggered, str_name, str_key )" "Summary: Force a trigger to trigger when time passes." "MandatoryArg: n_time: the amount of time." "OptionalArg: b_cancel_on_triggered: don't trigger the trigger if it gets triggered before the time is up." "OptionalArg: str_name: name of the trigger." "OptionalArg: str_key: KVP key of the trigger." "Example: trigger::trigger_on_timeout( 5, true, "my_trigger", "targetname" );" @/ function trigger_on_timeout( n_time, b_cancel_on_triggered = true, str_name, str_key = "targetname" ) { trig = self; if ( isdefined( str_name ) ) { trig = GetEnt( str_name, str_key ); } if ( b_cancel_on_triggered ) { if ( is_look_trigger( trig ) ) { trig endon( "trigger_look" ); } else { trig endon( "trigger" ); } } trig endon( "death" ); wait n_time; trig use(); } function multiple_waits( str_trigger_name, str_trigger_notify ) { foreach ( trigger in GetEntArray( str_trigger_name, "targetname") ) { trigger thread multiple_wait( str_trigger_notify ); } } function multiple_wait( str_trigger_notify )// self = trigger ent { level endon( str_trigger_notify ); self waittill( "trigger" ); level notify( str_trigger_notify ); } /@ "Name: add_function( , [str_remove_on], , [param_1], [param_2], [param_3], [param_4], [param_5], [param_6] )" "Summary: Runs a function when a trigger is hit." "Module: Utility" "CallOn: level" "MandatoryArg: : targetname of the trigger" "OptionalArg: [str_remove_on] : remove the function on this notify to the trigger" "MandatoryArg: : pointer to a script function" "OptionalArg: [param_1] : parameter 1 to pass to the func" "OptionalArg: [param_2] : parameter 2 to pass to the func" "OptionalArg: [param_3] : parameter 3 to pass to the func" "OptionalArg: [param_4] : parameter 4 to pass to the func" "OptionalArg: [param_5] : parameter 5 to pass to the func" "OptionalArg: [param_6] : parameter 6 to pass to the func" "Example: add_function( "my_trigger",&my_trigger_function );" "SPMP: SP" @/ function add_function( trigger, str_remove_on, func, param_1, param_2, param_3, param_4, param_5, param_6 ) { self thread _do_trigger_function( trigger, str_remove_on, func, param_1, param_2, param_3, param_4, param_5, param_6 ); } function _do_trigger_function( trigger, str_remove_on, func, param_1, param_2, param_3, param_4, param_5, param_6 ) { self endon( "death" ); trigger endon( "death" ); if ( isdefined( str_remove_on ) ) { trigger endon( str_remove_on ); } while ( true ) { if ( IsString( trigger ) ) { wait_till( trigger ); } else { trigger wait_till(); } util::single_thread( self, func, param_1, param_2, param_3, param_4, param_5, param_6 ); } } function kill_spawner_trigger( trigger ) { trigger trigger::wait_till(); a_spawners = GetSpawnerArray( trigger.script_killspawner, "script_killspawner" ); foreach ( sp in a_spawners ) { sp Delete(); } a_ents = GetEntArray( trigger.script_killspawner, "script_killspawner" ); foreach ( ent in a_ents ) { if ( ( ent.classname === "spawn_manager" ) && ( ent != trigger ) ) { ent Delete(); } } } function get_script_linkto_targets() { targets = []; if( !isdefined( self.script_linkto ) ) { return targets; } tokens = Strtok( self.script_linkto, " " ); for( i = 0; i < tokens.size; i++ ) { token = tokens[i]; target = GetEnt( token, "script_linkname" ); if( isdefined( target ) ) { targets[targets.size] = target; } } return targets; } function delete_link_chain( trigger ) { // deletes all entities that it script_linkto's, and all entities that entity script linktos, etc. trigger waittill( "trigger" ); targets = trigger get_script_linkto_targets(); array::thread_all( targets, &delete_links_then_self ); } function delete_links_then_self() { targets = get_script_linkto_targets(); array::thread_all( targets, &delete_links_then_self ); self Delete(); } function no_crouch_or_prone_think( trigger ) { while ( true ) { trigger waittill( "trigger", other ); if( !IsPlayer( other ) ) { continue; } while( other IsTouching( trigger ) ) { other AllowProne( false ); other AllowCrouch( false ); {wait(.05);}; } other AllowProne( true ); other AllowCrouch( true ); } } function no_prone_think( trigger ) { while ( true ) { trigger waittill( "trigger", other ); if( !IsPlayer( other ) ) { continue; } while( other IsTouching( trigger ) ) { other AllowProne( false ); {wait(.05);}; } other AllowProne( true ); } } function trigger_group() { self thread trigger_group_remove(); level endon( "trigger_group_" + self.script_trigger_group ); self waittill( "trigger" ); level notify( "trigger_group_" + self.script_trigger_group, self ); } function trigger_group_remove() { level waittill( "trigger_group_" + self.script_trigger_group, trigger ); if( self != trigger ) { self Delete(); } } //trigger_thread function function_thread(ent, on_enter_payload, on_exit_payload) { ent endon("entityshutdown"); if(ent ent_already_in(self)) return; add_to_ent(ent, self); // iprintlnbold("Trigger " + self.targetname + " hit by ent " + ent getentitynumber()); if(isdefined(on_enter_payload)) { [[on_enter_payload]](ent); } while(isdefined(ent) && ent istouching(self)) { wait(0.01); } // iprintlnbold(ent getentitynumber() + " leaves trigger " + self.targetname + "."); if(isdefined(ent) && isdefined(on_exit_payload)) { [[on_exit_payload]](ent); } if(isdefined(ent)) { remove_from_ent(ent, self); } } function ent_already_in(trig) { if(!isdefined(self._triggers)) return false; if(!isdefined(self._triggers[trig getentitynumber()])) return false; if(!self._triggers[trig getentitynumber()]) return false; return true; // We're already in this trigger volume. } function add_to_ent(ent, trig) { if(!isdefined(ent._triggers)) { ent._triggers = []; } ent._triggers[trig getentitynumber()] = 1; } function remove_from_ent(ent, trig) { if(!isdefined(ent._triggers)) return; if(!isdefined(ent._triggers[trig getentitynumber()])) return; ent._triggers[trig getentitynumber()] = 0; }