cod5-sdk/raw/maps/mp/_dogs.gsc

1462 lines
30 KiB
Text
Raw Permalink Normal View History

2008-11-20 00:00:00 +00:00
#include maps\mp\_utility;
#include common_scripts\utility;
init()
{
level.friendlyDogModel = "german_shepherd";
2009-07-17 00:00:00 +00:00
if(GetDvar("use_zombie_dog") != "")
{
level.enemyDogModel = "zombie_wolf";
}
else
{
level.enemyDogModel = "german_shepherd_black";
}
2008-11-20 00:00:00 +00:00
precacheModel(level.friendlyDogModel);
precacheModel(level.enemyDogModel);
precacheItem("dog_bite_mp");
precacheShellshock("dog_bite");
level.maxDogsAttackingPerPlayer = 2;
level.spawnTimeWaitMin = 2;
level.spawnTimeWaitMax = 5;
level.no_dogs = false;
init_node_arrays();
if ( level.no_pathnodes )
level.no_dogs = true;
regenTime = 5;
level.dogHealth_RegularRegenDelay = regenTime * 1000;
level.dogHealthRegenDisabled = (level.dogHealth_RegularRegenDelay <= 0);
dog_dvar_update();
thread dog_dvar_updater();
thread dog_usage_init();
thread init_all_preexisting_dogs();
// create_dogs();
}
pick_random_nodes( from, count )
{
to = [];
if ( from.size < count )
{
to = from;
}
else
{
for ( i = 0; i < count; i++ )
{
to[i] = from[randomInt(from.size)];
}
}
return to;
}
init_node_arrays()
{
nodes = getallnodes();
pathnodes = [];
for ( i = 0; i < nodes.size; i++ )
{
// anything with a scriptworthy is automatically a non-patrol node
if ( isdefined(nodes[i].script_noteworthy) /* || nodes[i].script_noteworthy != "" */)
continue;
if ( isdefined(nodes[i].targetname) && nodes[i].targetname == "traverse" )
continue;
pathnodes[pathnodes.size] = nodes[i];
}
if ( pathnodes.size == 0 )
{
level.no_pathnodes = true;
}
else
{
level.no_pathnodes = false;
}
level.patrolnodes = [];
level.patrolnodes = pick_random_nodes( pathnodes, 200 );
level.dogspawnnodes = [];
level.dogspawnnodes = getnodearray( "spawn", "script_noteworthy");
if ( level.dogspawnnodes.size == 0 )
{
/#
println("DOG PATHING: Could not find spawn nodes");
#/
// pick a random set of spawn nodes so we do not tax the spawn logic to much
level.dogspawnnodes = pick_random_nodes( pathnodes, 20 );
}
level.dogexitnodes = [];
level.dogexitnodes = getnodearray( "exit", "script_noteworthy");
if ( level.dogexitnodes.size == 0 )
{
/#
println("DOG PATHING: Could not find exit nodes");
#/
// pick a random set of spawn nodes so we do not tax the spawn logic to much
level.dogexitnodes = pick_random_nodes( pathnodes, 20 );
}
}
dog_dvar_update()
{
level.dog_time = dog_get_dvar_int("scr_dog_time", "60" );
level.dog_health = dog_get_dvar_int("scr_dog_health", "100" );
level.dog_count = dog_get_dvar_int("scr_dog_count", "8" );
level.dog_count_max_at_once = dog_get_dvar_int("scr_dog_max_at_once", "4" );
if ( level.dog_count < level.dog_count_max_at_once )
{
level.dog_count_max_at_once = level.dog_count;
}
level.dog_debug = dog_get_dvar_int("debug_dogs", "0" );
level.dog_debug_sound = dog_get_dvar_int("debug_dog_sound", "0" );
level.dog_debug_anims = dog_get_dvar_int("debug_dog_anims", "0" );
level.dog_debug_anims_ent = dog_get_dvar_int("debug_dog_anims_ent", "0" );
level.dog_debug_turns = dog_get_dvar_int("debug_dog_turns", "0" );
level.dog_debug_orient = dog_get_dvar_int("debug_dog_orient", "0" );
level.dog_debug_usage = dog_get_dvar_int("debug_dog_usage", "1" );
}
dog_dvar_updater()
{
dogs_in_the_bsp = count_preexisting_dogs();
while(1)
{
dog_dvar_update();
// 16 is max allowed by engine
if ( level.dog_count + dogs_in_the_bsp > 16 )
{
level.dog_count = 16 - dogs_in_the_bsp;
}
wait (1);
}
}
count_preexisting_dogs()
{
dogs = getentarray( "actor_enemy_dog", "classname" );
alive_count = 0;
for ( i = 0; i < dogs.size; i ++ )
{
if ( !isdefined(dogs[i]) )
continue;
if ( !isai(dogs[i]) )
continue;
alive_count++;
}
return alive_count;
}
init_all_preexisting_dogs()
{
array_thread( getentarray( "actor_enemy_dog", "classname" ), ::preexisting_init_dog );
}
preexisting_init_dog()
{
self init_dog();
}
dog_set_model()
{
self setModel(level.friendlyDogModel);
self setEnemyModel(level.enemyDogModel);
}
init_dog()
{
if ( !isai(self) )
return;
self.aiteam = "axis";
self.animTree = "dog.atr";
self.type = "dog";
self.accuracy = 0.2;
self.health = level.dog_health;
self.maxhealth = level.dog_health; // this currently does not hook to code maxhealth
self.aiweapon = "dog_bite_mp";
self.secondaryweapon = "";
self.sidearm = "";
self.grenadeAmmo = 0;
self.goalradius = 128;
self.noDodgeMove = true;
self.ignoreSuppression = true;
self.suppressionThreshold = 1;
self.disableArrivals = false;
self.pathEnemyFightDist = 512;
self.meleeAttackDist = 102;
self dog_set_model();
self thread dogHealthRegen();
self thread selfDefenseChallenge();
}
get_spawn_node( team )
{
if ( !level.teambased )
return dog_pick_node_away_from_enemy(level.dogspawnnodes, team);
return dog_pick_node_near_team(level.dogspawnnodes, team);
}
dog_watch_for_owner_team_change(owner)
{
self endon("death");
owner endon("disconnect");
while(1)
{
owner waittill("joined_team");
if ( owner.pers["team"] != self.aiteam )
{
self clearentityowner();
self notify("clear_owner");
return;
}
}
}
dog_set_owner( owner, team, requiredDeathCount )
{
/#
// no owner so he attacks the person who called him in
if ( level.dog_debug )
return;
#/
if ( !isdefined( owner ) )
return;
// if the owner switches teams while dogs are still spawning
// do not set the owner
if ( level.teambased && isplayer(owner) && owner.pers["team"] != team )
return;
self setentityowner(owner);
self.requiredDeathCount = requiredDeathCount;
self thread dog_watch_for_owner_team_change(owner);
self endon("death");
owner waittill("disconnect");
self clearentityowner();
}
dog_create_spawn_influencer()
{
self maps\mp\gametypes\_spawning::create_dog_influencers();
}
dog_manager_spawn_dog( owner, team, spawn_node, index, requiredDeathCount )
{
dog = level.dog_spawner spawnactor();
dog forceteleport(spawn_node.origin, spawn_node.angles);
dog setgoalnode( spawn_node );
dog.spawnnode = spawn_node;
dog show();
dog init_dog();
dog dog_set_team(team);
dog dog_set_model();
dog dog_create_spawn_influencer();
dog thread dog_set_owner(owner, team, requiredDeathCount );
dog thread dog_usage(index);
dog thread dog_owner_kills();
dog thread dog_clean_up();
dog thread dog_notify_level_on_death();
dog dog_thread_behavior_function();
return dog;
}
get_debug_team( team )
{
/#
if ( level.teambased )
{
otherteam = getotherteam(team);
if ( level.dog_debug )
return otherteam;
}
#/
if ( !level.teambased )
return "free";
return team;
}
dog_manager_spawn_dogs( team, enemyTeam, deathCount )
{
// this can hit if the round ends as the dogs are getting called in
level endon("dogs done");
level endon("dogs leaving");
self endon("disconnect");
if ( level.no_dogs )
return;
team = get_debug_team(team);
requiredDeathCount = deathCount;
level.dog_spawner = getent("dog_spawner","targetname" );
if ( !isdefined( level.dog_spawner ) )
return;
level.dogs = [];
level thread dog_manager_game_ended();
level thread dog_manager_dog_alive_tracker();
level thread dog_manager_dog_time_limit();
level thread dog_usage_monitor();
for ( i = 0; i < level.dog_count_max_at_once; i++ )
{
node = self get_spawn_node( team );
level.dogs[i] = dog_manager_spawn_dog( self, team, node, i, requiredDeathCount );
wait ( randomfloat( level.spawnTimeWaitMin, level.spawnTimeWaitMax ) );
}
level thread dog_manager_spawn_more_dogs_on_death( self, level.dog_count - level.dog_count_max_at_once, team );
}
dog_manager_spawn_more_dogs_on_death( owner, count, team )
{
level endon("dogs done");
level endon("dogs leaving");
while( count > 0 )
{
level waittill("dog died");
// wait a bit before sending in the next dog
wait ( randomfloat( level.spawnTimeWaitMin, level.spawnTimeWaitMax ) );
node = get_spawn_node( team );
level.dogs[level.dogs.size] = dog_manager_spawn_dog( owner, team, node, level.dogs.size );
count -= 1;
}
/#
iprintln("All dogs spawned");
#/
level notify("all dogs spawned");
}
dog_manager_dog_time_limit()
{
level endon("dogs done");
level endon("dogs leaving");
wait( level.dog_time );
/#
dog_debug_print( "time limit hit notify dogs leaving" );
#/
// this will shut this thread down
level notify("dogs leaving");
}
dog_cleanup_wait( wait_for, notify_name )
{
self endon( notify_name );
self waittill( wait_for );
self notify( notify_name, wait_for );
}
dog_cleanup_waiter()
{
self thread dog_cleanup_wait( "all dogs spawned", "start_tracker");
self thread dog_cleanup_wait( "dogs leaving", "start_tracker" );
self waittill( "start_tracker", wait_for );
/#
self dog_debug_print("starting dog_manager_dog_alive_tracker reason " + wait_for );
#/
}
dog_manager_dog_alive_tracker()
{
level dog_cleanup_waiter();
while (1)
{
alive_count = 0;
for ( i = 0; i < level.dogs.size; i ++ )
{
if ( !isdefined(level.dogs[i]) )
continue;
if ( !isalive(level.dogs[i]) )
continue;
alive_count++;
}
if ( alive_count == 0 )
{
wait(1);
dog_manager_delete_dogs();
level notify("dogs done");
return;
}
wait (1);
}
}
dog_manager_delete_dogs()
{
for ( i = 0; i < level.dogs.size; i ++ )
{
if ( !isdefined(level.dogs[i]) )
continue;
level.dogs[i] delete();
}
level.dogs = undefined;
}
dog_manager_game_ended()
{
level waittill("game_ended");
make_all_dogs_leave();
}
make_all_dogs_leave()
{
/#
dog_debug_print( "make_all_dogs_leave notify dogs leaving" );
#/
level notify("dogs leaving");
}
dog_set_team( team )
{
self.aiteam = team;
}
dog_clean_up()
{
self endon("death");
self endon("leaving");
level waittill("dogs leaving");
thread dog_leave();
}
dog_notify_level_on_death()
{
self endon("leaving");
self waittill("death");
// do not access self past this point as its not valid
level notify("dog died");
}
dog_thread_behavior_function()
{
self thread dog_patrol_when_no_enemy();
// self thread dog_attack_when_enemy();
}
dog_leave()
{
self notify("leaving");
self thread dog_leave_failsafe();
// have them run to an exit node
self clearentitytarget();
self.ignoreall = true;
self.goalradius = 30;
self setgoalnode( self dog_get_exit_node() );
self waittill("goal");
self delete();
}
dog_leave_failsafe()
{
self endon("death");
start_origin = self.origin;
wait(2);
if ( distance( start_origin, self.origin ) < 10 )
{
/#
println( "DOG DELETE FAILSAFE: Dog appears to be stuck at " + self.origin );
#/
self delete();
return;
}
wait(20);
/#
println( "DOG DELETE FAILSAFE: Dog has not gotten to it's delete point after 20 seconds. Currently at " + self.origin );
#/
self delete();
}
dog_patrol_when_no_enemy()
{
self endon("death");
self endon("leaving");
while(1)
{
if ( !isdefined(self.enemy) )
{
self dog_debug_print( "no enemy starting patrol" );
self thread dog_patrol();
}
self waittill("enemy");
}
}
dog_patrol_wait( wait_for, notify_name )
{
self endon("attacking");
dog_wait( wait_for, notify_name );
}
dog_wait( wait_for, notify_name )
{
self endon("death");
self endon("leaving");
self endon( notify_name );
self waittill( wait_for );
self notify( notify_name, wait_for );
}
dog_patrol_path_waiter()
{
self thread dog_patrol_wait( "bad_path", "next_patrol_point");
self thread dog_patrol_wait( "goal", "next_patrol_point" );
self waittill( "next_patrol_point", wait_for );
/#
self dog_debug_print("ending patrol wait recieved " + wait_for );
#/
}
dog_patrol()
{
self endon("death");
self endon("enemy");
self endon("leaving");
self endon("attacking");
self notify("on patrol");
self dog_patrol_debug();
while(1)
{
node = level.patrolnodes[randomInt(level.patrolnodes.size)];
// ignore all nodes with a script_noteworthy on them
if ( !isdefined( node.script_noteworthy ) )
{
/#
self dog_debug_print("patroling to node at " + node.origin );
#/
self setgoalnode( node );
self dog_patrol_path_waiter();
}
}
}
dog_wait_print( wait_for )
{
/#
self endon("kill dog_wait_prints");
self waittill( wait_for );
self notify("kill dog_wait_prints");
self dog_debug_print( "PATROL ENDING " + wait_for );
#/
}
dog_patrol_debug()
{
self thread dog_wait_print("death");
self thread dog_wait_print("enemy");
self thread dog_wait_print("leaving");
self thread dog_wait_print("attacking");
}
dog_get_dvar_int( dvar, def )
{
return int( dog_get_dvar( dvar, def ) );
}
// dvar set/fetch/check
dog_get_dvar( dvar, def )
{
if ( getdvar( dvar ) != "" )
return getdvarfloat( dvar );
else
{
setdvar( dvar, def );
return def;
}
}
dog_usage_init()
{
level.dog_usage = [];
for ( index = 0; index < level.dog_count; index++ )
{
level.dog_usage[index] = spawnStruct();
level.dog_usage[index].spawn_time = 0;
level.dog_usage[index].death_time = 0;
level.dog_usage[index].kills = 0;
level.dog_usage[index].died = false;
}
}
dog_usage_monitor()
{
start_time = GetTime();
level waittill("dogs done");
index = 0;
total_kills = 0;
last_alive = 0;
all_dead = true;
alive_count = 0;
never_spawned_count = 0;
total_count = 0;
for ( index = 0; index < level.dog_count; index++ )
{
total_count++;
if ( level.dog_usage[index].spawn_time == 0 )
{
never_spawned_count++;
continue;
}
else if ( !level.dog_usage[index].died )
{
alive_count++;
all_dead = false;
}
seconds = (level.dog_usage[index].death_time - level.dog_usage[index].spawn_time) / 1000;
if ( seconds > last_alive )
{
last_alive = seconds;
}
total_kills += level.dog_usage[index].kills;
}
/#
seconds = (GetTime() - start_time) / 1000;
msg = "Dogs- Time: " + seconds + " Kills: " + total_kills + " Last: " + last_alive;
// make sure that the dogs have printed everything
wait (1);
iprintln( msg );
println( msg );
#/
}
dog_usage(index)
{
level.dog_usage[index].spawn_time = GetTime();
level.dog_usage[index].death_time = 0;
level.dog_usage[index].kills = 0;
level.dog_usage[index].died = false;
self thread dog_usage_kills(index);
self thread dog_usage_time_alive(index);
}
dog_usage_kills(index)
{
self endon("death");
while(1)
{
self waittill("killed", player);
level.dog_usage[index].kills++;
}
}
dog_owner_kills(index)
{
if ( !isdefined( self.script_owner ) )
return;
self endon("clear_owner");
self endon("death");
self.script_owner endon("disconnect");
while(1)
{
self waittill("killed", player);
self.script_owner notify( "dog_handler" );
}
}
dog_usage_time_alive(index)
{
self endon("leaving");
self waittill("death");
level.dog_usage[index].death_time = GetTime();
level.dog_usage[index].died = true;
seconds = (level.dog_usage[index].death_time - level.dog_usage[index].spawn_time) / 1000 ;
/#
iprintln( "Dog#" + index + " killed. Alive for: "+ seconds + " seconds. Kills: " + level.dog_usage[index].kills );
println( "Dog#" + index + " killed. Alive for: "+ seconds + " seconds. Kills: " + level.dog_usage[index].kills );
#/
}
dogHealthRegen()
{
self endon("death");
self endon("end_healthregen");
if ( self.health <= 0 )
{
assert( !isalive( self ) );
return;
}
maxhealth = self.health;
oldhealth = maxhealth;
dog = self;
health_add = 0;
regenRate = 0.1; // 0.017;
veryHurt = false;
lastSoundTime_Recover = 0;
hurtTime = 0;
newHealth = 0;
for (;;)
{
wait (0.05);
if (dog.health == maxhealth)
{
veryHurt = false;
continue;
}
if (dog.health <= 0)
return;
wasVeryHurt = veryHurt;
ratio = dog.health / maxHealth;
if (ratio <= 0.55)
{
veryHurt = true;
if (!wasVeryHurt)
{
hurtTime = gettime();
}
}
if (dog.health >= oldhealth)
{
if (gettime() - hurttime < level.dogHealth_RegularRegenDelay)
continue;
if ( level.dogHealthRegenDisabled )
continue;
if (veryHurt)
{
newHealth = ratio;
if (gettime() > hurtTime + 3000)
newHealth += regenRate;
}
else
newHealth = 1;
if ( newHealth >= 1.0 )
{
newHealth = 1.0;
}
if (newHealth <= 0)
{
// dog is dead
return;
}
dog setnormalhealth (newHealth);
oldhealth = dog.health;
continue;
}
oldhealth = dog.health;
health_add = 0;
hurtTime = gettime();
}
}
selfDefenseChallenge()
{
self waittill ("death", attacker);
if ( isdefined( attacker ) && isPlayer( attacker ) )
{
if (isdefined ( self.script_owner ) && self.script_owner == attacker)
return;
if ( level.teambased && isdefined ( self.script_owner ) && self.script_owner.team == attacker.team )
return;
attacker notify ("selfdefense_dog");
}
}
dog_get_exit_node()
{
return getclosest( self.origin, level.dogexitnodes );
}
dog_debug_print( message )
{
/#
if ( level.dog_debug )
{
if ( isai( self ) )
{
println( " " + gettime() + " DOG " + self getentnum() + ": " + message );
}
else
{
println( " " + gettime() + " DOGS: " + message );
}
}
#/
}
// ================================================
getAllOtherPlayers()
{
aliveplayers = [];
// Make a list of fully connected, non-spectating, alive players
for(i = 0; i < level.players.size; i++)
{
if ( !isdefined( level.players[i] ) )
continue;
player = level.players[i];
if ( player.sessionstate != "playing" || player == self )
continue;
aliveplayers[aliveplayers.size] = player;
}
return aliveplayers;
}
dog_pick_node_near_team( nodes, team )
{
// There are no valid nodes in the map
if(!isdefined(nodes))
return undefined;
if ( !level.teambased )
return dog_pick_node_away_from_enemy(level.dogspawnnodes, team);
//prof_begin("basic_spawnlogic");
initWeights(nodes);
update_all_nodes( nodes, team );
//prof_begin(" getteams");
obj = spawnstruct();
getAllAlliedAndEnemyPlayers(obj, team);
//prof_end(" getteams");
numplayers = obj.allies.size + obj.enemies.size;
alliedDistanceWeight = 2;
dogDistanceWeight = 3;
//prof_begin(" sumdists");
myTeam = team;
enemyTeam = getOtherTeam( myTeam );
for (i = 0; i < nodes.size; i++)
{
node = nodes[i];
node.weight = 0;
if ( node.numPlayersAtLastUpdate > 0 )
{
allyDistSum = node.distSum[ myTeam ];
enemyDistSum = node.distSum[ enemyTeam ];
// high enemy distance is good, high ally distance is bad
node.weight = (enemyDistSum - alliedDistanceWeight*allyDistSum) / node.numPlayersAtLastUpdate;
}
if ( node.numDogsAtLastUpdate > 0 )
{
dogDistSum = node.distSum[ "dogs" ];
// high ally distance is bad
node.weight -= (dogDistSum*dogDistSum) / node.numDogsAtLastUpdate;
}
}
//prof_end(" sumdists");
//prof_end("basic_spawnlogic");
//prof_begin("complex_spawnlogic");
avoidSpawnReuse(nodes);
avoidEnemies(nodes, team, true);
//prof_end("complex_spawnlogic");
result = dog_pick_node_final(nodes, team, obj.enemies);
return result;
}
dog_pick_node_away_from_enemy(nodes, team)
{
// There are no valid nodes in the map
if(!isdefined(nodes))
return undefined;
initWeights(nodes);
update_all_nodes( nodes, team );
aliveplayers = getAllOtherPlayers();
// new logic: we want most players near idealDist units away.
// players closer than badDist units will be considered negatively
idealDist = 1600;
badDist = 1200;
if (aliveplayers.size > 0)
{
for (i = 0; i < nodes.size; i++)
{
totalDistFromIdeal = 0;
nearbyBadAmount = 0;
for (j = 0; j < aliveplayers.size; j++)
{
dist = distance(nodes[i].origin, aliveplayers[j].origin);
if (dist < badDist)
nearbyBadAmount += (badDist - dist) / badDist;
distfromideal = abs(dist - idealDist);
totalDistFromIdeal += distfromideal;
}
avgDistFromIdeal = totalDistFromIdeal / aliveplayers.size;
wellDistancedAmount = (idealDist - avgDistFromIdeal) / idealDist;
// wellDistancedAmount is between -inf and 1, 1 being best (likely around 0 to 1)
// nearbyBadAmount is between 0 and inf,
// and it is very important that we get a bad weight if we have a high nearbyBadAmount.
nodes[i].weight = wellDistancedAmount - nearbyBadAmount * 2 + randomfloat(.2);
}
}
avoidSpawnReuse(nodes);
avoidEnemies(nodes, team, true);
return dog_pick_node_final(nodes, team, aliveplayers);
}
dog_pick_node_random( nodes, team )
{
// There are no valid nodes in the map
if(!isdefined(nodes))
return undefined;
// randomize order
for(i = 0; i < nodes.size; i++)
{
j = randomInt(nodes.size);
node = nodes[i];
nodes[i] = nodes[j];
nodes[j] = node;
}
return dog_pick_node_final(nodes, team, undefined, false);
}
// selects a node, preferring ones with heigher weights (or toward the beginning of the array if no weights).
// also does final things like setting self.lastnode to the one chosen.
// this takes care of avoiding telefragging, so it doesn't have to be considered by any other function.
dog_pick_node_final( nodes, team, enemies, useweights )
{
//prof_begin( "dog_pick_node_final" );
bestnode = undefined;
if ( !isdefined( nodes ) || nodes.size == 0 )
return undefined;
if ( !isdefined( useweights ) )
useweights = true;
if ( useweights )
{
// choose node with best weight
// (if a tie, choose randomly from the best)
bestnode = getBestWeightedNode( nodes, team, enemies );
}
else
{
// (only place we actually get here from is dog_pick_node_random() )
// no weights. prefer nodes toward beginning of array
for ( i = 0; i < nodes.size; i++ )
{
if ( positionWouldTelefrag( nodes[i].origin ) )
continue;
bestnode = nodes[i];
break;
}
}
if ( !isdefined( bestnode ) )
{
// couldn't find a useable node! all will telefrag.
if ( useweights )
{
// at this point, forget about weights. just take a random one.
bestnode = nodes[randomint(nodes.size)];
}
else
{
bestnode = nodes[0];
}
}
self finalizeNodeChoice( bestnode );
//prof_end( "dog_pick_node_final" );
return bestnode;
}
getBestWeightedNode( nodes, team, enemies )
{
maxSightTracedNodes = 3;
for ( try = 0; try <= maxSightTracedNodes; try++ )
{
bestnodes = [];
bestweight = undefined;
bestnode = undefined;
for ( i = 0; i < nodes.size; i++ )
{
if ( !isdefined( bestweight ) || nodes[i].weight > bestweight )
{
if ( positionWouldTelefrag( nodes[i].origin ) )
continue;
bestnodes = [];
bestnodes[0] = nodes[i];
bestweight = nodes[i].weight;
}
else if ( nodes[i].weight == bestweight )
{
if ( positionWouldTelefrag( nodes[i].origin ) )
continue;
bestnodes[bestnodes.size] = nodes[i];
}
}
if ( bestnodes.size == 0 )
return undefined;
// pick randomly from the available nodes with the best weight
bestnode = bestnodes[randomint( bestnodes.size )];
if ( try == maxSightTracedNodes )
return bestnode;
if ( isdefined( bestnode.lastSightTraceTime ) && bestnode.lastSightTraceTime == gettime() )
return bestnode;
if ( !lastMinuteSightTraces( bestnode, team, enemies ) )
return bestnode;
penalty = getLosPenalty();
bestnode.weight -= penalty;
bestnode.lastSightTraceTime = gettime();
}
}
finalizeNodeChoice( node )
{
time = getTime();
self.lastnode = node;
self.lastspawntime = time;
node.lastspawneddog = self;
node.lastspawntime = time;
}
getLosPenalty()
{
return 100000;
}
lastMinuteSightTraces( node, dog_team, enemies )
{
//prof_begin("lastMinuteSightTraces");
team = "all";
if ( level.teambased )
team = getOtherTeam( dog_team );
if ( !isdefined( enemies ) )
return false;
closest = undefined;
closestDistsq = undefined;
secondClosest = undefined;
secondClosestDistsq = undefined;
for ( i = 0; i < enemies.size; i++ )
{
player = node.nearbyPlayers[team][i];
if ( !isdefined( player ) )
continue;
if ( player.sessionstate != "playing" )
continue;
if ( player == self )
continue;
distsq = distanceSquared( node.origin, player.origin );
if ( !isdefined( closest ) || distsq < closestDistsq )
{
secondClosest = closest;
secondClosestDistsq = closestDistsq;
closest = player;
closestDistSq = distsq;
}
else if ( !isdefined( secondClosest ) || distsq < secondClosestDistSq )
{
secondClosest = player;
secondClosestDistSq = distsq;
}
}
if ( isdefined( closest ) )
{
if ( bullettracepassed( closest.origin + (0,0,50), node.origin + (0,0,50), false, undefined) )
return true;
}
if ( isdefined( secondClosest ) )
{
if ( bullettracepassed( secondClosest.origin + (0,0,50), node.origin + (0,0,50), false, undefined) )
return true;
}
return false;
}
update_all_nodes( nodes, team )
{
for ( i = 0; i < nodes.size; i++ )
{
nodeUpdate( nodes[i], team );
}
}
avoidEnemies(nodes, team,teambased)
{
lospenalty = getLosPenalty();
otherteam = "axis";
if ( team == "axis" )
otherteam = "allies";
minDistTeam = otherteam;
if ( !teambased )
{
minDistTeam = "all";
}
avoidWeight = getdvarfloat("scr_spawn_enemyavoidweight");
if ( avoidWeight != 0 )
{
nearbyEnemyOuterRange = getdvarfloat("scr_spawn_enemyavoiddist");
nearbyEnemyOuterRangeSq = nearbyEnemyOuterRange * nearbyEnemyOuterRange;
nearbyEnemyPenalty = 1500 * avoidWeight; // typical base weights tend to peak around 1500 or so. this is large enough to upset that while only locally dominating it.
nearbyEnemyMinorPenalty = 800 * avoidWeight; // additional negative weight for distances up to 2 * nearbyEnemyOuterRange
lastAttackerOrigin = (-99999,-99999,-99999);
lastDeathPos = (-99999,-99999,-99999);
for ( i = 0; i < nodes.size; i++ )
{
// penalty for nearby enemies
mindist = nodes[i].minDist[minDistTeam];
if ( mindist < nearbyEnemyOuterRange*2 )
{
penalty = nearbyEnemyMinorPenalty * (1 - mindist / (nearbyEnemyOuterRange*2));
if ( mindist < nearbyEnemyOuterRange )
penalty += nearbyEnemyPenalty * (1 - mindist / nearbyEnemyOuterRange);
if ( penalty > 0 )
{
nodes[i].weight -= penalty;
}
}
}
}
// DEBUG
//prof_end(" spawn_sc");
}
nodeUpdate( node, team )
{
if ( level.teambased )
{
node.sights["axis"] = 0;
node.sights["allies"] = 0;
node.nearbyPlayers["axis"] = [];
node.nearbyPlayers["allies"] = [];
}
else
{
node.sights = 0;
node.nearbyPlayers["all"] = [];
}
node.nearbyDogs = [];
nodedir = node.forward;
debug = false;
node.distSum["all"] = 0;
node.distSum["allies"] = 0;
node.distSum["axis"] = 0;
node.distSum["dogs"] = 0;
node.minDist["all"] = 9999999;
node.minDist["allies"] = 9999999;
node.minDist["axis"] = 9999999;
node.minDist["dogs"] = 9999999;
node.numPlayersAtLastUpdate = 0;
node.numDogsAtLastUpdate = 0;
for (i = 0; i < level.players.size; i++)
{
player = level.players[i];
if ( player.sessionstate != "playing" )
continue;
diff = player.origin - node.origin;
diff = (diff[0], diff[1], 0);
dist = length( diff ); // needs to be actual distance for distSum value
player_team = "all";
if ( level.teambased )
player_team = player.pers["team"];
if ( dist < 1024 )
{
node.nearbyPlayers[player_team][node.nearbyPlayers[player_team].size] = player;
}
if ( dist < node.minDist[player_team] )
node.minDist[player_team] = dist;
node.distSum[ player_team ] += dist;
node.numPlayersAtLastUpdate++;
}
for (i = 0; i < level.dogs.size; i++)
{
dog = level.dogs[i];
if ( !isdefined(dog) || !isalive(dog) )
continue;
diff = dog.origin - node.origin;
diff = (diff[0], diff[1], 0);
dist = length( diff ); // needs to be actual distance for distSum value
if ( dist < 1024 )
{
node.nearbyDogs[node.nearbyDogs.size] = dog;
}
if ( dist < node.minDist["dogs"] )
node.minDist["dogs"] = dist;
node.distSum[ "dogs" ] += dist;
node.numDogsAtLastUpdate++;
}
}
initWeights(nodes)
{
for (i = 0; i < nodes.size; i++)
nodes[i].weight = 0;
}
getAllAlliedAndEnemyPlayers( obj, team )
{
if ( level.teambased )
{
if ( team == "allies" )
{
obj.allies = level.alivePlayers["allies"];
obj.enemies = level.alivePlayers["axis"];
}
else
{
assert( team == "axis" );
obj.allies = level.alivePlayers["axis"];
obj.enemies = level.alivePlayers["allies"];
}
}
else
{
obj.allies = [];
obj.enemies = level.activePlayers;
}
}
avoidSpawnReuse(nodes)
{
time = getTime();
maxtime = 3*1000;
maxdistSq = 1024 * 1024;
for (i = 0; i < nodes.size; i++)
{
node = nodes[i];
if (!isdefined(node.lastspawntime))
continue;
timepassed = time - node.lastspawntime;
if (timepassed < maxtime)
{
worsen = 1000 * (1 - timepassed/maxtime);
node.weight -= worsen;
}
}
}
flash_dogs( area )
{
self endon("disconnect");
if ( isdefined(level.dogs) )
{
for (i = 0; i < level.dogs.size; i++)
{
dog = level.dogs[i];
if ( !isalive(dog) )
continue;
if ( dog istouching(area) )
{
do_flash = true;
if ( isPlayer( self ) )
{
if ( level.teamBased && (dog.aiteam == self.pers["team"]) )
{
do_flash = false;
}
else if ( !level.teambased && isdefined(dog.script_owner) && self == dog.script_owner )
{
do_flash = false;
}
}
if ( isdefined( dog.lastFlashed ) && dog.lastFlashed + 1500 > gettime() )
{
do_flash = false;
}
if ( do_flash )
{
dog setFlashBanged( true, 500 );
dog.lastFlashed = gettime();
}
}
}
}
2009-07-17 00:00:00 +00:00
}