268 lines
6.6 KiB
Text
268 lines
6.6 KiB
Text
|
/**** 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);
|
||
|
}
|
||
|
}
|