offline-megas/mods/offline_megas/scripts/zm/_zm_utility.gsc
2024-05-28 16:45:43 -04:00

6182 lines
143 KiB
Plaintext

#using scripts\codescripts\struct;
#using scripts\shared\array_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\flag_shared;
#using scripts\shared\hud_message_shared;
#using scripts\shared\laststand_shared;
#using scripts\shared\util_shared;
#insert scripts\shared\shared.gsh;
#insert scripts\shared\statstable_shared.gsh;
#using scripts\shared\ai\zombie_utility;
#using scripts\zm\_util;
#using scripts\zm\_zm;
#using scripts\zm\_zm_ai_faller;
#using scripts\zm\_zm_audio;
#using scripts\zm\_zm_bgb;
#using scripts\zm\_zm_equipment;
#using scripts\zm\_zm_laststand;
#using scripts\zm\_zm_perks;
#using scripts\zm\_zm_power;
#using scripts\zm\_zm_powerups;
#using scripts\zm\_zm_server_throttle;
#using scripts\zm\_zm_stats;
#using scripts\zm\_zm_spawner;
#using scripts\zm\_zm_weapons;
#insert scripts\zm\_zm_perks.gsh;
#insert scripts\zm\_zm_utility.gsh;
#namespace zm_utility;
function init_utility()
{
// level thread edge_fog_start();
// level thread hudelem_count();
}
function is_Classic()
{
return true;
}
function is_Standard()
{
dvar = GetDvarString( "ui_gametype" );
if ( dvar == "zstandard" )
{
return true;
}
return false;
}
function ConvertSecondsToMilliseconds( seconds )
{
return ( seconds * 1000 );
}
function is_player()
{
return ( IsPlayer( self ) || ( IsDefined( self.pers ) && IS_TRUE( self.pers[ "isBot" ] ) ) );
}
// self is Ai and chunk is selected piece
function lerp( chunk )
{
// anim_reach_aligned
link = Spawn( "script_origin", self GetOrigin() ); // link is a new origin of the ai
link.angles = self.first_node.angles ; // link now has the angles of itself, perhaps these angles aren't coming over..
self LinkTo(link); // link ai + origin to chunk + origin
// link RotateTo(chunk.origin GetTagAngles("Tag_bottom"), level._CONTEXTUAL_GRAB_LERP_TIME); // this should angle him to spot
// link MoveTo(chunk.origin GetTagOrigin("Tag_bottom"), level._CONTEXTUAL_GRAB_LERP_TIME); // this should move him over to spot
// I need to have the offest for the bar
link RotateTo(self.first_node.angles , level._CONTEXTUAL_GRAB_LERP_TIME); // this should angle him to spot
link MoveTo(self.attacking_spot , level._CONTEXTUAL_GRAB_LERP_TIME); // this should move him over to spot
//link RotateTo(self GetTagAngles ("Tag_player"), level._CONTEXTUAL_GRAB_LERP_TIME); // this should angle him to spot
//link MoveTo(self GetTagOrigin ("Tag_player"), level._CONTEXTUAL_GRAB_LERP_TIME); // this should move him over to spot
link util::waittill_multiple("rotatedone", "movedone");
self Unlink();
link Delete();
return;
}
function recalc_zombie_array()
{
/*
enemies = [];
level.current_zombie_array = [];
enemies = GetAiSpeciesArray( level.zombie_team, "all" );
for( i = 0; i < enemies.size; i++ )
{
if ( IS_TRUE( enemies[i].ignore_enemy_count ) )
{
continue;
}
ARRAY_ADD( level.current_zombie_array, enemies[i] );
}
level.current_zombie_count = level.current_zombie_array.size;
*/
}
function init_zombie_run_cycle()
{
if ( isdefined( level.speed_change_round ) )
{
if ( level.round_number >= level.speed_change_round )
{
speed_percent = 0.2 + ( ( level.round_number - level.speed_change_round ) * 0.2 );
speed_percent = min( speed_percent, 1 );
change_round_max = Int( level.speed_change_max * speed_percent );
change_left = change_round_max - level.speed_change_num;
if ( change_left == 0 )
{
self zombie_utility::set_zombie_run_cycle();
return;
}
change_speed = RandomInt( 100 );
if ( change_speed > 80 )
{
self change_zombie_run_cycle();
return;
}
zombie_count = zombie_utility::get_current_zombie_count();
zombie_left = level.zombie_ai_limit - zombie_count;
if ( zombie_left == change_left ) // need to force the speed change at this point
{
self change_zombie_run_cycle();
return;
}
}
}
self zombie_utility::set_zombie_run_cycle();
}
function change_zombie_run_cycle()
{
level.speed_change_num++;
if ( level.gamedifficulty == 0 )
{
self zombie_utility::set_zombie_run_cycle( "sprint" );
}
else
{
/*
iprintln( "walker round " + level.round_number + " change " + level.speed_change_num );
*/
self zombie_utility::set_zombie_run_cycle( "walk" );
}
self thread speed_change_watcher();
}
function make_supersprinter()
{
self zombie_utility::set_zombie_run_cycle( "super_sprint" );
}
function speed_change_watcher()
{
self waittill( "death" );
if ( level.speed_change_num > 0 )
{
level.speed_change_num--;
}
}
function move_zombie_spawn_location(spot)
{
self endon( "death" );
if(IsDefined(self.spawn_pos))
{
self notify("risen", self.spawn_pos.script_string );
return;
}
self.spawn_pos = spot;
// give target from spawn location to spawner to path
if(IsDefined(spot.target))
{
self.target = spot.target;
}
if(IsDefined(spot.zone_name))
{
self.zone_name = spot.zone_name;
self.previous_zone_name = spot.zone_name;
}
if(IsDefined(spot.script_parameters))
{
self.script_parameters = spot.script_parameters;
}
if(!IsDefined(spot.script_noteworthy))
{
spot.script_noteworthy = "spawn_location";
}
tokens = StrTok( spot.script_noteworthy, " " );
foreach ( index, token in tokens )
{
// time bomb needs to spawn zombies away from their original spawn point; this should point to a struct
if ( IsDefined( self.spawn_point_override ) )
{
spot = self.spawn_point_override;
token = spot.script_noteworthy;
}
if ( token == "custom_spawner_entry" )
{
next_token = index + 1;
if ( IsDefined( tokens[ next_token ] ) )
{
str_spawn_entry = tokens[ next_token ];
if ( IsDefined( level.custom_spawner_entry ) && IsDefined( level.custom_spawner_entry[ str_spawn_entry ] ) )
{
self thread [[ level.custom_spawner_entry[ str_spawn_entry ] ]]( spot );
continue;
}
}
}
if(token == "riser_location")
{
self thread zm_spawner::do_zombie_rise(spot);
}
else if (token == "faller_location")
{
self thread zm_ai_faller::do_zombie_fall(spot);
}
else if (token == "spawn_location" )
{
// anchor defined by some other custom spawner behavior, so bypass standard behavior
if ( IsDefined( self.anchor ) )
{
return;
}
self.anchor = spawn("script_origin", self.origin);
self.anchor.angles = self.angles;
self linkto(self.anchor);
self.anchor thread anchor_delete_failsafe( self );
if( !isDefined( spot.angles ) )
{
spot.angles = (0, 0, 0);
}
self Ghost();
self.anchor moveto(spot.origin, .05);
self.anchor waittill("movedone");
// face goal
target_org = zombie_utility::get_desired_origin();
if (IsDefined(target_org))
{
anim_ang = VectorToAngles(target_org - self.origin);
self.anchor RotateTo((0, anim_ang[1], 0), .05);
self.anchor waittill("rotatedone");
}
if(isDefined(level.zombie_spawn_fx))
{
playfx(level.zombie_spawn_fx,spot.origin);
}
self unlink();
if(isDefined(self.anchor))
{
self.anchor delete();
}
if(!IS_TRUE(self.dontShow))
{
self Show();
}
self notify("risen", spot.script_string );
}
}
}
// self is an anchor script_origin
// There is a very small window where a zombie could be killed and the anchor would be left hanging around.
function anchor_delete_failsafe( ai_zombie )
{
ai_zombie endon( "risen" );
ai_zombie waittill( "death" );
if( isdefined( self ) )
{
self Delete();
}
}
function run_spawn_functions()
{
self endon( "death" );
waittillframeend; // spawn functions should override default settings, so they need to be last
for (i = 0; i < level.spawn_funcs[ self.team ].size; i++)
{
func = level.spawn_funcs[ self.team ][ i ];
util::single_thread(self, func[ "function" ], func[ "param1" ], func[ "param2" ], func[ "param3" ], func[ "param4" ], func[ "param5" ] );
}
if ( IsDefined( self.spawn_funcs ))
{
for (i = 0; i < self.spawn_funcs.size; i++)
{
func = self.spawn_funcs[ i ];
util::single_thread(self, func[ "function" ], func[ "param1" ], func[ "param2" ], func[ "param3" ], func[ "param4" ] );
}
/#
self.saved_spawn_functions = self.spawn_funcs;
#/
self.spawn_funcs = undefined;
/#
// keep them around in developer mode, for debugging
self.spawn_funcs = self.saved_spawn_functions;
self.saved_spawn_functions = undefined;
#/
self.spawn_funcs = undefined;
}
}
function create_simple_hud( client, team )
{
if ( IsDefined( team ) )
{
hud = NewTeamHudElem( team );
hud.team = team;
}
else
{
if( IsDefined( client ) )
{
hud = NewClientHudElem( client );
}
else
{
hud = NewHudElem();
}
}
level.hudelem_count++;
hud.foreground = true;
hud.sort = 1;
hud.hidewheninmenu = false;
return hud;
}
function destroy_hud()
{
level.hudelem_count--;
self Destroy();
}
// self = exterior_goal which is barrier_chunks
function all_chunks_intact( barrier, barrier_chunks )
{
if(isdefined(barrier.zbarrier))
{
pieces = barrier.zbarrier GetZBarrierPieceIndicesInState("closed");
if(pieces.size != barrier.zbarrier GetNumZBarrierPieces())
{
return false;
}
}
else
{
for( i = 0; i < barrier_chunks.size; i++ ) // Count up barrier_chunks total size
{
if( barrier_chunks[i] get_chunk_state() != "repaired" ) // if any piece has the state of not repaired then return false
{
return false;
}
}
}
return true; // if the board has been repaired then return true
}
// self = exterior_goal which is barrier_chunks
function no_valid_repairable_boards( barrier, barrier_chunks )
{
if(isdefined(barrier.zbarrier))
{
pieces = barrier.zbarrier GetZBarrierPieceIndicesInState("open");
if(pieces.size)
{
return false;
}
}
else
{
for( i = 0; i < barrier_chunks.size; i++ ) // Count up barrier_chunks total size
{
if( barrier_chunks[i] get_chunk_state() == "destroyed" ) // if any piece has been destroyed return false
{
return false;
}
}
}
return true; // if any piece is not destroyed then return true
}
function is_Survival()
{
return false;
}
function is_Encounter()
{
return false;
}
function all_chunks_destroyed( barrier, barrier_chunks )
{
if(isdefined(barrier.zbarrier))
{
pieces = ArrayCombine(barrier.zbarrier GetZBarrierPieceIndicesInState("open"), barrier.zbarrier GetZBarrierPieceIndicesInState("opening"), true, false);
if(pieces.size != barrier.zbarrier GetNumZBarrierPieces())
{
return false;
}
}
else if( IsDefined( barrier_chunks ) )
{
ASSERT( IsDefined(barrier_chunks), "zombie_utility::all_chunks_destroyed - Barrier chunks undefined" );
for( i = 0; i < barrier_chunks.size; i++ )
{
if( barrier_chunks[i] get_chunk_state() != "destroyed" )
{
return false;
}
}
}
return true;
}
function check_point_in_playable_area( origin )
{
playable_area = getentarray("player_volume","script_noteworthy");
if ( !IsDefined( level.check_model ) )
{
level.check_model = spawn ("script_model", origin + (0,0,40));
}
else
{
level.check_model.origin = origin + ( 0, 0, 40 );
}
valid_point = false;
for (i = 0; i < playable_area.size; i++)
{
if (level.check_model istouching(playable_area[i]))
{
valid_point = true;
}
}
return valid_point;
}
//*****************************************************************************
// origin -
// zone_is_active - (optional) if set the zone must also be active as well
// player_zones - (optional) optimization
//*****************************************************************************
//aka check_point_in_active_zone( origin )
function check_point_in_enabled_zone( origin, zone_is_active, player_zones )
{
if( !IsDefined(player_zones) )
{
player_zones = getentarray("player_volume","script_noteworthy");
}
if( !isDefined( level.zones ) || !isDefined( player_zones ) )
{
return true;
}
if ( !isdefined( level.e_check_point ) )
{
// Just spawn the checker entity once and move it around as needed instead of creating and deleting all the time
level.e_check_point = spawn( "script_origin", origin+(0, 0, 40) );
}
else
{
level.e_check_point.origin = origin+(0,0,40);
}
one_valid_zone = false;
for( i = 0; i < player_zones.size; i++ )
{
if( level.e_check_point IsTouching( player_zones[i] ) )
{
zone = level.zones[player_zones[i].targetname];
if( IsDefined(zone) && IS_TRUE(zone.is_enabled) )
{
if( IsDefined(zone_is_active) && (zone_is_active == true) && !IS_TRUE(zone.is_active) )
{
continue;
}
one_valid_zone = true;
break;
}
}
}
return one_valid_zone;
}
function round_up_to_ten( score )
{
new_score = score - score % 10;
if( new_score < score )
{
new_score += 10;
}
return new_score;
}
function round_up_score( score, value )
{
score = int(score); // Make sure it's an int or modulus will die
new_score = score - score % value;
if( new_score < score )
{
new_score += value;
}
return new_score;
}
function halve_score( n_score )
{
n_score = n_score / 2;
n_score = zm_utility::round_up_score( n_score, 10 );
return n_score;
}
function random_tan()
{
rand = randomint( 100 );
if(isDefined(level.char_percent_override) )
{
percentNotCharred = level.char_percent_override;
}
else
{
percentNotCharred = 65;
}
// if( rand > percentNotCharred )
// {
// self StartTanning();
// }
// PI_CHANGE_END
}
// Returns the amount of places before the decimal, ie 1000 = 4, 100 = 3...
function places_before_decimal( num )
{
abs_num = abs( num );
count = 0;
while( 1 )
{
abs_num *= 0.1; // Really doing num / 10
count += 1;
if( abs_num < 1 )
{
return count;
}
}
}
function create_zombie_point_of_interest( attract_dist, num_attractors, added_poi_value, start_turned_on, initial_attract_func, arrival_attract_func,poi_team )
{
if( !isDefined( added_poi_value ) )
{
self.added_poi_value = 0;
}
else
{
self.added_poi_value = added_poi_value;
}
if( !isDefined( start_turned_on ) )
{
start_turned_on = true;
}
if ( !isdefined( attract_dist ) )
{
attract_dist = 1536; // Covers all available zombies within a given district
}
self.script_noteworthy = "zombie_poi";
self.poi_active = start_turned_on;
if( isDefined( attract_dist ) )
{
self.max_attractor_dist = attract_dist;
self.poi_radius = attract_dist * attract_dist;
}
else // This poi has no maximum attract distance, it will attract all zombies
{
self.poi_radius = undefined;
}
self.num_poi_attracts = num_attractors;
self.attract_to_origin = true;
self.attractor_array = [];
self.initial_attract_func = undefined;
self.arrival_attract_func = undefined;
if(isDefined(poi_team))
{
self._team = poi_team;
}
// any special functions for initial reaction or arrival at the poi are stored here for get_zombie_point_of_intrest
if( IsDefined( initial_attract_func ) )
{
self.initial_attract_func = initial_attract_func;
}
if( IsDefined( arrival_attract_func ) )
{
self.arrival_attract_func = arrival_attract_func;
}
ARRAY_ADD( level.zombie_poi_array, self );
self thread zm_utility::watch_for_poi_death();
}
function watch_for_poi_death()
{
self waittill( "death" );
//Remove from list
if ( IsInArray( level.zombie_poi_array, self ) )
{
ArrayRemoveValue( level.zombie_poi_array, self );
}
}
function debug_draw_new_attractor_positions()
{
self endon( "death" );
while ( 1 )
{
foreach( attract in self.attractor_positions )
{
passed = BulletTracePassed( attract[0] + (0, 0, 24), self.origin + (0, 0, 24), false, self );
if ( passed )
{
/# debugstar( attract[0], 6, (1,1,1) ); #/
}
else
{
/# debugstar( attract[0], 6, (1,0,0) ); #/
}
}
WAIT_SERVER_FRAME;
}
}
function create_zombie_point_of_interest_attractor_positions( num_attract_dists, attract_dist )
{
self endon( "death" );
if( !isdefined( self.num_poi_attracts ) || (isDefined(self.script_noteworthy) && self.script_noteworthy != "zombie_poi" ))
{
return;
}
if( !isdefined( num_attract_dists ) ) // TODO Holdover from previous logic. Should be reevaluated
{
num_attract_dists = 4;
}
// Creates matrix of attraction points and assigns them to grenade
queryResult = PositionQuery_Source_Navigation( self.origin, (attract_dist / 2), self.max_attractor_dist, (attract_dist / 2), (attract_dist / 2), true, (attract_dist / 2) );
if( queryResult.data.size < self.num_poi_attracts )
{
self.num_poi_attracts = queryResult.data.size;
}
for ( i = 0; i < self.num_poi_attracts; i++ )
{
if ( IS_TRUE( level.validate_poi_attractors ) )
{
passed = BulletTracePassed( queryResult.data[i].origin + (0, 0, 24), self.origin + (0, 0, 24), false, self );
if ( passed )
{
self.attractor_positions[i][0] = queryResult.data[i].origin;
self.attractor_positions[i][1] = self;
}
}
else
{
self.attractor_positions[i][0] = queryResult.data[i].origin;
self.attractor_positions[i][1] = self;
}
}
if( !IsDefined( self.attractor_positions ) )
{
self.attractor_positions = [];
}
self.num_attract_dists = num_attract_dists;
// The last index in the attractor_position arrays for each of the possible distances. The array is a holdover from previous logic.
self.last_index = [];
for( i = 0; i < num_attract_dists; i++ )
{
self.last_index[i] = -1;
}
// Represents origin point TODO Holdover from previous logic. Should be reevaluated
self.last_index[0] = 1;
// Represents total number of attraction points TODO Holdover from previous logic. Should be reevaluated
self.last_index[1] = self.attractor_positions.size;
self.attract_to_origin = false;
self notify( "attractor_positions_generated" );
level notify( "attractor_positions_generated" );
// self thread debug_draw_new_attractor_positions();
}
function generated_radius_attract_positions( forward, offset, num_positions, attract_radius )
{
self endon( "death" );
epsilon = 1;
failed = 0;
degs_per_pos = 360 / num_positions;
for( i = offset; i < 360+offset; i += degs_per_pos )
{
altforward = forward * attract_radius;
rotated_forward = ( (cos(i)*altforward[0] - sin(i)*altforward[1]), (sin(i)*altforward[0] + cos(i)*altforward[1]), altforward[2] );
if(isDefined(level.poi_positioning_func))
{
pos = [[level.poi_positioning_func]](self.origin, rotated_forward);
}
else if(IS_TRUE(level.use_alternate_poi_positioning))
{
pos = zm_server_throttle::server_safe_ground_trace( "poi_trace", 10, self.origin + rotated_forward + ( 0, 0, 10 ) ); //only trace from 10 units above instead of 100 units
}
else
{
pos = zm_server_throttle::server_safe_ground_trace( "poi_trace", 10, self.origin + rotated_forward + ( 0, 0, 100 ) );
}
if(!isDefined(pos))
{
failed++;
continue;
}
if(IS_TRUE(level.use_alternate_poi_positioning)) // Attractors are defined and sent to the array here
{
if ( isDefined( self ) && isDefined( self.origin ) )
{
if( self.origin[2] >= (pos[2]-epsilon) && self.origin[2] - pos[2] <= 150 )
{
pos_array = [];
pos_array[0] = pos;
pos_array[1] = self;
ARRAY_ADD( self.attractor_positions , pos_array );
}
}
else
{
failed++;
}
}
else if(abs( pos[2] - self.origin[2] ) < 60 )
{
pos_array = [];
pos_array[0] = pos;
pos_array[1] = self;
ARRAY_ADD( self.attractor_positions , pos_array );
}
else
{
failed++;
}
}
return failed;
}
function debug_draw_attractor_positions()
{
/#
while( true )
{
while( !isDefined( self.attractor_positions ) )
{
WAIT_SERVER_FRAME;
continue;
}
for( i = 0; i < self.attractor_positions.size; i++ )
{
Line( self.origin, self.attractor_positions[i][0], (1, 0, 0), true, 1 );
}
WAIT_SERVER_FRAME;
if( !IsDefined( self ) )
{
return;
}
}
#/
}
function debug_draw_claimed_attractor_positions()
{
/#
while( true )
{
while( !isDefined( self.claimed_attractor_positions ) )
{
WAIT_SERVER_FRAME;
continue;
}
for( i = 0; i < self.claimed_attractor_positions.size; i++ )
{
Line( self.origin, self.claimed_attractor_positions[i][0], (0, 1, 0), true, 1 );
}
WAIT_SERVER_FRAME;
if( !IsDefined( self ) )
{
return;
}
}
#/
}
function get_zombie_point_of_interest( origin, poi_array )
{
AIProfile_BeginEntry( "get_zombie_point_of_interest" );
if ( IS_TRUE( self.ignore_all_poi ) )
{
AIProfile_EndEntry();
return undefined;
}
curr_radius = undefined;
if ( isdefined( poi_array ) )
{
ent_array = poi_array;
}
else
{
ent_array = level.zombie_poi_array;//getEntArray( "zombie_poi", "script_noteworthy" );
}
best_poi = undefined;
position = undefined;
best_dist = 10000 * 10000;
for( i = 0; i < ent_array.size; i++ )
{
if( !isDefined( ent_array[i] ) || !isDefined( ent_array[i].poi_active ) || !ent_array[i].poi_active )
{
continue;
}
if ( isDefined( self.ignore_poi_targetname ) && self.ignore_poi_targetname.size > 0 )
{
if ( isDefined( ent_array[i].targetname ) )
{
ignore = false;
for ( j = 0; j < self.ignore_poi_targetname.size; j++ )
{
if ( ent_array[i].targetname == self.ignore_poi_targetname[j] )
{
ignore = true;
break;
}
}
if ( ignore )
{
continue;
}
}
}
if ( isDefined( self.ignore_poi ) && self.ignore_poi.size > 0 )
{
ignore = false;
for ( j = 0; j < self.ignore_poi.size; j++ )
{
if ( self.ignore_poi[j] == ent_array[i] )
{
ignore = true;
break;
}
}
if ( ignore )
{
continue;
}
}
dist = distanceSquared( origin, ent_array[i].origin );
dist -= ent_array[i].added_poi_value;
if( isDefined( ent_array[i].poi_radius ) )
{
curr_radius = ent_array[i].poi_radius;
}
if( (!isDefined( curr_radius ) || dist < curr_radius) && dist < best_dist && ent_array[i] can_attract(self) )
{
best_poi = ent_array[i];
best_dist = dist;
}
}
if( isDefined( best_poi ) )
{
if(isDefined(best_poi._team))
{
if(isDefined(self._race_team) && self._race_team != best_poi._team)
{
AIProfile_EndEntry();
return undefined;
}
}
if( IS_TRUE( best_poi._new_ground_trace ) ) // needed for the bhb so it won't trace through metal clip
{
position = [];
position[0] = groundpos_ignore_water_new( best_poi.origin + (0, 0, 100) );
position[1] = self;
}
else if( isDefined( best_poi.attract_to_origin ) && best_poi.attract_to_origin ) // Override, currently only used for monkeys in the air.
{
position = [];
position[0] = groundpos( best_poi.origin + (0, 0, 100) );
position[1] = self;
}
else
{
position = self add_poi_attractor( best_poi );
}
if( IsDefined( best_poi.initial_attract_func ) )
{
self thread [[ best_poi.initial_attract_func ]]( best_poi );
}
if( IsDefined( best_poi.arrival_attract_func ) )
{
self thread [[ best_poi.arrival_attract_func ]]( best_poi );
}
}
AIProfile_EndEntry();
return position;
}
function activate_zombie_point_of_interest()
{
if( self.script_noteworthy != "zombie_poi" )
{
return;
}
self.poi_active = true;
}
function deactivate_zombie_point_of_interest( dont_remove )
{
if( self.script_noteworthy != "zombie_poi" )
{
return;
}
self.attractor_array = array::remove_undefined( self.attractor_array );
for( i = 0; i < self.attractor_array.size; i++ )
{
self.attractor_array[i] notify( "kill_poi" );
}
self.attractor_array = [];
self.claimed_attractor_positions = [];
self.poi_active = false;
if ( IS_TRUE( dont_remove ) )
{
return;
}
//Remove from list
if ( isdefined( self ) )
{
if ( IsInArray( level.zombie_poi_array, self ) )
{
ArrayRemoveValue( level.zombie_poi_array, self );
}
}
}
//PI_CHANGE_BEGIN - 6/18/09 JV This works to help set "wait" points near the stage if all players are in the process teleportation.
//It is unlike the previous function in that you dictate the poi.
function assign_zombie_point_of_interest (origin, poi)
{
position = undefined;
doremovalthread = false;
if (IsDefined(poi) && poi can_attract(self))
{
//don't want to touch add poi attractor, but yeah, this is kind of weird
if (!IsDefined(poi.attractor_array) || ( IsDefined(poi.attractor_array) && !IsInArray( poi.attractor_array, self ) ))
doremovalthread = true;
position = self add_poi_attractor( poi );
//now that I know this is the first time they've been added, set up the thread to remove them from the array
if (IsDefined(position) && doremovalthread && IsInArray( poi.attractor_array, self ))
self thread update_on_poi_removal( poi );
}
return position;
}
//PI_CHANGE_END
function remove_poi_attractor( zombie_poi )
{
if( !isDefined( zombie_poi ) || !isDefined( zombie_poi.attractor_array ) )
{
return;
}
for( i = 0; i < zombie_poi.attractor_array.size; i++ )
{
if( zombie_poi.attractor_array[i] == self )
{
ArrayRemoveValue( zombie_poi.attractor_array, zombie_poi.attractor_array[i] );
ArrayRemoveValue( zombie_poi.claimed_attractor_positions, zombie_poi.claimed_attractor_positions[i] );
if ( isdefined( self ) )
{
self notify( "kill_poi" );
}
}
}
}
function array_check_for_dupes_using_compare( array, single, is_equal_fn )
{
for( i = 0; i < array.size; i++ )
{
if( [[is_equal_fn]]( array[i], single ) )
{
return false;
}
}
return true;
}
function poi_locations_equal( loc1, loc2 )
{
return loc1[0]==loc2[0];
}
function add_poi_attractor( zombie_poi )
{
if( !isDefined( zombie_poi ) )
{
return;
}
if( !isDefined( zombie_poi.attractor_array ) )
{
zombie_poi.attractor_array = [];
}
// If we are not yet an attractor to this poi, claim an attractor position and start attracting to it
if( !IsInArray( zombie_poi.attractor_array, self ) )
{
if( !isDefined( zombie_poi.claimed_attractor_positions ) )
{
zombie_poi.claimed_attractor_positions = [];
}
if( !isDefined( zombie_poi.attractor_positions ) || zombie_poi.attractor_positions.size <= 0 )
{
return undefined;
}
start = -1;
end = -1;
last_index = -1;
for( i = 0; i < 4; i++ )
{
if( zombie_poi.claimed_attractor_positions.size < zombie_poi.last_index[i] )
{
start = last_index+1;
end = zombie_poi.last_index[i];
break;
}
last_index = zombie_poi.last_index[i];
}
best_dist = 10000*10000;
best_pos = undefined;
if( start < 0 )
{
start = 0;
}
if( end < 0 )
{
return undefined;
}
for( i = int(start); i <= int(end); i++ )
{
if(!isDefined(zombie_poi.attractor_positions[i]))
{
continue;
}
//if( !IsInArray( zombie_poi.claimed_attractor_positions, zombie_poi.attractor_positions[i] ) )
if( array_check_for_dupes_using_compare( zombie_poi.claimed_attractor_positions, zombie_poi.attractor_positions[i], &poi_locations_equal ) )
{
if ( isDefined( zombie_poi.attractor_positions[i][0] ) && isDefined( self.origin ) )
{
dist = distancesquared( zombie_poi.attractor_positions[i][0], zombie_poi.origin );
if( dist < best_dist || !isDefined( best_pos ) )
{
best_dist = dist;
best_pos = zombie_poi.attractor_positions[i];
}
}
}
}
if( !isDefined( best_pos ) )
{
if ( IS_TRUE( level.validate_poi_attractors ) )
{
valid_pos = [];
valid_pos[0] = zombie_poi.origin;
valid_pos[1] = zombie_poi;
return valid_pos;
}
return undefined;
}
ARRAY_ADD( zombie_poi.attractor_array, self );
self thread update_poi_on_death( zombie_poi );
ARRAY_ADD( zombie_poi.claimed_attractor_positions, best_pos );
return best_pos;
}
else
{
for( i = 0; i < zombie_poi.attractor_array.size; i++ )
{
if( zombie_poi.attractor_array[i] == self )
{
if( isDefined( zombie_poi.claimed_attractor_positions ) && isDefined( zombie_poi.claimed_attractor_positions[i] ) )
{
return zombie_poi.claimed_attractor_positions[i];
}
}
}
}
return undefined;
}
function can_attract( attractor )
{
if( !isDefined( self.attractor_array ) )
{
self.attractor_array = [];
}
//Raven Begin - Allow only selected zombies to be attracted
if( isDefined(self.attracted_array) && !IsInArray(self.attracted_array, attractor) )
{
return false;
}
//Raven End
if( IsInArray( self.attractor_array, attractor ) )
{
return true;
}
if( isDefined(self.num_poi_attracts) && self.attractor_array.size >= self.num_poi_attracts )
{
return false;
}
return true;
}
function update_poi_on_death( zombie_poi )
{
self endon( "kill_poi" );
self waittill( "death" );
self remove_poi_attractor( zombie_poi );
}
//PI_CHANGE_BEGIN - 6/18/09 JV This was set up to work with assign_zombie_point_of_interest (which works with the teleportation in theater).
//The poi attractor array needs to be emptied when a player is teleported out of projection room (if they were all in there).
//As a result, we wait for the poi's death (I'm sending that notify via the level script)
function update_on_poi_removal (zombie_poi )
{
zombie_poi waittill( "death" );
if( !isDefined( zombie_poi.attractor_array ) )
return;
for( i = 0; i < zombie_poi.attractor_array.size; i++ )
{
if( zombie_poi.attractor_array[i] == self )
{
ArrayRemoveIndex( zombie_poi.attractor_array, i );
ArrayRemoveIndex( zombie_poi.claimed_attractor_positions, i );
}
}
}
//PI_CHANGE_END
function invalidate_attractor_pos( attractor_pos, zombie )
{
if( !isDefined( self ) || !isDefined( attractor_pos ) )
{
wait( 0.1 );
return undefined;
}
if( isDefined( self.attractor_positions) && !array_check_for_dupes_using_compare( self.attractor_positions, attractor_pos, &poi_locations_equal ) )
{
index = 0;
for( i = 0; i < self.attractor_positions.size; i++ )
{
if( poi_locations_equal( self.attractor_positions[i], attractor_pos) )
{
index = i;
}
}
for( i = 0; i < self.last_index.size; i++ )
{
if( index <= self.last_index[i] )
{
self.last_index[i]--;
}
}
ArrayRemoveValue( self.attractor_array, zombie );
ArrayRemoveValue( self.attractor_positions, attractor_pos );
for( i = 0; i < self.claimed_attractor_positions.size; i++ )
{
if( self.claimed_attractor_positions[i][0] == attractor_pos[0] )
{
ArrayRemoveValue( self.claimed_attractor_positions, self.claimed_attractor_positions[i] );
}
}
}
else
{
wait( 0.1 );
}
return get_zombie_point_of_interest( zombie.origin );
}
function remove_poi_from_ignore_list( poi )
{
if ( isDefined( self.ignore_poi ) && self.ignore_poi.size > 0 )
{
for ( i = 0; i < self.ignore_poi.size; i++ )
{
if ( self.ignore_poi[i] == poi )
{
ArrayRemoveValue( self.ignore_poi, self.ignore_poi[i] );
return;
}
}
}
}
function add_poi_to_ignore_list( poi )
{
if ( !isDefined( self.ignore_poi ) )
{
self.ignore_poi = [];
}
add_poi = true;
if ( self.ignore_poi.size > 0 )
{
for ( i = 0; i < self.ignore_poi.size; i++ )
{
if ( self.ignore_poi[i] == poi )
{
add_poi = false;
break;
}
}
}
if ( add_poi )
{
self.ignore_poi[self.ignore_poi.size] = poi;
}
}
//-------------------------------------------------------------------------------
// player should be within a couple feet of enemy
//-------------------------------------------------------------------------------
function default_validate_enemy_path_length( player )
{
max_dist = 1296;
d = DistanceSquared( self.origin, player.origin );
if ( d <= max_dist )
{
return true;
}
return false;
}
function get_closest_valid_player( origin, ignore_player )
{
AIProfile_BeginEntry( "get_closest_valid_player" );
valid_player_found = false;
players = GetPlayers();
if( isdefined( level.get_closest_valid_player_override ) )
{
players = [[ level.get_closest_valid_player_override ]]();
}
b_designated_target_exists = false;
for(i = 0; i < players.size; i++ )
{
player = players[i];
//if( !is_player_valid( players[i], true ) )
if( !player.am_i_valid )
{
continue;
}
if( isDefined( level.evaluate_zone_path_override ) )
{
if( ![[ level.evaluate_zone_path_override ]]( player ) )
{
array::add( ignore_player, player );
}
}
// is any player a designated target?
if( IS_TRUE( player.b_is_designated_target ) )
{
b_designated_target_exists = true;
}
}
if( IsDefined( ignore_player ) )
{
for(i = 0; i < ignore_player.size; i++ )
{
ArrayRemoveValue( players, ignore_player[i] );
}
}
// pre-cull any players that are in last stand or not designated target when a designated target is present
done = false;
while ( players.size && !done )
{
done = true;
for(i = 0; i < players.size; i++ )
{
player = players[i];
//if( !is_player_valid( player, true ) )
if( !player.am_i_valid )
{
ArrayRemoveValue( players, player );
done = false;
break;
}
if( b_designated_target_exists && !IS_TRUE( player.b_is_designated_target ) )
{
ArrayRemoveValue( players, player );
done = false;
break;
}
}
}
if( players.size == 0 )
{
AIProfile_EndEntry();
return undefined;
}
while( !valid_player_found )
{
// find the closest player
if( IsDefined( self.closest_player_override ) )
{
player = [[ self.closest_player_override ]]( origin, players );
}
else if( isdefined( level.closest_player_override ) )
{
player = [[ level.closest_player_override ]]( origin, players );
}
else
{
player = ArrayGetClosest( origin, players );
}
if( !isdefined( player ) || players.size == 0 )
{
AIProfile_EndEntry();
return undefined;
}
if( IS_TRUE(level.allow_zombie_to_target_ai) || IS_TRUE(player.allow_zombie_to_target_ai) )
{
AIProfile_EndEntry();
return player;
}
// make sure they're not a zombie or in last stand
//if( !is_player_valid( player, true ) )
if( !player.am_i_valid )
{
// unlikely to get here unless there is a wait in one of the closest player overrides
ArrayRemoveValue( players, player );
if( players.size == 0 )
{
AIProfile_EndEntry();
return undefined;
}
continue;
}
AIProfile_EndEntry();
return player;
}
}
//modified version of get_closest_valid_player that gives perfect info and sets up ignoreEnts to respect the ignore_player array.
function update_valid_players( origin, ignore_player )
{
AIProfile_BeginEntry( "update_valid_players" );
valid_player_found = false;
players = ArrayCopy( level.players ); // Have to use ArrayCopy otherwise the ArrayRemove calls below will remove the players from level.players
//new zombie enemy selection
foreach( player in players )
{
self SetIgnoreEnt( player, true );
}
b_designated_target_exists = false;
for(i = 0; i < players.size; i++ )
{
player = players[i];
//if( !is_player_valid( players[i], true ) )
if( !player.am_i_valid )
{
continue;
}
if( isDefined( level.evaluate_zone_path_override ) )
{
if( ![[ level.evaluate_zone_path_override ]]( player ) )
{
array::add( ignore_player, player );
}
}
// is any player a designated target?
if( IS_TRUE( player.b_is_designated_target ) )
{
b_designated_target_exists = true;
}
}
if( IsDefined( ignore_player ) )
{
for(i = 0; i < ignore_player.size; i++ )
{
ArrayRemoveValue( players, ignore_player[i] );
}
}
// pre-cull any players that are in last stand or not designated target when a designated target is present
done = false;
while ( players.size && !done )
{
done = true;
for(i = 0; i < players.size; i++ )
{
player = players[i];
//if( !is_player_valid( player, true ) )
if( !player.am_i_valid )
{
ArrayRemoveValue( players, player );
done = false;
break;
}
if( b_designated_target_exists && !IS_TRUE( player.b_is_designated_target ) )
{
ArrayRemoveValue( players, player );
done = false;
break;
}
}
}
//new zombie enemy selection
foreach( player in players )
{
self SetIgnoreEnt( player, false );
self GetPerfectInfo( player );
}
AIProfile_EndEntry();
}
function is_player_valid( player, checkIgnoreMeFlag,ignore_laststand_players )
{
if( !IsDefined( player ) )
{
return false;
}
if( !IsAlive( player ) )
{
return false;
}
if( !IsPlayer( player ) )
{
return false;
}
if( IsDefined(player.is_zombie) && player.is_zombie == true )
{
return false;
}
if( player.sessionstate == "spectator" )
{
return false;
}
if( player.sessionstate == "intermission" )
{
return false;
}
if( IS_TRUE( level.intermission ) )
{
return false;
}
if( !IS_TRUE( ignore_laststand_players ) )
{
if( player laststand::player_is_in_laststand() )
{
return false;
}
}
//T6.5todo if ( player isnotarget() )
//T6.5todo {
//T6.5todo return false;
//T6.5todo }
//We only want to check this from the zombie attack script
if( IS_TRUE(checkIgnoreMeFlag) && player.ignoreme )
{
//IPrintLnBold(" ignore me ");
return false;
}
//for additional level specific checks
if( IsDefined( level.is_player_valid_override ) )
{
return [[ level.is_player_valid_override ]]( player );
}
return true;
}
function get_number_of_valid_players()
{
players = GetPlayers();
num_player_valid = 0;
for( i = 0 ; i < players.size; i++ )
{
if( is_player_valid( players[i] ) )
num_player_valid += 1;
}
return num_player_valid;
}
function in_revive_trigger()
{
if (isdefined(self.rt_time) && self.rt_time + 100 >= GetTime())
return self.in_rt_cached;
self.rt_time = GetTime();
players = level.players; //GetPlayers();
for( i = 0; i < players.size; i++ )
{
current_player = players[i];
//if( !IsDefined( current_player )) || !IsAlive( current_player ) )
//{
// continue;
//}
if( IsDefined( current_player ) && IsDefined( current_player.revivetrigger ) && IsAlive( current_player ) )
{
if( self IsTouching( current_player.revivetrigger ) )
{
self.in_rt_cached = true;
return true;
}
}
}
self.in_rt_cached = false;
return false;
}
function get_closest_node( org, nodes )
{
return ArrayGetClosest( org, nodes );
}
// bars are not damaged pull them off now.
function non_destroyed_bar_board_order( origin, chunks )
{
//bars = getentarray("bar","script_parameters");
first_bars = []; // first set of 2 bars to be removed
first_bars1 = []; // Added single check when combined with wood
first_bars2 = []; // Added single check when combined with wood
//-------------------------BOARDS----------------------------------------------------------
// If all boards do the old system
for( i=0;i<chunks.size;i++ ) // Go through the array
{
if (IsDefined ( chunks[i].script_team ) && ( chunks[i].script_team == "classic_boards" ) )
{
if (IsDefined (chunks[i].script_parameters) && (chunks[i].script_parameters == "board") )
{
return get_closest_2d( origin, chunks );
}
// I need to add a script name team regular boards
else if (IsDefined ( chunks[i].script_team ) && chunks[i].script_team == "bar_board_variant1" || chunks[i].script_team == "bar_board_variant2" ||
chunks[i].script_team == "bar_board_variant4" || chunks[i].script_team == "bar_board_variant5" )
{
return undefined;
}
}
// DCS: adding new variable to start with like new condition repaired with boards.
else if(IsDefined(chunks[i].script_team ) && chunks[i].script_team == "new_barricade")
{
if(IsDefined(chunks[i].script_parameters) && (chunks[i].script_parameters == "repair_board" || chunks[i].script_parameters == "barricade_vents"))
{
return get_closest_2d( origin, chunks );
}
}
}
//-------------------------BOARDS----------------------------------------------------------
//-------------------------BARS------------------------------------------------------------
for(i=0;i<chunks.size;i++) // Go through the array
{
if ( IsDefined (chunks[i].script_team ) && ( chunks[i].script_team == "6_bars_bent" ) || ( chunks[i].script_team == "6_bars_prestine" ) )
{
if (IsDefined (chunks[i].script_parameters) && (chunks[i].script_parameters == "bar") )
{
if(isDefined(chunks[i].script_noteworthy))
{
if(chunks[i].script_noteworthy == "4" || chunks[i].script_noteworthy == "6" ) // this two are defined create a new array that just keeps track of them
{
first_bars[first_bars.size] = chunks[i]; // In total this should be a size of two
}
}
}
}
}
for(i=0;i<first_bars.size;i++) // Jl added second check if there is only peace
{
if ( IsDefined (chunks[i].script_team ) && ( chunks[i].script_team == "6_bars_bent" ) || ( chunks[i].script_team == "6_bars_prestine" ) )
{
if (IsDefined (chunks[i].script_parameters) && (chunks[i].script_parameters == "bar") )
{
//send back the first bars that are NOT destroyed
if( !first_bars[i].destroyed )
{
return first_bars[i];
}
}
}
}
// Grab the remaining bars that are the closest to the ai
for(i=0;i<chunks.size;i++)
{
if ( IsDefined (chunks[i].script_team ) && ( chunks[i].script_team == "6_bars_bent" ) || ( chunks[i].script_team == "6_bars_prestine" ) )
{
if (IsDefined (chunks[i].script_parameters) && (chunks[i].script_parameters == "bar") )
{
if( !chunks[i].destroyed )
{
return get_closest_2d( origin, chunks );
//return chunks[i];
}
}
}
}
//-------------------------BARS------------------------------------------------------------
}
function non_destroyed_grate_order( origin, chunks_grate )
{
//-------------------------GRATES----------------------------------------------------------
grate_order = [];
grate_order1 =[]; // this sets up the order for the grates
grate_order2 =[]; // this sets up the order for the grates
grate_order3 =[]; // this sets up the order for the grates
grate_order4 =[]; // this sets up the order for the grates
grate_order5 =[]; // this sets up the order for the grates
grate_order6 =[]; // this sets up the order for the grates
if ( IsDefined ( chunks_grate ) )
{
for(i=0;i<chunks_grate.size;i++) // Go through the array
{
if (IsDefined (chunks_grate[i].script_parameters) && (chunks_grate[i].script_parameters == "grate") )
{
//return grate_order[i];
if ( IsDefined ( chunks_grate[i].script_noteworthy ) && ( chunks_grate[i].script_noteworthy == "1" ) )
{
grate_order1[grate_order1.size] = chunks_grate[i];
// send back order here
}
if ( IsDefined ( chunks_grate[i].script_noteworthy ) && ( chunks_grate[i].script_noteworthy == "2" ) )
{
grate_order2[grate_order2.size] = chunks_grate[i];
// send back order here
}
if ( IsDefined ( chunks_grate[i].script_noteworthy ) && ( chunks_grate[i].script_noteworthy == "3" ) )
{
grate_order3[grate_order3.size] = chunks_grate[i];
// send back order here
}
if ( IsDefined ( chunks_grate[i].script_noteworthy ) && ( chunks_grate[i].script_noteworthy == "4" ) )
{
grate_order4[grate_order4.size] = chunks_grate[i];
// send back order here
}
if ( IsDefined ( chunks_grate[i].script_noteworthy ) && ( chunks_grate[i].script_noteworthy == "5" ) )
{
grate_order5[grate_order5.size] = chunks_grate[i];
// send back order here
}
if ( IsDefined ( chunks_grate[i].script_noteworthy ) && ( chunks_grate[i].script_noteworthy == "6" ) )
{
grate_order6[grate_order6.size] = chunks_grate[i];
// send back order here
}
}
}
// I need to make this function also tell which piece to move again.
for(i=0;i<chunks_grate.size;i++) // Go through the array
{
if (IsDefined ( chunks_grate[i].script_parameters ) && ( chunks_grate[i].script_parameters == "grate") )
{
if ( IsDefined ( grate_order1[i] ) )
{
if( ( grate_order1[i].state == "repaired" ) )
{
grate_order2[i] thread show_grate_pull();
return grate_order1[i];
}
if( ( grate_order2[i].state == "repaired" ) )
{
/#
IPrintLnBold(" pull bar2 ");
#/
grate_order3[i] thread show_grate_pull();
return grate_order2[i];
}
else if( ( grate_order3[i].state == "repaired" ) )
{
/#
IPrintLnBold(" pull bar3 ");
#/
grate_order4[i] thread show_grate_pull();
return grate_order3[i];
}
else if( ( grate_order4[i].state == "repaired" ) )
{
/#
IPrintLnBold(" pull bar4 ");
#/
grate_order5[i] thread show_grate_pull();
return grate_order4[i];
}
else if( ( grate_order5[i].state == "repaired" ) )
{
/#
IPrintLnBold(" pull bar5 ");
#/
grate_order6[i] thread show_grate_pull();
return grate_order5[i];
}
else if( ( grate_order6[i].state == "repaired" ) )
{
// I need to return nothing here.
//return undefined();
return grate_order6[i];
}
}
}
}
}
//-------------------------GRATES----------------------------------------------------------
}
//////////////////////////////////////////////////////////////////////////////////////////////
//
// A seperate function is needed for each variant because there are different pull down and repair orders for each
// Also I had to add extra strings to idetify combined pieces that used the same script_noteworthy
//
//////////////////////////////////////////////////////////////////////////////////////////////
// variant1
function non_destroyed_variant1_order( origin, chunks_variant1 )
{
//-------------------------VARIANT1----------------------------------------------------------
variant1_order = [];
variant1_order1 =[]; // this sets up the order for the grates
variant1_order2 =[]; // this sets up the order for the grates
variant1_order3 =[]; // this sets up the order for the grates
variant1_order4 =[]; // this sets up the order for the grates
variant1_order5 =[]; // this sets up the order for the grates
variant1_order6 =[]; // this sets up the order for the grates
if ( IsDefined ( chunks_variant1 ) )
{
for(i=0;i<chunks_variant1.size;i++) // Go through the array
{
if (IsDefined (chunks_variant1[i].script_team) && (chunks_variant1[i].script_team == "bar_board_variant1") )
{
//return grate_order[i];
if ( IsDefined ( chunks_variant1[i].script_noteworthy ) )
{
if ( chunks_variant1[i].script_noteworthy == "1" )
{
variant1_order1[variant1_order1.size] = chunks_variant1[i];
}
if ( chunks_variant1[i].script_noteworthy == "2" )
{
variant1_order2[variant1_order2.size] = chunks_variant1[i];
}
if ( chunks_variant1[i].script_noteworthy == "3" )
{
variant1_order3[variant1_order3.size] = chunks_variant1[i];
}
if ( chunks_variant1[i].script_noteworthy == "4" )
{
variant1_order4[variant1_order4.size] = chunks_variant1[i];
}
if ( chunks_variant1[i].script_noteworthy == "5" )
{
variant1_order5[variant1_order5.size] = chunks_variant1[i];
}
if ( chunks_variant1[i].script_noteworthy == "6" )
{
variant1_order6[variant1_order6.size] = chunks_variant1[i];
}
}
}
}
// This needs a different order
for(i=0;i<chunks_variant1.size;i++) // Go through the array
{
if (IsDefined ( chunks_variant1[i].script_team ) && ( chunks_variant1[i].script_team == "bar_board_variant1") )
{
if( IsDefined ( variant1_order2[i] ) )
{
if( ( variant1_order2[i].state == "repaired" ) )
{
return variant1_order2[i];
}
else if( ( variant1_order3[i].state == "repaired" ) )
{
return variant1_order3[i];
}
else if( ( variant1_order4[i].state == "repaired" ) )
{
return variant1_order4[i];
}
else if( ( variant1_order6[i].state == "repaired" ) )
{
return variant1_order6[i];
}
else if( ( variant1_order5[i].state == "repaired" ) )
{
return variant1_order5[i];
}
else if( ( variant1_order1[i].state == "repaired" ) )
{
return variant1_order1[i];
}
}
}
}
}
//if( chunks_variant1.size == 0 )
//{
// return undefined; // If there are no more pieces left then don't allow it to continue
//}
//-------------------------VARIANT1----------------------------------------------------------
}
// variant2
function non_destroyed_variant2_order( origin, chunks_variant2 )
{
//-------------------------VARIENT2----------------------------------------------------------
variant2_order = [];
variant2_order1 =[]; // this sets up the order for the grates
variant2_order2 =[]; // this sets up the order for the grates
variant2_order3 =[]; // this sets up the order for the grates
variant2_order4 =[]; // this sets up the order for the grates
variant2_order5 =[]; // this sets up the order for the grates
variant2_order6 =[]; // this sets up the order for the grates
if ( IsDefined ( chunks_variant2 ) )
{
for(i=0;i<chunks_variant2.size;i++) // Go through the array
{
if (IsDefined (chunks_variant2[i].script_team) && (chunks_variant2[i].script_team == "bar_board_variant2") )
{
//return grate_order[i];
if ( IsDefined ( chunks_variant2[i].script_noteworthy ) && ( chunks_variant2[i].script_noteworthy == "1" ) )
{
variant2_order1[variant2_order1.size] = chunks_variant2[i];
// send back order here
}
if ( IsDefined ( chunks_variant2[i].script_noteworthy ) && ( chunks_variant2[i].script_noteworthy == "2" ) )
{
variant2_order2[variant2_order2.size] = chunks_variant2[i];
// send back order here
}
if ( IsDefined ( chunks_variant2[i].script_noteworthy ) && ( chunks_variant2[i].script_noteworthy == "3" ) )
{
variant2_order3[variant2_order3.size] = chunks_variant2[i];
// send back order here
}
if ( IsDefined ( chunks_variant2[i].script_noteworthy ) && ( chunks_variant2[i].script_noteworthy == "4" ) )
{
variant2_order4[variant2_order4.size] = chunks_variant2[i];
// send back order here
}
// I had to add another string to check against out of order noteworthy when combining board and wood
if ( IsDefined ( chunks_variant2[i].script_noteworthy ) && ( chunks_variant2[i].script_noteworthy == "5" ) && IsDefined( chunks_variant2[i].script_location ) && (chunks_variant2[i].script_location == "5") )
{
variant2_order5[variant2_order5.size] = chunks_variant2[i];
// send back order here
}
if ( IsDefined ( chunks_variant2[i].script_noteworthy ) && ( chunks_variant2[i].script_noteworthy == "5" ) && IsDefined( chunks_variant2[i].script_location ) && (chunks_variant2[i].script_location == "6") )
{
variant2_order6[variant2_order6.size] = chunks_variant2[i];
// send back order here
}
}
}
// There is a different pull order for every variant
for(i=0;i<chunks_variant2.size;i++) // Go through the array
{
if (IsDefined ( chunks_variant2[i].script_team ) && ( chunks_variant2[i].script_team == "bar_board_variant2") )
{
if( IsDefined ( variant2_order1[i] ) )
{
if( ( variant2_order1[i].state == "repaired" ) )
{
return variant2_order1[i];
}
else if( ( variant2_order2[i].state == "repaired" ) )
{
return variant2_order2[i];
}
else if( ( variant2_order3[i].state == "repaired" ) )
{
return variant2_order3[i];
}
else if( ( variant2_order5[i].state == "repaired" ) )
{
return variant2_order5[i];
}
else if( ( variant2_order4[i].state == "repaired" ) )
{
return variant2_order4[i];
}
else if( ( variant2_order6[i].state == "repaired" ) )
{
return variant2_order6[i];
}
}
}
}
}
//-------------------------VARIENT2----------------------------------------------------------
}
// variant4
function non_destroyed_variant4_order( origin, chunks_variant4 )
{
//-------------------------VARIENT4----------------------------------------------------------
variant4_order = [];
variant4_order1 =[]; // this sets up the order for the grates
variant4_order2 =[]; // this sets up the order for the grates
variant4_order3 =[]; // this sets up the order for the grates
variant4_order4 =[]; // this sets up the order for the grates
variant4_order5 =[]; // this sets up the order for the grates
variant4_order6 =[]; // this sets up the order for the grates
if ( IsDefined ( chunks_variant4 ) )
{
for(i=0;i<chunks_variant4.size;i++) // Go through the array
{
if (IsDefined (chunks_variant4[i].script_team) && (chunks_variant4[i].script_team == "bar_board_variant4") )
{
//return grate_order[i];
if ( IsDefined ( chunks_variant4[i].script_noteworthy ) && ( chunks_variant4[i].script_noteworthy == "1" ) && !IsDefined( chunks_variant4[i].script_location ) )
{
variant4_order1[variant4_order1.size] = chunks_variant4[i];
// send back order here
}
if ( IsDefined ( chunks_variant4[i].script_noteworthy ) && ( chunks_variant4[i].script_noteworthy == "2" ) )
{
variant4_order2[variant4_order2.size] = chunks_variant4[i];
// send back order here
}
if ( IsDefined ( chunks_variant4[i].script_noteworthy ) && ( chunks_variant4[i].script_noteworthy == "3" ) )
{
variant4_order3[variant4_order3.size] = chunks_variant4[i];
// send back order here
}
if ( IsDefined ( chunks_variant4[i].script_noteworthy ) && ( chunks_variant4[i].script_noteworthy == "1" ) && IsDefined( chunks_variant4[i].script_location ) && (chunks_variant4[i].script_location == "3") )
{
variant4_order4[variant4_order4.size] = chunks_variant4[i];
// send back order here
}
// There isn't a noteworthy 4
if ( IsDefined ( chunks_variant4[i].script_noteworthy ) && ( chunks_variant4[i].script_noteworthy == "5" ) )
{
variant4_order5[variant4_order5.size] = chunks_variant4[i];
// send back order here
}
if ( IsDefined ( chunks_variant4[i].script_noteworthy ) && ( chunks_variant4[i].script_noteworthy == "6" ) )
{
variant4_order6[variant4_order6.size] = chunks_variant4[i];
// send back order here
}
}
}
// There is a different pull order for every variant
for(i=0;i<chunks_variant4.size;i++) // Go through the array
{
if (IsDefined ( chunks_variant4[i].script_team ) && ( chunks_variant4[i].script_team == "bar_board_variant4") )
{
if( IsDefined ( variant4_order1[i] ) ) // last one here
{
if( ( variant4_order1[i].state == "repaired" ) )
{
return variant4_order1[i];
}
else if( ( variant4_order6[i].state == "repaired" ) )
{
return variant4_order6[i];
}
else if( ( variant4_order3[i].state == "repaired" ) )
{
return variant4_order3[i];
}
else if( ( variant4_order4[i].state == "repaired" ) ) // second one
{
return variant4_order4[i];
}
else if( ( variant4_order2[i].state == "repaired" ) )
{
return variant4_order2[i];
}
else if( ( variant4_order5[i].state == "repaired" ) )
{
return variant4_order5[i];
}
}
}
}
}
//-------------------------Variant2----------------------------------------------------------
}
// variant5
function non_destroyed_variant5_order( origin, chunks_variant5 )
{
//-------------------------VARIANT5----------------------------------------------------------
variant5_order = [];
variant5_order1 =[]; // this sets up the order for the grates
variant5_order2 =[]; // this sets up the order for the grates
variant5_order3 =[]; // this sets up the order for the grates
variant5_order4 =[]; // this sets up the order for the grates
variant5_order5 =[]; // this sets up the order for the grates
variant5_order6 =[]; // this sets up the order for the grates
if ( IsDefined ( chunks_variant5 ) )
{
for(i=0;i<chunks_variant5.size;i++) // Go through the array
{
if (IsDefined (chunks_variant5[i].script_team) && (chunks_variant5[i].script_team == "bar_board_variant5") )
{
//return grate_order[i];
if ( IsDefined ( chunks_variant5[i].script_noteworthy ) )
{
// if ( IsDefined ( chunks_variant4[i].script_noteworthy ) && ( chunks_variant4[i].script_noteworthy == "1" ) && !IsDefined( chunks_variant4[i].script_location ) )
if ( ( chunks_variant5[i].script_noteworthy == "1" ) && !IsDefined( chunks_variant5[i].script_location ) )
{
variant5_order1[variant5_order1.size] = chunks_variant5[i];
}
if ( chunks_variant5[i].script_noteworthy == "2" )
{
variant5_order2[variant5_order2.size] = chunks_variant5[i];
}
if ( IsDefined ( chunks_variant5[i].script_noteworthy ) && ( chunks_variant5[i].script_noteworthy == "1" ) && IsDefined( chunks_variant5[i].script_location ) && (chunks_variant5[i].script_location == "3") )
{
variant5_order3[variant5_order3.size] = chunks_variant5[i];
}
if ( chunks_variant5[i].script_noteworthy == "4" )
{
variant5_order4[variant5_order4.size] = chunks_variant5[i];
}
if ( chunks_variant5[i].script_noteworthy == "5" )
{
variant5_order5[variant5_order5.size] = chunks_variant5[i];
}
if ( chunks_variant5[i].script_noteworthy == "6" )
{
variant5_order6[variant5_order6.size] = chunks_variant5[i];
}
}
}
}
for(i=0;i<chunks_variant5.size;i++) // Go through the array
{
if (IsDefined ( chunks_variant5[i].script_team ) && ( chunks_variant5[i].script_team == "bar_board_variant5") )
{
if( IsDefined ( variant5_order1[i] ) )
{
if( ( variant5_order1[i].state == "repaired" ) )
{
return variant5_order1[i];
}
else if( ( variant5_order6[i].state == "repaired" ) )
{
return variant5_order6[i];
}
else if( ( variant5_order3[i].state == "repaired" ) )
{
return variant5_order3[i];
}
else if( ( variant5_order2[i].state == "repaired" ) )
{
return variant5_order2[i];
}
else if( ( variant5_order5[i].state == "repaired" ) )
{
return variant5_order5[i];
}
else if( ( variant5_order4[i].state == "repaired" ) )
{
return variant5_order4[i];
}
}
}
}
}
//-------------------------VARIANT5----------------------------------------------------------
}
function show_grate_pull()
{
wait(0.53);
self Show();
self vibrate(( 0, 270, 0 ), 0.2, 0.4, 0.4);
// I could fx and sound from here as well.
}
function get_closest_2d( origin, ents )
{
if( !IsDefined( ents ) )
{
return undefined;
}
dist = Distance2d( origin, ents[0].origin );
index = 0;
temp_array = [];
for( i = 1; i < ents.size; i++ )
{
if(IsDefined(ents[i].unbroken) && ents[i].unbroken == true)
{
ents[i].index = i;
ARRAY_ADD(temp_array, ents[i]);
}
}
if(temp_array.size > 0)
{
index = temp_array[RandomIntRange(0, temp_array.size)].index; // must pick unbroken piece first!
return ents[index];
}
else
{
for( i = 1; i < ents.size; i++ )
{
temp_dist = Distance2d( origin, ents[i].origin );
if( temp_dist < dist )
{
dist = temp_dist;
index = i;
}
}
return ents[index];
}
}
//edge_fog_start()
//{
// playpoint = struct::get( "edge_fog_start", "targetname" );
//
// if( !IsDefined( playpoint ) )
// {
//
// }
//
// while( isdefined( playpoint ) )
// {
// playfx( level._effect["edge_fog"], playpoint.origin );
//
// if( !isdefined( playpoint.target ) )
// {
// return;
// }
//
// playpoint = struct::get( playpoint.target, "targetname" );
// }
//}
//chris_p - fix bug with this not being an ent array!
function in_playable_area()
{
playable_area = getentarray("player_volume","script_noteworthy");
if( !IsDefined( playable_area ) )
{
/# println( "No playable area playable_area found! Assume EVERYWHERE is PLAYABLE" ); #/
return true;
}
for(i=0;i<playable_area.size;i++)
{
if( self IsTouching( playable_area[i] ) )
{
return true;
}
}
return false;
}
// I beleive this is where I can do the check to see what
// barrier_chunks is the total amount of bars or boards that the exterior_goal was connected to.
function get_closest_non_destroyed_chunk( origin, barrier, barrier_chunks )
{
chunks = undefined;
chunks_grate = undefined;
// This returns only if grate is defined
chunks_grate = get_non_destroyed_chunks_grate( barrier, barrier_chunks );
// This grabs classic boards, 6 bar prestine set and 6 bar bent set
chunks = get_non_destroyed_chunks( barrier, barrier_chunks ); // Grab all the chunks that are repaired
if(isdefined(barrier.zbarrier))
{
if(isdefined(chunks))
{
return array::randomize(chunks)[0];
}
if(isdefined(chunks_grate))
{
return array::randomize(chunks_grate)[0];
}
}
else
{
// This returns an array of what chunks can be pulled
if( IsDefined( chunks ) ) // && IsDefined ( chunks.script_parameters ) && chunks.script_parameters == "board" )
{
// Jl This was the original call
// return get_closest_2d( origin, chunks );
return non_destroyed_bar_board_order ( origin, chunks ); // Go through all the repaired chunk pieces
}
else if ( IsDefined ( chunks_grate ) )
{
return non_destroyed_grate_order ( origin, chunks_grate ); // Go through all the repaired chunk pices
}
}
return undefined;
}
// Jluyties barrier_chunks is the total amount of bars or boards that the exterior_goal was connected to
// The grates do not return random
function get_random_destroyed_chunk( barrier, barrier_chunks )
{
if(isdefined(barrier.zbarrier))
{
ret = undefined;
pieces = barrier.zbarrier GetZBarrierPieceIndicesInState("open");
if(pieces.size)
{
ret = array::randomize(pieces)[0];
}
return ret;
}
else
{
chunk = undefined;
chunks_repair_grate = undefined;
chunks = get_destroyed_chunks( barrier_chunks );
chunks_repair_grate = get_destroyed_repair_grates ( barrier_chunks );
// for(i = 0; i < chunks.size; i++ )
if ( IsDefined( chunks ) )
{
return chunks[RandomInt( chunks.size )];
//return get_destroyed_chunks_without_grate ( chunks );
}
else if( IsDefined( chunks_repair_grate ) )
{
return grate_order_destroyed ( chunks_repair_grate );
}
return undefined;
}
}
function get_destroyed_repair_grates( barrier_chunks )
{
// I may have to do my check here
array = []; // Setup array
for( i = 0; i < barrier_chunks.size; i++ ) // Cycle through and grab all chunks
{
if( IsDefined ( barrier_chunks[i] ) )
{
if( IsDefined ( barrier_chunks[i].script_parameters ) && ( barrier_chunks[i].script_parameters == "grate" ) )
{
array[array.size] = barrier_chunks[i];
}
}
}
if( array.size == 0 )
{
return undefined; // If there are no more pieces left then don't allow it to continue
}
return array; // send back state of array so it knows if boards are full or note and which board it is.
}
// this is the layer I want to do the check
// I need to define each part of
function get_non_destroyed_chunks( barrier, barrier_chunks )
{
if(isdefined(barrier.zbarrier))
{
return barrier.zbarrier GetZBarrierPieceIndicesInState("closed");
}
else
{
array = []; // Setup array
for( i = 0; i < barrier_chunks.size; i++ ) // Cycle through and grab all chunks
{
if(IsDefined (barrier_chunks[i].script_team) && (barrier_chunks[i].script_team == "classic_boards") )
{
if (IsDefined (barrier_chunks[i].script_parameters) && (barrier_chunks[i].script_parameters == "board") )
{
if( barrier_chunks[i] get_chunk_state() == "repaired" ) // If the state of the chunk is repaired then continue
{
if( barrier_chunks[i].origin == barrier_chunks[i].og_origin ) // If this chunk has its original origin then continue
{
array[array.size] = barrier_chunks[i]; //
}
}
}
}
//DCS: new barricade added for pentagon.
if(IsDefined (barrier_chunks[i].script_team) && (barrier_chunks[i].script_team == "new_barricade") )
{
if(IsDefined(barrier_chunks[i].script_parameters) && (barrier_chunks[i].script_parameters == "repair_board" || barrier_chunks[i].script_parameters == "barricade_vents"))
{
if( barrier_chunks[i] get_chunk_state() == "repaired" ) // If the state of the chunk is repaired then continue
{
if( barrier_chunks[i].origin == barrier_chunks[i].og_origin ) // If this chunk has its original origin then continue
{
array[array.size] = barrier_chunks[i]; //
}
}
}
}
else if ( IsDefined (barrier_chunks[i].script_team ) && ( barrier_chunks[i].script_team == "6_bars_bent" ) )
{
if (IsDefined (barrier_chunks[i].script_parameters) && (barrier_chunks[i].script_parameters == "bar") )
{
if( barrier_chunks[i] get_chunk_state() == "repaired" ) // If the state of the chunk is repaired then continue
{
if( barrier_chunks[i].origin == barrier_chunks[i].og_origin ) // If this chunk has its original origin then continue
{
array[array.size] = barrier_chunks[i]; //
}
}
}
}
else if ( IsDefined (barrier_chunks[i].script_team ) && ( barrier_chunks[i].script_team == "6_bars_prestine" ) )
{
if (IsDefined (barrier_chunks[i].script_parameters) && (barrier_chunks[i].script_parameters == "bar") )
{
if( barrier_chunks[i] get_chunk_state() == "repaired" ) // If the state of the chunk is repaired then continue
{
if( barrier_chunks[i].origin == barrier_chunks[i].og_origin ) // If this chunk has its original origin then continue
{
array[array.size] = barrier_chunks[i]; //
}
}
}
}
}
if( array.size == 0 )
{
return undefined; // If there are no more pieces left then don't allow it to continue
}
return array; // send back state of array
}
}
function get_non_destroyed_chunks_grate( barrier, barrier_chunks )
{
if(isdefined(barrier.zbarrier))
{
return barrier.zbarrier GetZBarrierPieceIndicesInState("closed");
}
else
{
array = []; // Setup array
for( i = 0; i < barrier_chunks.size; i++ ) // Cycle through and grab all chunks
{
if (IsDefined (barrier_chunks[i].script_parameters) && (barrier_chunks[i].script_parameters == "grate") )
{
if( IsDefined ( barrier_chunks[i] ) )
{
array[array.size] = barrier_chunks[i]; //
}
}
}
if( array.size == 0 )
{
return undefined; // If there are no more pieces left then don't allow it to continue
}
return array; // send back state of array so it knows if boards are full or note and which board it is.
}
}
function get_non_destroyed_variant1( barrier_chunks )
{
array = []; // Setup array
for( i = 0; i < barrier_chunks.size; i++ ) // Cycle through and grab all chunks
{
if (IsDefined (barrier_chunks[i].script_team) && (barrier_chunks[i].script_team == "bar_board_variant1") )
{
if( IsDefined ( barrier_chunks[i] ) )
{
array[array.size] = barrier_chunks[i];
}
}
}
if( array.size == 0 )
{
return undefined; // If there are no more pieces left then don't allow it to continue
}
return array; // send back state of array so it knows if boards are full or note and which board it is.
}
function get_non_destroyed_variant2( barrier_chunks )
{
array = []; // Setup array
for( i = 0; i < barrier_chunks.size; i++ ) // Cycle through and grab all chunks
{
if (IsDefined (barrier_chunks[i].script_team) && (barrier_chunks[i].script_team == "bar_board_variant2") )
{
if( IsDefined ( barrier_chunks[i] ) )
{
array[array.size] = barrier_chunks[i];
}
}
}
if( array.size == 0 )
{
return undefined; // If there are no more pieces left then don't allow it to continue
}
return array; // send back state of array so it knows if boards are full or note and which board it is.
}
function get_non_destroyed_variant4( barrier_chunks )
{
array = []; // Setup array
for( i = 0; i < barrier_chunks.size; i++ ) // Cycle through and grab all chunks
{
if (IsDefined (barrier_chunks[i].script_team) && (barrier_chunks[i].script_team == "bar_board_variant4") )
{
if( IsDefined ( barrier_chunks[i] ) )
{
array[array.size] = barrier_chunks[i]; //
}
}
}
if( array.size == 0 )
{
return undefined; // If there are no more pieces left then don't allow it to continue
}
return array; // send back state of array so it knows if boards are full or note and which board it is.
}
function get_non_destroyed_variant5( barrier_chunks )
{
array = []; // Setup array
for( i = 0; i < barrier_chunks.size; i++ ) // Cycle through and grab all chunks
{
if (IsDefined (barrier_chunks[i].script_team) && (barrier_chunks[i].script_team == "bar_board_variant5") )
{
if( IsDefined ( barrier_chunks[i] ) )
{
array[array.size] = barrier_chunks[i]; //
}
}
}
if( array.size == 0 )
{
return undefined; // If there are no more pieces left then don't allow it to continue
}
return array; // send back state of array so it knows if boards are full or note and which board it is.
}
function get_destroyed_chunks( barrier_chunks )
{
array = [];
for( i = 0; i < barrier_chunks.size; i++ )
{
if( barrier_chunks[i] get_chunk_state() == "destroyed" ) // if the chunks state says it is destroyed then continue
{
if (IsDefined (barrier_chunks[i].script_parameters) && barrier_chunks[i].script_parameters == "board")
{
array[array.size] = barrier_chunks[i]; // create a new array from barrier chunks
}
else if (IsDefined (barrier_chunks[i].script_parameters) && barrier_chunks[i].script_parameters == "repair_board" || barrier_chunks[i].script_parameters == "barricade_vents")
{
array[array.size] = barrier_chunks[i]; // create a new array from barrier chunks
}
else if (IsDefined (barrier_chunks[i].script_parameters) && (barrier_chunks[i].script_parameters == "bar") )
{
array[array.size] = barrier_chunks[i]; // create a new array from barrier chunks
}
else if (IsDefined (barrier_chunks[i].script_parameters) && (barrier_chunks[i].script_parameters == "grate") )
{
// This makes sure that it isn't returned
return undefined;
//array[array.size] = barrier_chunks[i]; // create a new array from barrier chunks
}
}
}
if( array.size == 0 )
{
return undefined;
}
return array;
//if( IsDefined( barrier_chunks ) )
//{
// return barrier_chunks;
//}
}
function grate_order_destroyed( chunks_repair_grate )
{
grate_repair_order = [];
grate_repair_order1 =[]; // this sets up the order for the grates
grate_repair_order2 =[]; // this sets up the order for the grates
grate_repair_order3 =[]; // this sets up the order for the grates
grate_repair_order4 =[]; // this sets up the order for the grates
grate_repair_order5 =[]; // this sets up the order for the grates
grate_repair_order6 =[]; // this sets up the order for the grates
// DEBUG
/*
for(i=0;i<chunks_repair_grate.size;i++) // Go through the array
{
if (IsDefined (chunks_repair_grate[i].script_parameters) && (chunks_repair_grate[i].script_parameters == "grate") )
{
grate_repair_order[grate_repair_order.size] = chunks_repair_grate[i]; // now chunks is the total amount of grates connecte
}
}
*/
for(i=0;i<chunks_repair_grate.size;i++)
{
if (IsDefined (chunks_repair_grate[i].script_parameters) && (chunks_repair_grate[i].script_parameters == "grate") )
{
if ( IsDefined ( chunks_repair_grate[i].script_noteworthy ) && ( chunks_repair_grate[i].script_noteworthy == "1" ) )
{
grate_repair_order1[grate_repair_order1.size] = chunks_repair_grate[i];
// send back order here
}
if ( IsDefined ( chunks_repair_grate[i].script_noteworthy ) && ( chunks_repair_grate[i].script_noteworthy == "2" ) )
{
grate_repair_order2[grate_repair_order2.size] = chunks_repair_grate[i];
// send back order here
}
if ( IsDefined ( chunks_repair_grate[i].script_noteworthy ) && ( chunks_repair_grate[i].script_noteworthy == "3" ) )
{
grate_repair_order3[grate_repair_order3.size] = chunks_repair_grate[i];
// send back order here
}
if ( IsDefined ( chunks_repair_grate[i].script_noteworthy ) && ( chunks_repair_grate[i].script_noteworthy == "4" ) )
{
grate_repair_order4[grate_repair_order4.size] = chunks_repair_grate[i];
// send back order here
}
if ( IsDefined ( chunks_repair_grate[i].script_noteworthy ) && ( chunks_repair_grate[i].script_noteworthy == "5" ) )
{
grate_repair_order5[grate_repair_order5.size] = chunks_repair_grate[i];
// send back order here
}
if ( IsDefined ( chunks_repair_grate[i].script_noteworthy ) && ( chunks_repair_grate[i].script_noteworthy == "6" ) )
{
grate_repair_order6[grate_repair_order6.size] = chunks_repair_grate[i];
// send back order here
}
}
}
for(i=0;i<chunks_repair_grate.size;i++) // Go through the array
{
if (IsDefined (chunks_repair_grate[i].script_parameters) && (chunks_repair_grate[i].script_parameters == "grate") )
{
if( IsDefined ( grate_repair_order1[i] ) ) // last one here
{
if( ( grate_repair_order6[i].state == "destroyed" ) )
{
/#
IPrintLnBold(" Fix grate6 ");
#/
// Here I will tell the other board to replace
return grate_repair_order6[i];
}
if( ( grate_repair_order5[i].state == "destroyed" ) )
{
/#
IPrintLnBold(" Fix grate5 ");
#/
grate_repair_order6[i] thread show_grate_repair();
return grate_repair_order5[i];
}
else if( ( grate_repair_order4[i].state == "destroyed" ) )
{
/#
IPrintLnBold(" Fix grate4 ");
#/
grate_repair_order5[i] thread show_grate_repair();
return grate_repair_order4[i];
}
else if( ( grate_repair_order3[i].state == "destroyed" ) )
{
/#
IPrintLnBold(" Fix grate3 ");
#/
grate_repair_order4[i] thread show_grate_repair();
return grate_repair_order3[i];
}
else if( ( grate_repair_order2[i].state == "destroyed" ) )
{
/#
IPrintLnBold(" Fix grate2 ");
#/
grate_repair_order3[i] thread show_grate_repair();
return grate_repair_order2[i];
}
else if( ( grate_repair_order1[i].state == "destroyed" ) )
{
/#
IPrintLnBold(" Fix grate1 ");
#/
grate_repair_order2[i] thread show_grate_repair();
// I need to return nothing here.
//return undefined();
return grate_repair_order1[i];
}
}
}
}
}
// Self is grate
function show_grate_repair()
{
wait( 0.34 );
self Hide();
}
function get_chunk_state()
{
assert( isdefined( self.state ) );
return self.state;
}
function array_limiter( array, total )
{
new_array = [];
for( i = 0; i < array.size; i++ )
{
if( i < total )
{
new_array[new_array.size] = array[i];
}
}
return new_array;
}
function fake_physicslaunch( target_pos, power )
{
start_pos = self.origin;
///////// Math Section
// Reverse the gravity so it's negative, you could change the gravity
// by just putting a number in there, but if you keep the dvar, then the
// user will see it change.
gravity = GetDvarInt( "bg_gravity" ) * -1;
dist = Distance( start_pos, target_pos );
time = dist / power;
delta = target_pos - start_pos;
drop = 0.5 * gravity *( time * time );
velocity = ( ( delta[0] / time ), ( delta[1] / time ), ( delta[2] - drop ) / time );
///////// End Math Section
level thread draw_line_ent_to_pos( self, target_pos );
self MoveGravity( velocity, time );
return time;
}
//
// STRINGS =======================================================================
//
function add_zombie_hint( ref, text )
{
if( !IsDefined( level.zombie_hints ) )
{
level.zombie_hints = [];
}
level.zombie_hints[ref] = text;
}
function get_zombie_hint( ref )
{
if( IsDefined( level.zombie_hints[ref] ) )
{
return level.zombie_hints[ref];
}
/#
println( "UNABLE TO FIND HINT STRING " + ref );
#/
return level.zombie_hints["undefined"];
}
// self is the trigger( usually spawned in on the fly )
// ent is the entity that has the script_hint info
function set_hint_string( ent, default_ref, cost )
{
ref = default_ref;
if( IsDefined( ent.script_hint ) )
{
ref = ent.script_hint;
}
if ( IS_TRUE( level.legacy_hint_system ) ) // T7TODO - this can be deleted
{
ref = ref + "_" + cost;
self SetHintString( get_zombie_hint( ref ) );
}
else
{
hint = get_zombie_hint( ref );
if (IsDefined(cost))
{
self SetHintString( hint, cost );
}
else
{
self SetHintString( hint );
}
}
}
function get_hint_string(ent, default_ref, cost )
{
ref = default_ref;
if( IsDefined( ent.script_hint ) )
{
ref = ent.script_hint;
}
if ( IS_TRUE( level.legacy_hint_system ) && IsDefined(cost) ) // T7TODO - this can be deleted
{
ref = ref + "_" + cost;
}
return get_zombie_hint( ref );
}
function unitrigger_set_hint_string( ent, default_ref, cost )
{
triggers=[];
if(self.trigger_per_player)
{
triggers = self.playertrigger;
}
else
{
triggers[0] = self.trigger;
}
foreach(trigger in triggers)
{
ref = default_ref;
if( IsDefined( ent.script_hint ) )
{
ref = ent.script_hint;
}
if ( IS_TRUE( level.legacy_hint_system ) ) // T7TODO - this can be deleted
{
ref = ref + "_" + cost;
trigger SetHintString( get_zombie_hint( ref ) );
}
else
{
hint = get_zombie_hint( ref );
if (IsDefined(cost))
{
trigger SetHintString( hint, cost );
}
else
{
trigger SetHintString( hint );
}
}
}
}
//
// SOUNDS ===========================================================
//
function add_sound( ref, alias )
{
if( !IsDefined( level.zombie_sounds ) )
{
level.zombie_sounds = [];
}
level.zombie_sounds[ref] = alias;
}
function play_sound_at_pos( ref, pos, ent )
{
if( IsDefined( ent ) )
{
if( IsDefined( ent.script_soundalias ) )
{
PlaySoundAtPosition( ent.script_soundalias, pos );
return;
}
if( IsDefined( self.script_sound ) )
{
ref = self.script_sound;
}
}
if( ref == "none" )
{
return;
}
if( !IsDefined( level.zombie_sounds[ref] ) )
{
AssertMsg( "Sound \"" + ref + "\" was not put to the zombie sounds list, please use add_sound( ref, alias ) at the start of your level." );
return;
}
PlaySoundAtPosition( level.zombie_sounds[ref], pos );
}
function play_sound_on_ent( ref )
{
if( IsDefined( self.script_soundalias ) )
{
self PlaySound( self.script_soundalias );
return;
}
if( IsDefined( self.script_sound ) )
{
ref = self.script_sound;
}
if( ref == "none" )
{
return;
}
if( !IsDefined( level.zombie_sounds[ref] ) )
{
AssertMsg( "Sound \"" + ref + "\" was not put to the zombie sounds list, please use add_sound( ref, alias ) at the start of your level." );
return;
}
self PlaySound( level.zombie_sounds[ref] );
}
function play_loopsound_on_ent( ref )
{
if( IsDefined( self.script_firefxsound ) )
{
ref = self.script_firefxsound;
}
if( ref == "none" )
{
return;
}
if( !IsDefined( level.zombie_sounds[ref] ) )
{
AssertMsg( "Sound \"" + ref + "\" was not put to the zombie sounds list, please use add_sound( ref, alias ) at the start of your level." );
return;
}
self PlaySound( level.zombie_sounds[ref] );
}
function string_to_float( string )
{
floatParts = strTok( string, "." );
if ( floatParts.size == 1 )
return int(floatParts[0]);
whole = int(floatParts[0]);
// Convert the decimal part into a floating point value
decimal = 0;
for ( i=floatParts[1].size-1; i>=0; i-- )
{
decimal = decimal/10 + int(floatParts[1][i])/10;
}
if ( whole >= 0 )
return (whole + decimal);
else
return (whole - decimal);
}
//
// TABLE LOOK SECTION ============================================================
//
// Read a value from a table and set the related level.zombie_var
//
function set_zombie_var( zvar, value, is_float, column, is_team_based )
{
if ( !IsDefined( is_float ) )
{
is_float = false;
}
if ( !IsDefined(column) )
{
column = 1;
}
if ( IS_TRUE( is_team_based ) )
{
foreach( team in level.teams )
{
level.zombie_vars[ team ][ zvar ] = value;
}
}
else
{
level.zombie_vars[zvar] = value;
}
return value;
}
// Read a value from a table and return the result
//
function get_table_var( table, var_name, value, is_float, column )
{
if ( !IsDefined(table) )
{
table = "mp/zombiemode.csv";
}
if ( !IsDefined(is_float) )
{
is_float = false;
}
if ( !IsDefined(column) )
{
column = 1;
}
// First look it up in the table
table_value = TableLookUp( table, 0, var_name, column );
if ( IsDefined( table_value ) && table_value != "" )
{
if( is_float )
{
value = string_to_float( table_value );
}
else
{
value = int( table_value );
}
}
return value;
}
function hudelem_count()
{
/#
max = 0;
curr_total = 0;
while( 1 )
{
if( level.hudelem_count > max )
{
max = level.hudelem_count;
}
println( "HudElems: " + level.hudelem_count + "[Peak: " + max + "]" );
WAIT_SERVER_FRAME;
}
#/
}
function debug_round_advancer()
{
/#
while( 1 )
{
zombs = zombie_utility::get_round_enemy_array();
for( i = 0; i < zombs.size; i++ )
{
zombs[i] dodamage( zombs[i].health + 666, ( 0, 0, 0 ) );
wait 0.5;
}
}
#/
}
function print_run_speed( speed )
{
/#
self endon( "death" );
while( 1 )
{
print3d( self.origin +( 0, 0, 64 ), speed, ( 1, 1, 1 ) );
WAIT_SERVER_FRAME;
}
#/
}
function draw_line_ent_to_ent( ent1, ent2 )
{
/#
if( GetDvarInt( "zombie_debug" ) != 1 )
{
return;
}
ent1 endon( "death" );
ent2 endon( "death" );
while( 1 )
{
line( ent1.origin, ent2.origin );
WAIT_SERVER_FRAME;
}
#/
}
function draw_line_ent_to_pos( ent, pos, end_on )
{
/#
if( GetDvarInt( "zombie_debug" ) != 1 )
{
return;
}
ent endon( "death" );
ent notify( "stop_draw_line_ent_to_pos" );
ent endon( "stop_draw_line_ent_to_pos" );
if( IsDefined( end_on ) )
{
ent endon( end_on );
}
while( 1 )
{
line( ent.origin, pos );
WAIT_SERVER_FRAME;
}
#/
}
function debug_print( msg )
{
/#
if( GetDvarInt( "zombie_debug" ) > 0 )
{
println( "######### ZOMBIE: " + msg );
}
#/
}
function debug_blocker( pos, rad, height )
{
/#
self notify( "stop_debug_blocker" );
self endon( "stop_debug_blocker" );
for( ;; )
{
if( GetDvarInt( "zombie_debug" ) != 1 )
{
return;
}
WAIT_SERVER_FRAME;
drawcylinder( pos, rad, height );
}
#/
}
function drawcylinder( pos, rad, height )
{
/#
currad = rad;
curheight = height;
for( r = 0; r < 20; r++ )
{
theta = r / 20 * 360;
theta2 = ( r + 1 ) / 20 * 360;
line( pos +( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos +( cos( theta2 ) * currad, sin( theta2 ) * currad, 0 ) );
line( pos +( cos( theta ) * currad, sin( theta ) * currad, curheight ), pos +( cos( theta2 ) * currad, sin( theta2 ) * currad, curheight ) );
line( pos +( cos( theta ) * currad, sin( theta ) * currad, 0 ), pos +( cos( theta ) * currad, sin( theta ) * currad, curheight ) );
}
#/
}
function print3d_at_pos( msg, pos, thread_endon, offset )
{
/#
self endon( "death" );
if( IsDefined( thread_endon ) )
{
self notify( thread_endon );
self endon( thread_endon );
}
if( !IsDefined( offset ) )
{
offset = ( 0, 0, 0 );
}
while( 1 )
{
print3d( self.origin + offset, msg );
WAIT_SERVER_FRAME;
}
#/
}
function debug_breadcrumbs()
{
/#
self endon( "disconnect" );
self notify("stop_debug_breadcrumbs");
self endon("stop_debug_breadcrumbs");
while( 1 )
{
if( GetDvarInt( "zombie_debug" ) != 1 )
{
wait( 1 );
continue;
}
for( i = 0; i < self.zombie_breadcrumbs.size; i++ )
{
drawcylinder( self.zombie_breadcrumbs[i], 5, 5 );
}
WAIT_SERVER_FRAME;
}
#/
}
/#
function debug_attack_spots_taken()
{
// this section was totally commented out.
self notify("stop_debug_breadcrumbs");
self endon("stop_debug_breadcrumbs");
while( 1 )
{
if( GetDvarInt( "zombie_debug" ) != 2 )
{
wait( 1 );
continue;
}
WAIT_SERVER_FRAME;
count = 0;
for( i = 0; i < self.attack_spots_taken.size; i++ )
{
if( self.attack_spots_taken[i] )
{
count++;
circle(self.attack_spots[i], 12, (1,0,0), false, true, 1);
}
else
{
circle(self.attack_spots[i], 12, (0,1,0), false, true, 1);
}
}
msg = "" + count + " / " + self.attack_spots_taken.size;
print3d( self.origin, msg );
}
}
#/
function float_print3d( msg, time )
{
/#
self endon( "death" );
time = GetTime() + ( time * 1000 );
offset = ( 0, 0, 72 );
while( GetTime() < time )
{
offset = offset + ( 0, 0, 2 );
print3d( self.origin + offset, msg, ( 1, 1, 1 ) );
WAIT_SERVER_FRAME;
}
#/
}
function do_player_vo(snd, variation_count)
{
index = get_player_index(self);
// updated to new alias format - Steve G
sound = "zmb_vox_plr_" + index + "_" + snd;
if(IsDefined (variation_count))
{
sound = sound + "_" + randomintrange(0, variation_count);
}
if(!isDefined(level.player_is_speaking))
{
level.player_is_speaking = 0;
}
if (level.player_is_speaking == 0)
{
level.player_is_speaking = 1;
self PlaySoundWithNotify(sound, "sound_done");
self waittill("sound_done");
//This ensures that there is at least 3 seconds waittime before playing another VO.
wait(2);
level.player_is_speaking = 0;
}
}
function is_magic_bullet_shield_enabled( ent )
{
if( !IsDefined( ent ) )
return false;
//return ( IsDefined( ent.magic_bullet_shield ) && ent.magic_bullet_shield == true );
return !IS_TRUE( ent.allowDeath );
}
function really_play_2D_sound(sound)
{
temp_ent = spawn("script_origin", (0,0,0));
temp_ent PlaySoundWithNotify (sound, sound + "wait");
temp_ent waittill (sound + "wait");
WAIT_SERVER_FRAME;
temp_ent delete();
}
function play_sound_2D(sound)
{
level thread really_play_2D_sound(sound);
/*
if(!isdefined(level.playsound2dent))
{
level.playsound2dent = spawn("script_origin",(0,0,0));
}
//players=GetPlayers();
level.playsound2dent playsound ( sound );
*/
/*
temp_ent = spawn("script_origin", (0,0,0));
temp_ent PlaySoundWithNotify (sound, sound + "wait");
temp_ent waittill (sound + "wait");
WAIT_SERVER_FRAME;
temp_ent delete();
*/
}
function include_weapon( weapon_name, in_box )
{
/# println( "ZM >> include_weapon = " + weapon_name ); #/
if( !isDefined( in_box ) )
{
in_box = true;
}
zm_weapons::include_zombie_weapon( weapon_name, in_box );
}
// Allows triggers to be un/seen by players
function trigger_invisible( enable )
{
players = GetPlayers();
for ( i = 0; i < players.size; i++ )
{
if ( isdefined( players[i] ) )
{
self SetInvisibleToPlayer( players[i], enable );
}
}
}
// Print3d
function print3d_ent( text, color, scale, offset, end_msg, overwrite )
{
self endon("death");
if ( IsDefined(overwrite) && overwrite && IsDefined( self._debug_print3d_msg ) )
{
// Kill the previous thread
self notify( "end_print3d" );
WAIT_SERVER_FRAME;
}
self endon("end_print3d");
if ( !IsDefined(color) )
{
color = (1,1,1);
}
if ( !IsDefined(scale) )
{
scale = 1.0;
}
if ( !IsDefined(offset) )
{
offset = (0,0,0);
}
if ( IsDefined(end_msg) )
{
self endon(end_msg);
}
// This way you can change the message dynamically by changing the var
self._debug_print3d_msg = text;
/#
while ( !IS_TRUE( level.disable_print3d_ent ) )
{
print3d( self.origin+offset, self._debug_print3d_msg, color, scale );
WAIT_SERVER_FRAME;
}
#/
}
//
//
function create_counter_hud( x )
{
if( !IsDefined( x ) )
{
x = 0;
}
hud = create_simple_hud();
hud.alignX = "left";
hud.alignY = "top";
hud.horzAlign = "user_left";
hud.vertAlign = "user_top";
hud.color = ( 1, 1, 1 );
// hud.color = ( 0.21, 0, 0 );
hud.fontscale = 32;
hud.x = x;
hud.alpha = 0;
hud SetShader( "hud_chalk_1", 64, 64 );
return hud;
}
//
// Get the name of the zone that the entity is currently in
// self is the entity to check on
function get_current_zone( return_zone )
{
level flag::wait_till( "zones_initialized" );
if ( IsDefined(self.cached_zone) )
{
zone = self.cached_zone;
zone_name = self.cached_zone_name;
vol = self.cached_zone_volume;
// check most recent zone and volume
if ( self IsTouching(zone.volumes[vol]) )
{
if ( IS_TRUE( return_zone ) )
{
return zone;
}
return zone_name;
}
// check other volumes in the most recent zone
for (i = 0; i < zone.volumes.size; i++)
{
if ( i == vol )
continue;
if ( self IsTouching(zone.volumes[i]) )
{
self.cached_zone = zone;
self.cached_zone_volume = i;
if ( IS_TRUE( return_zone ) )
{
return zone;
}
return zone_name;
}
}
}
// clear out active zone flags
for( z=0; z<level.zone_keys.size; z++ )
{
zone_name = level.zone_keys[z];
zone = level.zones[ zone_name ];
if ( IS_EQUAL( zone, self.cached_zone ) )
continue;
// Okay check to see if the entity is in one of the zone volumes
for (i = 0; i < zone.volumes.size; i++)
{
if ( self IsTouching(zone.volumes[i]) )
{
self.cached_zone = zone;
self.cached_zone_name = zone_name;
self.cached_zone_volume = i;
if ( IS_TRUE( return_zone ) )
{
return zone;
}
return zone_name;
}
}
}
self.cached_zone = undefined;
self.cached_zone_name = undefined;
self.cached_zone_volume = undefined;
return undefined;
}
function remove_mod_from_methodofdeath( mod )
{
/*modStrings = strtok( mod, "mod_" );
modName = "";
for ( i = 1; i < modStrings.size; i++ )//skip the MOD_
{
modName += modStrings[i];
}*/
return mod;
}
function clear_fog_threads()
{
players = GetPlayers();
for( i = 0; i < players.size; i++ )
{
players[i] notify( "stop_fog" );
}
}
function display_message( titleText, notifyText, duration )
{
notifyData = spawnStruct();
notifyData.titleText = notifyText;//titleText;
notifyData.notifyText = titleText;//notifyText;
//notifyData.titleText = &"ZM_MEAT_GRAB";
//notifyData.notifyText = "MEAT GRAB";
notifyData.sound = "mus_level_up";
notifyData.duration = duration;
notifyData.glowColor = (1.0, 0.0, 0.0);
notifyData.color = (0.0, 0.0, 0.0);
notifyData.iconName = "hud_zombies_meat";
self thread hud_message::notifyMessage( notifyData );
}
function is_quad()
{
return self.animname == "quad_zombie";
}
function is_leaper()
{
return self.animname == "leaper_zombie";
}
function shock_onpain()
{
self endon( "death" );
self endon( "disconnect" );
self notify("stop_shock_onpain");
self endon("stop_shock_onpain");
if( GetDvarString( "blurpain" ) == "" )
{
SetDvar( "blurpain", "on" );
}
while( 1 )
{
oldhealth = self.health;
self waittill( "damage", damage, attacker, direction_vec, point, mod );
if( IsDefined( level.shock_onpain ) && !level.shock_onpain )
{
continue;
}
if( IsDefined( self.shock_onpain ) && !self.shock_onpain )
{
continue;
}
if( self.health < 1 )
{
continue;
}
if ( IsDefined(attacker) && IsDefined(attacker.custom_player_shellshock) )
{
self [[ attacker.custom_player_shellshock ]] ( damage, attacker, direction_vec, point, mod );
}
else if( mod == "MOD_PROJECTILE" || mod == "MOD_PROJECTILE_SPLASH" )
{
continue;
}
else if( mod == "MOD_GRENADE_SPLASH" || mod == "MOD_GRENADE" || mod == "MOD_EXPLOSIVE" )
{
shockType = undefined;
shockLight = undefined;
if ( IS_TRUE( self.is_burning ) )
{
shockType = "lava";
shockLight = "lava_small";
}
self shock_onexplosion( damage, shockType, shockLight );
}
else
{
if( GetDvarString( "blurpain" ) == "on" )
{
self ShellShock( "pain_zm", 0.5 );
}
}
}
}
function shock_onexplosion( damage, shockType, shockLight )
{
time = 0;
scaled_damage = 100 * damage / self.maxhealth;
if( scaled_damage >= 90 )
{
time = 4;
}
else if( scaled_damage >= 50 )
{
time = 3;
}
else if( scaled_damage >= 25 )
{
time = 2;
}
else if( scaled_damage > 10 )
{
time = 1;
}
if( time )
{
if ( !IsDefined( shockType ) )
{
shockType = "explosion";
}
self ShellShock( shockType, time );
}
else if (IsDefined(shockLight))
{
self ShellShock( shockLight, time );
}
}
function increment_ignoreme()
{
DEFAULT( self.ignorme_count, 0 );
self.ignorme_count++;
self.ignoreme = ( self.ignorme_count > 0 );
}
function decrement_ignoreme()
{
DEFAULT( self.ignorme_count, 0 );
if( self.ignorme_count > 0 )
{
self.ignorme_count--;
}
else
{
AssertMsg( "making ignorme_count less than 0" );
}
self.ignoreme = ( self.ignorme_count > 0 );
}
// ww: increment the is_drinking variable on a player
function increment_is_drinking()
{
//self endon( "death" );
/#
if( IS_TRUE(level.devgui_dpad_watch) )
{
self.is_drinking++;
return;
}
#/
if( !isdefined(self.is_drinking) )
self.is_drinking = 0;
if( self.is_drinking == 0 )
{
self DisableOffhandWeapons();
self DisableWeaponCycling();
}
self.is_drinking++;
}
// ww: checks is_drinking
//is_drinking()
//{
// //self endon( "death" );
// return ( self.is_drinking > 0 );
//}
// to check if more than one is active at once
function is_multiple_drinking()
{
//self endon( "death" );
return ( self.is_drinking > 1 );
}
// ww: decrement drinking
function decrement_is_drinking()
{
//self endon( "death" );
if( self.is_drinking > 0 )
{
self.is_drinking--;
}
else
{
AssertMsg( "making is_drinking less than 0" );
}
if( self.is_drinking == 0 )
{
self EnableOffhandWeapons();
self EnableWeaponCycling();
}
}
// ww: clear the variable, used for players going in to last stand
function clear_is_drinking()
{
//self endon( "death" );
self.is_drinking = 0;
self EnableOffhandWeapons();
self EnableWeaponCycling();
}
// PORTIZ 7/27/16: At this point there are multiple mechanics prolonging solo games when player doesn't have Quick Revive, so we need a
// better way of supporting them in conjunction
function increment_no_end_game_check()
{
DEFAULT( level.n_no_end_game_check_count, 0 );
level.n_no_end_game_check_count++;
level.no_end_game_check = ( level.n_no_end_game_check_count > 0 );
}
function decrement_no_end_game_check()
{
DEFAULT( level.n_no_end_game_check_count, 0 );
if( level.n_no_end_game_check_count > 0 )
{
level.n_no_end_game_check_count--;
}
else
{
AssertMsg( "making no_end_game_check_count less than 0" );
}
level.no_end_game_check = ( level.n_no_end_game_check_count > 0 );
if ( !level.no_end_game_check )
{
level zm::checkForAllDead(); // run this manually any time this is decremented back to a false state
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
function fade_out(time)
{
if (!isDefined(time))
{
time = 1;
}
if( !IsDefined(level.introblack) )
{
level.introblack = NewHudElem();
level.introblack.x = 0;
level.introblack.y = 0;
level.introblack.horzAlign = "fullscreen";
level.introblack.vertAlign = "fullscreen";
level.introblack.foreground = true;
level.introblack SetShader( "black", 640, 480 );
level.introblack.alpha = 0;
wait .05;
}
if( time > 0 )
{
level.introblack FadeOverTime( time );
}
level.introblack.alpha = 1;
players = GetPlayers();
for(i = 0; i < players.size; i++)
{
players[i] freezecontrols(true);
}
wait time;
}
function fade_in( hold_black_time )
{
if( !IsDefined(level.introblack) )
{
level.introblack = NewHudElem();
level.introblack.x = 0;
level.introblack.y = 0;
level.introblack.horzAlign = "fullscreen";
level.introblack.vertAlign = "fullscreen";
level.introblack.foreground = true;
level.introblack SetShader( "black", 640, 480 );
level.introblack.alpha = 1;
wait .05;
}
level.introblack.alpha = 1;
if( IsDefined( hold_black_time ) )
wait hold_black_time;
else
wait .2;
level.introblack FadeOverTime( 1.5 );
level.introblack.alpha = 0;
level notify("fade_introblack");
wait 1.5;
players = GetPlayers();
for(i = 0; i < players.size; i++)
{
players[i] freezecontrols(false);
}
level notify("fade_in_complete");
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// WEAPONS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function getWeaponClassZM( weapon )
{
assert( isdefined( weapon ) );
if ( !isdefined( weapon ) )
{
return undefined;
}
if ( !isdefined ( level.weaponClassArray ) )
{
level.weaponClassArray = [];
}
if ( isdefined( level.weaponClassArray[weapon] ) )
{
return level.weaponClassArray[weapon];
}
baseWeaponIndex = GetBaseWeaponItemIndex( weapon );
statsTableName = util::getStatsTableName();
weaponClass = tableLookup( statsTableName, 0, baseWeaponIndex, STATS_TABLE_COL_GROUP);
level.weaponClassArray[weapon] = weaponClass;
return weaponClass;
}
function spawn_weapon_model( weapon, model, origin, angles, options )
{
if ( !isdefined( model ) )
{
model = weapon.worldModel;
}
weapon_model = spawn( "script_model", origin );
if ( isdefined( angles ) )
{
weapon_model.angles = angles;
}
if ( isdefined( options ) )
{
weapon_model useweaponmodel( weapon, model, options );
}
else
{
weapon_model useweaponmodel( weapon, model );
}
return weapon_model;
}
function spawn_buildkit_weapon_model( player, weapon, camo, origin, angles )
{
weapon_model = spawn( "script_model", origin );
if ( isdefined( angles ) )
{
weapon_model.angles = angles;
}
upgraded = zm_weapons::is_weapon_upgraded( weapon );
if ( upgraded && (!IsDefined( camo ) || 0 > camo) )
{
camo = zm_weapons::get_pack_a_punch_camo_index( undefined );
}
weapon_model UseBuildKitWeaponModel( player, weapon, camo, upgraded );
return weapon_model;
}
function is_player_revive_tool( weapon )
{
if ( weapon == level.weaponReviveTool || IS_EQUAL(weapon,self.weaponReviveTool) )
{
return true;
}
return false;
}
function is_limited_weapon( weapon )
{
if ( IsDefined( level.limited_weapons ) && IsDefined( level.limited_weapons[weapon] ) )
{
return true;
}
return false;
}
function register_lethal_grenade_for_level( weaponname )
{
weapon = GetWeapon( weaponname );
if ( is_lethal_grenade( weapon ) )
{
return;
}
if ( !isdefined( level.zombie_lethal_grenade_list ) )
{
level.zombie_lethal_grenade_list = [];
}
level.zombie_lethal_grenade_list[weapon] = weapon;
}
function is_lethal_grenade( weapon )
{
if ( !isdefined( weapon ) || !isdefined( level.zombie_lethal_grenade_list ) )
{
return false;
}
return isdefined(level.zombie_lethal_grenade_list[weapon]);
}
function is_player_lethal_grenade( weapon )
{
if ( !isdefined( weapon ) || !isdefined( self.current_lethal_grenade ) )
{
return false;
}
return self.current_lethal_grenade == weapon;
}
function get_player_lethal_grenade()
{
grenade = level.weaponNone;
if(IsDefined(self.current_lethal_grenade))
{
grenade = self.current_lethal_grenade;
}
return grenade;
}
function set_player_lethal_grenade( weapon )
{
if ( !IsDefined( weapon ) )
{
weapon = level.weaponNone;
}
self notify( "new_lethal_grenade", weapon );
self.current_lethal_grenade = weapon;
}
function init_player_lethal_grenade()
{
self set_player_lethal_grenade( level.zombie_lethal_grenade_player_init );
}
function register_tactical_grenade_for_level( weaponname )
{
weapon = GetWeapon( weaponname );
if ( is_tactical_grenade( weapon ) )
{
return;
}
if ( !isdefined( level.zombie_tactical_grenade_list ) )
{
level.zombie_tactical_grenade_list = [];
}
level.zombie_tactical_grenade_list[weapon] = weapon;
}
function is_tactical_grenade( weapon )
{
if ( !isdefined( weapon ) || !isdefined( level.zombie_tactical_grenade_list ) )
{
return false;
}
return isdefined(level.zombie_tactical_grenade_list[weapon]);
}
function is_player_tactical_grenade( weapon )
{
if ( !isdefined( weapon ) || !isdefined( self.current_tactical_grenade ) )
{
return false;
}
return self.current_tactical_grenade == weapon;
}
function get_player_tactical_grenade()
{
tactical = level.weaponNone;
if(IsDefined(self.current_tactical_grenade))
{
tactical = self.current_tactical_grenade;
}
return tactical;
}
function set_player_tactical_grenade( weapon )
{
if ( !IsDefined( weapon ) )
{
weapon = level.weaponNone;
}
self notify( "new_tactical_grenade", weapon );
self.current_tactical_grenade = weapon;
}
function init_player_tactical_grenade()
{
self set_player_tactical_grenade( level.zombie_tactical_grenade_player_init );
}
function is_placeable_mine( weapon )
{
DEFAULT(level.placeable_mines,[]);
if ( !isdefined( weapon ) || weapon == level.weaponNone )
{
return false;
}
return isdefined( level.placeable_mines[weapon.name] );
}
function is_player_placeable_mine( weapon )
{
if ( !isdefined( weapon ) || !isdefined( self.current_placeable_mine ) )
{
return false;
}
return self.current_placeable_mine == weapon;
}
function get_player_placeable_mine()
{
placeable_mine = level.weaponNone;
if(IsDefined(self.current_placeable_mine))
{
placeable_mine = self.current_placeable_mine;
}
return placeable_mine;
}
function set_player_placeable_mine( weapon )
{
if ( !IsDefined( weapon ) )
{
weapon = level.weaponNone;
}
self notify( "new_placeable_mine", weapon );
self.current_placeable_mine = weapon;
}
function init_player_placeable_mine()
{
self set_player_placeable_mine( level.zombie_placeable_mine_player_init );
}
function register_melee_weapon_for_level( weaponname )
{
weapon = GetWeapon( weaponname );
if ( is_melee_weapon( weapon ) )
{
return;
}
if ( !isdefined( level.zombie_melee_weapon_list ) )
{
level.zombie_melee_weapon_list = [];
}
level.zombie_melee_weapon_list[weapon] = weapon;
}
function is_melee_weapon( weapon )
{
if ( !isdefined( weapon ) || !isdefined( level.zombie_melee_weapon_list ) || ( weapon == GetWeapon( "none" ) ) )
{
return false;
}
return isdefined(level.zombie_melee_weapon_list[weapon]);
}
function is_player_melee_weapon( weapon )
{
if ( !isdefined( weapon ) || !isdefined( self.current_melee_weapon ) )
{
return false;
}
return self.current_melee_weapon == weapon;
}
function get_player_melee_weapon()
{
melee_weapon = level.weaponNone;
if(IsDefined(self.current_melee_weapon))
{
melee_weapon = self.current_melee_weapon;
}
return melee_weapon;
}
function set_player_melee_weapon( weapon )
{
if ( !IsDefined( weapon ) )
{
weapon = level.weaponNone;
}
self notify( "new_melee_weapon", weapon );
self.current_melee_weapon = weapon;
}
function init_player_melee_weapon()
{
self set_player_melee_weapon( level.zombie_melee_weapon_player_init );
}
function register_hero_weapon_for_level( weaponname )
{
weapon = GetWeapon( weaponname );
if ( is_hero_weapon( weapon ) )
{
return;
}
if ( !isdefined( level.zombie_hero_weapon_list ) )
{
level.zombie_hero_weapon_list = [];
}
level.zombie_hero_weapon_list[weapon] = weapon;
}
function is_hero_weapon( weapon )
{
if ( !isdefined( weapon ) || !isdefined( level.zombie_hero_weapon_list ) )
{
return false;
}
return isdefined(level.zombie_hero_weapon_list[weapon]);
}
function is_player_hero_weapon( weapon )
{
if ( !isdefined( weapon ) || !isdefined( self.current_hero_weapon ) )
{
return false;
}
return self.current_hero_weapon == weapon;
}
function get_player_hero_weapon()
{
hero_weapon = level.weaponNone;
if(IsDefined(self.current_hero_weapon))
{
hero_weapon = self.current_hero_weapon;
}
return hero_weapon;
}
function set_player_hero_weapon( weapon )
{
if ( !IsDefined( weapon ) )
{
weapon = level.weaponNone;
}
self notify( "new_hero_weapon", weapon );
self.current_hero_weapon = weapon;
}
function init_player_hero_weapon()
{
self set_player_hero_weapon( level.zombie_hero_weapon_player_init );
}
function has_player_hero_weapon()
{
return (IsDefined(self.current_hero_weapon) && self.current_hero_weapon != level.weaponNone);
}
function should_watch_for_emp()
{
return IS_TRUE( level.should_watch_for_emp );
}
function register_offhand_weapons_for_level_defaults()
{
if ( isdefined( level.register_offhand_weapons_for_level_defaults_override ) )
{
[[ level.register_offhand_weapons_for_level_defaults_override ]]();
return;
}
register_lethal_grenade_for_level( "frag_grenade" );
level.zombie_lethal_grenade_player_init = GetWeapon( "frag_grenade" );
register_tactical_grenade_for_level( "cymbal_monkey" );
level.zombie_tactical_grenade_player_init = undefined;
level.zombie_placeable_mine_player_init = undefined;
register_melee_weapon_for_level( "knife" );
register_melee_weapon_for_level( "bowie_knife" );
level.zombie_melee_weapon_player_init = GetWeapon( "knife" );
level.zombie_equipment_player_init = undefined;
}
function init_player_offhand_weapons()
{
init_player_lethal_grenade();
init_player_tactical_grenade();
init_player_placeable_mine();
init_player_melee_weapon();
init_player_hero_weapon();
zm_equipment::init_player_equipment();
}
function is_offhand_weapon( weapon )
{
return (is_lethal_grenade( weapon ) || is_tactical_grenade( weapon ) || is_placeable_mine( weapon ) || is_melee_weapon( weapon ) || is_hero_weapon( weapon ) || zm_equipment::is_equipment( weapon ) );
}
function is_player_offhand_weapon( weapon )
{
return (self is_player_lethal_grenade( weapon ) || self is_player_tactical_grenade( weapon ) || self is_player_placeable_mine( weapon ) || self is_player_melee_weapon( weapon ) || self is_player_hero_weapon( weapon ) || self zm_equipment::is_player_equipment( weapon ) );
}
function has_powerup_weapon()
{
return IS_TRUE( self.has_powerup_weapon );
}
function has_hero_weapon()
{
weapon = self GetCurrentWeapon();
return IS_TRUE( weapon.isheroweapon );
}
function give_start_weapon( b_switch_weapon )
{
/*
DEFAULT( self.hasCompletedSuperEE, self zm_stats::get_global_stat( "DARKOPS_GENESIS_SUPER_EE" ) > 0 );
if( self.hasCompletedSuperEE )
{
self zm_weapons::weapon_give( level.start_weapon, false, false, true, false );
self GiveMaxAmmo( level.start_weapon );
self zm_weapons::weapon_give( level.super_ee_weapon, false, false, true, b_switch_weapon );
}
else
{
self zm_weapons::weapon_give( level.start_weapon, false, false, true, b_switch_weapon );
}
*/
self zm_weapons::weapon_give( level.start_weapon, false, false, true, false );
self GiveMaxAmmo( level.start_weapon );
self zm_weapons::weapon_give( level.super_ee_weapon, false, false, true, b_switch_weapon );
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function array_flag_wait_any( flag_array )
{
if( !IsDefined ( level._array_flag_wait_any_calls ) )
{
level._n_array_flag_wait_any_calls = 0;
}
else
{
level._n_array_flag_wait_any_calls ++; // Used to ensure that we can have multiple calls to this concurrently, that don't interfere with each other.
}
str_condition = "array_flag_wait_call_" + level._n_array_flag_wait_any_calls;
for(index = 0; index < flag_array.size; index ++)
{
level thread array_flag_wait_any_thread ( flag_array[ index ], str_condition );
}
level waittill( str_condition );
}
function array_flag_wait_any_thread( flag_name, condition )
{
level endon( condition );
level flag::wait_till( flag_name );
level notify( condition );
}
function groundpos( origin )
{
return bullettrace( origin, ( origin + ( 0, 0, -100000 ) ), 0, self )[ "position" ];
}
function groundpos_ignore_water( origin )
{
return bullettrace( origin, ( origin + ( 0, 0, -100000 ) ), 0, self, true )[ "position" ];
}
function groundpos_ignore_water_new( origin )
{
return groundtrace( origin, ( origin + ( 0, 0, -100000 ) ), 0, self, true )[ "position" ];
}
/@
"Name: self_delete()"
"Summary: Just calls the delete() script command on self. Reason for this is so that we can use array::thread_all to delete entities"
"Module: Entity"
"CallOn: An entity"
"Example: ai[ 0 ] thread self_delete();"
"SPMP: singleplayer"
@/
function self_delete()
{
if (IsDefined(self))
{
self delete();
}
}
/@
"Name: ignore_triggers( <timer> )"
"Summary: Makes the entity that this is threaded on not able to set off triggers for a certain length of time."
"Module: Utility"
"CallOn: an entity"
"Example: guy thread ignore_triggers( 0.2 );"
"SPMP: singleplayer"
@/
function ignore_triggers( timer )
{
// ignore triggers for awhile so others can trigger the trigger we're in.
self endon( "death" );
self.ignoreTriggers = true;
if( IsDefined( timer ) )
{
wait( timer );
}
else
{
wait( 0.5 );
}
self.ignoreTriggers = false;
}
/@
"Name: giveachievement_wrapper( <achievment>, [all_players] )"
"Summary: Gives an Achievement to the specified player"
"Module: Mp"
"MandatoryArg: <achievment>: The code string for the achievement"
"OptionalArg: [all_players]: If true, then give everyone the achievement"
"Example: player giveachievement_wrapper( "MAK_ACHIEVEMENT_RYAN" );"
"SPMP: singleplayer"
@/
function giveachievement_wrapper( achievement, all_players )
{
if ( achievement == "" )
{
return;
}
//don't do stats stuff if stats are disabled
if ( IS_TRUE( level.zm_disable_recording_stats ) )
{
return;
}
achievement_lower = tolower(achievement);
global_counter = 0;
if ( IsDefined( all_players ) && all_players )
{
players = GetPlayers();
for ( i = 0; i < players.size; i++ )
{
players[i] GiveAchievement( achievement );
has_achievement = false; // T7 DLC5 TODO: players[i] zm_stats::get_global_stat( achievement_lower );
if(!IS_TRUE(has_achievement))
{
global_counter++;
}
// T7 DLC5 TODO: players[i] zm_stats::increment_client_stat( achievement_lower,false );
if( issplitscreen() && i == 0 || !issplitscreen() )
{
if(isDefined(level.achievement_sound_func))
{
players[i] thread [[level.achievement_sound_func]](achievement_lower);
}
}
}
}
else
{
if ( !IsPlayer( self ) )
{
/# println( "^1self needs to be a player for util::giveachievement_wrapper()" ); #/
return;
}
self GiveAchievement( achievement );
//test the stat before updating it from 0 to 1
has_achievement = false; // T7 DLC5 TODO: self zm_stats::get_global_stat( achievement_lower );
if(!IS_TRUE(has_achievement))
{
global_counter++;
}
// T7 DLC5 TODO: self zm_stats::increment_client_stat( achievement_lower,false );
if(isDefined(level.achievement_sound_func))
{
self thread [[level.achievement_sound_func]](achievement_lower);
}
}
if(global_counter)
{
incrementCounter( "global_" + achievement_lower,global_counter);
}
}
function GetYaw(org)
{
angles = VectorToAngles(org-self.origin);
return angles[1];
}
function GetYawToSpot(spot)
{
pos = spot;
yaw = self.angles[1] - GetYaw(pos);
yaw = AngleClamp180( yaw );
return yaw;
}
/*
=============
///ScriptDocBegin
"Name: disable_react()"
"Summary: Disables reaction behavior of given AI"
"Module: Utility"
"CallOn: An ai"
"Example: level.zakhaev disable_react();"
"SPMP: singleplayer"
///ScriptDocEnd
=============
*/
function disable_react()
{
assert( isalive( self ), "Tried to disable react on a non ai" );
self.a.disableReact = true;
self.allowReact = false;
}
/*
=============
///ScriptDocBegin
"Name: enable_react()"
"Summary: Enables reaction behavior of given AI"
"Module: Utility"
"CallOn: An ai"
"Example: level.zakhaev enable_react();"
"SPMP: singleplayer"
///ScriptDocEnd
=============
*/
function enable_react()
{
assert( isalive( self ), "Tried to enable react on a non ai" );
self.a.disableReact = false;
self.allowReact = true;
}
// MikeD (12/15/2007): IW abandoned the auto-adjust feature, however, we can use it for stats?
// SCRIPTER_MOD: JesseS (4/14/2008): Added back in for Arcade mode
function bullet_attack( type )
{
if ( type == "MOD_PISTOL_BULLET" )
{
return true;
}
return type == "MOD_RIFLE_BULLET";
}
function pick_up()
{
player = self.owner;
self destroy_ent();
clip_ammo = player GetWeaponAmmoClip( self.weapon );
clip_max_ammo = self.weapon.clipSize;
if( clip_ammo < clip_max_ammo )
{
clip_ammo++;
}
player SetWeaponAmmoClip( self.weapon, clip_ammo );
}
function destroy_ent()
{
self delete();
}
/@
"Name: waittill_not_moving()"
"Summary: waits for the object to stop moving"
"Module: Utility"
"CallOn: Object that moves like a thrown grenade"
"Example: self waittill_not_moving();"
"SPMP: singleplayer"
@/
function waittill_not_moving()
{
self endon("death");
self endon( "disconnect" );
self endon( "detonated" );
level endon( "game_ended" );
if ( self.classname == "grenade" )
{
self waittill("stationary");
}
else
{
prevorigin = self.origin;
while(1)
{
wait .15;
if ( self.origin == prevorigin )
break;
prevorigin = self.origin;
}
}
}
/@
"Name: get_closest_player( <org> )"
"Summary: Returns the closest player to the given origin."
"Module: Coop"
"MandatoryArg: <origin>: The vector to use to compare the distances to"
"Example: closest_player = get_closest_player( objective.origin );"
"SPMP: singleplayer"
@/
function get_closest_player( org )
{
players = [];
players = GetPlayers();
return ArrayGetClosest( org, players );
}
function ent_flag_init_ai_standards()
{
message_array = [];
message_array[ message_array.size ] = "goal";
message_array[ message_array.size ] = "damage";
for( i = 0; i < message_array.size; i++)
{
self flag::init( message_array[ i ] );
self thread ent_flag_wait_ai_standards( message_array[ i ] );
}
}
function ent_flag_wait_ai_standards( message )
{
/*
only runs the first time on the message, so for
example if it's waiting on goal, it will only set
the goal to true the first time. It also doesn't
call ent_set_flag() because that would notify the
message possibly twice in the same frame, or worse
in the next frame.
*/
self endon("death");
self waittill( message );
self.ent_flag[ message ] = true;
}
/@
"Name: flat_angle( <angle> )"
"Summary: Returns the specified angle as a flat angle.( 45, 90, 30 ) becomes( 0, 90, 0 ). Useful if you just need an angle around Y - axis."
"Module: Vector"
"CallOn: "
"MandatoryArg: <angle> : angles to flatten"
"Example: yaw = flat_angle( node.angles );"
"SPMP: singleplayer"
@/
function flat_angle( angle )
{
rangle = ( 0, angle[ 1 ], 0 );
return rangle;
}
/@
"Name: clear_run_anim()"
"Summary: Clears any set run anims "
"Module: AI"
"CallOn: an actor"
"Example: guy clear_run_anim();"
"SPMP: singleplayer"
@/
function clear_run_anim()
{
self.alwaysRunForward = undefined;
self.a.combatrunanim = undefined;
self.run_noncombatanim = undefined;
self.walk_combatanim = undefined;
self.walk_noncombatanim = undefined;
self.preCombatRunEnabled = true;
}
function track_players_intersection_tracker()
{
self endon( "disconnect" );
self endon( "death" );
level endon( "end_game" );
wait( 5 );
while ( 1 )
{
killed_players = false;
players = GetPlayers();
for ( i = 0; i < players.size; i++ )
{
if ( players[i] laststand::player_is_in_laststand() || "playing" != players[i].sessionstate )
{
continue;
}
for ( j = 0; j < players.size; j++ )
{
if ( i == j || players[j] laststand::player_is_in_laststand() || "playing" != players[j].sessionstate )
{
continue;
}
if ( isDefined( level.player_intersection_tracker_override ) )
{
if ( players[i] [[level.player_intersection_tracker_override]]( players[j] ) )
{
continue;
}
}
playerI_origin = players[i].origin;
playerJ_origin = players[j].origin;
//Check height first
if ( abs(playerI_origin[2] - playerJ_origin[2] ) > 60 )
continue;
//Check 2d distance
distance_apart = distance2d( playerI_origin, playerJ_origin );
//IPrintLnBold( "player=", i, ",", j, "distance_apart=", distance_apart );
if ( abs(distance_apart) > 18 )
continue;
/#
IPrintLnBold( "PLAYERS ARE TOO FRIENDLY!!!!!" );
#/
players[i] dodamage( 1000, (0, 0, 0) );
players[j] dodamage( 1000, (0, 0, 0) );
if ( !killed_players )
{
players[i] playlocalsound( level.zmb_laugh_alias );
}
players[i] zm_stats::increment_map_cheat_stat( "cheat_too_friendly" );
players[i] zm_stats::increment_client_stat( "cheat_too_friendly",false );
players[i] zm_stats::increment_client_stat( "cheat_total",false );
players[j] zm_stats::increment_map_cheat_stat( "cheat_too_friendly" );
players[j] zm_stats::increment_client_stat( "cheat_too_friendly",false );
players[j] zm_stats::increment_client_stat( "cheat_total",false );
killed_players = true;
}
}
wait( .5 );
}
}
/@
"Name: is_player_looking_at( <origin>, <dot>, <do_trace> )"
"Summary: Checks to see if the player can dot and trace to a point"
"Module: Player"
"CallOn: A Player"
"MandatoryArg: <org> The position you're checking if the player is looking at"
"OptionalArg: <dot> Optional override dot (between 0 and 1) the higher the number, the more the player has to be looking right at the spot."
"OptionalArg: <do_trace> Set to false to skip the bullet trace check"
"OptionalArg: <ignore_ent> Ignore ent passed to trace check"
"Example: if ( GetPlayers()[0] is_player_looking_at( org.origin ) )"
"SPMP: zombies"
@/
function is_player_looking_at(origin, dot, do_trace, ignore_ent)
{
assert(IsPlayer(self), "player_looking_at must be called on a player.");
if (!IsDefined(dot))
{
dot = .7;
}
if (!IsDefined(do_trace))
{
do_trace = true;
}
eye = self util::get_eye();
delta_vec = AnglesToForward(VectorToAngles(origin - eye));
view_vec = AnglesToForward(self GetPlayerAngles());
new_dot = VectorDot( delta_vec, view_vec );
if ( new_dot >= dot )
{
if (do_trace)
{
return BulletTracePassed( origin, eye, false, ignore_ent );
}
else
{
return true;
}
}
return false;
}
/@
"Name: add_gametype()"
"Summary: dummy - Rex looks for these to populate the gametype pulldown"
"SPMP: zombies"
@/
function add_gametype( gt, dummy1, name, dummy2 )
{
}
/@
"Name: add_gameloc()"
"Summary: dummy - Rex looks for these to populate the location pulldown"
"SPMP: zombies"
@/
function add_gameloc( gl, dummy1, name, dummy2 )
{
}
/@
"Name: get_closest_index( <org> , <array> , <dist> )"
"Summary: same as getClosest but returns the closest entity's array index instead of the actual entity."
"Module: Distance"
"CallOn: "
"MandatoryArg: <org> : Origin to be closest to."
"MandatoryArg: <array> : Array of entities to check distance on."
"OptionalArg: <dist> : Maximum distance to check"
"Example: "
"SPMP: mp"
@/
function get_closest_index( org, array, dist )
{
if( !IsDefined( dist ) )
{
dist = 9999999;
}
distsq = dist*dist;
if( array.size < 1 )
{
return;
}
index = undefined;
for( i = 0;i < array.size;i++ )
{
newdistsq = distancesquared( array[ i ].origin, org );
if( newdistsq >= distsq )
{
continue;
}
distsq = newdistsq;
index = i;
}
return index;
}
function is_valid_zombie_spawn_point(point)
{
liftedorigin = point.origin + (0,0,5);
size = 48;
height = 64;
mins = (-1 * size,-1 * size,0 );
maxs = ( size,size,height );
absmins = liftedorigin + mins;
absmaxs = liftedorigin + maxs;
// check to see if we would telefrag any players
if ( BoundsWouldTelefrag( absmins, absmaxs ) )
{
return false;
}
return true;
}
/@
"Name: get_closest_index( <org> , <array> , <dist> )"
"Summary: same as getClosest but returns the closest entity's array index instead of the actual entity."
"Module: Distance"
"CallOn: "
"MandatoryArg: <org> : Origin to be closest to."
"MandatoryArg: <array> : Array of entities to check distance on."
"OptionalArg: <dist> : Maximum distance to check"
"Example: "
"SPMP: mp"
@/
function get_closest_index_to_entity( entity, array, dist, extra_check )
{
org = entity.origin;
if( !IsDefined( dist ) )
{
dist = 9999999;
}
distsq = dist*dist;
if( array.size < 1 )
{
return;
}
index = undefined;
for( i = 0;i < array.size;i++ )
{
if (isdefined(extra_check) && ![[extra_check]](entity,array[ i ]) )
continue;
newdistsq = distancesquared( array[ i ].origin, org );
if( newdistsq >= distsq )
{
continue;
}
distsq = newdistsq;
index = i;
}
return index;
}
function set_gamemode_var(gvar, val)
{
if(!isdefined(game["gamemode_match"]))
{
game["gamemode_match"] = [];
}
game["gamemode_match"][gvar] = val;
}
function set_gamemode_var_once(gvar, val)
{
if(!isdefined(game["gamemode_match"]))
{
game["gamemode_match"] = [];
}
if(!isdefined(game["gamemode_match"][gvar]))
{
game["gamemode_match"][gvar] = val;
}
}
function set_game_var(gvar, val)
{
game[gvar] = val;
}
function set_game_var_once(gvar, val)
{
if(!isdefined(game[gvar]))
{
game[gvar] = val;
}
}
function get_game_var( gvar )
{
if(isdefined(game[gvar]))
{
return game[gvar];
}
return undefined;
}
function get_gamemode_var( gvar )
{
if(isdefined(game["gamemode_match"]) && isdefined(game["gamemode_match"][gvar]))
{
return game["gamemode_match"][gvar];
}
return undefined;
}
function waittill_subset(min_num, string1, string2, string3, string4, string5 )
{
self endon ("death");
ent = SpawnStruct();
ent.threads = 0;
returned_threads = 0;
if (IsDefined (string1))
{
self thread util::waittill_string(string1, ent);
ent.threads++;
}
if (IsDefined (string2))
{
self thread util::waittill_string(string2, ent);
ent.threads++;
}
if (IsDefined (string3))
{
self thread util::waittill_string(string3, ent);
ent.threads++;
}
if (IsDefined (string4))
{
self thread util::waittill_string(string4, ent);
ent.threads++;
}
if (IsDefined (string5))
{
self thread util::waittill_string(string5, ent);
ent.threads++;
}
while (ent.threads)
{
ent waittill ("returned");
ent.threads--;
returned_threads++;
if(returned_threads >= min_num ) //if we've got the minimum number of waittills returned, then that is good enough!
{
break;
}
}
ent notify ("die");
}
function is_headshot( weapon, sHitLoc, sMeansOfDeath )
{
if( !isdefined( sHitLoc ) )
{
return false;
}
if( (sHitLoc != "head" && sHitLoc != "helmet") )
{
return false;
}
//ballsitic knives
if( sMeansofDeath == "MOD_IMPACT" && weapon.isBallisticKnife )
{
return true;
}
return sMeansOfDeath != "MOD_MELEE" && sMeansOfDeath != "MOD_IMPACT" && sMeansofDeath != "MOD_UNKNOWN";
}
function is_jumping()
{
// this probably doesn't work correctly on the bus
// checking PMF_JUMPING in code would give more accurate results
ground_ent = self GetGroundEnt();
return (!isdefined(ground_ent));
}
function is_explosive_damage( mod )
{
if( !IsDefined( mod ) )
return false;
if( mod == "MOD_GRENADE" || mod == "MOD_GRENADE_SPLASH" || mod == "MOD_PROJECTILE" || mod == "MOD_PROJECTILE_SPLASH" || mod == "MOD_EXPLOSIVE" )
return true;
return false;
}
function sndSwitchAnnouncerVox( who )
{
switch( who )
{
case "sam":
game["zmbdialog"]["prefix"] = "vox_zmba_sam";
level.zmb_laugh_alias = "zmb_laugh_sam";
level.sndAnnouncerIsRich = false;
break;
}
}
function do_player_general_vox(category,type,timer,chance)
{
if( isDefined(timer) && isDefined(level.votimer[type]) && level.votimer[type] > 0)
{
return;
}
self thread zm_audio::create_and_play_dialog( category, type);
if(isDefined(timer))
{
level.votimer[type] = timer;
level thread general_vox_timer( level.votimer[type],type );
}
}
function general_vox_timer(timer,type)
{
level endon("end_game");
/# println( "ZM >> VOX TIMER STARTED FOR " + type + " ( " + timer + ")" ); #/
while(timer > 0 )
{
wait(1);
timer--;
}
level.votimer[type] = timer;
/# println( "ZM >> VOX TIMER ENDED FOR " + type + " ( " + timer + ")" ); #/
}
function create_vox_timer(type)
{
level.votimer[type] = 0;
}
function play_vox_to_player(category,type,force_variant )
{
//self thread zm_audio::playVoxToPlayer( category, type, force_variant );
}
function is_favorite_weapon(weapon_to_check)
{
if(!isDefined(self.favorite_wall_weapons_list))
{
return false;
}
foreach(weapon in self.favorite_wall_weapons_list)
{
if (weapon_to_check == weapon )
{
return true;
}
}
return false;
}
function add_vox_response_chance(event,chance)
{
level.response_chances[event] = chance;
}
function set_demo_intermission_point()
{
spawnpoints = getentarray("mp_global_intermission", "classname");
if ( !spawnpoints.size )
{
return;
}
spawnpoint = spawnpoints[0];
match_string = "";
location = level.scr_zm_map_start_location;
if ( (location == "default" || location == "") && IsDefined( level.default_start_location ) )
{
location = level.default_start_location;
}
match_string = level.scr_zm_ui_gametype + "_" + location;
for ( i = 0; i < spawnpoints.size; i++ )
{
if ( IsDefined( spawnpoints[i].script_string ) )
{
tokens = strtok( spawnpoints[i].script_string," " );
foreach ( token in tokens )
{
if ( token == match_string )
{
spawnpoint = spawnpoints[i];
i = spawnpoints.size; // to get out of the outer for loop
break;
}
}
}
}
setDemoIntermissionPoint( spawnpoint.origin, spawnpoint.angles );
}
function register_map_navcard(navcard_on_map,navcard_needed_for_computer)
{
level.navcard_needed = navcard_needed_for_computer;
level.map_navcard = navcard_on_map;
}
function does_player_have_map_navcard(player)
{
return player zm_stats::get_global_stat( level.map_navcard );
}
function does_player_have_correct_navcard(player)
{
if(!isDefined(level.navcard_needed ))
{
return false;
}
return player zm_stats::get_global_stat( level.navcard_needed );
}
function place_navcard( str_model, str_stat, org, angles )
{
navcard = spawn("script_model",org);
navcard setmodel( str_model );
navcard.angles = angles;
wait 1; // delay between spawning card and picking it up
navcard_pickup_trig = Spawn( "trigger_radius_use", org, 0, 84, 72 );
navcard_pickup_trig SetCursorHint( "HINT_NOICON" );
navcard_pickup_trig SetHintString( &"ZOMBIE_NAVCARD_PICKUP" );
navcard_pickup_trig TriggerIgnoreTeam();
a_navcard_stats = array( "navcard_held_zm_transit", "navcard_held_zm_highrise", "navcard_held_zm_buried" );
is_holding_card = false;
str_placing_stat = undefined;
while(1)
{
navcard_pickup_trig waittill("trigger",who );
if( is_player_valid(who) )
{
// check for any currently held card. If found, clear that stat and save which it was
foreach ( str_cur_stat in a_navcard_stats )
{
if ( who zm_stats::get_global_stat( str_cur_stat ) )
{
str_placing_stat = str_cur_stat;
is_holding_card = true;
who zm_stats::set_global_stat( str_cur_stat, 0 );
}
}
who playsound( "zmb_buildable_piece_add" );
who zm_stats::set_global_stat( str_stat, 1 );
who.navcard_grabbed = str_stat;
util::wait_network_frame();
is_stat = who zm_stats::get_global_stat( str_stat );
thread sq_refresh_player_navcard_hud();
break;
}
}
navcard delete();
navcard_pickup_trig delete();
// if a card was held, place a new card with the stat of the one that was held (set down the old card)
if ( is_holding_card )
{
level thread place_navcard( str_model, str_placing_stat, org, angles );
}
}
function sq_refresh_player_navcard_hud()
{
if (!IsDefined(level.navcards))
return;
players = GetPlayers();
foreach( player in players )
{
player thread sq_refresh_player_navcard_hud_internal();
}
}
function sq_refresh_player_navcard_hud_internal()
{
self endon("disconnect");
navcard_bits = 0;
for(i = 0;i < level.navcards.size; i++)
{
hasit = self zm_stats::get_global_stat( level.navcards[i] );
if (isdefined(self.navcard_grabbed) && self.navcard_grabbed == level.navcards[i] )
hasit = 1;
if( hasit )
{
navcard_bits +=( 1 << i );
}
}
util::wait_network_frame();
self clientfield::set( "navcard_held", 0 );
if ( navcard_bits > 0 )
{
util::wait_network_frame();
self clientfield::set( "navcard_held", navcard_bits );
}
}
function disable_player_move_states(forceStanceChange)
{
self AllowCrouch( true );
self AllowLean( false );
self AllowAds( false );
self AllowSprint( false );
self AllowProne( false );
self AllowMelee( false );
if((isdefined(forceStanceChange)) && (forceStanceChange == true))
{
if ( self GetStance() == "prone" )
{
self SetStance( "crouch" );
}
}
}
function enable_player_move_states()
{
if((!isdefined(self._allow_lean)) || (self._allow_lean == true))
{
self AllowLean( true );
}
if((!isdefined(self._allow_ads)) || (self._allow_ads == true))
{
self AllowAds( true );
}
if((!isdefined(self._allow_sprint)) || (self._allow_sprint == true))
{
self AllowSprint( true );
}
if((!isdefined(self._allow_prone)) || (self._allow_prone == true))
{
self AllowProne( true );
}
if((!isdefined(self._allow_melee)) || (self._allow_melee == true))
{
self AllowMelee( true );
}
}
function check_and_create_node_lists()
{
if(!isdefined(level._link_node_list))
{
level._link_node_list = [];
}
if(!isdefined(level._unlink_node_list))
{
level._unlink_node_list = [];
}
}
function link_nodes(a, b, bDontUnlinkOnMigrate = false)
{
if(NodesAreLinked(a,b))
{
return;
}
check_and_create_node_lists();
a_index_string = "" + a.origin;
b_index_string = "" + b.origin;
if(!isdefined(level._link_node_list[a_index_string]))
{
level._link_node_list[a_index_string] = spawnstruct();
level._link_node_list[a_index_string].node = a;
level._link_node_list[a_index_string].links = [];
level._link_node_list[a_index_string].ignore_on_migrate = [];
}
if(!isdefined(level._link_node_list[a_index_string].links[b_index_string]))
{
level._link_node_list[a_index_string].links[b_index_string] = b; // Add a record of the link.
level._link_node_list[a_index_string].ignore_on_migrate[b_index_string] = bDontUnlinkOnMigrate;
}
if(isdefined(level._unlink_node_list[a_index_string]))
{
if(isdefined(level._unlink_node_list[a_index_string].links[b_index_string]))
{
level._unlink_node_list[a_index_string].links[b_index_string] = undefined; // Remove record of earlier unlink
level._unlink_node_list[a_index_string].ignore_on_migrate[b_index_string] = undefined;
}
}
// /# println("Linking node at " + a.origin + " to node at " + b.origin); #/
LinkNodes(a,b);
}
function unlink_nodes(a,b, bDontLinkOnMigrate = false)
{
if(!NodesAreLinked(a,b))
{
return;
}
check_and_create_node_lists();
a_index_string = "" + a.origin;
b_index_string = "" + b.origin;
if(!isdefined(level._unlink_node_list[a_index_string]))
{
level._unlink_node_list[a_index_string] = spawnstruct();
level._unlink_node_list[a_index_string].node = a;
level._unlink_node_list[a_index_string].links = [];
level._unlink_node_list[a_index_string].ignore_on_migrate = [];
}
if(!isdefined(level._unlink_node_list[a_index_string].links[b_index_string]))
{
level._unlink_node_list[a_index_string].links[b_index_string] = b; // Add a record of the unlink.
level._unlink_node_list[a_index_string].ignore_on_migrate[b_index_string] = bDontLinkOnMigrate;
}
if(isdefined(level._link_node_list[a_index_string]))
{
if(isdefined(level._link_node_list[a_index_string].links[b_index_string]))
{
level._link_node_list[a_index_string].links[b_index_string] = undefined; // Remove record of earlier link.
level._link_node_list[a_index_string].ignore_on_migrate[b_index_string] = undefined;
}
}
// /# println("Unlinking node at " + a.origin + " from node at " + b.origin); #/
UnlinkNodes(a,b);
}
//spawn_path_node( (-6392, 4329, 0), (0,0,0), "targetname", "blah" );
function spawn_path_node(origin, angles, k1, v1, k2, v2)
{
if(!isdefined(level._spawned_path_nodes))
{
level._spawned_path_nodes = [];
}
node = spawnstruct();
node.origin = origin;
node.angles = angles;
node.k1 = k1;
node.v1 = v1;
node.k2 = k2;
node.v2 = v2;
node.node = spawn_path_node_internal(origin, angles, k1, v1, k2, v2);
level._spawned_path_nodes[level._spawned_path_nodes.size] = node;
return node.node;
}
function spawn_path_node_internal(origin, angles, k1, v1, k2, v2)
{
if(isdefined(k2))
{
return SpawnPathNode("node_pathnode", origin, angles, k1, v1, k2, v2);
}
else if(isdefined(k1))
{
return SpawnPathNode("node_pathnode", origin, angles, k1, v1);
}
else
{
return SpawnPathNode("node_pathnode", origin, angles);
}
return undefined;
}
function delete_spawned_path_nodes()
{
/* if(!isdefined(level._spawned_path_nodes))
{
return;
}
//for(i = 0; i < level._spawned_path_nodes.size; i ++)
for(i = level._spawned_path_nodes.size - 1; i > -1; i --)
{
/# println("Deleting spawned path node @ " + level._spawned_path_nodes[i].origin); #/
DeletePathNode(level._spawned_path_nodes[i].node);
level._spawned_path_nodes[i].node = undefined;
}*/
}
function respawn_path_nodes()
{
if(!isdefined(level._spawned_path_nodes))
{
return;
}
for(i = 0; i < level._spawned_path_nodes.size; i ++)
{
node_struct = level._spawned_path_nodes[i];
/# println("Re-spawning spawned path node @ " + node_struct.origin); #/
node_struct.node = spawn_path_node_internal(node_struct.origin, node_struct.angles, node_struct.k1, node_struct.v1, node_struct.k2, node_struct.v2);
}
}
function link_changes_internal_internal(list, func)
{
keys = GetArrayKeys(list);
for(i = 0; i < keys.size; i ++)
{
node = list[keys[i]].node;
node_keys = GetArrayKeys(list[keys[i]].links);
for(j = 0; j < node_keys.size; j ++)
{
if(isdefined(list[keys[i]].links[node_keys[j]]))
{
if(IS_TRUE(list[keys[i]].ignore_on_migrate[node_keys[j]]))
{
/# println("Node at " + keys[i] + " to node at " + node_keys[j] + " - IGNORED"); #/
}
else
{
/# println("Node at " + keys[i] + " to node at " + node_keys[j]); #/
[[func]](node, list[keys[i]].links[node_keys[j]]);
}
}
}
}
}
function link_changes_internal(func_for_link_list, func_for_unlink_list)
{
if(isdefined(level._link_node_list))
{
/# println("Link List"); #/
link_changes_internal_internal(level._link_node_list, func_for_link_list);
}
if(isdefined(level._unlink_node_list))
{
/# println("UnLink List"); #/
link_changes_internal_internal(level._unlink_node_list, func_for_unlink_list);
}
}
function link_nodes_wrapper(a, b)
{
if(!NodesAreLinked(a,b))
{
LinkNodes(a,b);
}
}
function unlink_nodes_wrapper(a, b)
{
if(NodesAreLinked(a,b))
{
UnlinkNodes(a,b);
}
}
function undo_link_changes()
{
/# println("***");
println("***");
println("*** Undoing link changes"); #/
link_changes_internal( &unlink_nodes_wrapper, &link_nodes_wrapper);
delete_spawned_path_nodes();
}
function redo_link_changes()
{
/# println("***");
println("***");
println("*** Redoing link changes"); #/
respawn_path_nodes();
link_changes_internal( &link_nodes_wrapper, &unlink_nodes_wrapper);
}
function is_gametype_active( a_gametypes )
{
b_is_gametype_active = false;
if ( !IsArray( a_gametypes ) )
{
a_gametypes = Array( a_gametypes );
}
for ( i = 0; i < a_gametypes.size; i++ )
{
if ( GetDvarString( "g_gametype" ) == a_gametypes[ i ] )
{
b_is_gametype_active = true;
}
}
return b_is_gametype_active;
}
function register_custom_spawner_entry( spot_noteworthy, func )
{
if ( !IsDefined( level.custom_spawner_entry ) )
{
level.custom_spawner_entry = [];
}
level.custom_spawner_entry[ spot_noteworthy ] = func;
}
function get_player_weapon_limit( player )
{
if ( IsDefined( self.get_player_weapon_limit ) )
{
return [[self.get_player_weapon_limit]]( player );
}
if ( IsDefined( level.get_player_weapon_limit ) )
{
return [[level.get_player_weapon_limit]]( player );
}
weapon_limit = 2;
if ( player HasPerk( PERK_ADDITIONAL_PRIMARY_WEAPON ) )
{
weapon_limit = level.additionalprimaryweapon_limit;
}
return weapon_limit;
}
function get_player_perk_purchase_limit()
{
n_perk_purchase_limit_override = level.perk_purchase_limit; // start with the default value
// level-specific override
if ( IsDefined( level.get_player_perk_purchase_limit ) )
{
n_perk_purchase_limit_override = self [[level.get_player_perk_purchase_limit]]();
}
return n_perk_purchase_limit_override;
}
function can_player_purchase_perk()
{
if ( self.num_perks < self zm_utility::get_player_perk_purchase_limit() )
{
return true;
}
// you can always buy one more if you currently have unquenchable
if ( self bgb::is_enabled( "zm_bgb_unquenchable" ) || self bgb::is_enabled( "zm_bgb_soda_fountain" ) )
{
return true;
}
return false;
}
// Give player all perks
// b_exclude_quick_revive - if you need to prevent a solo player from getting quick revive
function give_player_all_perks( b_exclude_quick_revive = false ) // self == player
{
// give the player all the perks in the map
a_str_perks = GetArrayKeys( level._custom_perks );
foreach( str_perk in a_str_perks )
{
if ( str_perk == PERK_QUICK_REVIVE && b_exclude_quick_revive )
{
continue;
}
if( !self HasPerk( str_perk ) )
{
self zm_perks::give_perk( str_perk, false );
if ( isdefined( level.perk_bought_func ) )
{
self [[ level.perk_bought_func ]]( str_perk );
}
}
}
}
function wait_for_attractor_positions_complete()
{
self waittill( "attractor_positions_generated" );
self.attract_to_origin = false;
}
// Migrated from _zm_weapons.
function get_player_index( player )
{
assert( IsPlayer( player ) );
assert( IsDefined( player.characterIndex ) );
/#
// used for testing to switch player's VO in-game from devgui
if ( player.entity_num == 0 && GetDvarString( "zombie_player_vo_overwrite" ) != "" )
{
new_vo_index = GetDvarInt( "zombie_player_vo_overwrite" );
return new_vo_index;
}
#/
return player.characterIndex;
}
// ****************************************
// get_specific_character() returns the player character associated with the index given.
// For zm_zod, the indices are defined as follows:
// #define FLOYD 0
// #define JACK 1
// #define ROSE 2
// #define NERO 3
// For other levels, indices will differ.
// Copied from zm_factory.gsc
function get_specific_character( n_character_index )
{
foreach( character in level.players )
{
if( character.characterIndex == n_character_index )
return character;
}
return undefined;
}
function zombie_goto_round( n_target_round )
{
level notify( "restart_round" );
if ( n_target_round < 1 )
{
n_target_round = 1;
}
level.zombie_total = 0;
zombie_utility::ai_calculate_health( n_target_round );
zm::set_round_number( n_target_round - 1 );
// kill all active zombies
zombies = zombie_utility::get_round_enemy_array();
if ( isdefined( zombies ) )
{
array::run_all( zombies, &Kill );
}
level.sndGotoRoundOccurred = true;
level waittill( "between_round_over" );
}
// spawn ent at v_point and test if it's touching any enabled zone volume; return true/false
// this is a workaround for not having a good way of testing whether a point or struct is inside a volume for now
// ignore_zone - zone that we don't want to return true from
function is_point_inside_enabled_zone( v_origin, ignore_zone )
{
temp_ent = Spawn( "script_origin", v_origin );
foreach( zone in level.zones )
{
// If the zone hasn't been enabled, don't even bother checking
if ( !zone.is_enabled )
{
continue;
}
if( isdefined( ignore_zone ) && ( zone == ignore_zone ) )
{
continue;
}
// Okay check to see if an entity is in one of the zone volumes
foreach( e_volume in zone.volumes )
{
if ( temp_ent IsTouching( e_volume ) )
{
temp_ent Delete();
return true;
}
}
}
temp_ent Delete();
return false;
}
function clear_streamer_hint()
{
if ( IsDefined(self.streamer_hint) )
{
self.streamer_hint Delete();
self.streamer_hint = undefined;
}
self notify("wait_clear_streamer_hint");
}
function wait_clear_streamer_hint( lifetime )
{
self endon("wait_clear_streamer_hint");
wait lifetime;
if ( IsDefined(self) )
self clear_streamer_hint();
}
function create_streamer_hint( origin, angles, value, lifetime )
{
if ( self == level )
{
foreach( player in GetPlayers() )
{
player clear_streamer_hint();
}
}
self clear_streamer_hint();
self.streamer_hint = CreateStreamerHint( origin, value );
if ( IsDefined(angles) )
self.streamer_hint.angles = angles;
if ( self != level )
{
self.streamer_hint SetInvisibleToAll();
self.streamer_hint SetVisibleToPlayer( self );
}
self.streamer_hint SetIncludeMeshes( true );
self notify("wait_clear_streamer_hint");
if ( IsDefined(lifetime) && lifetime > 0 )
{
self thread wait_clear_streamer_hint(lifetime);
}
}
function approximate_path_dist( player )
{
AIProfile_BeginEntry( "approximate_path_dist" );
goal_pos = player.origin;
if ( isdefined( player.last_valid_position ) )
{
goal_pos = player.last_valid_position;
}
if ( IS_TRUE( player.b_teleporting ) )
{
if ( isdefined( player.teleport_location ) )
{
goal_pos = player.teleport_location;
if ( !IsPointOnNavmesh( goal_pos, self ) )
{
position = GetClosestPointOnNavMesh( goal_pos, 100, 15 );
if ( IsDefined( position ) )
{
goal_pos = position;
}
}
}
}
assert( IsDefined( level.pathdist_type ), "level.pathdist_type must be set before calling PathDistance" );
//PathDistance( <start>, <end>, <generatePathForAccurateDist>, <pathEnt>, <pathDistanceType>, <maxCornerPredictions> )
approx_dist = PathDistance( self.origin, goal_pos, true, self, level.pathdist_type );
AIProfile_EndEntry();
return approx_dist;
}
// Helper function for slowdowns
function register_slowdown( str_type, n_rate, n_duration )
{
if ( !isdefined( level.a_n_slowdown_rates ) )
{
level.a_n_slowdown_rates = [];
}
level.a_s_slowdowns[ str_type ] = SpawnStruct();
level.a_s_slowdowns[ str_type ].n_rate = n_rate;
level.a_s_slowdowns[ str_type ].n_duration = n_duration;
}
// All-purpose function to slow a zombie. Can handle slowdowns from multiple sources.
// The slowest rate will always be applied first, until it wears out, then the next highest one will be applied.
// str_type is the reason for the slow
// n_rate is the new animation rate
function slowdown_ai( str_type )
{
self notify( "starting_slowdown_ai" );
self endon( "starting_slowdown_ai" );
self endon( "death" );
Assert( isdefined( level.a_s_slowdowns[ str_type ] ), "Slowdown \"" + str_type + "\" must be registered through register_slowdown first" );
if ( !isdefined( self.a_n_slowdown_timeouts ) )
{
self.a_n_slowdown_timeouts = [];
}
n_time = GetTime();
n_timeout = n_time + level.a_s_slowdowns[ str_type ].n_duration;
// See if the slowdown is already being applied
if ( !isdefined( self.a_n_slowdown_timeouts[ str_type ] ) ||
self.a_n_slowdown_timeouts[ str_type ] < n_timeout )
{
self.a_n_slowdown_timeouts[ str_type ] = n_timeout;
}
// search for the lowest rate and apply that
while ( self.a_n_slowdown_timeouts.size )
{
str_lowest_type = undefined;
n_lowest_rate = 10.0;
foreach( str_index, n_slowdown_timeout in self.a_n_slowdown_timeouts )
{
//TODO Make sure clearing an entry doesn't mess up the foreach
// remove old expired times
if ( n_slowdown_timeout <= n_time )
{
self.a_n_slowdown_timeouts[ str_index ] = undefined;
continue;
}
if ( level.a_s_slowdowns[ str_index ].n_rate < n_lowest_rate )
{
str_lowest_type = str_index;
n_lowest_rate = level.a_s_slowdowns[ str_index ].n_rate;
}
}
if ( isdefined ( str_lowest_type ) )
{
// Apply the slowest rate
self ASMSetAnimationRate( n_lowest_rate );
n_duration = self.a_n_slowdown_timeouts[ str_lowest_type ] - n_time;
wait( n_duration );
// Remove slowdown
self.a_n_slowdown_timeouts[ str_lowest_type ] = undefined;
}
}
// No more slowdowns, return to normal
self ASMSetAnimationRate( 1.0 );
}
//*****************************************************************************
//*****************************************************************************
function get_player_closest_to( e_target )
{
a_players= ArrayCopy( level.activeplayers );
// If the target is also a player, remove it from the copied array of players.
ArrayRemoveValue( a_players, e_target );
e_closest_player = ArrayGetClosest( e_target.origin, a_players );
return e_closest_player;
}
//*****************************************************************************
//*****************************************************************************
function is_facing( facee, requiredDot = 0.5, b_2d = true )
{
orientation = self getPlayerAngles();
v_forward = anglesToForward( orientation );
v_to_facee = facee.origin - self.origin;
if( b_2d )
{
v_forward_computed = ( v_forward[0], v_forward[1], 0 );
v_to_facee_computed = ( v_to_facee[0], v_to_facee[1], 0 );
}
else
{
v_forward_computed = v_forward;
v_to_facee_computed = v_to_facee;
}
v_unit_forward_computed = VectorNormalize( v_forward_computed );
v_unit_to_facee_computed = VectorNormalize( v_to_facee_computed );
dotProduct = VectorDot( v_unit_forward_computed, v_unit_to_facee_computed );
return ( dotProduct > requiredDot ); // reviver is facing player within given dot tolerance.
}
//Returns true if the player is in a solo game that cannot be hotjoined
function is_solo_ranked_game()
{
return ( level.players.size == 1 && GetDvarInt( "zm_private_rankedmatch", 0 ) );
}
function upload_zm_dash_counters( force_upload = false ) {}
function upload_zm_dash_counters_end_game() {}
function increment_zm_dash_counter( counter_name, amount ) {}
function zm_dash_stats_game_start() {}
function zm_dash_stats_game_end() {}
function zm_dash_stats_wait_for_consumable_use() {}