/**** LEAPFROG SYSTEM **** Thread maps\_leapfrog::leapfrog() on any AI that uses a chain of nodes. Make sure to check the NOT_CHAIN check box on each node in the chain to allow chains to merge or loop. You need at least two chains for this to look good. level.leap_delay_min and max determines how fast they try to advance. set script_delay on a node to have the ai use a delay instead of waiting for a leap notify. script_delay = 0 will make them run past that node before going to the next one. *************************/ #include maps\_utility; main() { // Set delays to tweak how fast the advance should be. level.leap_delay_min = 6; level.leap_delay_max = 14; level.leap_delay_override = false; // there will never be more ai on one leap node then what this is set to. level.leapfrog_max_node_ai = 6; level.leap_node_array = []; level.leapfrog_random_int = randomint( 5 ); // lower threat threatbias group for when leaping. createthreatbiasgroup( "leapfrog" ); setthreatbiasagainstall( "leapfrog", -200 ); level thread leapfrog_masterthread(); } leapfrog_masterthread() { while ( true ) { if ( !level.leap_delay_override ) wait( randomFloatRange( level.leap_delay_min, level.leap_delay_max ) ); else wait .05; level.leap_delay_override = false; // used to make ai take the same fork in a path when script_delay is set. level.leapfrog_random_int = randomint( 5 ); node_arr = []; high_weight = -1000000; if ( !level.leap_node_array.size ) continue; for ( i = 0; i < level.leap_node_array.size; i++ ) { weight = level.leap_node_array[ i ].leap_weight; if ( !isdefined( node_arr[ weight ] ) ) node_arr[ weight ] = []; node_arr[ weight ][ node_arr[ weight ].size ] = level.leap_node_array[ i ]; if ( weight > high_weight ) high_weight = weight; } assertEx( isdefined( node_arr[ high_weight ] ), "high_weight is: " + high_weight ); assertEx( isdefined( high_weight >= 0 ), "high_weight is below zero: " + high_weight ); node = node_arr[ high_weight ][ randomint( node_arr[ high_weight ].size ) ]; assert( isdefined( node.target ) );// there should always be a new node or it shouldn't be in the array. node_arr = getnodearray( node.target, "targetname" ); next_node = node_arr[ randomint( node_arr.size ) ]; // reset future ai count if ( isdefined( next_node.leapfrog_ai_count ) ) next_node.leapfrog_future_ai_count = next_node.leapfrog_ai_count; else next_node.leapfrog_future_ai_count = 0; // increase the weight of all none chosen nodes. array_thread( level.leap_node_array, ::increment_leap_weight, node ); new_weight = int( node.leap_weight * - .25 ); if ( isdefined( next_node.leap_weight ) ) new_weight += next_node.leap_weight; add_leap_node( next_node, new_weight ); node notify( "leapfrog", next_node ); remove_leap_node( node ); } } increment_leap_weight( node ) { if ( self == node ) return; diff_weight = node.leap_weight - self.leap_weight; self.leap_weight += ( int( diff_weight * 0.5 ) + 1 );// old .75; } leapfrog() { self endon( "death" ); self endon( "stop_leapfrog" ); self notify( "stop_going_to_node" ); // get first node node_arr = getnodearray( self.target, "targetname" ); node = node_arr[ randomint( node_arr.size ) ]; while ( true ) { if ( node.radius != 0 ) self.goalradius = node.radius; if ( isdefined( node.height ) ) self.goalheight = node.height; self setgoalnode( node ); old_maxsightdistsqrd = self.maxsightdistsqrd; self.maxsightdistsqrd = 350 * 350; old_group = self getthreatbiasgroup(); self setthreatbiasgroup( "leapfrog" ); self waittill( "goal" ); // Notify the node and pass the guy. Might be good for something node notify( "trigger", self ); self.maxsightdistsqrd = old_maxsightdistsqrd; self setthreatbiasgroup( old_group ); self thread leapfrog_on_death( node ); if ( !isdefined( node.target ) ) break; if ( isdefined( node.script_delay ) ) { node script_delay(); node_arr = getnodearray( node.target, "targetname" ); next_node = node_arr[ level.leapfrog_random_int % node_arr.size ]; } else { if ( !add_leap_node( node ) ) break; node waittill( "leapfrog", next_node ); next_node.leapfrog_future_ai_count++ ; max_node_ai = level.leapfrog_max_node_ai; if ( isdefined( node.script_noteworthy ) ) max_node_ai = int( node.script_noteworthy ); if ( next_node.leapfrog_future_ai_count > max_node_ai ) { level.leap_delay_override = true; if ( isdefined( next_node.leap_weight ) ) { next_node.leap_weight += 1; // make the full node more likely to leap. } next_node = node; // stay on old node. } } node = next_node; } // notify level and pass the guy that reached his final leapfrog node. level notify( "leapfrog_completed", self ); } leapfrog_on_death( node ) { node endon( "leapfrog" ); if ( !isdefined( node.leapfrog_ai_count ) ) node.leapfrog_ai_count = 0; node.leapfrog_ai_count++ ; self waittill( "death" ); node.leapfrog_ai_count -- ; if ( isdefined( node.leap_weight ) ) { new_weight = node.leap_weight - 1; if ( new_weight < 1 ) new_weight = 1; node.leap_weight = new_weight; } if ( !node.leapfrog_ai_count ) remove_leap_node( node ); } add_leap_node( node, weight ) { if ( !isdefined( node.target ) || isdefined( node.script_delay ) ) return false; if ( getdvar( "debug" ) == "1" ) node thread debug_leap_node(); if ( !is_in_array( level.leap_node_array, node ) ) { level.leap_node_array = array_add( level.leap_node_array, node ); node.leap_weight = 0; } if ( isdefined( weight ) ) node.leap_weight = weight; else node.leap_weight += 2; return true; } remove_leap_node( node ) { node.leap_weight = undefined; node.leapfrog_ai_count = undefined; level.leap_node_array = array_remove( level.leap_node_array, node ); } /* debug stuff */ debug_leap_node() { if ( isdefined( self.debug_leapnode ) ) return; self.debug_leapnode = true; while ( true ) { if ( isdefined( self.leap_weight ) ) self thread print3Dmessage( self.leap_weight, .5 ); if ( isdefined( self.leapfrog_ai_count ) ) self thread print3Dmessage( self.leapfrog_ai_count, 0.5, ( 1, 0, 0 ), ( 0, 0, 128 ), 3 ); wait .5; } } print3Dmessage( message, show_time, color, offset, scale ) { if ( !isdefined( color ) ) color = ( 0.5, 1, 0.5 ); if ( !isdefined( offset ) ) offset = ( 0, 0, 56 ); if ( !isdefined( scale ) ) scale = 6; show_time = gettime() + ( show_time * 1000 ); while ( gettime() < show_time ) { print3d( self.origin + offset, message, color, 1, scale ); wait( 0.05 ); } }