cod4-sdk/raw/maps/village_defend.gsc

5439 lines
137 KiB
Text
Raw Normal View History

2008-01-19 00:00:00 +00:00
/****************************************************************************
Level: The Village (village_defend.bsp)
Location: Northern Azerbaijan
Campaign: British SAS Woodland Scheme
Objectives: 1. Obtain new orders from Captain Price.
2. Take up a defensive position along the ridgeline.
3. Defend the southern hill approach.
4. Fall back and defend the southwestern approaches.
5. Use the detonators to delay the enemy attack.
6. Get the Javelin.
7. Destroy the incoming armor.
8. Survive until the helicopter arrives.
9. Destroy the enemy attack helicopter.
10. Board the rescue helicopter before it leaves.
*****************************************************************************/
#include common_scripts\utility;
#include maps\_utility;
#include maps\_hud_util;
#include maps\_vehicle;
#include maps\_anim;
#include maps\village_defend_code;
main()
{
preCacheModel( "weapon_c4" );
preCacheModel( "projectile_cbu97_clusterbomb" );
preCacheModel( "tag_origin" );
preCacheModel( "weapon_javelin_obj" );
preCacheModel( "vehicle_av8b_harrier_jet" );
preCacheItem( "c4" );
preCacheItem( "javelin" );
preCacheItem( "airstrike_support" );
preCacheItem( "flash_grenade" );
precacheshader( "popmenu_bg" );
precacheshader( "compass_objpoint_airstrike" );
precacheShader( "hud_dpad" );
precacheShader( "hud_arrow_down" );
precacheShader( "white" );
precacheShader( "black" );
precacheShader( "hud_temperature_gauge" );
precachestring( &"VILLAGE_DEFEND_HINT_SPINUP_MINIGUN" );
precachestring( &"VILLAGE_DEFEND_HELICOPTER_EXTRACTION" );
precacheString( &"VILLAGE_DEFEND_CASREADY" );
precacheString( &"SCRIPT_PLATFORM_HINT_GET_DETONATOR" );
precachestring( &"VILLAGE_DEFEND_TAKE_UP_A_DEFENSIVE_POSITION" );
precachestring( &"VILLAGE_DEFEND_DEFEND_THE_SOUTHERN_HILL" );
precachestring( &"VILLAGE_DEFEND_FALL_BACK_AND_DEFEND" );
precachestring( &"VILLAGE_DEFEND_USE_THE_DETONATORS_IN" );
precachestring( &"VILLAGE_DEFEND_FALL_BACK_TO_THE_FARM" );
precachestring( &"VILLAGE_DEFEND_GET_THE_JAVELIN_IN_THE" );
precachestring( &"VILLAGE_DEFEND_SURVIVE_UNTIL_THE_HELICOPTER" );
precachestring( &"VILLAGE_DEFEND_GET_TO_THE_LZ" );
precachestring( &"VILLAGE_DEFEND_BOARD_THE_HELICOPTER" );
precachestring( &"VILLAGE_DEFEND_USE_THE_DETONATORS_IN1" );
precachestring( &"VILLAGE_DEFEND_DESTROY_THE_INCOMING" );
precachestring( &"VILLAGE_DEFEND_OBTAIN_NEW_ORDERS_FROM" );
precachestring( &"VILLAGE_DEFEND_YOU_DIDNT_REACH_THE_HELICOPTER" );
precachestring( &"VILLAGE_DEFEND_CLOSE_AIR_SUPPORT_STANDING" );
precachestring( &"VILLAGE_DEFEND_CLOSE_AIR_SUPPORT_STANDING_PC" );
precachestring( &"VILLAGE_DEFEND_INTRO_1" );
precachestring( &"VILLAGE_DEFEND_INTRO_2" );
precachestring( &"VILLAGE_DEFEND_INTRO_3" );
precachestring( &"VILLAGE_DEFEND_INTRO_4" );
precachestring( &"VILLAGE_DEFEND_INTRO_5" );
precachestring( &"VILLAGE_DEFEND_DESTROY_THE_INCOMING1" );
precachestring( &"VILLAGE_DEFEND_AIRSTRIKE_UNAVAIL" );
precachestring( &"SCRIPT_PLATFORM_SPOOL_MINIGUN" );
precacherumble( "minigun_rumble" );
set_console_status();
//add_start( "cobras", ::start_cobras );
//add_start( "end", ::start_end );
add_start( "southern_hill", ::start_southern_hill, &"STARTS_SOUTHERNHILL" );
add_start( "minigun_fallback", ::start_minigun_fallback, &"STARTS_MINIGUNFALLBACK" );
add_start( "minigun", ::start_minigun, &"STARTS_MINIGUN" );
add_start( "helidrop", ::start_helidrop, &"STARTS_HELIDROP" );
add_start( "clackers", ::start_clackers, &"STARTS_CLACKERS" );
add_start( "field_fallback", ::start_field_fallback, &"STARTS_FIELDFALLBACK" );
add_start( "javelin", ::start_javelin, &"STARTS_JAVELIN" );
add_start( "final_battle", ::start_final_battle, &"STARTS_FINALBATTLE" );
add_start( "seaknight", ::start_seaknight, &"STARTS_SEAKNIGHT1" );
default_start( ::start_village_defend );
createthreatbiasgroup( "player" );
level.weaponClipModels = [];
level.weaponClipModels[ 0 ] = "weapon_ak47_clip";
level.weaponClipModels[ 1 ] = "weapon_saw_clip";
level.weaponClipModels[ 2 ] = "weapon_g36_clip";
level.weaponClipModels[ 3 ] = "weapon_ak74u_clip";
level.weaponClipModels[ 4 ] = "weapon_dragunov_clip";
level.weaponClipModels[ 5 ] = "weapon_mp5_clip";
level.weaponClipModels[ 6 ] = "weapon_m16_clip";
maps\_t72::main( "vehicle_t72_tank_woodland" );
maps\_mi17::main( "vehicle_mi17_woodland_fly_cheap" );
//maps\_mig29::main( "vehicle_mig29_desert" );
maps\_seaknight_village_defend::main( "vehicle_ch46e" );
thread maps\_pipes::main();
thread maps\_leak::main();
maps\_load::set_player_viewhand_model( "viewhands_player_sas_woodland" );
maps\village_defend_fx::main();
maps\village_defend_anim::main();
maps\_load::main();
maps\_javelin::init();
level thread maps\village_defend_amb::main();
level.killzoneBigExplosion_fx = loadfx( "explosions/artilleryExp_dirt_brown_low" );
level.killzoneMudExplosion_fx = loadfx( "explosions/grenadeExp_mud_1" );
level.killzoneDirtExplosion_fx = loadfx( "explosions/grenadeExp_dirt_1" );
level.killzoneFuelExplosion_fx = loadfx( "explosions/grenadeExp_fuel" );
level.air_support_fx_yellow = loadfx( "misc/ui_pickup_available" );
level.air_support_fx_red = loadfx( "misc/ui_pickup_unavailable" );
killzoneFxProgram();
maps\createart\village_defend_art::main();
maps\_compass::setupMiniMap("compass_map_village_defend");
level.price = getent( "price", "targetname" );
level.price make_hero();
level.price.animname = "price";
level.gaz = getent( "redshirt2", "targetname" );
level.gaz make_hero();
level.gaz.animname = "gaz";
level.redshirt = getent( "redshirt1", "targetname" );
battlechatter_off( "allies" );
battlechatter_off( "axis" );
setdvar( "village_defend_one_minute", "0" );
flag_init( "intro_tank_fire_authorization" );
flag_init( "church_tower_explodes" );
flag_init( "stop_ambush_music" );
flag_init( "objective_price_orders_southern_hill" );
flag_init( "objective_player_on_ridgeline" );
flag_init( "objective_price_on_ridgeline" );
flag_init( "objective_on_ridgeline" );
flag_init( "objective_price_orders_minigun" );
flag_init( "objective_player_uses_minigun" );
flag_init( "objective_player_at_vantage_point" );
flag_init( "price_ordered_hill_detonation" );
flag_init( "southern_hill_action_started" );
flag_init( "southern_hill_killzone_detonate" );
flag_init( "southern_mg_openfire" );
flag_init( "southern_hill_smoked" );
flag_init( "southern_hill_smoke_entry" );
flag_init( "enemy_breached_wire" );
flag_init( "ridgeline_targeted" );
flag_init( "ridgeline_unsafe" );
flag_init( "disable_overheat" );
flag_init( "helidrop_started" );
flag_init( "objective_minigun_baglimit_done" );
flag_init( "divert_for_clacker" );
flag_init( "stop_minigun_fallback_shouting" );
flag_init( "objective_detonators" );
flag_init( "detonators_activate" );
flag_init( "got_the_clacker" );
flag_init( "clacker_has_been_exercised" );
flag_init( "crashsite_exploded" );
flag_init( "cliffside_exploded" );
flag_init( "nearslope_exploded" );
flag_init( "farslope_exploded" );
flag_init( "clacker_far_and_near_slope_done" );
flag_init( "spawncull" );
flag_init( "player_entered_clacker_house_top_floor" );
flag_init( "storm_the_tavern" );
flag_init( "player_running_to_farm" );
flag_init( "fall_back_to_barn" );
flag_init( "farm_reached" );
flag_init( "objective_armor_arrival" );
flag_init( "got_the_javelin" );
flag_init( "objective_all_tanks_destroyed" );
flag_init( "kill_jav_glow" );
flag_init( "start_final_battle" );
flag_init( "return_trip_begins" );
flag_init( "airstrikes_ready" );
flag_init( "falcon_one_finished_talking" );
flag_init( "engage_delaying_action" );
flag_init( "objective_get_to_lz" );
flag_init( "rescue_chopper_ingress" );
flag_init( "seaknight_can_be_boarded" );
flag_init( "lz_reached" );
flag_init( "no_more_grenades" );
flag_init( "player_made_it" );
flag_init( "player_made_it_with_rescue" );
flag_init( "minigun_lesson_learned" );
flag_init( "all_fake_friendlies_aboard" );
flag_init( "all_real_friendlies_on_board" );
flag_init( "seaknight_guards_boarding" );
flag_init( "seaknight_unboardable" );
flag_init( "aa_southernhill" );
flag_init( "aa_minigun" );
flag_init( "aa_detonators" );
flag_init( "aa_fallback" );
flag_init( "aa_javelin" );
flag_init( "aa_returntrip" );
flag_init( "airstrike_in_progress" );
if (level.gameSkill == 0)
{
level.southernHillAdvanceBaglimit = 4;
level.minigunBreachBaglimit = 4;
}
if (level.gameSkill == 1)
{
level.southernHillAdvanceBaglimit = 6;
level.minigunBreachBaglimit = 6;
}
if (level.gameSkill == 2)
{
level.southernHillAdvanceBaglimit = 8;
level.minigunBreachBaglimit = 8;
}
if (level.gameSkill == 3)
{
level.southernHillAdvanceBaglimit = 10;
level.minigunBreachBaglimit = 10;
}
level.hint_text_size = 1.6;
if ( getdvar( "village_defend_one_minute") != "1" )
level.stopwatch = 4; //minutes
else
level.stopwatch = 1; //minutes
level.encroachMinWait = 3;
level.encroachMaxWait = 5;
assertEX( level.encroachMinWait < level.encroachMaxWait, "encroachMinWait must be less than encroachMaxWait!" );
level.magicSniperTalk = true;
level.southern_hill_magic_sniper_min_cycletime = 5;
level.southern_hill_magic_sniper_max_cycletime = 15;
level.southernMortarIntroTimer = 3.5; //this many seconds before Price mentions mortars and order the team to pull back
level.southernMortarKillTimer = 25; //this many seconds before player is struck by enemy mortars in the ridgeline area
level.genericBaitCount = 0; //circulates spare enemies to the clacker bait locations for the clacker objective
level.irrelevantDist = 1000;
level.irrelevantPopLimit = 8;
level.divertClackerRange = 1000; //distance beyond which enemies will break off attacking the player and move to a prearranged spot
level.encroachRate = 0.85; //percentage of goal reduction per encroaching iteration
level.objectiveClackers = 0;
level.tankPop = 4;
level.tankid = 0;
level thread minigun_const();
run_thread_on_targetname( "minigun", ::minigun_think );
level.aSpawners = getspawnerarray();
level.aRouteNodes = getnodearray( "flanking_route", "targetname" );
level.airstrikeCalledRecently = false;
level.airStriker = level.player;
//Primary Zone Spawn Controllers
level.maxAI = 32;
level.reqSlots = 8;
level.detectionCycleTime = 45;
level.smokeBuildTime = 8;
level.smokeSpawnSafeDist = 640;
level.detectionRefreshTime = 3;
level.volumeDesertionTime = 6;
//Airstrike Controllers
level.lowplaneflyby = 0;
level.strikeZoneGracePeriod = 20;
level.airstrikeCooldown = 135;
level.dangerCloseSafeDist = 1200;
level.airstrikeSupportCallsRemaining = 5;
level.sasSeaKnightBoarded = 0;
level.minigunSessions = 0;
level.delayingActionEnemyWaves = 0;
level.activeAirstrikes = 0;
if( level.gameskill == 0 )
level.enemyWavesAllowed = 1;
else
if( level.gameskill == 1 )
level.enemyWavesAllowed = 3;
else
if( level.gameskill == 2 )
level.enemyWavesAllowed = 4;
else
if( level.gameskill == 3 )
level.enemyWavesAllowed = 5;
level.sniperfx = "weap_m40a3sniper_fire_village";
level thread objectives();
level thread magic_sniper();
level thread southern_hill_ambush_mg();
level thread southern_hill_vanguard_setup();
level thread friendly_setup();
level thread southern_hill_killzone_sequence();
level thread helidrop();
level thread clacker_init();
level thread clacker_primary_attack();
level thread player_interior_detect_init();
level thread enemy_interior_flashbangs();
level thread javelin_init();
level thread tanks_init();
level thread barn_helidrop();
level thread field_fallback();
level thread barn_fallback();
level thread final_battle();
level thread autosaves_return_trip();
level thread airstrike_command();
level thread begin_delaying_action();
level thread begin_delaying_action_timeout();
level thread player_detection_volume_init();
level thread escape_fallback();
level thread music();
level thread seaknight_music();
level thread southern_hill_shotmonitor();
level thread return_trip_friendly_boost();
diff = [];
diff[ 0 ] = 0.3;
diff[ 1 ] = 0.6;
diff[ 2 ] = 1;
diff[ 3 ] = 1.2;
level.village_diff = diff;
level thread return_trip_enemy_acc_prep();
//Left trigger spin functionality for console controllers
if( level.console )
{
level thread minigun_firstuse_check();
//level thread minigun_session_check();
add_hint_string( "minigun_spin_left_trigger", &"SCRIPT_PLATFORM_SPOOL_MINIGUN", maps\village_defend::should_break_minigun_spin_hint );
}
level.playerSafetyBlocker = getent( "helo_safety_blocker", "targetname" );
level.playerSafetyBlocker notsolid();
}
should_break_minigun_spin_hint()
{
minigun = getent( "minigun", "targetname" );
minigunUser = minigun getTurretOwner();
if ( !isdefined( minigunUser ) )
return true;
if ( !flag( "minigun_lesson_learned" ) )
return false;
return level.player == minigunUser;
}
start_village_defend()
{
thread intro();
level.start_intro = true;
level.player setthreatbiasgroup( "player" );
setignoremegroup( "axis", "allies" ); // allies ignore axis
setignoremegroup( "allies", "axis" ); // axis ignore allies
setignoremegroup( "player", "axis" ); // axis ignore player
}
start_southern_hill()
{
level.player setthreatbiasgroup( "player" );
setignoremegroup( "axis", "allies" ); // allies ignore axis
setignoremegroup( "allies", "axis" ); // axis ignore allies
setignoremegroup( "player", "axis" ); // axis ignore player
flag_set( "church_tower_explodes" );
flag_set( "objective_price_orders_southern_hill" );
flag_set( "objective_player_on_ridgeline" );
//flag_set( "objective_price_on_ridgeline" );
flag_set( "objective_on_ridgeline" );
playerStart = getnode( "player_southern_start", "targetname" );
level.player setorigin (playerStart.origin);
priceStart = getnode( "price_southern_start", "targetname" );
level.price = getent( "price", "targetname" );
level.price teleport (priceStart.origin);
introHillTrigs = getentarray( "introHillTrig", "targetname" );
for( i = 0 ; i < introHillTrigs.size; i++ )
{
introHillTrigs[ i ] notify ("trigger");
}
//thread intro_tankdrive();
thread southern_hill_defense();
}
start_minigun_fallback()
{
//Advance objectives, set past game states
flag_set( "stop_ambush_music" );
flag_set( "objective_player_on_ridgeline" );
flag_set( "church_tower_explodes" );
flag_set( "objective_price_orders_southern_hill" );
flag_set( "objective_on_ridgeline" );
flag_set( "southern_hill_killzone_detonate" );
//Position player
//playerStart = getnode( "player_start_minigun", "targetname" );
playerStart = getnode( "player_southern_start", "targetname" );
level.player setorigin (playerStart.origin);
//Position friendlies
priceStart = getnode( "price_southern_start", "targetname" );
level.price = getent( "price", "targetname" );
level.price teleport (priceStart.origin);
thread moveRedshirts( "redshirt_southern_start1", "redshirt_southern_start2" );
//Restore game state
introHillTrigs = getentarray( "introHillTrig", "targetname" );
for( i = 0 ; i < introHillTrigs.size; i++ )
{
introHillTrigs[ i ] notify ("trigger");
}
thread southern_hill_smokescreens();
thread saw_gunner_friendly();
}
start_minigun()
{
//Advance objectives, set past game states
flag_set( "stop_ambush_music" );
flag_set( "church_tower_explodes" );
flag_set( "objective_price_orders_southern_hill" );
flag_set( "objective_on_ridgeline" );
flag_set( "objective_player_on_ridgeline" );
flag_set( "southern_hill_killzone_detonate" );
flag_set( "objective_price_orders_minigun" );
flag_set( "southern_hill_smoke_entry" );
//Position player
playerStart = getnode( "player_start_minigun", "targetname" );
level.player setorigin (playerStart.origin);
//Position friendlies
priceStart = getnode( "fallback_price", "targetname" );
level.price = getent( "price", "targetname" );
level.price teleport (priceStart.origin);
level.price setgoalnode( priceStart );
thread moveRedshirts( "fallback_redshirt1", "fallback_redshirt2" );
//Restore game state
thread southern_hill_mortars_killtimer();
thread minigun_primary_attack();
thread minigun_smokescreens();
thread saw_gunner_friendly();
}
start_helidrop()
{
//Advance objectives, set past game states
flag_set( "stop_ambush_music" );
flag_set( "church_tower_explodes" );
flag_set( "objective_price_orders_southern_hill" );
flag_set( "objective_on_ridgeline" );
flag_set( "objective_player_on_ridgeline" );
flag_set( "southern_hill_killzone_detonate" );
flag_set( "objective_price_orders_minigun" );
flag_set( "southern_hill_smoke_entry" );
flag_set( "objective_minigun_baglimit_done" );
flag_set( "divert_for_clacker" );
//Position player
playerStart = getnode( "player_start_minigun", "targetname" );
level.player setorigin (playerStart.origin);
//Position friendlies
priceStart = getnode( "fallback_price", "targetname" );
level.price = getent( "price", "targetname" );
level.price teleport (priceStart.origin);
level.price setgoalnode( priceStart );
thread moveRedshirts( "fallback_redshirt1", "fallback_redshirt2" );
//Restore game state
thread southern_hill_mortars_killtimer();
thread minigun_primary_attack();
thread minigun_smokescreens();
thread saw_gunner_friendly();
}
start_clackers()
{
//Advance objectives, set past game states
flag_set( "stop_ambush_music" );
flag_set( "church_tower_explodes" );
flag_set( "objective_price_orders_southern_hill" );
flag_set( "objective_on_ridgeline" );
flag_set( "objective_player_on_ridgeline" );
flag_set( "southern_hill_killzone_detonate" );
flag_set( "objective_price_orders_minigun" );
flag_set( "southern_hill_smoke_entry" );
flag_set( "objective_detonators" );
flag_set( "detonators_activate" );
//Position player
playerStart = getnode( "player_start_clacker", "targetname" );
level.player setorigin (playerStart.origin);
//Restore game state
thread southern_hill_mortars_killtimer();
thread minigun_primary_attack();
thread minigun_smokescreens();
thread saw_gunner_friendly();
wait 7;
flag_set( "objective_minigun_baglimit_done" );
flag_set( "divert_for_clacker" );
}
start_field_fallback()
{
//Advance objectives, set past game states
flag_set( "stop_ambush_music" );
flag_set( "church_tower_explodes" );
flag_set( "objective_price_orders_southern_hill" );
flag_set( "objective_on_ridgeline" );
flag_set( "objective_player_on_ridgeline" );
flag_set( "southern_hill_killzone_detonate" );
flag_set( "objective_price_orders_minigun" );
flag_set( "southern_hill_smoke_entry" );
flag_set( "objective_detonators" );
flag_set( "divert_for_clacker" );
flag_set( "fall_back_to_barn" );
flag_set( "barn_assault_begins" );
flag_set( "objective_armor_arrival" );
flag_set( "storm_the_tavern" );
//Position player
playerStart = getnode( "player_start_clacker", "targetname" );
level.player setorigin (playerStart.origin);
//Restore game state
thread southern_hill_mortars_killtimer();
thread minigun_primary_attack();
thread minigun_smokescreens();
thread saw_gunner_friendly();
}
start_javelin()
{
//Advance objectives, set past game states
flag_set( "stop_ambush_music" );
flag_set( "church_tower_explodes" );
flag_set( "objective_price_orders_southern_hill" );
flag_set( "objective_on_ridgeline" );
flag_set( "objective_player_on_ridgeline" );
flag_set( "southern_hill_killzone_detonate" );
flag_set( "objective_price_orders_minigun" );
flag_set( "southern_hill_smoke_entry" );
flag_set( "objective_detonators" );
flag_set( "divert_for_clacker" );
flag_set( "fall_back_to_barn" );
flag_set( "farm_reached" );
flag_set( "barn_assault_begins" );
flag_set( "objective_armor_arrival" );
flag_set( "storm_the_tavern" );
//Position player
level.player setorigin ( ( 1021, 7309, 1006 ) );
//Restore game state
//thread southern_hill_mortars_killtimer();
//thread minigun_primary_attack();
//thread minigun_smokescreens();
thread saw_gunner_friendly();
}
start_final_battle()
{
//Advance objectives, set past game states
flag_set( "stop_ambush_music" );
flag_set( "church_tower_explodes" );
flag_set( "objective_price_orders_southern_hill" );
flag_set( "objective_on_ridgeline" );
flag_set( "objective_player_on_ridgeline" );
flag_set( "southern_hill_killzone_detonate" );
flag_set( "objective_price_orders_minigun" );
flag_set( "southern_hill_smoke_entry" );
flag_set( "objective_detonators" );
flag_set( "divert_for_clacker" );
flag_set( "fall_back_to_barn" );
flag_set( "barn_assault_begins" );
flag_set( "objective_armor_arrival" );
flag_set( "farm_reached" );
flag_set( "got_the_javelin" );
flag_set( "objective_all_tanks_destroyed" );
flag_set( "airstrikes_ready" );
flag_set( "storm_the_tavern" );
flag_set( "start_final_battle" );
//Position player
level.player setorigin ( ( 1021, 7309, 1006 ) );
//Restore game state
//thread southern_hill_mortars_killtimer();
//thread minigun_primary_attack();
//thread minigun_smokescreens();
thread saw_gunner_friendly();
//Delete the barbed wire
barbedDets = getentarray( "barbed_wire_detonator", "targetname" );
thread minigun_barbed_wire_detonate( "southern_hill_barbed_wire_wall_1", barbedDets );
wait 2;
thread minigun_barbed_wire_detonate( "southern_hill_barbed_wire_wall_2", barbedDets );
wait 3;
thread minigun_barbed_wire_detonate( "southern_hill_barbed_wire_wall_3", barbedDets );
}
start_seaknight()
{
//Advance objectives, set past game states
flag_set( "stop_ambush_music" );
flag_set( "church_tower_explodes" );
flag_set( "objective_price_orders_southern_hill" );
flag_set( "objective_on_ridgeline" );
flag_set( "objective_player_on_ridgeline" );
flag_set( "southern_hill_killzone_detonate" );
flag_set( "objective_price_orders_minigun" );
flag_set( "southern_hill_smoke_entry" );
flag_set( "objective_detonators" );
flag_set( "divert_for_clacker" );
flag_set( "fall_back_to_barn" );
flag_set( "farm_reached" );
flag_set( "barn_assault_begins" );
flag_set( "objective_armor_arrival" );
flag_set( "got_the_javelin" );
flag_set( "objective_all_tanks_destroyed" );
flag_set( "airstrikes_ready" );
flag_set( "storm_the_tavern" );
flag_set( "rescue_chopper_ingress" );
//Position player
level.player setorigin ( ( -64, -1904, -80 ) );
//Restore game state
//thread southern_hill_mortars_killtimer();
//thread minigun_primary_attack();
//thread minigun_smokescreens();
thread saw_gunner_friendly();
//Delete the barbed wire
barbedDets = getentarray( "barbed_wire_detonator", "targetname" );
thread minigun_barbed_wire_detonate( "southern_hill_barbed_wire_wall_1", barbedDets );
thread minigun_barbed_wire_detonate( "southern_hill_barbed_wire_wall_2", barbedDets );
thread minigun_barbed_wire_detonate( "southern_hill_barbed_wire_wall_3", barbedDets );
wait 0.05;
aAxis = getaiarray( "axis" );
for( i = 0; i < aAxis.size; i++ )
{
aAxis[ i ] delete();
}
}
moveRedshirts( node1, node2 )
{
redshirt1 = getent( "redshirt1", "targetname" );
redshirt2 = getent( "redshirt2", "targetname" );
redshirt_node1 = getnode( node1, "targetname" );
redshirt_node2 = getnode( node2, "targetname" );
redshirt1 teleport ( redshirt_node1.origin );
redshirt1 setgoalnode ( redshirt_node1 );
redshirt2 teleport ( redshirt_node2.origin );
redshirt2 setgoalnode ( redshirt_node2 );
}
intro()
{
thread intro_loudspeaker();
aAllies = getaiarray( "allies" );
for( i = 0 ; i < aAllies.size; i++ )
{
aAllies[ i ].dontavoidplayer = true;
aAllies[ i ].baseaccuracy = 15;
}
aAllies = remove_heroes_from_array( aAllies );
for( i = 0 ; i < aAllies.size; i++ )
{
aAllies[ i ] allowedstances ("crouch");
aAllies[ i ].disableArrivals = true;
aAllies[ i ].ignoresuppression = true;
}
introTrigs = getentarray( "introTrig", "targetname" );
for( i = 0 ; i < introTrigs.size; i++ )
{
introTrigs[ i ] notify ("trigger");
}
for( i = 0 ; i < aAllies.size; i++ )
{
aAllies[i] allowedStances ("stand", "crouch", "prone");
}
wait 18;
price_intro_route = getnode( "price_intro_route", "targetname" );
redshirt1 = getent( "redshirt1", "targetname" );
redshirt2 = getent( "redshirt2", "targetname" );
//redshirt_routes = [];
redshirt_route1 = getnode( "sas1_intro_route", "targetname" );
redshirt_route2 = getnode( "sas2_intro_route", "targetname" );
level.price thread followScriptedPath( price_intro_route, undefined, "prone" );
redshirt1 thread followScriptedPath( redshirt_route1, 0.75, "prone" );
redshirt2 thread followScriptedPath( redshirt_route2, 0.75, "prone" );
//wait 6.5;
wait 1;
//"Ignore that load of bollocks. Their counterattack is imminent. Spread out and cover the southern approach."
//iprintln( "Their counterattack is imminent. Spread out and cover the southern approach." );
level.price anim_single_queue( level.price, "spreadout" );
flag_set( "objective_price_orders_southern_hill" );
thread intro_ridgeline_check( level.player, "player_southern_start" );
thread intro_ridgeline_check( level.price, "price_southern_start" );
thread intro_hillpatrol_check();
//"Bell tower here. Two enemy squads forming up to the south."
//iprintln( "Bell tower here. Two enemy squads forming up to the south." );
//radio_dialogue_queue( "belltowerhere" );
//wait 6.2;
//"Sir, they're slowly coming up the hill. Just say when."
//iprintln( "Sir, they're slowly coming up the hill. Just say when." );
radio_dialogue_queue( "justsaywhen" );
thread southern_hill_defense();
}
intro_church_tower_explode()
{
temp_tower_sequence = getent( "intro_tank_tower_target", "targetname" );
wait 2;
temp_tower_sequence playsound ( "artillery_incoming" );
wait 1;
//incoming tracer and explosion
exploder( 1000 );
wait 1.1;
exploder( 1001 );
temp_tower_sequence playsound( "exp_bell_tower" );
earthquake( 0.65, 1, temp_tower_sequence.origin, 3000 );
flag_set( "church_tower_explodes" );
deathVolume = getent( "church_explosion_damage", "targetname" );
for( i = 0; i < 20; i++ )
{
if( level.player isTouching( deathVolume ) )
level.player doDamage( level.player.health + 10000, level.player.origin );
wait 0.05;
}
}
intro_hillpatrol_check()
{
trig = getent( "hill_patrol_trig", "targetname" );
trig waittill ( "trigger" );
flag_set( "objective_player_on_ridgeline" );
}
intro_ridgeline_check( guy, nodename )
{
ridgelinePos = getnode( nodename, "targetname" );
dist = length(level.player.origin - ridgelinePos.origin);
//Wait for guy to reach his place on the ridgeline
while(dist > 128)
{
dist = length(guy.origin - ridgelinePos.origin);
wait 0.1;
}
if( guy == level.price )
flag_set( "objective_on_ridgeline" );
//flag_set( "objective_price_on_ridgeline" );
if( guy == level.player )
{
//flag_set( "objective_on_ridgeline" );
//flag_set( "objective_player_on_ridgeline" );
flag_set( "objective_player_at_vantage_point" );
}
}
intro_loudspeaker()
{
//Ultranationalist Russian commander demanding the surrender of the SAS troops
aSpeakerTalk = [];
//TEMP DIALOGUE
//"Surrender at once and your lives will be spared. I am sure you will make the right choice given the circumstances."
aSpeakerTalk[ 0 ] = "villagedef_rul_surrenderatonce";
//TEMP DIALOGUE
//"Drop your weapons and surrender at once. You will not be harmed if you surrender."
aSpeakerTalk[ 1 ] = "villagedef_rul_dropyourweapons";
//TEMP DIALOGUE
//"We know you are hiding in the village. You are surrounded, there is nowhere to run. Surrender and make it easy on yourselves."
aSpeakerTalk[ 2 ] = "villagedef_rul_weknowyourehiding";
aSpeakers = getentarray( "russian_loudspeaker", "targetname" );
speakerCount = aSpeakers.size;
j = 0;
for( i = 0; i < aSpeakerTalk.size; i++ )
{
if( j >= speakerCount)
j = 0;
play_sound_in_space( aSpeakerTalk[ i ], aSpeakers[ j ].origin);
wait randomfloatrange( 5 , 8);
j++;
}
}
southern_hill_defense()
{
thread southern_hill_intro();
thread southern_hill_intro_interrupt();
thread southern_hill_panic_screaming();
thread southern_hill_javelin();
thread southern_hill_ambush();
thread southern_hill_primary_attack();
thread southern_hill_baglimit();
}
southern_hill_primary_attack()
{
//level endon ( "objective_player_uses_minigun" );
level endon ( "southern_hill_smoked" );
startNode = getnode( "southern_hill_waypoint", "targetname" );
unitName = "southern_hill_assaulter";
endonMsg = "southern_hill_attack_stop";
squad1 = "spawnRock";
squad2 = "spawnRoad";
squad3 = "spawnGas";
level endon ( endonMsg );
flag_wait( "southern_hill_killzone_detonate" );
wait 1;
while( 1 )
{
thread encroach_start( startNode, unitName, endonMsg, squad1, "southern_hill" );
thread encroach_start( startNode, unitName, endonMsg, squad2, "southern_hill" );
thread encroach_start( startNode, unitName, endonMsg, squad3, "southern_hill" );
wait randomfloat( 6, 8 );
thread encroach_start( startNode, unitName, endonMsg, squad2, "southern_hill" );
thread encroach_start( startNode, unitName, endonMsg, squad2, "southern_hill" );
thread encroach_start( startNode, unitName, endonMsg, squad3, "southern_hill" );
wait randomfloat( 8, 10 );
thread encroach_start( startNode, unitName, endonMsg, squad1, "southern_hill" );
thread encroach_start( startNode, unitName, endonMsg, squad3, "southern_hill" );
thread encroach_start( startNode, unitName, endonMsg, squad2, "southern_hill" );
wait randomfloat( 10, 12 );
}
}
magic_sniper()
{
flag_wait( "southern_hill_killzone_detonate" );
wait 2;
n = undefined;
j = 0;
magic_sniper = getent( "southern_hill_magic_sniper", "targetname" );
//sniperfx = "weap_m40a3sniper_fire_village";
while( 1 )
{
aAxis = [];
aValidSniperTargets = [];
aAxis = getaiarray( "axis" ); //bad get?
for( i = 0; i < aAxis.size; i++ )
{
guy = aAxis[ i ];
if( !isdefined( guy.targetname ) && !isdefined( guy.script_noteworthy ) )
continue;
if( guy.script_noteworthy == "spawnGas" )
{
aValidSniperTargets[ aValidSniperTargets.size ] = guy;
}
else
if( guy.script_noteworthy == "spawnRoad" )
{
aValidSniperTargets[ aValidSniperTargets.size ] = guy;
}
else
if( guy.script_noteworthy == "spawnRock" )
{
aValidSniperTargets[ aValidSniperTargets.size ] = guy;
}
else
if( isdefined( guy.targetname ) && guy.targetname == "vanguard" )
{
aValidSniperTargets[ aValidSniperTargets.size ] = guy;
}
else
if ( guy.script_noteworthy == "spawnHillFence" )
{
aValidSniperTargets[ aValidSniperTargets.size ] = guy;
}
else
if ( guy.script_noteworthy == "spawnHillChurch" )
{
aValidSniperTargets[ aValidSniperTargets.size ] = guy;
}
else
if ( guy.script_noteworthy == "spawnHillGraveyard" )
{
aValidSniperTargets[ aValidSniperTargets.size ] = guy;
}
else
if ( guy.script_noteworthy == "spawnHillFlank" )
{
aValidSniperTargets[ aValidSniperTargets.size ] = guy;
}
}
if( aValidSniperTargets.size == 0 )
{
wait 1;
continue;
}
n = randomint( aValidSniperTargets.size );
sniperTarget = aValidSniperTargets[ n ];
magic_sniper playsound( level.sniperfx );
sniperTarget doDamage ( sniperTarget.health + 100, (0, 0, 0) );
if( level.magicSniperTalk )
{
if( j == 0 )
{
//"Target down."
radio_dialogue_queue( "targetdown" );
j++;
}
else
if( j == 1 )
{
//"Got him."
radio_dialogue_queue( "gothim" );
j++;
}
else
if( j == 2 )
{
//"Target eliminated."
radio_dialogue_queue( "targeteliminated" );
j++;
}
else
if( j == 3 )
{
//"Goodbye."
radio_dialogue_queue( "goodbye" );
j = 0;
}
}
aAxis = undefined;
aValidSniperTargets = undefined;
cycleDelay = randomfloatrange( level.southern_hill_magic_sniper_min_cycletime, level.southern_hill_magic_sniper_max_cycletime );
wait cycleDelay;
}
}
southern_hill_vanguard_setup()
{
vanguards = [];
vanguards = getentarray( "vanguard", "targetname" );
for( i = 0; i < vanguards.size; i++ )
{
vanguards[ i ].goalradius = 16;
}
flag_wait( "objective_player_on_ridgeline" );
//flag_wait( "objective_price_on_ridgeline" );
//flag_wait( "objective_on_ridgeline" );
for( i = 0; i < vanguards.size; i++ )
{
//vanguards[ i ] enable_cqbwalk();
if( isdefined( vanguards[ i ] ) )
{
vanguards[ i ].animname = "axis";
vanguards[ i ] set_run_anim( "patrolwalk_" + ( randomint(5) + 1 ) );
vanguards[ i ] thread southern_hill_vanguard_nav();
vanguards[ i ] thread southern_hill_vanguard_wakeup();
vanguards[ i ] thread southern_hill_deathmonitor();
vanguards[ i ] thread southern_hill_damagemonitor();
}
wait 0.05;
}
}
southern_hill_vanguard_nav()
{
self endon ( "death" );
node = undefined;
if( !isdefined( self.script_noteworthy ) )
{
node = getnode( "default_vanguard_dest", "targetname" );
}
else
{
nodes = getnodearray( "vanguard_node", "targetname" );
for( i = 0; i < nodes.size; i++ )
{
assertEX( isdefined( nodes[ i ].script_noteworthy ), "vanguard_node without a script_noteworthy" );
if( self.script_noteworthy == nodes[ i ].script_noteworthy )
{
node = nodes[ i ];
break;
}
}
}
self setgoalnode( node );
self.goalradius = 2048;
self thread southern_hill_vanguard_aim();
}
southern_hill_vanguard_aim()
{
self endon ( "death" );
aimpoints = [];
aimpoints = getentarray( "vanguard_aimpoint", "targetname" );
while( 1 )
{
i = randomint( aimpoints.size );
self cqb_aim ( aimpoints[ i ] );
wait randomfloat(1, 2);
}
}
southern_hill_vanguard_wakeup()
{
self endon ( "death" );
flag_wait( "southern_hill_action_started" );
self clear_run_anim();
}
southern_hill_timeout()
{
//timeout on waiting for player if player was close to Price at the time Price reached his goal
wait 10;
flag_set( "objective_player_at_vantage_point" );
}
southern_hill_intro()
{
level endon ( "intro_hill_interrupted" );
flag_wait( "objective_player_on_ridgeline" ); //guys are walking
//flag_wait( "objective_price_on_ridgeline" );
flag_wait( "objective_on_ridgeline" ); //price is there
dist = length( level.player.origin - level.price.origin );
if( dist < 512 )
{
thread southern_hill_timeout();
flag_wait( "objective_player_at_vantage_point" ); //wait longer if player is likely following price
}
wait 6;
if( !flag( "southern_hill_action_started" ) )
{
//"Do it."
//iprintln( "Do it." );
flag_set( "price_ordered_hill_detonation" );
radio_dialogue_queue( "doit" );
}
//"Ka-boom."
//iprintln( "Ka-boom." );
radio_dialogue_queue( "kaboom" );
if( !flag( "southern_hill_action_started" ) )
{
flag_set( "southern_hill_killzone_detonate" );
wait 0.5;
flag_set( "southern_hill_action_started" );
}
else
{
flag_set( "southern_hill_killzone_detonate" );
}
}
southern_hill_intro_interrupt()
{
//if a grenade is thrown by the player and kills an enemy on the hill or the player opens fire, start the battle
flag_wait( "southern_hill_action_started" );
level notify ( "intro_hill_interrupted" );
flag_set( "southern_hill_action_started" );
wait 0.35;
if( !flag( "price_ordered_hill_detonation" ) )
{
radio_dialogue_queue( "doit" );
radio_dialogue_queue( "kaboom" );
}
flag_set( "southern_hill_killzone_detonate" );
}
southern_hill_ambush()
{
flag_wait( "southern_hill_action_started" );
//wait 0.15;
flag_set( "southern_mg_openfire" );
//wait 0.3;
setthreatbias( "player", "axis", 0 ); // axis fight player
setthreatbias( "allies", "axis", 0 ); // axis fight allies
setthreatbias( "axis", "allies", 0 ); // allies fight axis
flag_wait( "southern_hill_killzone_detonate" );
wait 2;
//"OPEN FIIRRRRRE!!!!!"
//iprintln( "OPEN FIIRRRRRE!!!!!" );
level.price thread anim_single_queue( level.price, "openfire" );
wait 1;
battlechatter_on( "allies" );
}
southern_hill_killzone_sequence()
{
killzone1 = [];
killzone2 = [];
killzone1point = getent( "southern_hill_killzone_1", "targetname" );
killzone2point = getent( "southern_hill_killzone_2", "targetname" );
while( 1 )
{
killzone1[ killzone1.size ] = killzone1point;
if( isdefined( killzone1point.target ) )
killzone1point = getent( killzone1point.target, "targetname" );
else
break;
wait 0.05;
}
while( 1 )
{
killzone2[ killzone2.size ] = killzone2point;
if( isdefined( killzone2point.target ) )
killzone2point = getent( killzone2point.target, "targetname" );
else
break;
wait 0.05;
}
flag_wait( "southern_hill_killzone_detonate" );
battlechatter_on( "axis" );
thread killzone_detonation( killzone1 );
wait 1.25;
thread killzone_detonation( killzone2 );
wait 2;
flag_set( "stop_ambush_music" );
musicStop( 1 );
}
southern_hill_panic_screaming()
{
//level endon ( "temp_demo_stopshooting" ); //TEMP LEVEL STOP FOR DEMOING PURPOSES ONLY
level endon ( "stop_hill_screaming" );
flag_wait( "southern_hill_action_started" );
speakers = getentarray( "ambush_speaker", "targetname" );
for( j = 0; j < 4; j++ )
{
for( i = 0; i < speakers.size; i++ )
{
speaker = speakers[ i ];
play_sound_in_space( "RU_1_reaction_casualty_generic", speaker.origin );
wait 1;
play_sound_in_space( "RU_1_order_move_generic", speaker.origin );
wait 1;
play_sound_in_space( "RU_1_order_attack_infantry", speaker.origin );
wait 1;
play_sound_in_space( "RU_1_order_action_coverme", speaker.origin );
wait 1;
play_sound_in_space( "RU_1_inform_suppressed_generic", speaker.origin );
wait 1;
play_sound_in_space( "RU_1_order_action_suppress", speaker.origin );
wait 1;
play_sound_in_space( "RU_1_response_ack_covering", speaker.origin );
wait 1;
play_sound_in_space( "RU_1_response_ack_follow", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru4_helpmeimwounded", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru1_noicantmove", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru2_death", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru3_death", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru4_wheretheyshooting", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru1_icantseethem", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru2_underheavyfire", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru4_reinforcements", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru1_goaroundwest", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru4_imhitmedic", speaker.origin );
wait 1;
play_sound_in_space( "villagedef_ru1_medic", speaker.origin );
wait 1;
}
}
}
southern_hill_ambush_mg()
{
southern_sas_mg = getent( "southern_house_manual_mg", "targetname" );
southern_sas_mg setmode( "manual" );
southern_sas_mg thread southern_hill_mg_targeting();
flag_wait( "southern_mg_openfire" );
southern_sas_mg thread manual_mg_fire();
}
southern_hill_mg_targeting()
{
level endon ( "sawgunner_moving" );
targets = getentarray( self.target, "targetname" );
n = 0;
while( 1 )
{
target = random( targets );
self settargetentity( target );
wait( randomfloatrange( 1, 5 ) );
n++;
//Occasionally pick off a bad guy
if( n > 8 )
{
aAxis = [];
aAxis = getaiarray( "axis" );
if( aAxis.size )
{
target = random( aAxis );
self settargetentity( target );
wait( randomfloatrange( 1, 2 ) );
n = 0;
aAxis = undefined;
}
else
{
break;
}
}
}
}
manual_mg_fire()
{
level endon( "sawgunner_moving" );
self.turret_fires = true;
n = 0;
for ( ;; )
{
timer = randomfloatrange( 0.4, 0.7 ) * 20;
if ( self.turret_fires )
{
for ( i = 0; i < timer; i++ )
{
self shootturret();
wait( 0.05 );
}
}
n++;
//time between bursts
wait( randomfloat( 3.3, 6 ) );
if(n >= 10)
{
//pretend reloading
wait randomfloat( 6.1, 7.4 );
n = 0;
}
}
}
southern_hill_javelin()
{
flag_wait( "southern_hill_action_started" );
wait 4;
//"Nice shot mate!"
radio_dialogue_queue( "niceshotmate" );
}
southern_hill_baglimit()
{
i=0;
speakers = getentarray( "ambush_speaker", "targetname" );
while( i < level.southernHillAdvanceBaglimit )
{
level waittill ( "player_killed_southern_hill_enemy" );
i++;
if( i == level.southernHillAdvanceBaglimit / 2 )
{
speaker = speakers[ randomint( speakers.size ) ];
play_sound_in_space( "villagedef_ru1_mustbetwoplatoons", speaker.origin );
wait 2;
//"Squad, hold your ground, they think we're a larger force than we really are."
radio_dialogue_queue( "largerforce" );
//"Copy."
radio_dialogue_queue( "copy" );
}
}
thread saw_gunner_friendly();
wait 7;
flag_set( "southern_hill_smoked" );
wait 20;
thread southern_hill_smokescreens();
}
southern_hill_deathmonitor()
{
self waittill ( "death", nAttacker );
flag_set( "southern_hill_action_started" );
if( isdefined( nAttacker ) && nAttacker == level.player )
{
level notify ( "player_killed_southern_hill_enemy" );
}
}
southern_hill_damagemonitor()
{
self waittill ( "damage", nAttacker );
flag_set( "southern_hill_action_started" );
}
southern_hill_shotmonitor()
{
trig = getent( "hill_patrol_shotdetector", "targetname" );
/*
trig waittill ( "damage", nAttacker );
if( isdefined( nAttacker ) && nAttacker == level.player )
{
flag_set( "southern_hill_action_started" );
}
*/
trig waittill ( "trigger" );
flag_set( "southern_hill_action_started" );
}
saw_gunner_friendly()
{
//spawn the SAW gunner
sasGunner = getent( "sasGunner", "targetname" );
level.sasGunner = sasGunner doSpawn();
if( spawn_failed( level.sasGunner ) )
{
return;
}
sasGunnerNode = getnode( "fallback_sasGunner", "targetname" );
level.sasGunner setgoalnode( sasGunnerNode );
level.sasGunner thread hero();
level.sasGunner.ignoreSuppression = true;
//level.sasGunner.baseaccuracy = 1;
flag_wait( "objective_minigun_baglimit_done" );
}
/*
intro_tankdrive()
{
tank = spawn_vehicle_from_targetname_and_drive( "intro_tank" );
node = getVehicleNode( "intro_tank_church_aim", "targetname" );
targetpoint = getent( "intro_tank_tower_target", "targetname" );
tank setwaitnode(node);
tank waittill ("reached_wait_node");
tank setTurretTargetEnt( targetpoint );
tank waittill_notify_or_timeout( "turret_rotate_stopped", 5.0 );
flag_wait( "intro_tank_fire_authorization" );
tank fireweapon();
}
*/
southern_hill_smokescreens()
{
//playfx(level.smokegrenade, smokeSquad.origin);
//smokescreen_southern_hill
speakers = getentarray( "ambush_speaker", "targetname" );
speaker = speakers[ randomint( speakers.size ) ];
play_sound_in_space( "villagedef_ru2_putupsmokescreen", speaker.origin );
aSmokes = getentarray( "smokescreen_southern_hill", "targetname" );
for( i = 0; i < aSmokes.size; i++ )
{
playfx(level.smokegrenade, aSmokes[ i ].origin);
}
level notify ( "sawgunner_moving" );
wait 2;
level notify ( "stop_hill_screaming" );
level.magicSniperTalk = false;
wait 2;
//"They're putting up smokescreens. Mac - you see anything?"
//iprintln( "They're putting up smokescreens. Mac - you see anything?" );
radio_dialogue_queue( "smokescreensmac" );
wait 0.5;
//"Not much movement on the road. They might be moving to our west."
//iprintln( "Not much movement on the road. They might be moving to our west." );
radio_dialogue_queue( "notmuchmovement" );
wait 4;
thread southern_hill_mortars();
while( !flag( "objective_player_uses_minigun" ) && !flag( "ridgeline_unsafe" ) )
{
for( i = 0; i < aSmokes.size; i++ )
{
playfx(level.smokegrenade, aSmokes[ i ].origin);
wait randomfloatrange( 1.2, 2.3 );
}
wait 32;
}
}
southern_hill_mortars()
{
//mortars start hitting around on the fake points
//Price orders everyone to fall back to the next defensive zone
//Price tells the player to get on the minigun
//after the friendlies are out of the killzone, mortars start hitting around the real points
//if the player enters the killzone after the timeout, he is killed by a magic mortar
//use level.killzoneBigExplosion_fx
aHits = getentarray( "southern_hill_mortar_hit", "targetname" );
aRealHits = getentarray( "southern_hill_mortar_hit_real", "targetname" );
thread minigun_fallback();
thread southern_hill_mortars_killtimer();
thread southern_hill_mortars_timing( "southern_hill_mortar_hit", "ridgeline_unsafe", 192 );
//start the barbed wire breach concealing smoke when the player killing mortars start happening
flag_set( "southern_hill_smoke_entry" );
thread minigun_smokescreens();
flag_wait( "ridgeline_unsafe" );
thread southern_hill_mortars_timing( "southern_hill_mortar_hit_real", "enemy_breached_wire", 0 );
wait 1.5;
thread minigun_primary_attack();
}
minigun_smokescreens()
{
//level endon ( "enemy_breached_wire" );
level endon ( "objective_detonators" );
aSmokes = getentarray( "smokescreen_barbed_wire", "targetname" );
//while( !flag( "enemy_breached_wire" ) )
while( 1 )
{
if( flag( "southern_hill_smoke_entry" ) )
{
for( i = 0; i < aSmokes.size; i++ )
{
playfx(level.smokegrenade, aSmokes[ i ].origin);
wait randomfloatrange( 1.2, 2.3 );
}
wait 28;
}
wait 0.25;
}
}
southern_hill_mortars_timing( mortarMsg, endonMsg, safeDist )
{
assertEX( isdefined( mortarMsg ), "mortarMsg not defined" );
assertEX( isdefined( endonMsg ), "endonMsg not defined" );
assertEX( isdefined( safeDist ), "safeDist not defined" );
level endon ( endonMsg );
aHits = getentarray( mortarMsg, "targetname" );
aHits = array_randomize(aHits);
while( !flag( endonMsg ) )
{
for( i = 0; i < aHits.size; i++ )
{
hit = aHits[ i ];
dist = distance(level.player.origin, hit.origin);
if( dist > safeDist )
{
southern_hill_mortar_detonate( hit );
wait randomfloatrange( 0.7, 1.4 );
}
}
aHits = array_randomize(aHits);
}
}
southern_hill_mortars_killtimer()
{
wait level.southernMortarIntroTimer;
flag_set( "ridgeline_targeted" );
wait level.southernMortarKillTimer;
flag_set( "ridgeline_unsafe" );
//wait 20;
thread southern_hill_mortars_killplayer();
}
southern_hill_mortars_killplayer()
{
//Blows up player if player is too close to the ridgeline after Price orders the team to fall back
level endon ( "arm_delaying_action" );
dangerZone = getent( "ridgeline_dangerarea", "targetname" );
while( 1 )
{
if( level.player isTouching( dangerZone ) )
{
wait 2;
if ( level.player isTouching( dangerZone ) )
{
thread southern_hill_mortar_detonate( level.player );
level.player doDamage( level.player.health + 10000, level.player.origin );
}
}
wait 0.5;
}
}
minigun_fallback()
{
flag_wait( "ridgeline_targeted" );
autosave_by_name( "ridgeline_under_mortar_fire" );
redshirt1 = getent( "redshirt1", "targetname" );
redshirt2 = getent( "redshirt2", "targetname" );
redshirt_node1 = getnode( "fallback_redshirt1", "targetname" );
redshirt_node2 = getnode( "fallback_redshirt2", "targetname" );
//"They're targeting our position with mortars. It's time to fall back."
//iprintln( "They're targeting our position with mortars. It's time to fall back." );
radio_dialogue_queue( "targetingour" );
thread minigun_orders();
wait 2;
//"Two, falling back."
radio_dialogue_queue( "twofallingback" );
redshirt1 allowedstances ( "stand", "crouch", "prone" );
redshirt1 setgoalnode( redshirt_node1 );
wait randomfloatrange( 0.7, 1.2 );
//"Three, on the move."
radio_dialogue_queue( "threeonthemove" );
redshirt2 allowedstances ( "stand", "crouch", "prone" );
redshirt2 setgoalnode( redshirt_node2 );
priceNode = getnode( "fallback_price", "targetname" );
level.price allowedstances ( "stand", "crouch", "prone" );
level.price setgoalnode( priceNode );
//"Three here. Two's in the far eastern building. We've got the eastern road locked down."
radio_dialogue_queue( "easternroadlocked" );
level.price.baseaccuracy = 1;
level.price.ignoreSuppression = true;
redshirt1.baseaccuracy = 1;
redshirt1.ignoreSuppression = true;
redshirt2.baseaccuracy = 1;
redshirt2.ignoreSuppression = true;
thread friendly_pushplayer( "off" );
wait 5;
thread intro_church_tower_explode();
}
minigun_orders()
{
level endon ( "objective_player_uses_minigun" );
level endon ( "objective_minigun_baglimit_done" );
//Price gives orders for the minigun.
flag_set( "objective_price_orders_minigun" );
//"Right. Soap, get to the minigun and cover the western flank. Go."
//iprintln( "Right. Soap, get to the minigun and cover the western flank. Go." );
radio_dialogue_queue( "minigunflank" );
thread minigun_use();
thread minigun_arming_check();
n = 0;
cycleTime = 30;
while( 1 )
{
wait cycleTime;
if( n == 0 )
{
//"Soap, get to the minigun! Move! It's attached to the crashed helicopter."
radio_dialogue_queue( "miniguncrashed" );
}
if( n == 1 )
{
//"Soap, the minigun's online. It's in the crashed helicopter."
radio_dialogue_queue( "gazminigunonline" );
}
if( n == 2 )
{
//"Soap, I need you to operate the minigun! Get your arse moving!"
radio_dialogue_queue( "minigunarse" );
}
if( n == 3 )
{
//Soap. The minigun is inside the crashed helicopter.
radio_dialogue_queue( "priceminiguninheli" );
}
if( n == 4 )
{
//Soap, get inside the crashed helicopter and use the minigun!
level.gaz anim_single_queue( level.gaz, "gazuseminigun" );
}
if( n == 5 )
{
//"Get on the minigun in the helicopter. Move!"
radio_dialogue_queue( "priceminiguninhelimove" );
n = 0;
cycleTime = 65;
continue;
}
n++;
}
}
minigun_fallback_shouting()
{
level endon ( "stop_minigun_fallback_shouting" );
minigun = getent( "minigun", "targetname" );
minigunNagDelayTime = 5;
normalNagDelayTime = 10;
normalNagOnly = false;
n = 0;
k = 0;
m = 0;
j = 0;
while( !flag( "stop_minigun_fallback_shouting" ) )
{
minigunUser = minigun getTurretOwner();
if( isdefined( minigunUser ) && !normalNagOnly )
{
if( k == 2 )
{
normalNagOnly = true;
continue;
}
if( n == 0 )
{
//GAZ: Soaap!!! Get off the miniguun! We're faalling baack!
radio_dialogue_queue( "detminigunfallbackremind1" );
}
if( n == 1 )
{
//GAZ: Forget the minigun! We've go to go! NOW!
radio_dialogue_queue( "detminigunfallbackremind2" );
n = 0;
k++;
wait minigunNagDelayTime * 3;
continue;
}
n++;
wait minigunNagDelayTime;
}
else
{
/*
if( m == 3 )
{
break;
}
*/
if( j == 0 )
{
//GAZ: Soap! We're falling back to the next phase line! Let's go! Let's go! You're gonna be left behind!!
radio_dialogue_queue( "detfallbackremind1" );
}
if( j == 1 )
{
//GAZ: Let's gooo!!! Fall back now!!!
radio_dialogue_queue( "detfallbackremind2" );
}
if( j == 2 )
{
//PRICE: Soap! Fall back to the next phase line! You're going to get overrun!
radio_dialogue_queue( "detfallbackremind3" );
j = 0;
//m++;
continue;
}
j++;
wait normalNagDelayTime;
}
}
}
minigun_fallback_shouting_cancel()
{
trig = getent( "minigun_fallback_shouting", "targetname" );
trig waittill ( "trigger" );
flag_set( "stop_minigun_fallback_shouting" );
thread clacker_use_shouting();
}
clacker_use_shouting()
{
level endon ( "clacker_has_been_exercised" );
wait 5;
//n = 0;
while( !flag( "clacker_has_been_exercised" ) )
{
/*
if( n == 2 )
{
break;
}
*/
//GAZ: Soap! Use the detonators! There's four of them in the tavern! Move!
radio_dialogue_queue( "detuseremind1" );
wait 20;
//GAZ: The detonators are on the second floor of the tavern! Check your compass and move! We'll try to hold them off!
radio_dialogue_queue( "detuseremind2" );
wait 25;
//n++;
}
}
minigun_use()
{
flag_wait( "objective_player_uses_minigun" );
level notify ( "southern_hill_attack_stop" ); //stops southern hill attack
}
minigun_primary_attack()
{
//Mortar shreds the barbed wire out of the way on the southern hill
barbedDets = getentarray( "barbed_wire_detonator", "targetname" );
thread minigun_barbed_wire_detonate( "southern_hill_barbed_wire_wall_1", barbedDets );
wait 2;
thread minigun_barbed_wire_detonate( "southern_hill_barbed_wire_wall_2", barbedDets );
wait 3;
thread minigun_barbed_wire_detonate( "southern_hill_barbed_wire_wall_3", barbedDets );
autosave_by_name( "southwestern_flanking_assault" );
thread minigun_breach_baglimit();
//startNode = getnode( "southern_hill_waypoint", "targetname" );
//unitName = "southern_hill_assaulter";
//endonMsg = "southern_hill_attack_stop";
//squad1 = "spawnRock";
//squad2 = "spawnRoad";
//squad3 = "spawnGas";
//thread encroach_start( startNode, unitName, endonMsg, squad1, "southern_hill" );
startnode1 = getnode( "southern_hill_breach_church", "targetname" );
startnode2 = getnode( "southern_hill_breach_graveyard", "targetname" );
startnode3 = getnode( "southern_hill_breach_housegap", "targetname" );
startnode4 = getnode( "southern_hill_breach_flank", "targetname" );
unitName = "southern_hill_breacher";
endonMsg = "halfway_through_field"; //enemy continues to attack heavily until player is in the barn and has picked up the javelin
squad1 = "spawnHillChurch";
squad2 = "spawnHillGraveyard";
squad3 = "spawnHillFence";
squad4 = "spawnHillFlank";
deathmonitorName = "minigun_breach";
level endon ( endonMsg );
while( 1 )
{
thread encroach_start( startNode2, unitName, endonMsg, squad1, deathmonitorName );
thread encroach_start( startNode2, unitName, endonMsg, squad2, deathmonitorName );
thread encroach_start( startNode3, unitName, endonMsg, squad3, deathmonitorName );
wait randomfloatrange( 6, 8 );
thread encroach_start( startNode1, unitName, endonMsg, squad1, deathmonitorName );
thread encroach_start( startNode2, unitName, endonMsg, squad2, deathmonitorName );
thread encroach_start( startNode1, unitName, endonMsg, squad3, deathmonitorName );
wait randomfloatrange( 9, 11 );
thread encroach_start( startNode3, unitName, endonMsg, squad1, deathmonitorName );
thread encroach_start( startNode2, unitName, endonMsg, squad2, deathmonitorName );
thread encroach_start( startNode2, unitName, endonMsg, squad3, deathmonitorName );
//thread encroach_start( startNode4, unitName, endonMsg, squad4, deathmonitorName );
wait randomfloatrange( 12, 14 );
}
}
minigun_breach_deathmonitor()
{
self waittill ( "death", nAttacker );
if( isdefined( nAttacker ) && nAttacker == level.player )
{
level notify ( "player_killed_minigun_breach_enemy" );
}
}
minigun_breach_baglimit()
{
i=0;
while( i < level.minigunBreachBaglimit )
{
level waittill ( "player_killed_minigun_breach_enemy" );
i++;
}
flag_set( "objective_minigun_baglimit_done" );
flag_set( "divert_for_clacker" );
}
minigun_barbed_wire_detonate( barricade, detonators )
{
obstacle = getentarray( barricade, "targetname" );
for( i = 0; i < detonators.size; i++ )
{
det = detonators[ i ];
if( !isdefined( det.script_noteworthy ) )
continue;
if( det.script_noteworthy != barricade )
continue;
playfx( level.megaExplosion, det.origin );
det playsound( "explo_mine" );
earthquake( 0.5, 0.5, level.player.origin, 1250 );
radiusDamage(det.origin, 256, 1000, 500); //radiusDamage(origin, range, maxdamage, mindamage);
}
for( i = 0; i < obstacle.size; i++ )
{
obstacle[ i ] delete();
}
flag_set( "enemy_breached_wire" );
level.magicSniperTalk = true;
}
minigun_firstuse_check()
{
while( !flag( "minigun_lesson_learned" ) )
{
minigun = getent( "minigun", "targetname" );
minigun waittill( "turretownerchange" );
minigunUser = minigun getTurretOwner();
if( !isdefined( minigunUser) )
{
level notify ( "minigun_session" );
continue;
}
if( level.console )
thread display_hint( "minigun_spin_left_trigger" );
}
}
/*
minigun_session_check()
{
//First three uses, player gets the hint to use left trigger
while( level.minigunSessions < 2 )
{
level waittill ( "minigun_session" );
level.minigunSessions++;
}
flag_set( "minigun_lesson_learned" );
}
*/
minigun_arming_check()
{
//Checks to see if the player is on the minigun.
//Lowers enemy AI accuracy when player is on the minigun.
minigun = getent( "minigun", "targetname" );
while(1)
{
minigunUser = minigun getTurretOwner();
if( !isdefined( minigunUser ) )
{
minigun waittill("turretownerchange");
minigunUser = minigun getTurretOwner();
}
wait 1;
if((isdefined(minigunUser) && level.player != minigunUser) || !isdefined(minigunUser))
{
aEnemy = [];
aEnemy = getaiarray( "axis" );
/*
for( i = 0; i < aEnemy.size; i++ )
{
aEnemy[ i ].baseAccuracy = 8;
}
*/
}
if( (isdefined(minigunUser) && level.player == minigunUser) )
{
if( !flag( "objective_player_uses_minigun" ) )
{
flag_set( "objective_player_uses_minigun" );
wait 2.5;
//"Soap. Keep the minigun spooled up. Fire in bursts, 30 seconds max."
radio_dialogue_queue( "spooledup" );
}
aEnemy = [];
aEnemy = getaiarray( "axis" );
/*
for( i = 0; i < aEnemy.size; i++ )
{
aEnemy[ i ].baseAccuracy = 5;
}
*/
}
}
}
helidrop()
{
flag_wait( "objective_minigun_baglimit_done" );
flag_set( "helidrop_started" );
level.magicSniperTalk = false;
spawn_vehicle_from_targetname_and_drive( "helidrop_01" );
spawn_vehicle_from_targetname_and_drive( "helidrop_02" );
spawn_vehicle_from_targetname_and_drive( "helidrop_03" );
spawn_vehicle_from_targetname_and_drive( "helidrop_04" );
spawn_vehicle_from_targetname_and_drive( "helidrop_05" );
thread helidrop_rider_setup( "helidrop_01" );
thread helidrop_rider_setup( "helidrop_02" );
thread helidrop_rider_setup( "helidrop_03" );
thread helidrop_rider_setup( "helidrop_04" );
thread helidrop_rider_setup( "helidrop_05" );
wait 20;
//"We've got a problem here...heads up!"
radio_dialogue_queue( "headsup" );
//"Bloody hell, that's a lot of helis innit?"
radio_dialogue_queue( "lotofhelis" );
//"Soap, fall back to the tavern and man the detonators."
//iprintln( "Soap, fall back to the tavern and man the detonators." );
radio_dialogue_queue( "tavern" );
flag_set( "objective_detonators" );
flag_set( "detonators_activate" );
//"The rest of us will keep them busy from the next defensive line. Everyone move!"
//iprintln( "The rest of us will keep them busy from the next defensive line. Everyone move!" );
radio_dialogue_queue( "nextdefensiveline" );
priceNode = getnode( "clacker_fallback_price", "targetname" );
level.price setgoalnode( priceNode );
level.price thread hero_scripted_travel();
redshirt1 = getent( "redshirt1", "targetname" );
redshirt_node1 = getnode( "clacker_fallback_redshirt1", "targetname" );
redshirt1 setgoalnode( redshirt_node1 );
redshirt1 thread hero_scripted_travel();
redshirt2 = getent( "redshirt2", "targetname" );
redshirt_node2 = getnode( "clacker_fallback_redshirt2", "targetname" );
redshirt2 setgoalnode( redshirt_node2 );
redshirt2 thread hero_scripted_travel();
sasGunnerNode = getnode( "clacker_fallback_sasGunner", "targetname" );
level.sasGunner setgoalnode( sasGunnerNode );
level.sasGunner thread hero_scripted_travel();
thread minigun_fallback_shouting_cancel();
thread minigun_fallback_shouting();
}
hero_scripted_travel()
{
self.disableArrivals = true;
self.goalradius = 16;
self waittill ( "goal" );
wait 2;
self.disableArrivals = false;
self.goalradius = 2048;
}
helidrop_rider_setup( heliName )
{
heli = getent( heliName, "targetname" );
aRiders = heli.riders;
for( i = 0; i < aRiders.size; i++ )
{
rider = aRiders[ i ];
rider thread hunt_player( heli );
rider thread helidrop_clacker_divert( heli );
}
}
hunt_player( heli )
{
self endon ( "death" );
self endon ( "going_to_baitnode" );
if( isdefined( heli ) )
heli waittill ( "unloaded" );
self.goalradius = 1800;
//Adjust accuracy of helidrop troops to make them more effective in the larger spaces inherent in this layout
/*
switch( level.gameSkill )
{
case 0:
self.baseAccuracy = 1;
break;
case 1:
self.baseAccuracy = 2;
break;
case 2:
self.baseAccuracy = 4;
break;
case 3:
self.baseAccuracy = 5;
break;
}
*/
//Encroach on the player and kill the player
//When player enters the upper floor of the clacker house a flag is set
self.pathenemyfightdist = 1800;
self.pathenemylookahead = 1800;
playerHeliDetector = getent( "player_in_blackhawk_detector", "targetname" );
heliDefaultNode = getnode( "bait_crashsite", "targetname" );
while( self.goalradius > 640 )
{
if( level.player isTouching( playerHeliDetector ) )
{
self setgoalnode( heliDefaultNode );
}
else
{
self setgoalpos( level.player.origin );
}
self.goalradius = self.goalradius * level.encroachRate;
self waittill ( "goal" );
wait randomintrange( 10, 15 );
}
}
helidrop_clacker_divert( heli )
{
self endon ( "death" );
if( isdefined( heli ) )
heli waittill ( "unloaded" );
flag_wait( "player_entered_clacker_house_top_floor" );
self notify ( "going_to_baitnode" );
//if enemy is already within X of player, commits to pursuing player
//outside of X enemy will maneuver to killzone
baitNode = undefined;
if( isdefined( self.script_noteworthy ) )
{
if( self.script_noteworthy == "helidrop_bait_grassyknoll" && !flag( "farslope_exploded" ) )
{
baitNode = getnode( "bait_farslope", "targetname" );
}
else
if( self.script_noteworthy == "helidrop_bait_grassyknoll" && flag( "farslope_exploded" ) && !flag( "nearslope_exploded") )
{
baitNode = getnode( "bait_nearslope", "targetname" );
}
else
if( self.script_noteworthy == "helidrop_bait_grassyknoll" && flag( "farslope_exploded" ) && flag( "nearslope_exploded" ) )
{
if( flag( "fall_back_to_barn" ) )
flag_wait( "storm_the_tavern" );
self thread hunt_player();
return;
}
else
if( self.script_noteworthy == "helidrop_bait_crashsite" && !flag( "crashsite_exploded" ) )
{
baitNode = getnode( "bait_crashsite", "targetname" );
}
else
if( self.script_noteworthy == "helidrop_bait_crashsite" && flag( "crashsite_exploded" ) && !flag( "cliffside_exploded" ) )
{
baitNode = getnode( "bait_crashsite", "targetname" );
}
else
if( self.script_noteworthy == "helidrop_bait_crashsite" && flag( "crashsite_exploded" ) && flag( "cliffside_exploded" ) )
{
baitNode = getnode( "bait_crashsite", "targetname" ); //best blocking position
}
else
if( self.script_noteworthy == "helidrop_bait_trees" && !flag( "cliffside_exploded" ) )
{
baitNode = getnode( "bait_trees", "targetname" );
}
if( self.script_noteworthy == "helidrop_bait_trees" && flag( "cliffside_exploded" ) && !flag( "crashsite_exploded" ) )
{
baitNode = getnode( "bait_crashsite", "targetname" );
}
else
if( self.script_noteworthy == "spawnHillFlank" )
{
baitNode = getnode( "bait_nearslope", "targetname" );
}
else
{
self.goalradius = 2400;
switch( level.genericBaitCount )
{
case 0:
baitNode = getnode( "bait_nearslope", "targetname" );
level.genericBaitCount++;
break;
case 1:
baitNode = getnode( "bait_trees", "targetname" );
level.genericBaitCount = 0;
break;
}
}
}
else
{
if( flag( "fall_back_to_barn" ) )
flag_wait( "storm_the_tavern" );
self thread hunt_player();
return;
}
distToPlayer = distance( level.player.origin, self.origin );
wait 0.5;
distToBaitNode = distance( baitNode.origin, self.origin );
if( ( level.divertClackerRange < distToPlayer ) && ( distToBaitNode < distToPlayer ) )
{
self setgoalnode( baitNode );
}
flag_wait( "fall_back_to_barn" );
//Storm the tavern and the player hardcore
//wait randomfloatrange( 1.5, 2.8 );
if( flag( "fall_back_to_barn" ) )
flag_wait( "storm_the_tavern" );
self thread hunt_player();
}
tavern_storming_delay()
{
trig = getent( "tavern_fallback_shouting", "targetname" );
trig thread tavern_stop_shouting();
thread tavern_storming_hints();
wait 5;
if( !flag( "player_running_to_farm" ) )
flag_clear( "can_save" );
wait 55;
flag_set( "storm_the_tavern" );
}
tavern_storming_hints()
{
level endon ( "stop_shouting_tavern" );
flag_wait( "objective_armor_arrival" );
for( i = 0; i < 2; i++ )
{
//PRICE: "Fall back to the farm at the top of the hill. Let's go. Now."
radio_dialogue_queue( "fallbacktofarm1" );
wait 1;
if( i < 1 )
{
//GAZ: "FALL BAAACK!!! FAALLL BAACK!!!"
level.gaz anim_single_queue( level.gaz, "fallbackgeneric" );
}
wait 1;
if( i < 1 )
{
//GAZ: "Head for the farm to the north! Go! Go! Go!"
level.gaz anim_single_queue( level.gaz, "fallbacktofarm3" );
}
wait 12;
//PRICE: "Soap! You wanna be left behind? Fall back to the farm. Move!"
radio_dialogue_queue( "fallbacktofarm2" );
wait 12;
//GAZ: "Soap! They're going to overrun your position! Fall back now!"
radio_dialogue_queue( "tavernoverrunsoon" );
wait 10;
}
}
tavern_stop_shouting()
{
self waittill ( "trigger" );
level notify ( "stop_shouting_tavern" );
flag_set( "player_running_to_farm" );
flag_set( "can_save" );
autosave_by_name( "running_to_farm" );
}
clacker_primary_attack()
{
flag_wait( "objective_minigun_baglimit_done" );
flag_set( "spawncull" );
thread clacker_nearfarslope_check();
startnode4 = getnode( "southern_hill_breach_flank", "targetname" );
unitName = "southern_hill_breacher";
endonMsg = "clacker_far_and_near_slope_done";
squad4 = "spawnHillFlank";
level endon ( endonMsg );
startAttackTrig = getent( "nearfarslope_activation", "targetname" );
startAttackTrig waittill ( "trigger" );
flag_set( "player_entered_clacker_house_top_floor" );
autosave_by_name( "player_entered_clacker_house" );
flag_wait( "helidrop_started" );
while( 1 )
{
aAxis = undefined;
aAxis = [];
aAxis = getaiarray( "axis" );
if( aAxis.size < 27 )
{
thread encroach_start( startNode4, unitName, endonMsg, squad4, undefined );
wait randomfloatrange( 2, 3 );
}
wait 0.5;
}
}
clacker_nearfarslope_check()
{
//if player has detonated the near and far slope mines, then stop attacks from the southern hill left flank
flag_wait( "nearslope_exploded" );
flag_wait( "farslope_exploded" );
flag_set( "clacker_far_and_near_slope_done" );
}
clacker_init()
{
aUseTrigs = getentarray( "detonator_usetrig", "targetname" );
aDets = [];
detEnts = [];
det = undefined;
for( i = 0; i < aUseTrigs.size; i++ )
{
if( !isdefined( aUseTrigs[ i ].target ) )
continue;
detEnts = getentarray( aUseTrigs[ i ].target, "targetname" );
for( j = 0; j < detEnts.size; j++ )
{
det = detEnts[ j ];
if( !isdefined( det.script_namenumber ) )
continue;
if( det.script_namenumber == "objective_clacker" )
{
level.objectiveClackers++;
aDets[ aDets.size ] = det;
det hide();
}
}
detEnts = [];
}
for( i = 0; i < aDets.size; i++ )
{
markers = [];
markers = aDets[ i ] clacker_marker_setup();
aDets[ i ] thread clacker_standby( markers );
}
}
clacker_marker_setup()
{
markers = [];
currentMarker = getent( self.target, "targetname" );
while( 1 )
{
markers[ markers.size ] = currentMarker;
if( isdefined( currentMarker.target ) )
currentMarker = getent( currentMarker.target, "targetname" );
else
break;
wait 0.05;
}
return( markers );
}
clacker_standby( markers )
{
assertEX( isdefined( self.targetname ), "clacker use trigger should target the clacker" );
trig = getent( self.targetname, "target" );
assertEX( isdefined( self.script_noteworthy ), "useVolume should have a targetname matching the clacker script_noteworthy" );
useVolume = getent( self.script_noteworthy, "targetname" );
flag_wait( "detonators_activate" );
self show();
trigFlag = trig.script_flag_true;
flag_set( trigFlag );
while( 1 )
{
self thread clacker_markers( useVolume, markers );
trig sethintstring( &"SCRIPT_PLATFORM_HINT_GET_DETONATOR" );
trig waittill ( "trigger" );
self thread clacker_enable( trig, useVolume, markers );
self thread clacker_notouch( trig, useVolume );
}
}
clacker_markers( useVolume, detMarkers )
{
//Display the marker effects
objGroup = undefined;
while( isdefined( useVolume ) )
{
if( level.player isTouching( useVolume ) )
{
setthreatbias( "player", "axis", 50 ); //don't shoot player as much when at detonator window
//effect = spawnFx( getfx( "firelp_small_dl" ), markerPos.origin + (0, 0, 64) );
objGroup = [];
for( i = 0; i < detMarkers.size; i++ )
{
obj = spawn( "script_model", ( 0, 0, 0 ) );
obj setModel( "tag_origin" );
obj.angles = ( -90, 0, 0 );
obj.origin = detMarkers[ i ].origin;
objGroup[ objGroup.size ] = obj;
playfxontag( getfx( "killzone_marker" ), obj, "tag_origin" );
}
}
while( isdefined( useVolume) && level.player isTouching( useVolume ) )
{
wait 0.1;
}
//Remove the glowing hint effects for the killzone if they were generated previously
if( isdefined( objGroup ) )
{
assertEX( objGroup.size > 0, "there are no detMarkers to delete" );
count = objGroup.size;
for( i = 0; i < count; i++ )
{
objGroup[ i ] delete();
}
objGroup = undefined;
setthreatbias( "player", "axis", 1000 ); //resume normal aggression when player is not near a detonator window
}
wait 0.1;
}
}
clacker_enable( trig, useVolume, markers )
{
if( level.player isTouching( useVolume ) )
{
self hide(); //hide the prop clacker
//Bring up the clacker in hand
flag_set( "got_the_clacker" );
level.player maps\_c4::switch_to_detonator();
self thread clacker_drop( trig, useVolume );
//The use trigger for this specific clacker is deactivated while player has the clacker
trigFlag = trig.script_flag_true;
flag_clear( trigFlag );
//trig hide();
//trig trigger_off();
self thread clacker_fire( trig, useVolume, markers );
while( level.player getcurrentweapon() != "c4" )
{
wait 0.05;
}
flag_clear( "got_the_clacker" );
}
}
clacker_drop( trig, useVolume )
{
//detects when player switches to another weapon, which automatically counts as 'clacker dropped'
while( isdefined( useVolume) && level.player isTouching ( useVolume ) && !flag( "got_the_clacker" ) )
{
//wait 2;
weapon = level.player getcurrentweapon();
if( weapon != "c4" )
self thread clacker_disable( trig, useVolume );
wait 0.05;
}
}
clacker_notouch(trig, useVolume )
{
while( isdefined( useVolume ) && level.player isTouching( useVolume ) )
{
wait 0.1;
}
self thread clacker_disable( trig, useVolume );
}
clacker_disable( trig, useVolume )
{
//Actively disarm the armed clacker
if( isdefined( trig ) )
{
level notify ( "detclacker_disarm" );
flag_clear( "got_the_clacker" );
//If clacker has been picked up
//and player is not in the detection volume
//or player switched weapons away from the clacker
//Return the clacker to its rightful spot
//Clacker reappears
level.player takeweapon( "c4" );
self show();
//Reenable use trigger for clacker pickup
trigFlag = trig.script_flag_true;
flag_set( trigFlag );
//trig show();
//trig trigger_on();
//Switch to normal weapon
level.player switchtoweapon( level.player GetWeaponsListPrimaries()[0] );
}
}
clacker_fire( trig, useVolume, markers )
{
level endon ( "detclacker_disarm" );
//Arm the clacker
level.player waittill( "detonate" );
flag_set( "clacker_has_been_exercised" );
assertEX( isdefined( trig ), "trig is not defined" );
if( !isdefined( trig ) )
return;
if( self.script_noteworthy == "detonator_nearslope" )
flag_set( "nearslope_exploded" );
if( self.script_noteworthy == "detonator_farslope" )
flag_set( "farslope_exploded" );
if( self.script_noteworthy == "detonator_crashsite" )
flag_set( "crashsite_exploded" );
if( self.script_noteworthy == "detonator_cliffside" )
flag_set( "cliffside_exploded" );
thread killzone_detonation( markers, level.player );
earthquake( 0.5, 2, level.player.origin, 1650 );
level.player takeweapon( "c4" );
level.player switchtoweapon( level.player GetWeaponsListPrimaries()[0] );
//Objective position updating for clackers
//Locate the clacker position that was just used
targ = undefined;
usedClackerObjectiveMarker = undefined;
trigTargets = getentarray( trig.target, "targetname" );
for( i = 0 ; i < trigTargets.size; i++ )
{
targ = trigTargets[ i ];
if( !isdefined( targ.script_noteworthy ) )
continue;
if( !( targ.script_noteworthy == "clacker_objective_marker" ) )
continue;
usedClackerObjectiveMarker = targ;
}
//Get the clacker positions and remove the position that was just used
aManualDets = getentarray( "clacker_objective_marker", "script_noteworthy" );
for( i = 0; i < aManualDets.size; i++ )
{
det = aManualDets[ i ];
if( det == usedClackerObjectiveMarker )
aManualDets = maps\_utility::array_remove(aManualDets, det);
}
useVolume delete();
//Reprint the objective with the latest unused clacker positions
objective_delete( 5 );
objective_add( 5, "active", &"VILLAGE_DEFEND_USE_THE_DETONATORS_IN1" );
objective_current( 5 );
for( i = 0; i < aManualDets.size; i++ )
{
det = aManualDets[ i ];
if( isdefined( det ) )
objective_additionalposition( 5, i, det.origin);
}
trig delete();
usedClackerObjectiveMarker delete();
level.objectiveClackers--;
if( !level.objectiveClackers )
{
flag_set( "fall_back_to_barn" );
flag_set( "barn_assault_begins" );
autosave_by_name( "clackers_all_used_up" );
thread tavern_storming_delay();
}
}
player_interior_detect_init()
{
level endon ( "farm_reached" );
flag_wait( "fall_back_to_barn" );
detectors = getentarray( "interior_detection_volume", "targetname" );
level.playerIndoors = false;
n = 0;
while( 1 )
{
for( i = 0; i < detectors.size; i++ )
{
if( level.player isTouching( detectors[ i ] ) )
{
level.playerIndoors = true;
}
else
{
n++;
}
wait 0.5;
}
if( n == detectors.size )
{
level.playerIndoors = false;
}
n = 0;
wait 0.5;
}
}
enemy_interior_flashbangs()
{
level endon ( "farm_reached" );
enemyApproachTrig = getent( "enemy_near_interior_trig", "targetname" );
flag_wait( "fall_back_to_barn" );
while( 1 )
{
enemyApproachTrig waittill ( "trigger", enemyAI );
enemyAI notify ( "reset_loadout" );
wait 0.1;
if( isdefined( enemyAI ) )
{
enemyAI thread enemy_interior_grenadeswap();
enemyAI thread enemy_loadout_reset();
}
}
}
enemy_interior_grenadeswap()
{
self endon ( "death" );
self endon ( "reset_loadout" );
level endon ( "farm_reached" );
while( 1 )
{
if( level.playerIndoors )
{
self.grenadeammo = 6;
self.grenadeweapon = "flash_grenade";
}
else
{
self.grenadeammo = 6;
self.grenadeweapon = "fraggrenade";
break;
}
wait 0.5;
}
}
enemy_loadout_reset()
{
self endon ( "death" );
self endon ( "reset_loadout" );
flag_wait( "farm_reached" );
wait 0.5;
self.grenadeammo = 6;
self.grenadeweapon = "fraggrenade";
}
javelin_init()
{
flag_wait( "fall_back_to_barn" );
javelin = spawn( "weapon_javelin", (1021.1, 7309.2, 1006), 1 ); // suspended
javelin.angles = (356.201, 346.91, -0.426635);
javelin thread add_jav_glow( "kill_jav_glow" );
javelin waittill ( "trigger" );
flag_set( "got_the_javelin" );
}
tanks_init()
{
if ( getdvar( "start" ) != "final_battle" && getdvar( "start" ) != "seaknight" )
{
flag_wait( "fall_back_to_barn" );
//"We have enemy tanks approaching from the north! (sounds of fighting for a second) Bloody hell I'm hit! Arrrgh - (static)"
radio_dialogue_queue( "enemytanksnorth" );
//"Mac's in trouble! Soap! Get to the barn at the northern end of the village and stop those tanks! Use the Javelins in the barn!"
radio_dialogue_queue( "gettothebarn" );
flag_set( "objective_armor_arrival" );
flag_wait( "got_the_javelin" );
//wait randomfloatrange( 3, 5 );
for( i = 1; i < 5; i++ )
{
thread tanks_deploy( "tank_backyard_0" + i );
}
}
}
tanks_engage( name )
{
self endon ( "death" );
level.player endon ( "death" );
node = undefined;
killzoneTrig = undefined;
if( name == "tank_backyard_01" )
{
node = getVehicleNode( "tank1_fire_position", "script_noteworthy" );
killzoneTrig = getent( "tank_killzone_east", "targetname" );
}
else
if( name == "tank_backyard_02" )
{
node = getVehicleNode( "tank2_fire_position", "script_noteworthy" );
killzoneTrig = getent( "tank_killzone_west", "targetname" );
}
else
if( name == "tank_backyard_03" )
{
node = getVehicleNode( "tank3_fire_position", "script_noteworthy" );
killzoneTrig = getent( "tank_killzone_west", "targetname" );
}
else
if( name == "tank_backyard_04" )
{
node = getVehicleNode( "tank4_fire_position", "script_noteworthy" );
killzoneTrig = getent( "tank_killzone_east", "targetname" );
}
self setwaitnode( node );
self waittill ("reached_wait_node");
while( 1 )
{
killzoneTrig waittill ( "trigger" );
self setTurretTargetVec( level.player.origin + ( 0, 0, 72 ) );
self waittill_notify_or_timeout( "turret_rotate_stopped", 8.0 );
self fireweapon();
wait 4;
}
}
tanks_deploy( name )
{
tank = spawn_vehicle_from_targetname_and_drive( name );
tank thread tanks_engage( name );
tank.mgturret[ 0 ].maxrange = 6000;
level.tankid++;
tanknumber = level.tankid;
tank thread tank_ping( tanknumber );
OFFSET = ( 0, 0, 60 );
target_set( tank, OFFSET );
target_setAttackMode( tank, "top" );
target_setJavelinOnly( tank, true );
tank waittill ( "death" );
level.tankPop--;
if( level.tankPop )
{
objective_delete( 8 );
objective_add( 8, "active", "" );
objective_string( 8, &"VILLAGE_DEFEND_DESTROY_THE_INCOMING", level.tankPop );
objective_current( 8 );
autosave_or_timeout( "save_tank_destroyed_with_javelin", 10 );
}
else
{
flag_set( "objective_all_tanks_destroyed" );
flag_set( "kill_jav_glow" );
}
if ( isdefined( tank ) )
{
target_remove( tank ); //javelin targeting reticle removal
}
arcadeMode_kill( tank.origin, "explosive", 1000 );
}
tank_ping( tanknumber )
{
self endon ( "death" );
while( isalive( self ) )
{
objective_additionalposition( 8, tanknumber, self.origin);
objective_ring( 8 );
wait 1.2;
}
}
barn_helidrop()
{
if ( getdvar( "start" ) != "final_battle" && getdvar( "start" ) != "javelin" && getdvar( "start" ) != "seaknight" )
{
//enemy_heli_reinforcement_shoulder
//enemy_heli_reinforcement_barncenter
//enemy_heli_reinforcement_parkinglot
//enemy_heli_reinforcement_barnleft
//enemy_heli_reinforcement_cowfield
barnHelidropTrig = getent( "barn_helidrop", "targetname" );
flag_wait( "barn_assault_begins" );
barnHelidropTrig waittill ( "trigger" );
level notify ( "halfway_through_field" );
spawn_vehicle_from_targetname_and_drive( "enemy_heli_reinforcement_shoulder" );
spawn_vehicle_from_targetname_and_drive( "enemy_heli_reinforcement_barncenter" );
spawn_vehicle_from_targetname_and_drive( "enemy_heli_reinforcement_cowfield" );
//spawn_vehicle_from_targetname_and_drive( "enemy_heli_reinforcement_barnleft" );
}
}
field_fallback()
{
redshirt1 = getent( "redshirt1", "targetname" );
redshirt2 = getent( "redshirt2", "targetname" );
redshirt_node1 = getnode( "field_fallback_redshirt1", "targetname" );
redshirt_node2 = getnode( "field_fallback_redshirt2", "targetname" );
priceNode = getnode( "field_fallback_price", "targetname" );
sasGunnerNode = getnode( "field_fallback_sasGunner", "targetname" );
flag_wait( "fall_back_to_barn" );
redshirt1 setgoalnode( redshirt_node1 );
wait 2;
redshirt2 setgoalnode( redshirt_node2 );
wait 2;
level.price setgoalnode( priceNode );
wait 5;
level.sasGunner setgoalnode( sasGunnerNode );
}
barn_fallback()
{
redshirt1 = getent( "redshirt1", "targetname" );
redshirt_node1 = getnode( "barn_fallback_redshirt1", "targetname" );
redshirt2 = getent( "redshirt2", "targetname" );
redshirt_node2 = getnode( "barn_fallback_redshirt2", "targetname" );
priceNode = getnode( "barn_fallback_price", "targetname" );
sasGunnerNode = getnode( "barn_fallback_sasGunner", "targetname" );
flag_wait( "got_the_javelin" );
redshirt1 setgoalnode( redshirt_node1 );
wait 1;
redshirt2 setgoalnode( redshirt_node2 );
wait 2;
level.price setgoalnode( priceNode );
wait 3;
level.sasGunner setgoalnode( sasGunnerNode );
}
escape_fallback()
{
trig = getent( "final_lz", "targetname" );
redshirt1 = getent( "redshirt1", "targetname" );
redshirt_node1 = getnode( "final_rally_gaz", "targetname" );
redshirt2 = getent( "redshirt2", "targetname" );
redshirt_node2 = getnode( "final_rally_redshirt2", "targetname" );
priceNode = getnode( "final_rally_price", "targetname" );
sasGunnerNode = getnode( "final_rally_redshirt1", "targetname" );
flag_wait( "arm_delaying_action" );
trig waittill ( "trigger" );
flag_set( "lz_reached" );
redshirt2 setgoalnode( redshirt_node2 );
level.price setgoalnode( priceNode );
level.sasGunner setgoalnode( sasGunnerNode );
redshirt1 setgoalnode( redshirt_node1 );
}
final_battle()
{
if ( getdvar( "start" ) != "seaknight" )
{
flag_wait( "start_final_battle" );
wait 6;
flag_set( "airstrikes_ready" );
wait 5;
flag_wait( "falcon_one_finished_talking" );
//"Bravo Six, this is Gryphon Two-Seven. We've just crossed into Azerbaijani airspace. E.T.A. is four minutes. Be ready for pickup."
radio_dialogue_queue( "etafourminutes" );
autosave_by_name( "start_the_clock" );
}
thread objective_stopwatch();
thread countdown_events();
//thread early_chopper();
thread rescue_chopper();
thread mandown_reverse_spawn();
if ( getdvar( "start" ) != "seaknight" )
{
if ( getdvar( "village_defend_one_minute") != "1" )
{
//MHP: Bravo Six, The LZ is too hot! We cannot land at the farm! I repeat, we CANNOT land at the farm! We're picking up SAM sites all over these mountains!
radio_dialogue_queue( "pickingupSAMs" );
thread escape_music();
//GAZ: That's just great!! Where the hell are they gonna land now?
level.gaz anim_single_queue( level.gaz, "thatsjustgreat" );
//"Bravo Six, we're getting' a lot of enemy radar signatures, we'll try to land closer to the bottom of the hill to avoid a lock-on."
radio_dialogue_queue( "lzbottomhill" );
//GAZ: Is he takin' the piss? We just busted our arses to get to this LZ and now they want us to go all the way back down?!
radio_dialogue_queue( "takingthepiss" );
//PRICE: Forget it Gaz! We've got to get to the new LZ at the bottom of the hill! Now! Soap! Take point! Go!
radio_dialogue_queue( "thenewlz" );
}
flag_set( "objective_get_to_lz" );
flag_set( "return_trip_begins" );
wait 15;
//Bravo Six, be advised, we're gonna come in low from the south across the river. Recommend you haul ass to LZ Bravo at the base of the hill. Out.
radio_dialogue_queue( "lzfoxtrot" );
//"Copy Two-Seven! Everyone - head for the landing zone! It's our last chance! Move!"
radio_dialogue_queue( "headlandingzone" );
}
}
return_trip_friendly_boost()
{
flag_wait( "return_trip_begins" );
aAllies = getaiarray( "allies" );
for( i = 0; i < aAllies.size; i++ )
{
if( level.gameSkill == 0 )
aAllies[ i ].baseAccuracy = 12;
if( level.gameSkill == 1 )
aAllies[ i ].baseAccuracy = 6;
if( level.gameSkill == 2 )
aAllies[ i ].baseAccuracy = 2;
if( level.gameSkill == 3 )
aAllies[ i ].baseAccuracy = 1.5;
}
}
airstrike_command()
{
flag_wait( "airstrikes_ready" );
thread callStrike( level.player.origin, 1, ( 0, 110, 0 ) );
wait 1.2;
thread callStrike( level.player.origin, 1, ( 0, 96, 0 ) );
wait 1;
thread callStrike( level.player.origin, 1, ( 0, 126, 0 ) );
wait 5;
//"Bravo Six, this is Falcon One standing by to provide close air support. Gimme a target over."
radio_dialogue_queue( "casready" );
if ( isdefined( level.console ) && level.console )
thread airstrike_hint_console();
else
thread airstrike_hint_pc();
level.player giveWeapon( "airstrike_support" );
level.player SetActionSlot( 2, "weapon" , "airstrike_support" );
thread airstrike_support();
wait 3;
flag_set( "falcon_one_finished_talking" );
flag_wait( "return_trip_begins" );
thread airstrike_frequency_check();
level endon ( "stop_airstrike_reminders" );
level endon ( "no_airstrike_ammo" );
while( 1 )
{
startTime = gettime();
wait 70;
if( !level.airstrikeCalledRecently )
{
//"Bravo Six, this is Falcon One standing by to provide close air support. Gimme a target over."
radio_dialogue_queue( "casready" );
level.airstrikeCalledRecently = false;
}
}
}
airstrike_frequency_check()
{
level endon ( "stop_airstrike_reminders" );
level endon ( "no_airstrike_ammo" );
while( 1 )
{
level waittill ( "air_support_called" );
level.airstrikeCalledRecently = true;
}
}
farm_javelin_nag()
{
wait 8;
while( !flag( "got_the_javelin" ) )
{
thread radio_dialogue_queue( "javelinorder2" );
wait 30;
}
}
objectives()
{
minigun = getent( "minigun", "targetname" );
aManualDets = getentarray( "clacker_objective_marker", "script_noteworthy" );
farmTrig = getent( "farm_reached_trig", "targetname" );
extractionPoint = getent( "extraction_point", "targetname" );
if ( is_default_start() )
{
wait 25;
}
objective_add( 1, "active", &"VILLAGE_DEFEND_OBTAIN_NEW_ORDERS_FROM", ( level.price.origin ) );
objective_current( 1 );
flag_wait( "objective_price_orders_southern_hill" );
objective_state( 1 , "done" );
//playerDefensePos = getnode( "player_southern_start", "targetname" );
flag_set( "aa_southernhill" );
objective_add( 2, "active", &"VILLAGE_DEFEND_TAKE_UP_A_DEFENSIVE_POSITION", ( -732, -1473, 188 ) );
objective_current( 2 );
//flag_wait( "objective_on_ridgeline" );
flag_wait( "objective_player_on_ridgeline" );
wait 3;
objective_state( 2 , "done" );
objective_add( 3, "active", &"VILLAGE_DEFEND_DEFEND_THE_SOUTHERN_HILL", ( -732, -1473, 188 ) );
objective_current( 3 );
autosave_by_name( "ready_for_ambush" );
flag_wait( "objective_price_orders_minigun" );
objective_state( 3 , "done" );
flag_clear( "aa_southernhill" );
flag_set( "aa_minigun" );
objective_add( 4, "active", &"VILLAGE_DEFEND_FALL_BACK_AND_DEFEND", ( minigun.origin ) );
objective_current( 4 );
arcademode_checkpoint( 4, "a" );
autosave_by_name( "minigun_defense" );
flag_wait( "objective_detonators" );
objective_state( 4 , "done" );
flag_clear( "aa_minigun" );
flag_set( "aa_detonators" );
objective_add( 5, "active", &"VILLAGE_DEFEND_USE_THE_DETONATORS_IN", aManualDets[ 0 ].origin );
objective_current( 5 );
arcademode_checkpoint( 5, "b" );
autosave_by_name( "detonator_defense" );
for( i = 1; i < aManualDets.size; i++ )
{
det = aManualDets[ i ];
objective_additionalposition( 5, i, det.origin);
}
flag_wait( "objective_armor_arrival" );
objective_state( 5, "done" );
flag_clear( "aa_detonators" );
flag_set( "aa_fallback" );
autosave_by_name( "detonators_all_used_up" );
objective_add( 6, "active", &"VILLAGE_DEFEND_FALL_BACK_TO_THE_FARM", farmTrig.origin );
objective_current( 6 );
arcademode_checkpoint( 3.5, "c" );
thread farm_javelin_nag();
if ( getdvar( "start" ) != "final_battle" && getdvar( "start" ) != "seaknight" && getdvar( "start" ) != "javelin" )
farmTrig waittill ( "trigger" );
flag_set( "farm_reached" );
objective_state( 6, "done" );
flag_clear( "aa_fallback" );
flag_set( "aa_javelin" );
autosave_by_name( "player_got_to_the_farm" );
objective_add( 7, "active", &"VILLAGE_DEFEND_GET_THE_JAVELIN_IN_THE", ( 1021.1, 7309.2, 1006 ) );
objective_current( 7 );
arcademode_checkpoint( 2, "d" );
//thread radio_dialogue_queue( "javelinorder2" );
flag_wait( "got_the_javelin" );
objective_state( 7, "done" );
autosave_by_name( "got_javelin" );
thread early_chopper();
objective_add( 8, "active", "" );
objective_string( 8, &"VILLAGE_DEFEND_DESTROY_THE_INCOMING", 4 );
objective_current( 8 );
arcademode_checkpoint( 4, "e" );
//objective_add( 8, "active", &"VILLAGE_DEFEND_DESTROY_THE_INCOMING", 4 );
flag_wait( "objective_all_tanks_destroyed" );
level.playerSafetyBlocker solid();
objective_string( 8, &"VILLAGE_DEFEND_DESTROY_THE_INCOMING1" );
objective_state( 8, "done" );
flag_clear( "aa_javelin" );
flag_set( "aa_returntrip" );
autosave_by_name( "tanks_cleared" );
flag_set( "arm_delaying_action" );
objective_add( 9, "active", &"VILLAGE_DEFEND_SURVIVE_UNTIL_THE_HELICOPTER" );
objective_current( 9 );
arcademode_checkpoint( 3, "f" );
flag_set( "start_final_battle" );
flag_wait( "objective_get_to_lz" );
objective_add( 9, "active", &"VILLAGE_DEFEND_GET_TO_THE_LZ", extractionPoint.origin );
objective_current( 9 );
autosave_by_name( "get_to_the_choppah" );
arcademode_checkpoint( 7, "g" );
priceDist = length( level.price.origin - level.player.origin );
priceCopy = getent( "price_seaknight_doppel", "targetname" );
gazDist = length( level.gaz.origin - level.player.origin );
gazCopy = getent( "gaz_seaknight_doppel", "targetname" );
redshirtDist = length( level.redshirt.origin - level.player.origin );
redshirtCopy = getent( "redshirt_seaknight_doppel", "targetname" );
gunnerDist = length( level.sasgunner.origin - level.player.origin );
gunnerCopy = getent( "sasGunner_seaknight_doppel", "targetname" );
playerFollowers = [];
playerFollowers[ 0 ] = level.price;
playerFollowers[ 1 ] = level.gaz;
playerFollowers[ 2 ] = level.redshirt;
playerFollowers[ 3 ] = level.sasgunner;
/*
aAllies = getaiarray( "allies" );
for( i = 0; i < aAllies.size; i++ )
{
aAllies[ i ] thread friendly_player_tracking_nav();
}
*/
for( i = 0; i < playerFollowers.size; i++ )
{
playerFollowers[ i ] thread friendly_player_tracking_nav();
}
flag_wait( "lz_reached" );
level notify ( "stop_airstrike_reminders" );
thread friendly_pushplayer( "on" );
objective_state( 9, "done" );
objective_add( 10, "active", &"VILLAGE_DEFEND_SURVIVE_UNTIL_THE_HELICOPTER" );
objective_current( 10 );
flag_wait( "seaknight_can_be_boarded" );
objective_state( 10, "done" );
objective_add( 11, "active", &"VILLAGE_DEFEND_BOARD_THE_HELICOPTER", extractionPoint.origin );
objective_current( 11 );
flag_wait( "player_made_it" );
arcademode_checkpoint( 1.75, "h" );
autosave_by_name( "inside_choppah" );
flag_wait( "outtahere" );
objective_state( 11, "done" );
flag_clear( "aa_returntrip" );
}
autosaves_return_trip()
{
level endon ( "outtahere" );
flag_wait( "return_trip_begins" );
saveTrig1 = getent( "first_return_save" , "targetname" );
saveTrig2 = getent( "second_return_save" , "targetname" );
saveTrig3 = getent( "third_return_save" , "targetname" );
totalTime = level.stopwatch * 60 * 1000;
startTime = gettime();
saveTrig1 waittill ( "trigger" );
timeSpent = ( gettime() - startTime ) / 1000;
maxTimeAllowed = 90;
thread autosaves_safety( timeSpent, maxTimeAllowed );
saveTrig2 waittill ( "trigger" );
timeSpent = ( gettime() - startTime ) / 1000;
maxTimeAllowed = 120;
thread autosaves_safety( timeSpent, maxTimeAllowed );
saveTrig3 waittill ( "trigger" );
timeSpent = ( gettime() - startTime ) / 1000;
//maxTimeAllowed = 160;
maxTimeAllowed = 180;
noExceptions = true;
thread autosaves_safety( timeSpent, maxTimeAllowed, noExceptions );
}
autosaves_safety( timeSpent, maxTimeAllowed, noExceptions )
{
if( !isdefined( noExceptions ) )
noExceptions = false;
if( timeSpent <= maxTimeAllowed )
{
//autosave_by_name( "return_trip_section" );
autosave_or_timeout( "return_trip_section", 10 );
if( noExceptions )
wait 3;
else
wait 10;
flag_clear( "can_save" );
wait 2;
flag_set( "can_save" );
}
}
objective_stopwatch()
{
flag_wait( "objective_get_to_lz" );
level notify ( "start stopwatch" );
//fMissionLength = level.stopwatch; //how long until relieved (minutes)
//iMissionTime_ms = gettime() + int(fMissionLength*60*1000); //convert to milliseconds
// Setup the HUD display of the timer.
level.hudelem = maps\_hud_util::get_countdown_hud();
level.hudelem SetPulseFX( 30, 900000, 700 );//something, decay start, decay duration
countdown = 20 * 60;
if ( isdefined( level.stopwatch ) )
countdown = level.stopwatch * 60;
level.hudelem.label = &"VILLAGE_DEFEND_HELICOPTER_EXTRACTION";// + minutes + ":" + seconds
level.hudelem settenthstimer( countdown );
wait(level.stopwatch*60);
//if( isdefined( level.timer ) )
//level.timer destroy();
if( isdefined( level.hudelem ) )
level.hudelem destroy();
}
countdown_speech( alias )
{
assertEX( isdefined( alias ), "Specify a speech sound." );
level endon ( "player_made_it" );
radio_dialogue_queue( alias );
}
countdown_events()
{
flag_wait( "objective_get_to_lz" );
level endon ( "player_made_it" );
missionTime = level.stopwatch * 60;
if ( getdvar( "village_defend_one_minute") != "1" )
{
wait 60;
if( !flag( "reached_evac_point" ) && !flag( "lz_reached" ) )
{
//Bravo Six, be advised we are almost there but we're low on fuel. You guys have three minutes before we have to leave without you, over.
thread countdown_speech( "almosttherethree" );
}
if( !flag( "lz_reached" ) )
{
//GAZ: "We're gonna get left behind! We've got to get to the landing zone!"
thread countdown_speech( "gettolandingzone" );
}
wait 60;
//You got two minutes, over! *MISSING*
thread countdown_speech( "twominutesleft" );
if( !flag( "lz_reached" ) )
{
//PRICE: Copy that, we're on our way!
thread countdown_speech( "copywereonourway" );
//PRICE: "We've got to break through their lines to reach the LZ! Keep pushing downhill!"
thread countdown_speech( "breakthroughtolz" );
//GAZ: Let's go! Let's go! Get down the hill!!
thread countdown_speech( "getdownthehill" );
}
wait 30;
//"Ninety seconds to dustoff."
thread countdown_speech( "ninetysecondsleft" );
flag_set( "rescue_chopper_ingress" );
wait 30;
}
//"One minute to bingo fuel."
thread countdown_speech( "oneminutebingo" );
if( !flag( "lz_reached" ) )
{
//PRICE: "Get to the bottom of the hill!!! Move move!!!"
thread countdown_speech( "bottomofthehill" );
}
wait 30;
//"Thirty seconds."
thread countdown_speech( "thirtyseconds" );
if( !flag( "lz_reached" ) )
{
//GAZ: Get to the LZ! Go! Go!
thread countdown_speech( "gettothelzgogo" );
}
wait 30;
if( !flag( "player_made_it" ) )
{
flag_set( "seaknight_guards_boarding" );
flag_wait( "seaknight_unboardable" );
wait 3;
if( !flag( "player_made_it" ) && isalive( level.player ) )
{
setDvar( "ui_deadquote", &"VILLAGE_DEFEND_YOU_DIDNT_REACH_THE_HELICOPTER" );
maps\_utility::missionFailedWrapper();
}
}
}
early_chopper()
{
trig = getent( "early_chopper", "targetname" );
trig waittill ( "trigger" );
flag_set( "rescue_chopper_ingress" );
}
escape_music()
{
level endon ( "open_bay_doors" );
MusicPlayWrapper( "village_defend_fallback" );
wait 94;
musicStop( 6 );
wait 6.1;
MusicPlayWrapper( "village_defend_direstraits" );
wait 83;
musicStop( 6 );
wait 6.1;
MusicPlayWrapper( "village_defend_fallback" );
wait 94;
musicStop( 6 );
wait 6.1;
MusicPlayWrapper( "village_defend_direstraits" );
wait 83;
musicStop( 6 );
wait 6.1;
}
seaknight_music()
{
flag_wait( "open_bay_doors" );
musicStop( 3 );
wait 3.1;
MusicPlayWrapper( "village_defend_escape" );
}
rescue_chopper()
{
if ( getdvar( "village_defend_one_minute") != "1" )
flag_wait( "rescue_chopper_ingress" );
thread seaknight();
flag_wait( "seaknight_can_be_boarded" );
trigger = spawn( "script_origin", (0,0,0) );
trigger.origin = level.seaknight1 gettagorigin( "tag_door_rear" );
trigger.radius = 27.731134;
for( ;; )
{
wait 0.05;
if ( distance( level.player.origin, trigger.origin ) >= trigger.radius )
continue;
else
break;
}
if( !flag( "seaknight_unboardable" ) )
{
flag_set( "player_made_it" );
rescue_ride();
thread rescue_teleport_friendlies();
thread rescue_failsafe();
if( isdefined( level.hudelem ) )
level.hudelem destroy();
flag_wait( "outtahere" );
wait 2;
//"Baseplate this is Gryphon Two-Seven. We got 'em and we're comin' home. Out."
radio_dialogue_queue( "cominhome" );
wait 1;
nextmission();
}
else
{
sniperSoundSource = getent( "intro_tank_tower_target", "targetname" );
sniperSoundSource playsound( level.sniperfx );
wait 0.1;
level.player doDamage( level.player.health + 10000, level.player.origin );
}
}
rescue_teleport_friendlies()
{
wait 2;
priceDist = length( level.price.origin - level.player.origin );
priceCopy = getent( "price_seaknight_doppel", "targetname" );
gazDist = length( level.gaz.origin - level.player.origin );
gazCopy = getent( "gaz_seaknight_doppel", "targetname" );
redshirtDist = length( level.redshirt.origin - level.player.origin );
redshirtCopy = getent( "redshirt_seaknight_doppel", "targetname" );
gunnerDist = length( level.sasgunner.origin - level.player.origin );
gunnerCopy = getent( "sasGunner_seaknight_doppel", "targetname" );
allowedDist = 1800;
if( priceDist > allowedDist )
{
level.price stop_magic_bullet_shield();
level.price delete();
priceCopy thread rescue_doppel_spawn();
}
if( gazDist > allowedDist )
{
level.gaz stop_magic_bullet_shield();
level.gaz delete();
gazCopy thread rescue_doppel_spawn();
}
if( redshirtDist > allowedDist )
{
level.redshirt stop_magic_bullet_shield();
level.redshirt delete();
redshirtCopy thread rescue_doppel_spawn();
}
if( gunnerDist > allowedDist )
{
level.sasgunner stop_magic_bullet_shield();
level.sasgunner delete();
gunnerCopy thread rescue_doppel_spawn();
}
}
rescue_doppel_spawn()
{
guy = self stalingradSpawn();
if( spawn_failed( guy ) )
{
return;
}
guy thread hero();
guy.fixedNode = false;
guy thread seaknight_sas_load();
}
rescue_failsafe()
{
//if the friendlies don't board the helicopter for any reason, failsafe
wait 45;
nextmission();
}
rescue_ride()
{
level.player disableweapons();
// this is the model the player will attach to for the pullout sequence
ePlayerview = spawn_anim_model( "player_carry" );
ePlayerview hide();
// put the ePlayerview in the first frame so the tags are in the right place
//level.seaknight1 anim_first_frame_solo( ePlayerview, "wounded_seaknight_putdown", "tag_detach" );
level.seaknight1 anim_first_frame_solo( ePlayerview, "village_player_getin", "tag_detach" );
ePlayerview linkto( level.seaknight1, "tag_detach" );
// this smoothly hooks the player up to the animating tag
ePlayerview lerp_player_view_to_tag( "tag_player", 0.5, 0.9, 35, 35, 45, 0 );
guys_animating = [];
guys_animating[ guys_animating.size ] = ePlayerview;
level.seaknight1 anim_single( guys_animating, "village_player_getin", "tag_detach" );
/* -- -- -- -- -- -- -- -- -- -- -- -
LINK PLAYER TO CURRENT POS TO SEE LANDSCAPE
-- -- -- -- -- -- -- -- -- -- -- -- -*/
level.player enableweapons();
// < viewpercentag fraction> , <right arc> , <left arc> , <top arc> , <bottom arc> )
level.player playerlinktodelta( ePlayerview, "tag_player", 1, 20, 45, 5, 25 );
}
music()
{
//flag_wait( "church_tower_explodes" );
level endon ( "stop_ambush_music" );
if ( getdvar( "start" ) != "final_battle" && getdvar( "start" ) != "seaknight" )
{
while( !flag( "stop_ambush_music" ) )
{
//MusicPlayWrapper( "village_defend_ambush_music" );
MusicPlayWrapper( "village_defend_vanguards" );
wait 85.2;
musicStop( 0.1 );
wait 0.15;
}
}
}
mandown_reverse_spawn()
{
trig = getent( "back_spawning_activator", "script_noteworthy" );
trig waittill ( "trigger" );
flag_set( "back_spawn_stoppable" );
}
//Datatables and Utilities
killzone_detonation( squibs, attacker )
{
n = 0;
for( i = 0 ; i < squibs.size; i++ )
{
squib = squibs[ i ];
vfx = level.killZoneFxProgram[ n ];
soundfx = level.killZoneSfx[ n ];
playfx( vfx, squib.origin );
squib playsound( soundfx );
earthquake( 0.1, 0.5, level.player.origin, 1250 );
if( !isdefined( attacker ) )
radiusDamage(squib.origin, 240, 100500, 100500); //radiusDamage(origin, range, maxdamage, mindamage);
else
radiusDamage(squib.origin, 240, 100500, 100500, attacker); //radiusDamage(origin, range, maxdamage, mindamage);
n++;
if( n >= level.killZoneFxProgram.size )
{
n = 0;
}
wait randomfloatrange( 0.05 , 0.15 );
}
}
killzoneFxProgram()
{
level.killZoneFxProgram = [];
level.killZoneFxProgram[ 0 ] = level.killzoneBigExplosion_fx;
level.killZoneFxProgram[ 1 ] = level.killzoneMudExplosion_fx;
level.killZoneFxProgram[ 2 ] = level.killzoneBigExplosion_fx;
level.killZoneFxProgram[ 3 ] = level.killzoneFuelExplosion_fx;
level.killZoneFxProgram[ 4 ] = level.killzoneDirtExplosion_fx;
level.killZoneFxProgram[ 5 ] = level.killzoneMudExplosion_fx;
level.killZoneFxProgram[ 6 ] = level.killzoneBigExplosion_fx;
level.killZoneFxProgram[ 7 ] = level.killzoneFuelExplosion_fx;
level.killZoneFxProgram[ 8 ] = level.killzoneDirtExplosion_fx;
level.killZoneFxProgram[ 9 ] = level.killzoneBigExplosion_fx;
level.killZoneSfx = [];
level.killZoneSfx[ 0 ] = "explo_mine";
level.killZoneSfx[ 1 ] = "explo_tree";
level.killZoneSfx[ 2 ] = "explo_mine";
level.killZoneSfx[ 3 ] = "explo_rock";
level.killZoneSfx[ 4 ] = "explo_roadblock";
level.killZoneSfx[ 5 ] = "explo_tree";
level.killZoneSfx[ 6 ] = "explo_mine";
level.killZoneSfx[ 7 ] = "explo_rock";
level.killZoneSfx[ 8 ] = "explo_roadblock";
level.killZoneSfx[ 9 ] = "explo_mine";
assertEX( level.killZoneFxProgram.size == level.killZoneSfx.size, "Fx and Sfx programs should have equal number of entries." );
}
followScriptedPath( node, delayTime, stance )
{
if( !isdefined( delayTime ) )
delayTime = 0;
wait delayTime;
nodes = [];
while( 1 )
{
nodes[ nodes.size ] = node;
if( isdefined( node.target ) )
{
node = getnode( node.target, "targetname" );
}
else
{
break;
}
}
self.disableArrivals = true;
for( i = 0; i < nodes.size; i++ )
{
node = nodes[ i ];
self setgoalnode( node );
if( isdefined( node.radius ) )
self.goalradius = node.radius;
if( isdefined( node.script_stance ) )
self allowedstances( node.script_stance );
self waittill( "goal" );
if( !isdefined( node.target ) )
self notify ("reached_last_node_in_chain");
if( !isdefined( node.script_noteworthy ) )
continue;
//if( node.script_noteworthy == "tower_reaction" )
//continue;
//iprintln( "Team reacts to bell tower explosion!" );
//TEMP ANIM OF REACTION TO BELL TOWER EXPLOSION
wait 0.1;
}
self.disableArrivals = false;
}
friendly_setup()
{
aAllies = getaiarray( "allies" );
for( i = 0; i < aAllies.size; i++ )
{
aAllies[ i ] thread hero();
aAllies[ i ].grenadeammo = 0;
}
flag_wait( "objective_price_orders_minigun" );
aAllies = getaiarray( "allies" );
for( i = 0; i < aAllies.size; i++ )
{
aAllies[ i ].grenadeammo = 5;
}
}
hero()
{
self thread magic_bullet_shield();
self pushPlayer( true );
self.IgnoreRandomBulletDamage = true;
self.ignoresuppression = true;
}
//self set_run_anim( "path_slow" );
//self clear_run_anim();
encroach_start( node, groupname, msg, squadname, deathmonitorname )
{
//node - ent - starting main node for enemy infantry attack run
//groupname - str - targetname of enemy spawners;
//msg - str - endon
//squadname - str - script_noteworthy of enemy spawners' starting area on spawner;
level endon ( msg );
aGroup = [];
aSquad = [];
guy = undefined;
aGroup = getentarray( groupname, "targetname" );
for( i = 0; i < aGroup.size; i++ )
{
if( isdefined( aGroup[ i ].script_noteworthy ) )
{
if( aGroup[ i ].script_noteworthy == squadname )
{
aSquad[ aSquad.size ] = aGroup[ i ];
}
}
}
for( i = 0; i < aSquad.size; i++ )
{
aSquad[ i ].count = 1;
guy = aSquad[ i ] stalingradSpawn();
if( spawn_failed( guy ) )
{
return;
}
if( flag( "no_more_grenades" ) )
self.grenadeammo = 0;
guy thread encroach_nav( node, msg );
minigun = getent( "minigun", "targetname" );
minigunUser = minigun getTurretOwner();
/*
if((isdefined(minigunUser) && level.player == minigunUser))
{
guy.baseAccuracy = 5;
}
*/
if( isdefined( deathmonitorname ) )
{
if( deathmonitorname == "southern_hill" )
guy thread southern_hill_deathmonitor();
}
if( isdefined( deathmonitorname ) )
{
if( deathmonitorname == "minigun_breach" )
guy thread minigun_breach_deathmonitor();
}
}
}
encroach_nav( node, msg )
{
level endon ( msg );
self endon ( "death" );
if( !flag( "objective_minigun_baglimit_done" ) )
{
aRoutes = [];
startNode = node;
n = undefined;
while( 1 )
{
aRoutes[ aRoutes.size ] = startNode;
if( isdefined( startNode.target ) )
{
aBranchNodes = getnodearray( startNode.target, "targetname" );
assertEX( aBranchNodes.size > 0, "At least one node should be targeted for encroach_nav routes" );
n = randomint( aBranchNodes.size );
startNode = aBranchNodes[ n ];
}
else
{
break;
}
}
for( i = 0; i < aRoutes.size; i++ )
{
self setgoalnode( aRoutes[ i ] );
self waittill ( "goal" );
wait randomfloatrange( level.encroachMinWait, level.encroachMaxWait );
}
//flag_wait( "objective_minigun_baglimit_done" );
flag_wait( "divert_for_clacker" );
}
if( flag( "fall_back_to_barn" ) )
flag_wait( "storm_the_tavern" );
self thread hunt_player();
self thread helidrop_clacker_divert();
}
southern_hill_mortar_detonate( squib )
{
//squib = origin ent
//inFX = incoming sound
//detFX = explosion sound
vfx = level.killzoneBigExplosion_fx;
inFX = "artillery_incoming";
detFX = [];
detFX[ 0 ] = "explo_mine";
detFX[ 1 ] = "explo_rock";
detFX[ 2 ] = "explo_tree";
squib playsound( inFX );
wait 0.25;
playfx( vfx, squib.origin );
j = randomintrange( 0, detFX.size );
detSound = detFX[ j ];
squib playsound( detSound );
earthquake( 0.35, 0.5, level.player.origin, 1250 );
radiusDamage(squib.origin, 256, 1000, 500); //radiusDamage(origin, range, maxdamage, mindamage);
}
//=======================================================================
begin_delaying_action()
{
flag_wait( "arm_delaying_action" );
if ( level.gameSkill == 0 )
{
//level.detectionCycleTime = 120;
level.detectionCycleTime = 60;
}
if ( level.gameSkill == 1 )
{
//level.detectionCycleTime = 90;
level.detectionCycleTime = 25;
}
if ( level.gameSkill == 2 )
{
//level.detectionCycleTime = 60;
level.detectionCycleTime = 22;
}
if ( level.gameSkill == 3 )
{
//level.detectionCycleTime = 50;
level.detectionCycleTime = 19;
}
trig = getent( "delaying_action_trigger", "targetname" );
trig waittill ( "trigger" );
flag_set( "engage_delaying_action" );
}
begin_delaying_action_timeout()
{
flag_wait( "arm_delaying_action" );
wait 180;
flag_set( "engage_delaying_action" );
}
//=======================================================================
player_detection_volume_init()
{
aVolumes = getentarray( "player_detection_volume", "targetname" );
for( i = 0; i < aVolumes.size; i++ )
{
aSpawnProcs = player_detection_collect( aVolumes[ i ] );
aProcEntsContainer = player_spawnProc_ents_collect( aVolumes[ i ] );
thread player_detection_loop( aVolumes[ i ], aSpawnProcs, aProcEntsContainer );
}
}
player_detection_collect( detectionVolume )
{
aSpawnProcs = getentarray( detectionVolume.target, "targetname" );
aProcEnts = [];
for( i = 0; i < aSpawnProcs.size; i++ )
{
aProcEnts = getentarray( aSpawnProcs[ i ].target, "targetname" );
}
return( aSpawnProcs );
}
player_spawnProc_ents_collect( detectionVolume )
{
aSpawnProcs = getentarray( detectionVolume.target, "targetname" );
aProcEntsContainer = [];
for( i = 0; i < aSpawnProcs.size; i++ )
{
aProcEnts = getentarray( aSpawnProcs[ i ].target, "targetname" );
aProcEntsContainer[ aProcEntsContainer.size ] = aProcEnts;
}
return( aProcEntsContainer );
}
player_detection_loop( detectionVolume, aSpawnProcs, aProcEntsContainer )
{
level endon ( "engage_delaying_action" );
flag_wait( "fall_back_to_barn" );
while( 1 )
{
//Check AI population capacity before spawning
aAxis = getaiarray( "axis" );
aAllies = getaiarray( "allies" );
//Some overspawning is ok but not too much
aiPop = aAxis.size + aAllies.size;
slotsAvailable = level.maxAI - aiPop;
//Detect player position using isTouching volume
if( slotsAvailable >= level.reqSlots )
{
if( level.player isTouching( detectionVolume ) )
{
thread ai_spawnprocessor( detectionVolume, aSpawnProcs, aProcEntsContainer );
if( flag( "objective_all_tanks_destroyed" ) )
level.delayingActionEnemyWaves++;
if( level.delayingActionEnemyWaves >= level.enemyWavesAllowed )
flag_set( "engage_delaying_action" );
}
wait level.detectionCycleTime;
}
wait 0.5;
}
}
ai_spawnprocessor( detectionVolume, aSpawnProcs, aProcEntsContainer )
{
//Activate the spawn processors for this detection volume
for( i = 0; i < aSpawnProcs.size; i++ )
{
thread ai_spawn_control_set_create( aSpawnProcs[ i ], detectionVolume, aProcEntsContainer[ i ] );
}
}
ai_spawn_control_set_create( spawnProc, detectionVolume, procEntsContainer )
{
//Get the spawners for this unit
aProcSpawners = [];
for( i = 0; i < level.aSpawners.size; i++ )
{
spawner = level.aSpawners[ i ];
if( !isdefined( spawner.targetname ) )
continue;
if( spawner.targetname == spawnProc.target )
{
aProcSpawners[ aProcSpawners.size ] = spawner;
}
}
//Check for smokescreen usage on this unit and get the smoke generator if it exists
smokeEnt = undefined;
aProcEnts = [];
aProcEnts = procEntsContainer;
for( i = 0; i < aProcEnts.size; i++ )
{
procEnt = aProcEnts[ i ];
if( !isdefined( procEnt.script_noteworthy ) )
{
continue;
}
if( procEnt.script_noteworthy == "smoke_generator" )
{
smokeEnt = procEnt;
break;
}
}
//Get the flank routing node for this unit
routeNode = undefined;
assertEX( isdefined( spawnProc.script_namenumber ), "Spawn processor is missing a routing label e.g. AR15" );
routeID = spawnProc.script_namenumber;
for( i = 0; i < level.aRouteNodes.size; i++ )
{
routeStartNode = level.aRouteNodes[ i ];
if( !isdefined( routeStartNode.script_noteworthy ) )
continue;
if( routeStartNode.script_noteworthy == routeID )
{
routeNode = routeStartNode;
break;
}
}
thread ai_spawn_and_attack( aProcSpawners, smokeEnt, routeNode, detectionVolume );
}
ai_spawn_and_attack( spawners, smokeEnt, routeNode, detectionVolume )
{
//If smoke is being deployed to cover the spawn:
//1. Wait X seconds for the smoke to build to sufficient opacity and size
//2. Confirm that the player is far enough from the smoke cloud origin
//3. Spawn and attack along assigned routes and run the reacquisition monitor
if( isdefined( smokeEnt ) )
{
playfx( level.smokegrenade, smokeEnt.origin );
wait level.smokeBuildTime;
dist = length( level.player.origin - smokeEnt.origin );
if( dist < level.smokeSpawnSafeDist )
{
return;
}
}
//If smoke is not being used to cover the spawn:
//1. Spawn and attack along assigned routes and run the reacquisition monitor
//Spawners become finite during the return trip
for( i = 0; i < spawners.size; i++ )
{
spawner = spawners[ i ];
/*
if( flag( "return_trip_begins" ))
{
if( !isdefined( spawner[ i ].script_namenumber ) )
{
if( level.gameSkill == 0 )
{
spawner[ i ].count = 3;
self.baseAccuracy = 0.3;
}
else
if( level.gameSkill == 1 )
{
spawner[ i ].count = 4;
self.baseAccuracy = 0.5;
}
else
if( level.gameSkill == 2 )
{
spawner[ i ].count = 5;
}
else
if( level.gameSkill == 3 )
{
spawner[ i ].count = 6;
}
}
spawner[ i ].script_namenumber = true;
}
else
{
spawners[ i ].count = 1;
}
*/
spawners[ i ].count = 1;
totalPop = aiPopCount();
if( totalPop < 32 )
{
guy = spawner stalingradSpawn();
if( spawn_failed( guy ) )
{
continue;
}
if( flag( "no_more_grenades" ) )
self.grenadeammo = 0;
guy thread ai_flank_route( routeNode );
guy thread ai_reacquire_player( detectionVolume );
}
}
}
ai_flank_route( routeNode )
{
self endon ( "death" );
self endon ( "reacquire_player" );
while( 1 )
{
self setgoalnode( routeNode );
if( isdefined( routeNode.radius ) )
self.goalradius = routeNode.radius;
self waittill ( "goal" );
if( isdefined( routeNode.script_node_pausetime ) )
{
pauseTime = routeNode.script_node_pausetime + randomfloatrange( 0.5, 1.5 );
wait( pauseTime );
}
if( !isdefined( routeNode.target ) )
{
if( flag( "fall_back_to_barn" ) )
flag_wait( "storm_the_tavern" );
self thread hunt_player();
break;
}
routeNode = getnode( routeNode.target, "targetname" );
}
}
ai_reacquire_player( detectionVolume )
{
//If player leaves the original detection volume substantially, the
//1. Check to see that the player is still touching the volume.
//2. Wait a bit, then resample to see if the player is still touching the volume.
//3. If not, send the guy after the player using hunt_player.
self endon ( "death" );
while( 1 )
{
if( !level.player isTouching ( detectionVolume ) )
{
wait level.volumeDesertionTime;
if( !level.player isTouching ( detectionVolume ) )
{
self notify ( "reacquire_player" );
wait 0.5;
if( flag( "fall_back_to_barn" ) )
flag_wait( "storm_the_tavern" );
self thread hunt_player();
break;
}
}
wait level.detectionRefreshTime;
}
}
return_trip_enemy_acc_prep()
{
aFloods = getentarray( "flood_spawner" , "targetname" );
aSpawners = [];
for( i = 0 ; i < aFloods.size; i++ )
{
aSpawners = getentarray( aFloods[ i ].target, "targetname" );
array_thread( aSpawners, ::add_spawn_function, ::return_trip_enemy_acc );
aSpawners = undefined;
aSpawners = [];
}
}
return_trip_enemy_acc()
{
flag_wait( "start_final_battle" );
self.baseAccuracy = level.village_diff[ level.gameskill ];
}
//=======================================================================
add_hint_background( double_line )
{
if ( isdefined ( double_line ) )
level.hintbackground = createIcon( "popmenu_bg", 650, 50 );
else
level.hintbackground = createIcon( "popmenu_bg", 650, 30 );
level.hintbackground setPoint( "TOP", undefined, 0, 125 );
level.hintbackground.alpha = .5;
}
airstrike_hint_console()
{
add_hint_background();
//Airstrikes standing by.
level.hintElem = createFontString( "objective", level.hint_text_size );
level.hintElem setPoint( "TOP", undefined, 0, 130 );
//level.hintElem.label = &"VILLAGE_DEFEND_CASREADY";
level.hintElem setText( &"VILLAGE_DEFEND_CLOSE_AIR_SUPPORT_STANDING" );
level.iconElem = createIcon( "hud_dpad", 32, 32 );
level.iconElem setPoint( "TOP", undefined, -16, 165 );
level.iconElem2 = createIcon( "compass_objpoint_airstrike", 32, 32 );
level.iconElem2 setPoint( "TOP", undefined, -15, 196 );
level.iconElem3 = createIcon( "hud_arrow_down", 24, 24 );
level.iconElem3 setPoint( "TOP", undefined, -15.5, 170 );
level.iconElem3.sort = 1;
level.iconElem3.color = (1,1,0);
level.iconElem3.alpha = .7;
wait 4;
level.iconElem setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 );
level.iconElem2 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 );
level.iconElem3 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 );
level.iconElem scaleovertime(1, 20, 20);
level.iconElem2 scaleovertime(1, 20, 20);
level.iconElem3 scaleovertime(1, 20, 20);
wait .70;
level.hintElem fadeovertime(.15);
level.hintElem.alpha = 0;
level.iconElem fadeovertime(.15);
level.iconElem.alpha = 0;
level.iconElem2 fadeovertime(.15);
level.iconElem2.alpha = 0;
level.iconElem3 fadeovertime(.15);
level.iconElem3.alpha = 0;
clear_hints();
}
airstrike_hint_pc()
{
add_hint_background();
//Airstrikes standing by.
level.hintElem = createFontString( "objective", level.hint_text_size );
level.hintElem setPoint( "TOP", undefined, 0, 130 );
//level.hintElem.label = &"VILLAGE_DEFEND_CASREADY";
level.hintElem setText( &"VILLAGE_DEFEND_CLOSE_AIR_SUPPORT_STANDING_PC" );
level.iconElem2 = createIcon( "compass_objpoint_airstrike", 32, 32 );
level.iconElem2 setPoint( "TOP", undefined, -15, 196 );
wait 4;
level.iconElem2 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 );
level.iconElem2 scaleovertime(1, 20, 20);
wait .70;
level.hintElem fadeovertime(.15);
level.hintElem.alpha = 0;
level.iconElem2 fadeovertime(.15);
level.iconElem2.alpha = 0;
clear_hints();
}
clear_hints()
{
if ( isDefined( level.hintElem ) )
level.hintElem destroyElem();
if ( isDefined( level.iconElem ) )
level.iconElem destroyElem();
if ( isDefined( level.iconElem2 ) )
level.iconElem2 destroyElem();
if ( isDefined( level.iconElem3 ) )
level.iconElem3 destroyElem();
if ( isDefined( level.hintbackground ) )
level.hintbackground destroyElem();
level notify ( "clearing_hints" );
}
airstrike_support()
{
level.playerPreviousWeapon = undefined;
for(;;)
{
while( level.player getcurrentweapon() != "airstrike_support" )
{
level.playerPreviousWeapon = level.player getcurrentweapon();
wait 0.05;
}
airstrike_ammo = level.player getWeaponAmmoStock( "airstrike_support" );
if( !isdefined( airstrike_ammo ) )
{
break;
}
else
if( airstrike_ammo == 0 )
{
break;
}
thread airstrike_support_activate();
while( level.player getcurrentweapon() == "airstrike_support" )
wait 0.05;
level notify( "air_support_canceled" );
thread airstrike_support_deactive();
}
}
airstrike_support_activate()
{
level endon( "air_support_canceled" );
level endon( "air_support_called" );
thread airstrike_support_paint_target();
// Make the arrow
level.airstrikeAttackArrow = spawn( "script_model", ( 0, 0, 0 ) );
level.airstrikeAttackArrow setModel( "tag_origin" );
level.airstrikeAttackArrow.angles = ( -90, 0, 0 );
level.airstrikeAttackArrow.offset = 4;
playfxontag( level.air_support_fx_yellow, level.airstrikeAttackArrow, "tag_origin" );
level.playerActivatedAirSupport = true;
coord = undefined;
traceOffset = 15;
traceLength = 15000;
minValidLength = 300 * 300;
trace = [];
trace[ 0 ] = spawnStruct();
trace[ 0 ].offsetDir = "vertical";
trace[ 0 ].offsetDist = traceOffset;
trace[ 1 ] = spawnStruct();
trace[ 1 ].offsetDir = "vertical";
trace[ 1 ].offsetDist = traceOffset * -1;
trace[ 2 ] = spawnStruct();
trace[ 2 ].offsetDir = "horizontal";
trace[ 2 ].offsetDist = traceOffset;
trace[ 3 ] = spawnStruct();
trace[ 3 ].offsetDir = "horizontal";
trace[ 3 ].offsetDist = traceOffset * -1;
for(;;)
{
wait 0.05;
prof_begin( "spotting_marker" );
// Trace to where the player is looking
direction = level.player getPlayerAngles();
direction_vec = anglesToForward( direction );
eye = level.player getEye();
for ( i = 0 ; i < trace.size ; i++ )
{
start = eye;
vec = undefined;
if ( trace[ i ].offsetDir == "vertical" )
vec = anglesToUp( direction );
else if ( trace[ i ].offsetDir == "horizontal" )
vec = anglesToRight( direction );
assert( isdefined( vec ) );
start = start + vector_multiply( vec, trace[ i ].offsetDist );
trace[ i ].trace = bullettrace( start, start + vector_multiply( direction_vec , traceLength ), 0, undefined );
trace[ i ].length = distanceSquared( start, trace[ i ].trace[ "position" ] );
if ( getdvar( "village_defend_debug_marker") == "1" )
thread draw_line_for_time( start, trace[ i ].trace[ "position" ], 1, 1, 1, 0.05 );
}
validLocations = [];
validNormals = [];
for ( i = 0 ; i < trace.size ; i++ )
{
if ( trace[ i ].length < minValidLength )
continue;
index = validLocations.size;
validLocations[ index ] = trace[ i ].trace[ "position" ];
validNormals[ index ] = trace[ i ].trace[ "normal" ];
if ( getdvar( "village_defend_debug_marker") == "1" )
thread draw_line_for_time( level.player getEye(), validLocations[ index ], 0, 1, 0, 0.05 );
}
// if all points are too close just use all of them since none are good
if ( validLocations.size == 0 )
{
for ( i = 0 ; i < trace.size ; i++ )
{
validLocations[ i ] = trace[ i ].trace[ "position" ];
validNormals[ i ] = trace[ i ].trace[ "normal" ];
}
}
assert( validLocations.size > 0 );
if ( validLocations.size == 4 )
{
fxLocation = findAveragePointVec( validLocations[ 0 ], validLocations[ 1 ], validLocations[ 2 ], validLocations[ 3 ] );
fxNormal = findAveragePointVec( validNormals[ 0 ], validNormals[ 1 ], validNormals[ 2 ], validNormals[ 3 ] );
}
else if ( validLocations.size == 3 )
{
fxLocation = findAveragePointVec( validLocations[ 0 ], validLocations[ 1 ], validLocations[ 2 ] );
fxNormal = findAveragePointVec( validNormals[ 0 ], validNormals[ 1 ], validNormals[ 2 ] );
}
else if ( validLocations.size == 2 )
{
fxLocation = findAveragePointVec( validLocations[ 0 ], validLocations[ 1 ] );
fxNormal = findAveragePointVec( validNormals[ 0 ], validNormals[ 1 ] );
}
else
{
fxLocation = validLocations[ 0 ];
fxNormal = validNormals[ 0 ];
}
if ( getdvar( "village_defend_debug_marker") == "1" )
thread draw_line_for_time( level.player getEye(), fxLocation, 1, 0, 0, 0.05 );
// Draw the arrow and circle around the arrow
thread drawAirstrikeAttackArrow( fxLocation, fxNormal );
prof_end( "spotting_marker" );
}
}
findAveragePointVec( point1, point2, point3, point4 )
{
assert( isdefined( point1 ) );
assert( isdefined( point2 ) );
if ( isdefined( point4 ) )
{
x = findAveragePoint( point1[ 0 ], point2[ 0 ], point3[ 0 ], point4[ 0 ] );
y = findAveragePoint( point1[ 1 ], point2[ 1 ], point3[ 1 ], point4[ 1 ] );
z = findAveragePoint( point1[ 2 ], point2[ 2 ], point3[ 2 ], point4[ 2 ] );
}
else if ( isdefined( point3 ) )
{
x = findAveragePoint( point1[ 0 ], point2[ 0 ], point3[ 0 ] );
y = findAveragePoint( point1[ 1 ], point2[ 1 ], point3[ 1 ] );
z = findAveragePoint( point1[ 2 ], point2[ 2 ], point3[ 2 ] );
}
else
{
x = findAveragePoint( point1[ 0 ], point2[ 0 ] );
y = findAveragePoint( point1[ 1 ], point2[ 1 ] );
z = findAveragePoint( point1[ 2 ], point2[ 2 ] );
}
return( x, y, z );
}
findAveragePoint( point1, point2, point3, point4 )
{
assert( isdefined( point1 ) );
assert( isdefined( point2 ) );
if ( isdefined( point4 ) )
return ( ( point1 + point2 + point3 + point4 ) / 4 );
else if ( isdefined( point3 ) )
return ( ( point1 + point2 + point3 ) / 3 );
else
return ( ( point1 + point2 ) / 2 );
}
drawAirstrikeAttackArrow( coord, normal )
{
assert( isdefined( level.airstrikeAttackArrow ) );
coord += vector_multiply( normal, level.airstrikeAttackArrow.offset );
level.airstrikeAttackArrow.origin = coord;
level.airstrikeAttackArrow rotateTo( vectortoangles( normal ), 0.2 );
}
airstrike_support_deactive()
{
wait 0.05;
if ( isdefined( level.airstrikeAttackArrow ) )
level.airstrikeAttackArrow delete();
}
airstrike_support_paint_target()
{
level endon( "air_support_canceled" );
level.player waittill ( "weapon_fired" );
flag_set( "airstrike_in_progress" );
maps\_friendlyfire::TurnOff();
level.activeAirstrikes++;
airstrike_ammo = level.player getWeaponAmmoStock( "airstrike_support" );
if( !isdefined( airstrike_ammo ) )
{
level notify ( "no_airstrike_ammo" );
}
else
if( airstrike_ammo == 0 )
{
level notify ( "no_airstrike_ammo" );
}
thread airstrike_support_mark();
// give player his weapon back
weaponList = level.player GetWeaponsListPrimaries();
if ( isdefined( weaponList[ 0 ] ) && ( weaponList[ 0 ] == level.playerPreviousWeapon ) )
{
level.player switchToWeapon( weaponList[ 0 ] );
}
else
if ( isdefined( weaponList[ 1 ] ) && ( weaponList[ 1 ] == level.playerPreviousWeapon ) )
{
level.player switchToWeapon( weaponList[ 1 ] );
}
else
{
level.player switchToWeapon( weaponList[ 0 ] );
}
coord = level.airstrikeAttackArrow.origin;
thread airstrike_support_launch( coord );
level notify( "air_support_called" );
airstrike_support_deactive();
level.airstrikeSupportCallsRemaining--;
if ( ( level.airstrikeSupportCallsRemaining % 2 ) == 0 )
radio_dialogue_queue( "airstrikewarning" );
else
if ( ( level.airstrikeSupportCallsRemaining % 2 ) != 0 )
radio_dialogue_queue( "airstrikewarning" );
else
if ( level.airstrikeSupportCallsRemaining <= 0 )
radio_dialogue_queue( "airstrikewarning" );
}
airstrike_support_launch( coord )
{
wait 5;
thread callStrike( coord );
}
airstrike_support_mark()
{
marker = spawn( "script_model", level.airstrikeAttackArrow.origin );
marker setModel( "tag_origin" );
marker.angles = level.airstrikeAttackArrow.angles;
wait 0.1;
playfxontag( level.air_support_fx_red, marker, "tag_origin" );
wait 5.0;
marker delete();
}
//=======================================================================
callStrike( coord, flybyOnly, direction )
{
// Get starting and ending point for the plane
if( !isdefined( direction ) )
{
//direction = ( 0, randomint( 360 ), 0 );
//get vector between player's current position and the target coordinates and pick a good flight path start point
//so that the planes don't cluster bomb the player, which is annoying
vec = coord - level.player.origin;
angles = vectortoangles( vec );
yaw = angles[ 1 ];
spread = 75;
for ( ;; )
{
direction = ( 0, randomint( 360 ), 0 );
absyawdiff = animscripts\utility::AbsAngleClamp180( yaw - direction[ 1 ] );
if ( absyawdiff < 180 - spread )
break;
if ( absyawdiff > 180 + spread )
break;
wait 0.05;
}
}
planeHalfDistance = 24000;
planeBombExplodeDistance = 200; //1500
if( level.lowplaneflyby < 3 )
{
planeFlyHeight = 850;
level.lowplaneflyby++;
}
else
{
planeFlyHeight = 1850; //850 original
}
planeFlySpeed = 6000; //7000
startPoint = coord + vector_scale( anglestoforward( direction ), -1 * planeHalfDistance );
startPoint += ( 0, 0, planeFlyHeight );
endPoint = coord + vector_scale( anglestoforward( direction ), planeHalfDistance );
endPoint += ( 0, 0, planeFlyHeight );
// Make the plane fly by
d = length( startPoint - endPoint );
flyTime = ( d / planeFlySpeed );
// bomb explodes planeBombExplodeDistance after the plane passes the center
d = abs( d/2 + planeBombExplodeDistance );
bombTime = ( d / planeFlySpeed );
assert( flyTime > bombTime );
if( isdefined( flybyOnly ) )
{
level thread doPlaneStrike( coord, startPoint+(0,0,randomInt(500)), endPoint+(0,0,randomInt(500)), bombTime, flyTime, direction, flybyOnly );
return;
}
level thread doPlaneStrike( coord, startPoint+(0,0,randomInt(500)), endPoint+(0,0,randomInt(500)), bombTime, flyTime, direction );
wait randomfloatrange( 1.5, 2.5 );
level thread doPlaneStrike( coord, startPoint+(0,0,randomInt(200)), endPoint+(0,0,randomInt(200)), bombTime, flyTime, direction );
wait randomfloatrange( .3, 1 );
level thread doPlaneStrike( coord, startPoint+(0,0,randomInt(200)), endPoint+(0,0,randomInt(200)), bombTime, flyTime, direction );
wait randomfloatrange( 1.5, 2.5 );
level thread doPlaneStrike( coord, startPoint+(0,0,randomInt(200)), endPoint+(0,0,randomInt(200)), bombTime, flyTime, direction );
thread airstrike_completion_check();
}
airstrike_completion_check()
{
wait 27;
level.activeAirstrikes--;
if( !level.activeAirstrikes )
{
flag_clear( "airstrike_in_progress" );
maps\_friendlyfire::TurnBackOn();
}
}
vector_scale(vec, scale)
{
vec = (vec[0] * scale, vec[1] * scale, vec[2] * scale);
return vec;
}
doPlaneStrike( bombsite, startPoint, endPoint, bombTime, flyTime, direction, flybyOnly )
{
// plane spawning randomness = up to 125 units, biased towards 0
// radius of bomb damage is 512
startPathRandomness = 100;
endPathRandomness = 150;
pathStart = startPoint + ( (randomfloat(2) - 1)*startPathRandomness, (randomfloat(2) - 1)*startPathRandomness, 0 );
pathEnd = endPoint + ( (randomfloat(2) - 1)*endPathRandomness , (randomfloat(2) - 1)*endPathRandomness , 0 );
// Spawn the planes
//plane = spawnplane( "script_model", pathStart );
plane = spawn( "script_model", pathStart );
//plane setModel( "vehicle_mig29_desert" );
plane setModel( "vehicle_av8b_harrier_jet" );
plane.angles = direction;
plane thread playContrail();
plane moveTo( pathEnd, flyTime, 0, 0 );
thread callStrike_planeSound( plane, bombsite );
// callStrike_bomb( bomb time, bomb location, number of bombs )
thread callStrike_bombEffect( plane, bombTime - 1.0, flybyOnly );
//thread callStrike_bomb( bombTime, bombsite, 2, owner );
// Delete the plane after its flyby
wait flyTime;
plane notify( "delete" );
plane delete();
}
playContrail()
{
self endon ( "death" );
if ( !isDefined( level.mapCenter ) )
mapCenter = (0,0,0);
else
mapCenter = level.mapCenter;
while ( isdefined( self ) )
{
if ( distance( self.origin , mapCenter ) <= 4000 )
{
playfxontag( level.fx_airstrike_contrail, self, "tag_right_wingtip" );
playfxontag( level.fx_airstrike_contrail, self, "tag_left_wingtip" );
return;
}
wait 0.05;
}
}
callStrike_planeSound( plane, bombsite )
{
plane thread play_loop_sound_on_entity( "veh_mig29_dist_loop" );
while( !targetisclose( plane, bombsite ) )
wait .05;
plane notify ( "stop sound" + "veh_mig29_dist_loop" );
plane thread play_loop_sound_on_entity( "veh_mig29_close_loop" );
while( targetisinfront( plane, bombsite ) )
wait .05;
wait .5;
//plane thread play_sound_in_space( "veh_mig29_sonic_boom" );
while( targetisclose( plane, bombsite ) )
wait .05;
plane notify ( "stop sound" + "veh_mig29_close_loop" );
plane thread play_loop_sound_on_entity( "veh_mig29_dist_loop" );
plane waittill( "delete" );
plane notify ( "stop sound" + "veh_mig29_dist_loop" );
}
targetisinfront(other, target)
{
forwardvec = anglestoforward(flat_angle(other.angles));
normalvec = vectorNormalize(flat_origin(target)-other.origin);
dot = vectordot(forwardvec,normalvec);
if(dot > 0)
return true;
else
return false;
}
targetisclose(other, target)
{
infront = targetisinfront(other, target);
if(infront)
dir = 1;
else
dir = -1;
a = flat_origin(other.origin);
b = a+vector_scale(anglestoforward(flat_angle(other.angles)), (dir*100000));
point = pointOnSegmentNearestToPoint(a,b, target);
dist = distance(a,point);
if (dist < 3000)
return true;
else
return false;
}
callStrike_bombEffect( plane, launchTime, flybyOnly )
{
wait ( launchTime );
plane thread play_sound_in_space( "veh_mig29_sonic_boom" );
if( !isdefined( flybyOnly ) )
{
bomb = spawnbomb( plane.origin, plane.angles );
bomb moveGravity( vector_scale( anglestoforward( plane.angles ), 7000/1.5 ), 3.0 );
wait ( 1.0 );
newBomb = spawn( "script_model", bomb.origin );
newBomb setModel( "tag_origin" );
newBomb.origin = bomb.origin;
newBomb.angles = bomb.angles;
wait (0.05);
bomb delete();
bomb = newBomb;
bombOrigin = bomb.origin;
bombAngles = bomb.angles;
playfxontag( level.airstrikefx, bomb, "tag_origin" );
// bomb hide();
//wait ( 0.5 );
wait 1.6;
repeat = 12;
minAngles = 5;
maxAngles = 55;
angleDiff = (maxAngles - minAngles) / repeat;
for( i = 0; i < repeat; i++ )
{
traceDir = anglesToForward( bombAngles + (maxAngles-(angleDiff * i),randomInt( 10 )-5,0) );
traceEnd = bombOrigin + vector_scale( traceDir, 10000 );
trace = bulletTrace( bombOrigin, traceEnd, false, undefined );
traceHit = trace["position"];
radiusDamage( traceHit + (0,0,16), 512, 400, 30, level.airStriker ); // targetpos, radius, maxdamage, mindamage
if ( i%3 == 0 )
{
thread playsoundinspace( "clusterbomb_explode_default", traceHit );
playRumbleOnPosition( "artillery_rumble", traceHit );
earthquake( 0.7, 0.75, traceHit, 1000 );
}
wait ( 0.75/repeat );
}
wait ( 1.0 );
bomb delete();
}
}
playSoundinSpace (alias, origin, master)
{
org = spawn ("script_origin",(0,0,1));
if (!isdefined (origin))
origin = self.origin;
org.origin = origin;
if (isdefined(master) && master)
org playsoundasmaster (alias);
else
org playsound (alias);
wait ( 10.0 );
org delete();
}
spawnbomb( origin, angles )
{
bomb = spawn( "script_model", origin );
bomb.angles = angles;
bomb setModel( "projectile_cbu97_clusterbomb" );
return bomb;
}
friendly_player_tracking_nav()
{
self endon ( "death" );
level endon ( "lz_reached" );
level endon ( "player_made_it" );
self.goalradius = 1400;
self.fixednode = false;
playerHeliDetector = getent( "player_in_blackhawk_detector", "targetname" );
heliDefaultNode = getnode( "bait_crashsite", "targetname" );
while( 1 )
{
wait randomfloatrange( 3, 5 );
if( level.player isTouching( playerHeliDetector ) )
{
self setgoalnode( heliDefaultNode );
}
else
{
self setgoalpos( level.player.origin );
}
}
}
aiPopCount()
{
aAllies = getaiarray( "allies" );
aAxis = getaiarray( "axis" );
totalPop = aAllies.size + aAxis.size;
return( totalPop );
}