#using scripts\shared\callbacks_shared; #using scripts\shared\clientfield_shared; #using scripts\shared\system_shared; #using scripts\shared\util_shared; #using scripts\shared\hostmigration_shared; #namespace oob; //Change the value in the _oob.csc file to match this one //Change the value in the _oob.csc file to match this one //Change the value in the _oob.csc file to match this one function autoexec __init__sytem__() { system::register("out_of_bounds",&__init__,undefined,undefined); } function __init__() { level.oob_triggers = []; if(SessionModeIsMultiplayerGame()) { level.oob_timekeep_ms = GetDvarInt( "oob_timekeep_ms", 3000 ); level.oob_timelimit_ms = GetDvarInt( "oob_timelimit_ms", 3000 ); level.oob_damage_interval_ms = GetDvarInt( "oob_damage_interval_ms", 3000 ); level.oob_damage_per_interval = GetDvarInt( "oob_damage_per_interval", 999 ); level.oob_max_distance_before_black = GetDvarInt( "oob_max_distance_before_black", 100000 ); level.oob_time_remaining_before_black = GetDvarInt( "oob_time_remaining_before_black", -1 ); } else { level.oob_timelimit_ms = GetDvarInt( "oob_timelimit_ms", 6000 ); level.oob_damage_interval_ms = GetDvarInt( "oob_damage_interval_ms", 1000 ); level.oob_damage_per_interval = GetDvarInt( "oob_damage_per_interval", 5 ); level.oob_max_distance_before_black = GetDvarInt( "oob_max_distance_before_black", 400 ); level.oob_time_remaining_before_black = GetDvarInt( "oob_time_remaining_before_black", 1000 ); } level.oob_damage_interval_sec = level.oob_damage_interval_ms / 1000; hurt_triggers = GetEntArray( "trigger_out_of_bounds","classname" ); foreach( trigger in hurt_triggers ) { trigger thread run_oob_trigger(); } clientfield::register( "toplayer", "out_of_bounds", 1, 5, "int" ); } function run_oob_trigger() { self.oob_players = []; if ( !isdefined( level.oob_triggers ) ) level.oob_triggers = []; else if ( !IsArray( level.oob_triggers ) ) level.oob_triggers = array( level.oob_triggers ); level.oob_triggers[level.oob_triggers.size]=self;; self thread waitForPlayerTouch(); self thread waitForCloneTouch(); } function IsOutOfBounds() { if( !IsDefined( self.oob_start_time ) ) { return false; } return self.oob_start_time != -1; } function IsTouchingAnyOOBTrigger() { triggers_to_remove = []; result = false; foreach( trigger in level.oob_triggers ) { if( !isdefined( trigger ) ) { if ( !isdefined( triggers_to_remove ) ) triggers_to_remove = []; else if ( !IsArray( triggers_to_remove ) ) triggers_to_remove = array( triggers_to_remove ); triggers_to_remove[triggers_to_remove.size]=trigger;; continue; } if( !trigger IsTriggerEnabled() ) { continue; } if( self IsTouching( trigger ) ) { result = true; break; } } foreach( trigger in triggers_to_remove ) { ArrayRemoveValue( level.oob_triggers, trigger ); } triggers_to_remove = []; triggers_to_remove = undefined; return result; } function ResetOOBTimer( is_host_migrating, b_disable_timekeep) { self.oob_lastValidPlayerLoc = undefined; self.oob_LastValidPlayerDir = undefined; self clientfield::set_to_player( "out_of_bounds", 0 ); self util::show_hud( 1 ); self.oob_start_time = -1; if( isdefined(level.oob_timekeep_ms)) { if(( isdefined( b_disable_timekeep ) && b_disable_timekeep )) { self.last_oob_timekeep_ms = undefined; } else { self.last_oob_timekeep_ms = GetTime(); } } if(!( isdefined( is_host_migrating ) && is_host_migrating )) { self notify( "oob_host_migration_exit" ); } self notify( "oob_exit" ); } function waitForCloneTouch()//self = trigger { self endon( "death" ); while( true ) { self waittill( "trigger", clone ); if( IsActor( clone ) && IsDefined( clone.isAiClone ) && clone.isAiClone && (!clone IsPlayingAnimScripted()) ) { clone notify( "clone_shutdown" ); } } } function GetAdjusedPlayer( Player ) { if( isdefined(player.hijacked_vehicle_entity) && IsAlive(player.hijacked_vehicle_entity) ) { return player.hijacked_vehicle_entity; } return Player; } function waitForPlayerTouch()//self = trigger { self endon( "death" ); while( true ) { if(SessionModeIsMultiplayerGame()) { hostmigration::waitTillHostMigrationDone(); } self waittill( "trigger", entity ); if( !IsPlayer(entity) && !(IsVehicle(entity) && ( isdefined( entity.hijacked ) && entity.hijacked ) && isdefined(entity.owner) && IsAlive(entity)) ) continue; if(IsPlayer(entity)) { player = entity; } else { vehicle = entity; player = vehicle.owner; } if( !(player IsOutOfBounds()) && !(player IsPlayingAnimScripted()) && !( isdefined( player.OOBDisabled ) && player.OOBDisabled ) ) { player notify( "oob_enter" ); //Logic to pause/continue the OOB time for a certain duration if the player come out/in from it. if( isdefined(level.oob_timekeep_ms) && isdefined(player.last_oob_timekeep_ms) && isdefined(player.last_oob_duration_ms) && ((GetTime() - player.last_oob_timekeep_ms) < level.oob_timekeep_ms) ) { player.oob_start_time = GetTime() - (level.oob_timelimit_ms - player.last_oob_duration_ms); } else { player.oob_start_time = GetTime(); } player.oob_LastValidPlayerLoc = entity.origin; player.oob_LastValidPlayerDir = VectorNormalize( entity GetVelocity() ) ; player util::show_hud( 0 ); player thread watchForLeave( self, entity ); player thread watchForDeath( self, entity ); if(SessionModeIsMultiplayerGame()) { player thread watchForHostMigration( self, entity ); } } } } function GetDistanceFromLastValidPlayerLoc(trigger, entity) { if(isdefined(self.oob_LastValidPlayerDir) && self.oob_LastValidPlayerDir != (0, 0, 0)) { vecToPlayerLocFromOrigin = entity.origin - self.oob_lastValidPlayerLoc; distance = VectorDot(vecToPlayerLocFromOrigin, self.oob_LastValidPlayerDir); } else { distance = Distance(entity.origin, self.oob_lastValidPlayerLoc); } if(distance < 0) distance = 0; if(distance > level.oob_max_distance_before_black) distance = level.oob_max_distance_before_black; return distance / level.oob_max_distance_before_black; } function UpdateVisualEffects( trigger, entity ) { timeRemaining = (level.oob_timelimit_ms - (GetTime() - self.oob_start_time)); if( isdefined(level.oob_timekeep_ms) ) { self.last_oob_duration_ms = timeRemaining; } oob_effectValue = 0; if(timeRemaining <= level.oob_time_remaining_before_black) { if(!isdefined(self.oob_lastEffectValue)) { self.oob_lastEffectValue = GetDistanceFromLastValidPlayerLoc(trigger, entity); } time_val = 1 - (timeRemaining / level.oob_time_remaining_before_black); if(time_val > 1) time_val = 1; oob_effectValue = self.oob_lastEffectValue + (1 - self.oob_lastEffectValue) * time_val; } else { oob_effectValue = GetDistanceFromLastValidPlayerLoc(trigger, entity); if(oob_effectValue > 0.9) { oob_effectValue = 0.9; } else if(oob_effectValue < 0.05) { oob_effectValue = 0.05; } self.oob_lastEffectValue = oob_effectValue; } oob_effectValue = ceil(oob_effectValue * 31); //5 bits 2^5 = 32 (so 31 values) self clientfield::set_to_player( "out_of_bounds", int(oob_effectValue) ); } function killEntity(entity) { entity_to_kill = entity; if ( IsPlayer( entity ) && entity IsInVehicle() ) { vehicle = entity GetVehicleOccupied(); if ( isdefined( vehicle ) && ( vehicle.is_oob_kill_target === true ) ) entity_to_kill = vehicle; } self ResetOOBTimer(); entity_to_kill DoDamage( entity_to_kill.health + 10000, entity_to_kill.origin, undefined, undefined, "none", "MOD_TRIGGER_HURT" ); } function watchForLeave( trigger, entity ) { self endon( "oob_exit" ); entity endon( "death" ); while( true ) { if( entity IsTouchingAnyOOBTrigger() ) { UpdateVisualEffects( trigger, entity ); if( (level.oob_timelimit_ms - (GetTime() - self.oob_start_time)) <= 0 ) { if( IsPlayer(entity) ) { entity DisableInvulnerability(); entity.ignoreme = false; entity.laststand = undefined; if( isdefined( entity.revivetrigger ) ) { entity.reviveTrigger delete(); } } self thread killEntity( entity ); } } else { self ResetOOBTimer(); } wait( 0.1 ); } } function watchForDeath( trigger, entity ) { self endon( "disconnect" ); self endon( "oob_exit" ); util::waittill_any_ents_two( self, "death", entity, "death" ); self ResetOOBTimer(); } function watchForHostMigration( trigger, entity ) { self endon( "oob_host_migration_exit" ); level waittill("host_migration_begin"); self ResetOOBTimer( true, true ); } function disablePlayerOOB( disabled ) { if ( disabled ) { self ResetOOBTimer(); self.OOBDisabled = true; } else { self.OOBDisabled = false; } }