IL-GSC/BO1/PC/ZM/maps/_zombiemode_ai_monkey.gsc
2024-02-18 17:32:07 -05:00

2179 lines
62 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include maps\_utility;
#include common_scripts\utility;
#include maps\_zombiemode_utility;
#include animscripts\zombie_Utility;
init()
{
PrecacheRumble( "explosion_generic" );
init_monkey_zombie_anims();
level._effect["monkey_groundhit"] = loadfx("maps/zombie/fx_zmb_monkey_ground_hit");
level._effect["monkey_death"] = loadfx("maps/zombie/fx_zmb_monkey_death");
level._effect["monkey_spawn"] = loadfx("maps/zombie/fx_zombie_ape_spawn_dust");
level._effect["monkey_eye_glow"] = LoadFx( "maps/zombie/fx_zmb_monkey_eyes" );
if( !isDefined( level.monkey_zombie_spawn_heuristic ) )
{
level.monkey_zombie_spawn_heuristic = maps\_zombiemode_ai_monkey::monkey_zombie_default_spawn_heuristic;
}
if ( !isDefined( level.monkey_zombie_enter_level ) )
{
level.monkey_zombie_enter_level = ::monkey_zombie_default_enter_level;
}
precacheshellshock( "electrocution" );
level.num_monkey_zombies = 0;
level.monkey_zombie_spawners = GetEntArray( "monkey_zombie_spawner", "targetname" );
array_thread( level.monkey_zombie_spawners, ::add_spawn_function, maps\_zombiemode_ai_monkey::monkey_prespawn );
if ( !isDefined( level.max_monkey_zombies ) )
{
level.max_monkey_zombies = 1;
}
if ( !isDefined( level.monkey_zombie_min_health ) )
{
level.monkey_zombie_min_health = 150;
}
if ( !isDefined( level.monkey_zombie_groundhit_damage ) )
{
level.monkey_zombie_groundhit_damage = 100;
}
if ( !isDefined( level.monkey_zombie_groundhit_trigger_radius ) )
{
level.monkey_zombie_groundhit_trigger_radius = 96;
}
if ( !isDefined( level.monkey_zombie_groundhit_damage_radius ) )
{
level.monkey_zombie_groundhit_damage_radius = 280;
}
if ( !isDefined( level.monkey_ground_attack_delay ) )
{
level.monkey_ground_attack_delay = 5000;
}
if ( !isdefined( level.monkeys_per_pack ) )
{
level.monkeys_per_pack = 3;
}
if ( !isDefined( level.monkey_pack_max ) )
{
level.monkey_pack_max = 1;
}
if ( !isdefined( level.monkey_pack ) )
{
level.monkey_pack = [];
}
if ( !isdefined( level.machine_health_max ) )
{
level.machine_health_max = 100;
}
if ( !isdefined( level.machine_damage_min ) )
{
level.machine_damage_min = 1;
}
if ( !isdefined( level.machine_damage_max ) )
{
level.machine_damage_max = 8;
}
if ( !isdefined( level.ground_hit_delay ) )
{
level.ground_hit_delay = RandomFloatRange( 4.5, 6.5 ) * 1000;
}
level.monkey_death = 0;
level.monkey_death_total = 0;
level.monkey_packs_killed = 0;
level.monkey_encounters = 1;
level.monkey_intermission = false;
flag_init( "monkey_round" );
flag_init( "last_monkey_down" );
flag_init( "monkey_pack_down" );
flag_init( "perk_bought" );
flag_init( "monkey_free_perk" );
level thread monkey_round_tracker();
level.perk_lost_func = ::monkey_perk_lost;
level.perk_bought_func = ::monkey_perk_bought;
level.revive_solo_fx_func = ::monkey_revive_solo_fx;
}
#using_animtree( "generic_human" );
monkey_prespawn()
{
self.animname = "monkey_zombie";
self.custom_idle_setup = maps\_zombiemode_ai_monkey::monkey_zombie_idle_setup;
self.a.idleAnimOverrideArray = [];
self.a.idleAnimOverrideArray["stand"] = [];
self.a.idleAnimOverrideWeights["stand"] = [];
self.a.idleAnimOverrideArray["stand"][0][0] = %ai_zombie_monkey_idle_01;
self.a.idleAnimOverrideWeights["stand"][0][0] = 10;
self.a.idleAnimOverrideArray["stand"][0][1] = %ai_zombie_monkey_idle_01;
self.a.idleAnimOverrideWeights["stand"][0][1] = 10;
rand = randomIntRange( 1, 4 );
self.deathanim = level.scr_anim["monkey_zombie"]["death"+rand];
self.ignorelocationaldamage = true;
self.ignoreall = true;
self.allowdeath = true;
self.is_zombie = true;
self.has_legs = true;
self allowedStances( "stand" );
self.gibbed = false;
self.head_gibbed = false;
self PushPlayer( true );
self.disableArrivals = true;
self.disableExits = true;
self.grenadeawareness = 0;
self.badplaceawareness = 0;
self.ignoreSuppression = true;
self.suppressionThreshold = 1;
self.noDodgeMove = true;
self.dontShootWhileMoving = true;
self.pathenemylookahead = 0;
self.badplaceawareness = 0;
self.chatInitialized = false;
self.a.disablePain = true;
self disable_react();
self.freezegun_damage = 0;
self.dropweapon = false;
self thread maps\_zombiemode_spawner::zombie_damage_failsafe();
self thread maps\_zombiemode_spawner::delayed_zombie_eye_glow();
self.flame_damage_time = 0;
self.meleeDamage = 40;
self.no_powerups = true;
self.no_gib = 1;
self.custom_damage_func = ::monkey_custom_damage;
self.chest_beat = false;
self.machine_damage = level.machine_damage_min;
self setPhysParams( 24, 0, 24 );
self.dropped = true;
self setTeamForEntity( "axis" );
self AllowPitchAngle( 1 );
self.thundergun_fling_func = ::monkey_fling;
self monkey_zombie_set_state( "default" );
self.noChangeDuringMelee = true;
if ( isDefined( level.monkey_prespawn ) )
{
self [[ level.monkey_prespawn ]]();
}
self notify( "zombie_init_done" );
}
monkey_zombie_idle_setup()
{
self.a.array["turn_left_45"] = %exposed_tracking_turn45L;
self.a.array["turn_left_90"] = %exposed_tracking_turn90L;
self.a.array["turn_left_135"] = %exposed_tracking_turn135L;
self.a.array["turn_left_180"] = %exposed_tracking_turn180L;
self.a.array["turn_right_45"] = %exposed_tracking_turn45R;
self.a.array["turn_right_90"] = %exposed_tracking_turn90R;
self.a.array["turn_right_135"] = %exposed_tracking_turn135R;
self.a.array["turn_right_180"] = %exposed_tracking_turn180L;
self.a.array["exposed_idle"] = array( %ai_zombie_monkey_idle_01, %ai_zombie_monkey_idle_01 );
self.a.array["straight_level"] = %ai_zombie_monkey_idle_01;
self.a.array["stand_2_crouch"] = %ai_zombie_shot_leg_right_2_crawl;
}
init_monkey_specific_zombie_anims()
{
level.scr_anim["monkey_zombie"]["death1"] = %ai_zombie_monkey_death_01;
level.scr_anim["monkey_zombie"]["death2"] = %ai_zombie_monkey_death_02;
level.scr_anim["monkey_zombie"]["death3"] = %ai_zombie_monkey_death_03;
level.scr_anim["monkey_zombie"]["walk1"] = %ai_zombie_monkey_run_01;
level.scr_anim["monkey_zombie"]["walk2"] = %ai_zombie_monkey_run_01;
level.scr_anim["monkey_zombie"]["walk3"] = %ai_zombie_monkey_run_01;
level.scr_anim["monkey_zombie"]["walk4"] = %ai_zombie_monkey_run_01;
level.scr_anim["monkey_zombie"]["walk5"] = %ai_zombie_monkey_run_01;
level.scr_anim["monkey_zombie"]["walk6"] = %ai_zombie_monkey_run_01;
level.scr_anim["monkey_zombie"]["walk7"] = %ai_zombie_monkey_run_01;
level.scr_anim["monkey_zombie"]["walk8"] = %ai_zombie_monkey_run_01;
level.scr_anim["monkey_zombie"]["run1"] = %ai_zombie_monkey_run_01;
level.scr_anim["monkey_zombie"]["run2"] = %ai_zombie_monkey_run_02;
level.scr_anim["monkey_zombie"]["sprint1"] = %ai_zombie_monkey_sprint_01;
level.scr_anim["monkey_zombie"]["sprint2"] = %ai_zombie_monkey_sprint_02;
level.scr_anim["monkey_zombie"]["sprint3"] = %ai_zombie_monkey_sprint_03;
level.scr_anim["monkey_zombie"]["sprint4"] = %ai_zombie_monkey_sprint_04;
level._zombie_melee["monkey_zombie"][0] = %ai_zombie_monkey_attack_01;
level._zombie_melee["monkey_zombie"][1] = %ai_zombie_monkey_attack_02;
level._zombie_melee["monkey_zombie"][2] = %ai_zombie_monkey_attack_03;
level._zombie_melee["monkey_zombie"][3] = %ai_zombie_monkey_attack_04;
level._zombie_melee["monkey_zombie"][4] = %ai_zombie_monkey_attack_05;
level._zombie_melee["monkey_zombie"][5] = %ai_zombie_monkey_attack_06;
level._zombie_melee["monkey_zombie"][6] = %ai_zombie_monkey_attack_07;
level._zombie_run_melee["monkey_zombie"][0] = %ai_zombie_monkey_attack_01;
level._zombie_run_melee["monkey_zombie"][1] = %ai_zombie_monkey_attack_02;
level._zombie_run_melee["monkey_zombie"][2] = %ai_zombie_monkey_attack_03;
level._zombie_deaths["monkey_zombie"] = [];
level._zombie_deaths["monkey_zombie"][0] = %ai_zombie_monkey_death_01;
level._zombie_deaths["monkey_zombie"][1] = %ai_zombie_monkey_death_02;
level._zombie_deaths["monkey_zombie"][2] = %ai_zombie_monkey_death_03;
level._zombie_board_taunt["monkey_zombie"][0] = %ai_zombie_monkey_taunt_01;
level._zombie_board_taunt["monkey_zombie"][1] = %ai_zombie_monkey_taunt_02;
level._zombie_board_taunt["monkey_zombie"][2] = %ai_zombie_monkey_taunt_03;
level._zombie_board_taunt["monkey_zombie"][3] = %ai_zombie_monkey_taunt_04;
level._zombie_board_taunt["monkey_zombie"][4] = %ai_zombie_monkey_taunt_05;
level.monkey_groundpound_anims[0] = %ai_zombie_monkey_groundpound_01;
level.monkey_groundpound_anims[1] = %ai_zombie_monkey_groundpound_02;
level.monkey_groundpound_anims[2] = %ai_zombie_monkey_groundpound_03;
level.monkey_groundpound_anims[3] = %ai_zombie_monkey_groundpound_04;
level.monkey_perk_attack_anims[0] = %ai_zombie_monkey_attack_perks_front;
level.monkey_perk_attack_anims[1] = %ai_zombie_monkey_attack_perks_left;
level.monkey_perk_attack_anims[2] = %ai_zombie_monkey_attack_perks_left_top;
level.monkey_perk_attack_anims[3] = %ai_zombie_monkey_attack_perks_right;
level.monkey_perk_attack_anims[4] = %ai_zombie_monkey_attack_perks_right_top;
level.monkey_perk_attack_anims["specialty_armorvest"]["left_top"] = %ai_zombie_monkey_attack_perks_left_top_jugg;
level.monkey_perk_attack_anims["specialty_armorvest"]["right_top"] = %ai_zombie_monkey_attack_perks_right_top_jugg;
level.monkey_perk_attack_anims["specialty_longersprint"]["left_top"] = %ai_zombie_monkey_attack_perks_left_top_marathon;
level.monkey_perk_attack_anims["specialty_longersprint"]["right_top"] = %ai_zombie_monkey_attack_perks_right_top_marathon;
level.monkey_perk_attack_anims["specialty_quickrevive"]["left_top"] = %ai_zombie_monkey_attack_perks_left_top_revive;
level.monkey_perk_attack_anims["specialty_quickrevive"]["right_top"] = %ai_zombie_monkey_attack_perks_right_top_revive;
level.monkey_perk_attack_anims["specialty_fastreload"]["left_top"] = %ai_zombie_monkey_attack_perks_left_top_speed;
level.monkey_perk_attack_anims["specialty_fastreload"]["right_top"] = %ai_zombie_monkey_attack_perks_right_top_speed;
level.monkey_thundergun_roll_anims[0] = %ai_zombie_monkey_thundergun_roll_01;
level.monkey_thundergun_roll_anims[1] = %ai_zombie_monkey_thundergun_roll_02;
level.monkey_thundergun_roll_anims[2] = %ai_zombie_monkey_thundergun_roll_03;
level.monkey_thundergun_roll_anims[3] = %ai_zombie_monkey_thundergun_roll_04;
}
#using_animtree( "generic_human" );
init_monkey_zombie_anims()
{
level.scr_anim["monkey_zombie"]["crawl1"] = %ai_zombie_crawl;
level.scr_anim["monkey_zombie"]["crawl2"] = %ai_zombie_crawl_v1;
level.scr_anim["monkey_zombie"]["crawl3"] = %ai_zombie_crawl_v2;
level.scr_anim["monkey_zombie"]["crawl4"] = %ai_zombie_crawl_v3;
level.scr_anim["monkey_zombie"]["crawl5"] = %ai_zombie_crawl_v4;
level.scr_anim["monkey_zombie"]["crawl6"] = %ai_zombie_crawl_v5;
level.scr_anim["monkey_zombie"]["crawl_hand_1"] = %ai_zombie_walk_on_hands_a;
level.scr_anim["monkey_zombie"]["crawl_hand_2"] = %ai_zombie_walk_on_hands_b;
level.scr_anim["monkey_zombie"]["crawl_sprint1"] = %ai_zombie_crawl_sprint;
level.scr_anim["monkey_zombie"]["crawl_sprint2"] = %ai_zombie_crawl_sprint_1;
level.scr_anim["monkey_zombie"]["crawl_sprint3"] = %ai_zombie_crawl_sprint_2;
if( !isDefined( level._zombie_melee ) )
{
level._zombie_melee = [];
}
if( !isDefined( level._zombie_walk_melee ) )
{
level._zombie_walk_melee = [];
}
if( !isDefined( level._zombie_run_melee ) )
{
level._zombie_run_melee = [];
}
level._zombie_melee["monkey_zombie"] = [];
level._zombie_walk_melee["monkey_zombie"] = [];
level._zombie_run_melee["monkey_zombie"] = [];
if( isDefined( level.monkey_zombie_anim_override ) )
{
[[ level.monkey_zombie_anim_override ]]();
}
if( !isDefined( level._zombie_melee_crawl ) )
{
level._zombie_melee_crawl = [];
}
level._zombie_melee_crawl["monkey_zombie"] = [];
level._zombie_melee_crawl["monkey_zombie"][0] = %ai_zombie_attack_crawl;
level._zombie_melee_crawl["monkey_zombie"][1] = %ai_zombie_attack_crawl_lunge;
if( !isDefined( level._zombie_stumpy_melee ) )
{
level._zombie_stumpy_melee = [];
}
level._zombie_stumpy_melee["monkey_zombie"] = [];
level._monkey_zombie_stumpy_melee["monkey_zombie"][0] = %ai_zombie_walk_on_hands_shot_a;
level._monkey_zombie_stumpy_melee["monkey_zombie"][1] = %ai_zombie_walk_on_hands_shot_b;
if( !isDefined( level._zombie_tesla_deaths ) )
{
level._zombie_tesla_deaths = [];
}
level._zombie_tesla_death["monkey_zombie"] = [];
level._zombie_tesla_death["monkey_zombie"][0] = %ai_zombie_boss_tesla_death_a;
level._zombie_tesla_death["monkey_zombie"][1] = %ai_zombie_boss_tesla_death_a;
level._zombie_tesla_death["monkey_zombie"][2] = %ai_zombie_boss_tesla_death_a;
level._zombie_tesla_death["monkey_zombie"][3] = %ai_zombie_boss_tesla_death_a;
level._zombie_tesla_death["monkey_zombie"][4] = %ai_zombie_boss_tesla_death_a;
if( !isDefined( level._zombie_tesla_crawl_death ) )
{
level._zombie_tesla_crawl_death = [];
}
level._zombie_tesla_crawl_death["monkey_zombie"] = [];
level._zombie_tesla_crawl_death["monkey_zombie"][0] = %ai_zombie_tesla_crawl_death_a;
level._zombie_tesla_crawl_death["monkey_zombie"][1] = %ai_zombie_tesla_crawl_death_b;
if( !isDefined( level._zombie_deaths ) )
{
level._zombie_deaths = [];
}
if( !isDefined( level._zombie_rise_anims ) )
{
level._zombie_rise_anims = [];
}
level._zombie_rise_anims["monkey_zombie"] = [];
level._zombie_rise_anims["monkey_zombie"][1]["walk"][0] = %ai_zombie_traverse_ground_v1_walk;
level._zombie_rise_anims["monkey_zombie"][1]["run"][0] = %ai_zombie_traverse_ground_v1_run;
level._zombie_rise_anims["monkey_zombie"][1]["sprint"][0] = %ai_zombie_traverse_ground_climbout_fast;
level._zombie_rise_anims["monkey_zombie"][2]["walk"][0] = %ai_zombie_traverse_ground_v2_walk_altA;
if( !isDefined( level._zombie_rise_death_anims ) )
{
level._zombie_rise_death_anims = [];
}
level._zombie_rise_death_anims["monkey_zombie"] = [];
level._zombie_rise_death_anims["monkey_zombie"][1]["in"][0] = %ai_zombie_traverse_ground_v1_deathinside;
level._zombie_rise_death_anims["monkey_zombie"][1]["in"][1] = %ai_zombie_traverse_ground_v1_deathinside_alt;
level._zombie_rise_death_anims["monkey_zombie"][1]["out"][0] = %ai_zombie_traverse_ground_v1_deathoutside;
level._zombie_rise_death_anims["monkey_zombie"][1]["out"][1] = %ai_zombie_traverse_ground_v1_deathoutside_alt;
level._zombie_rise_death_anims["monkey_zombie"][2]["in"][0] = %ai_zombie_traverse_ground_v2_death_low;
level._zombie_rise_death_anims["monkey_zombie"][2]["in"][1] = %ai_zombie_traverse_ground_v2_death_low_alt;
level._zombie_rise_death_anims["monkey_zombie"][2]["out"][0] = %ai_zombie_traverse_ground_v2_death_high;
level._zombie_rise_death_anims["monkey_zombie"][2]["out"][1] = %ai_zombie_traverse_ground_v2_death_high_alt;
if( !isDefined( level._zombie_run_taunt ) )
{
level._zombie_run_taunt = [];
}
if( !isDefined( level._zombie_board_taunt ) )
{
level._zombie_board_taunt = [];
}
level._zombie_run_taunt["monkey_zombie"] = [];
level._zombie_board_taunt["monkey_zombie"] = [];
init_monkey_specific_zombie_anims();
}
monkey_zombie_spawn( pack )
{
self.script_moveoverride = true;
if( !isDefined( level.num_monkey_zombies ) )
{
level.num_monkey_zombies = 0;
}
level.num_monkey_zombies++;
monkey_zombie = self maps\_zombiemode_net::network_safe_stalingrad_spawn( "monkey_zombie_spawn", 1 );
self.count = 666;
self.last_spawn_time = GetTime();
if( !spawn_failed( monkey_zombie ) )
{
monkey_zombie.script_noteworthy = self.script_noteworthy;
monkey_zombie.targetname = self.targetname;
monkey_zombie.target = self.target;
monkey_zombie.deathFunction = maps\_zombiemode_ai_monkey::monkey_zombie_die;
monkey_zombie.animname = "monkey_zombie";
monkey_zombie.pack = pack;
monkey_zombie.perk = pack.perk;
monkey_zombie.ground_hit_time = pack.ground_hit_time;
monkey_zombie.spawn_origin = self.origin;
monkey_zombie.spawn_angles = self.angles;
monkey_zombie thread monkey_zombie_think();
}
else
{
level.num_monkey_zombies--;
}
return monkey_zombie;
}
monkey_round_spawning()
{
level endon( "intermission" );
level endon( "end_of_round" );
level endon( "restart_round" );
if ( level.intermission )
{
return;
}
level.monkey_intermission = true;
level thread monkey_round_aftermath();
pack_idx = 0;
while ( 1 )
{
level monkey_pack_spawn();
pack_idx++;
if ( pack_idx >= level.monkey_pack_max )
{
break;
}
time = RandomFloatRange( 3.2, 4.4 );
wait( time );
wait_network_frame();
}
}
monkey_setup_packs()
{
level.monkey_packs_killed = 0;
players = getplayers();
if ( players.size > level.monkey_encounters )
{
level.monkey_pack_max = players.size + level.monkey_encounters;
}
else
{
level.monkey_pack_max = players.size * 2;
}
level.monkey_encounters++;
}
monkey_setup_health()
{
switch( level.monkey_encounters )
{
case 1:
level.monkey_zombie_health = level.zombie_health * 0.25;
break;
case 2:
level.monkey_zombie_health = level.zombie_health * 0.5;
break;
case 3:
level.monkey_zombie_health = level.zombie_health * 0.75;
break;
default:
level.monkey_zombie_health = level.zombie_health;
break;
}
if ( level.zombie_health > 1600 )
{
level.zombie_health = 1600;
}
monkey_print( "monkey health = " + level.monkey_zombie_health );
}
monkey_setup_spawners()
{
level.current_monkey_spawners = [];
for ( i = 0; i < level.monkey_zombie_spawners.size; i++ )
{
if ( level.zones[ level.monkey_zombie_spawners[i].script_noteworthy ].is_enabled )
{
level.current_monkey_spawners[ level.current_monkey_spawners.size ] = level.monkey_zombie_spawners[i];
}
}
level.current_monkey_spawners = array_randomize( level.current_monkey_spawners );
level.monkey_spawner_idx = 0;
}
monkey_get_next_spawner()
{
spawner = level.current_monkey_spawners[ level.monkey_spawner_idx ];
assertex( isdefined( spawner ), "no monkey spawner found" );
if ( isdefined( spawner ) )
{
level.monkey_spawner_idx++;
if ( level.monkey_spawner_idx == level.current_monkey_spawners.size )
{
level monkey_setup_spawners();
}
}
return spawner;
}
monkey_get_available_spawners()
{
spawners = [];
for ( i = 0; i < level.monkey_zombie_spawners.size; i++ )
{
if ( level.zones[ level.monkey_zombie_spawners[i].script_noteworthy ].is_enabled )
{
spawners[ spawners.size ] = level.monkey_zombie_spawners[i];
}
}
spawners = array_randomize( spawners );
return spawners;
}
monkey_pack_man_setup_perks()
{
level.monkey_perks = [];
vending_triggers = getentarray( "zombie_vending", "targetname" );
for ( i = 0; i < vending_triggers.size; i++ )
{
if ( vending_triggers[i].targeted )
{
continue;
}
players = getplayers();
for ( j = 0; j < players.size; j++ )
{
perk = vending_triggers[i].script_noteworthy;
org = vending_triggers[i].origin;
if ( isdefined( vending_triggers[i].realorigin ) )
{
org = vending_triggers[i].realorigin;
}
zone_enabled = check_point_in_active_zone( org );
if ( players[j] HasPerk( perk ) && zone_enabled )
{
level.monkey_perks[ level.monkey_perks.size ] = vending_triggers[i];
break;
}
}
}
if ( level.monkey_perks.size > 1 )
{
level.monkey_perks = array_randomize( level.monkey_perks );
}
level.monkey_perk_idx = 0;
}
monkey_pack_man_get_next_perk()
{
if ( level.monkey_perks.size == 0 )
{
self.perk = undefined;
return;
}
perk = level.monkey_perks[ level.monkey_perk_idx ];
perk.targeted = 1;
level.monkey_perk_idx++;
if ( level.monkey_perk_idx == level.monkey_perks.size )
{
level monkey_pack_man_setup_perks();
}
self.perk = perk;
}
monkey_pack_spawn()
{
monkey_print( "spawning pack" );
pack = SpawnStruct();
pack.monkeys = [];
pack.attack = [];
pack.target = undefined;
level.monkey_pack[ level.monkey_pack.size ] = pack;
pack thread monkey_pack_think();
}
monkey_pack_think()
{
self.ground_hit_time = GetTime();
self monkey_pack_man_get_next_perk();
self monkey_pack_set_machine();
self monkey_pack_choose_enemy();
self.spawning_done = false;
for ( i = 0; i < level.monkeys_per_pack; i++ )
{
spawner = monkey_get_next_spawner();
if ( isdefined( spawner ) )
{
monkey = spawner monkey_zombie_spawn( self );
self.monkeys[ self.monkeys.size ] = monkey;
}
if ( i < (level.monkeys_per_pack-1) )
{
time = RandomFloatRange( 2.2, 4.4 );
wait( time );
}
}
self.spawning_done = true;
self thread monkey_pack_update_enemy();
self thread monkey_pack_update_perk();
}
monkey_pack_update_perk()
{
while ( 1 )
{
if ( !isdefined( self.perk ) )
{
break;
}
if ( self.machine.monkey_health == 0 )
{
monkey_print( "pack destroyed " + self.machine.targetname );
self monkey_pack_take_perk();
wait_network_frame();
self monkey_pack_clear_perk_pos();
self monkey_pack_man_get_next_perk();
self monkey_pack_set_machine();
for ( i = 0; i < self.monkeys.size; i++ )
{
if ( !self.monkeys[i].charge_player )
{
self.monkeys[i].perk = self.perk;
self.monkeys[i] notify( "stop_perk_attack" );
}
}
}
wait_network_frame();
}
}
monkey_pack_next_perk()
{
perk = undefined;
perk_idx = -1;
num_perks = 0;
keys = getarraykeys( level.monkey_perks );
for ( i = 0; i < keys.size; i++ )
{
if ( level.monkey_perks[ keys[i] ] > num_perks )
{
num_perks = level.monkey_perks[ keys[i] ];
perk_idx = i;
}
}
if ( perk_idx >= 0 )
{
perk = keys[ perk_idx ];
}
if ( isdefined( perk ) )
{
monkey_print( "perk is " + perk );
}
else
{
monkey_print( "no more perks" );
}
self.perk = perk;
}
monkey_pack_set_machine()
{
self.machine = undefined;
if ( !isdefined( self.perk ) )
{
return;
}
targets = getentarray( self.perk.target, "targetname" );
for ( j = 0; j < targets.size; j++ )
{
if ( targets[j].classname == "script_model" )
{
self.machine = targets[j];
}
}
}
monkey_pack_choose_enemy()
{
monkey_enemy = [];
players = getplayers();
for ( i = 0; i < players.size; i++ )
{
if ( !is_player_valid( players[i] ) )
{
continue;
}
monkey_enemy[ monkey_enemy.size ] = players[i];
}
monkey_enemy = array_randomize( monkey_enemy );
if ( monkey_enemy.size > 0 )
{
self.enemy = monkey_enemy[0];
}
else
{
self.enemy = players[0];
}
}
monkey_pack_update_enemy()
{
while ( self.monkeys.size > 0 )
{
players = getplayers();
total_dist = 1000000;
player_idx = 0;
for ( i = 0; i < players.size; i++ )
{
if ( !is_player_valid( players[i] ) )
{
continue;
}
dist = 0;
for ( j = 0; j < self.monkeys.size; j++ )
{
if ( !isdefined( self.monkeys[j] ) )
{
continue;
}
dist += Distance( players[i].origin, self.monkeys[j].origin );
}
if ( dist < total_dist )
{
total_dist = dist;
player_idx = i;
}
}
if ( isdefined( players ) )
{
if ( isdefined( self.enemy ) )
{
if ( self.enemy != players[ player_idx ] )
{
monkey_print( "pack enemy is " + self.enemy.playername );
}
}
else
{
monkey_print( "pack enemy is " + players[ player_idx ].playername );
}
self.enemy = players[ player_idx ];
}
wait( 0.2 );
}
}
monkey_zombie_check_ground_hit()
{
if ( GetTime() >= self.ground_hit_time )
{
return true;
}
return false;
}
monkey_pack_update_ground_hit( hitter )
{
self.ground_hit_time = GetTime() + level.ground_hit_delay;
level.ground_hit_delay = RandomFloatRange( 4.5, 6.5 ) * 1000;
for ( i = 0; i < self.monkeys.size; i++ )
{
if ( isDefined( self.monkeys[i] ) )
{
self.monkeys[i].ground_hit_time = self.ground_hit_time;
}
}
groundpound_reset = level.monkey_zombie_groundhit_trigger_radius * 2;
groundpound_reset_sq = groundpound_reset * groundpound_reset;
for ( i = 0; i < level.monkey_pack.size; i++ )
{
pack = level.monkey_pack[i];
if ( self == pack )
{
continue;
}
for ( j = 0; j < pack.monkeys.size; j++ )
{
monkey = pack.monkeys[j];
if ( !isDefined( monkey ) )
{
continue;
}
if ( hitter == monkey )
{
continue;
}
dist_sq = DistanceSquared( hitter.origin, monkey.origin );
if ( dist_sq <= groundpound_reset_sq )
{
monkey.ground_hit_time = self.ground_hit_time;
}
}
}
monkey_print( "next ground hit in " + level.ground_hit_delay );
}
monkey_round_wait()
{
wait( 1 );
if ( flag( "monkey_round" ) )
{
wait( 7 );
while ( level.monkey_intermission )
{
wait( 0.5 );
}
}
}
monkey_round_aftermath()
{
flag_wait( "last_monkey_down" );
level thread maps\_zombiemode_audio::change_zombie_music( "dog_end" );
level.round_spawn_func = level.monkey_save_spawn_func;
level.round_wait_func = level.monkey_save_wait_func;
wait( 6 );
level.monkey_intermission = false;
}
monkey_round_tracker()
{
flag_wait( "power_on" );
flag_wait( "perk_bought" );
level.monkey_save_spawn_func = level.round_spawn_func;
level.monkey_save_wait_func = level.round_wait_func;
level.next_monkey_round = level.round_number + randomintrange( 1, 4 );
level.prev_monkey_round = level.next_monkey_round;
while ( 1 )
{
level waittill( "between_round_over" );
if ( level.round_number == level.next_monkey_round )
{
if ( !monkey_player_has_perk() )
{
level.next_monkey_round++;
monkey_print( "next monkey round at " + level.next_monkey_round );
continue;
}
level.music_round_override = true;
level.monkey_save_spawn_func = level.round_spawn_func;
level.monkey_save_wait_func = level.round_wait_func;
monkey_round_start();
level.round_spawn_func = ::monkey_round_spawning;
level.round_wait_func = ::monkey_round_wait;
level.prev_monkey_round = level.next_monkey_round;
level.next_monkey_round = level.round_number + randomintrange( 4, 6 );
monkey_print( "next monkey round at " + level.next_monkey_round );
}
else if ( flag( "monkey_round" ) )
{
monkey_round_stop();
level.music_round_override = false;
}
}
}
monkey_round_start()
{
flag_set( "monkey_round" );
flag_set( "monkey_free_perk" );
if ( isDefined( level.monkey_round_start ) )
{
level thread [[ level.monkey_round_start ]]();
}
level thread monkey_zombie_setup_perks();
level monkey_setup_health();
level monkey_setup_spawners();
level monkey_setup_packs();
level monkey_pack_man_setup_perks();
level thread monkey_grenade_watcher();
clientnotify( "monkey_start" );
level thread play_delayed_player_vox();
}
play_delayed_player_vox()
{
wait(8);
players = getplayers();
players[RandomIntRange(0,players.size)] maps\_zombiemode_audio::create_and_play_dialog( "general", "monkey_spawn" );
}
monkey_round_stop()
{
flag_clear( "monkey_round" );
flag_clear( "last_monkey_down" );
if ( isDefined( level.monkey_round_stop ) )
{
level thread [[ level.monkey_round_stop ]]();
}
clientnotify( "monkey_stop" );
level notify( "grenade_watcher_stop" );
}
monkey_player_has_perk()
{
vending_triggers = getentarray( "zombie_vending", "targetname" );
for ( i = 0; i < vending_triggers.size; i++ )
{
players = getplayers();
for ( j = 0; j < players.size; j++ )
{
perk = vending_triggers[i].script_noteworthy;
org = vending_triggers[i].origin;
if ( isdefined( vending_triggers[i].realorigin ) )
{
org = vending_triggers[i].realorigin;
}
zone_enabled = check_point_in_active_zone( org );
if ( players[j] HasPerk( perk ) && zone_enabled )
{
return true;
}
}
}
return false;
}
monkey_zombie_manager()
{
while( true )
{
AssertEx( isDefined( level.num_monkey_zombies ) && isDefined( level.max_monkey_zombies ), "Either max_monkey_zombies or num_monkey_zombies not defined, this should never be the case!" );
while( level.num_monkey_zombies < level.max_monkey_zombies )
{
spawner = monkey_zombie_pick_best_spawner();
if( isDefined( spawner ) )
{
spawner monkey_zombie_spawn();
}
wait( 10 );
}
wait( 10 );
}
}
monkey_zombie_pick_best_spawner()
{
best_spawner = undefined;
best_score = -1;
for( i = 0; i < level.monkey_zombie_spawners.size; i++ )
{
score = [[ level.monkey_zombie_spawn_heuristic ]]( level.monkey_zombie_spawners[i] );
if( score > best_score )
{
best_spawner = level.monkey_zombie_spawners[i];
best_score = score;
}
}
return best_spawner;
}
monkey_zombie_choose_run()
{
self endon( "death" );
rand = randomIntRange( 1, 3 );
self set_run_anim( "run"+rand );
self.run_combatanim = level.scr_anim["monkey_zombie"]["run"+rand];
self.crouchRunAnim = level.scr_anim["monkey_zombie"]["run"+rand];
self.crouchrun_combatanim = level.scr_anim["monkey_zombie"]["run"+rand];
self.zombie_move_speed = "run";
self waittill( "speed_up" );
rand = randomIntRange( 1, 5 );
self set_run_anim( "sprint"+rand );
self.run_combatanim = level.scr_anim["monkey_zombie"]["sprint"+rand];
self.crouchRunAnim = level.scr_anim["monkey_zombie"]["sprint"+rand];
self.crouchrun_combatanim = level.scr_anim["monkey_zombie"]["sprint"+rand];
self.zombie_move_speed = "sprint";
}
monkey_zombie_think()
{
self endon( "death" );
self thread play_random_monkey_vox();
self.goalradius = 32;
self.pathEnemyFightDist = 64;
self.meleeAttackDist = 64;
self.charge_player = false;
level.monkey_zombie_min_health = int( level.monkey_zombie_health );
if( self.maxhealth < level.monkey_zombie_min_health )
{
self.maxhealth = level.monkey_zombie_min_health;
self.health = level.monkey_zombie_min_health;
}
if ( isdefined( level.user_ryan_monkey_health ) )
{
self.maxhealth = 1;
self.health = 1;
}
self thread monkey_zombie_choose_run();
self.maxsightdistsqrd = 96 * 96;
self [[ level.monkey_zombie_enter_level ]]();
if ( isDefined( level.monkey_zombie_custom_think ) )
{
self thread [[ level.monkey_zombie_custom_think ]]();
}
self thread monkey_zombie_ground_hit_think();
self thread monkey_zombie_grenade_watcher();
self thread monkey_zombie_bhb_watcher();
self thread monkey_zombie_speed_watcher();
self thread monkey_zombie_fling_watcher();
self thread monkey_zombie_update();
if ( isDefined( level.monkey_zombie_failsafe ) )
{
self thread [[ level.monkey_zombie_failsafe ]]();
}
}
monkey_zombie_debug()
{
self endon( "death" );
while( true )
{
forward = VectorNormalize( AnglesToForward( self.angles ) );
end_pos = self.origin - vector_scale( forward, 120 );
recordLine( self.origin, end_pos, (.5,1,0), "Script", self );
wait_network_frame();
}
}
monkey_zombie_update()
{
self endon( "death" );
self endon( "monkey_update_stop" );
self animmode( "none" );
while( true )
{
if ( isDefined( self.custom_think ) && self.custom_think )
{
wait_network_frame();
continue;
}
else if ( self.state == "bhb_response" || self.state == "grenade_response" )
{
wait_network_frame();
continue;
}
else if ( isDefined( self.perk ) )
{
self thread monkey_zombie_destroy_perk();
self waittill( "stop_perk_attack" );
wait_network_frame();
continue;
}
else if ( isDefined( self.ground_hit ) && self.ground_hit )
{
wait_network_frame();
continue;
}
else if( !isDefined( self.following_player ) || !self.following_player )
{
self thread maps\_zombiemode_ai_monkey::monkey_find_flesh();
self.following_player = true;
self monkey_zombie_set_state( "charge_player" );
}
wait( 1 );
}
}
monkey_zombie_get_perk_pos()
{
points = getstructarray( self.pack.machine.target, "targetname" );
for ( i = 0; i < points.size; i++ )
{
if ( isdefined( self.pack.attack[i] ) )
{
continue;
}
self.pack.attack[i] = self;
self.attack = points[i];
break;
}
}
monkey_pack_clear_perk_pos()
{
self.attack = [];
}
monkey_zombie_health_watcher()
{
self endon( "death" );
health_limit = self.health * 0.75;
while ( 1 )
{
if ( self.health <= health_limit )
{
self StopAnimScripted();
wait_network_frame();
self notify( "stop_perk_attack" );
self monkey_zombie_set_state( "charge_player" );
self.charge_player = true;
self.perk = undefined;
break;
}
wait_network_frame();
}
}
monkey_zombie_fling_watcher()
{
self endon( "death" );
half_health = level.monkey_zombie_health * 0.5;
while ( 1 )
{
if ( self.health <= half_health )
{
self.thundergun_fling_func = undefined;
break;
}
wait_network_frame();
}
}
monkey_zombie_speed_watcher()
{
self endon( "death" );
while ( 1 )
{
if ( self.health < self.maxhealth )
{
break;
}
wait_network_frame();
}
self notify( "speed_up" );
}
monkey_grenade_watcher()
{
self endon( "death" );
level.monkey_grenades = [];
level.monkey_bhbs = [];
players = getplayers();
for ( i = 0; i < players.size; i++ )
{
players[i] thread monkey_grenade_watch();
}
}
monkey_grenade_watch()
{
self endon( "death" );
level endon( "grenade_watcher_stop" );
while ( true )
{
self waittill( "grenade_fire", grenade, weapName );
if ( is_lethal_grenade( weapName ) )
{
grenade thread monkey_grenade_wait();
grenade.thrower = self;
level.monkey_grenades[ level.monkey_grenades.size ] = grenade;
}
if ( weapName == "zombie_black_hole_bomb" )
{
grenade thread monkey_bhb_wait();
level.monkey_bhbs[ level.monkey_bhbs.size ] = grenade;
}
monkey_print( "thrown from " + weapName );
}
}
monkey_grenade_wait()
{
self waittill( "death" );
level.monkey_grenades = array_remove( level.monkey_grenades, self );
monkey_print( "remove grenade from level" );
}
monkey_bhb_wait()
{
self waittill( "death" );
level.monkey_bhbs = array_remove( level.monkey_bhbs, self );
monkey_print( "remove bhb from level" );
}
monkey_zombie_grenade_throw_watcher( target, animname )
{
self endon( "death" );
self waittillmatch( animname, "grenade_throw" );
throw_angle = RandomIntRange( 20, 30 );
dir = VectorToAngles( target.origin - self.origin );
dir = ( dir[0] - throw_angle, dir[1], dir[2] );
dir = AnglesToForward( dir );
velocity = dir * 550;
fuse = RandomFloatRange( 1, 2 );
hand_pos = self GetTagOrigin( "TAG_WEAPON_RIGHT" );
grenade_type = target get_player_lethal_grenade();
self MagicGrenadeType( grenade_type, hand_pos, velocity, fuse );
}
monkey_zombie_grenade_throw( target )
{
self endon( "death" );
throw_anim = [];
forward = VectorNormalize( AnglesToForward( self.angles ) );
end_pos = self.origin + vector_scale( forward, 96 );
if ( BulletTracePassed( self.origin, end_pos, false, undefined ) )
{
throw_anim[ throw_anim.size ] = %ai_zombie_monkey_grenade_throw_back_run_01;
throw_anim[ throw_anim.size ] = %ai_zombie_monkey_grenade_throw_back_run_02;
throw_anim[ throw_anim.size ] = %ai_zombie_monkey_grenade_throw_back_run_03;
throw_anim[ throw_anim.size ] = %ai_zombie_monkey_grenade_throw_back_run_04;
}
else
{
throw_anim[ throw_anim.size ] = %ai_zombie_monkey_grenade_throw_back_still_01;
throw_anim[ throw_anim.size ] = %ai_zombie_monkey_grenade_throw_back_still_02;
throw_anim[ throw_anim.size ] = %ai_zombie_monkey_grenade_throw_back_still_03;
throw_anim[ throw_anim.size ] = %ai_zombie_monkey_grenade_throw_back_still_04;
}
throw_back_anim = throw_anim[ RandomInt( throw_anim.size ) ];
self animscripted( "throw_back_anim", self.origin, self.angles, throw_back_anim );
self thread monkey_zombie_grenade_throw_watcher( target, "throw_back_anim" );
animscripts\traverse\zombie_shared::wait_anim_length( throw_back_anim, .02 );
choose = RandomInt( level._zombie_board_taunt["monkey_zombie"].size );
taunt_anim = level._zombie_board_taunt["monkey_zombie"][ choose ];
self animscripted( "taunt_anim", self.origin, self.angles, taunt_anim );
animscripts\traverse\zombie_shared::wait_anim_length( taunt_anim, .02 );
self notify( "throw_done" );
}
monkey_zombie_watch_machine_damage()
{
self endon( "death" );
self endon( "stop_perk_attack" );
self endon( "stop_machine_watch" );
arrival_health = self.health;
while ( 1 )
{
monkey_zone = self monkey_get_zone();
if ( isdefined( monkey_zone ) )
{
if ( monkey_zone.is_occupied || self.health < arrival_health )
{
monkey_print( "player is here, go crazy" );
self.machine_damage = level.machine_damage_max;
break;
}
}
wait_network_frame();
}
}
monkey_zombie_set_state( state )
{
self.state = state;
monkey_print( "set state to " + state );
}
monkey_zombie_get_state()
{
if ( isdefined( self.state ) )
{
return self.state;
}
return undefined;
}
monkey_zombie_attack_perk()
{
self endon( "death" );
self endon( "stop_perk_attack" );
self endon( "next_perk" );
if ( !isdefined( self.perk ) )
{
return;
}
flag_clear( "monkey_free_perk" );
self.following_player = false;
self thread monkey_zombie_health_watcher();
self monkey_zombie_set_state( "attack_perk" );
level thread play_player_perk_theft_vox( self.perk.script_noteworthy, self );
spot = self.attack.script_int;
self Teleport( self.attack.origin, self.attack.angles );
monkey_print( "attack " + self.perk.script_noteworthy + " from " + spot );
choose = 0;
if ( spot == 1 )
{
choose = RandomIntRange( 1, 3 );
}
else if ( spot == 3 )
{
choose = RandomIntRange( 3, 5 );
}
perk_attack_anim = undefined;
if ( choose == 2 )
{
if ( isdefined( level.monkey_perk_attack_anims[ self.perk.script_noteworthy ] ) )
{
perk_attack_anim = level.monkey_perk_attack_anims[ self.perk.script_noteworthy ][ "left_top" ];
}
}
else if ( choose == 4 )
{
if ( isdefined( level.monkey_perk_attack_anims[ self.perk.script_noteworthy ] ) )
{
perk_attack_anim = level.monkey_perk_attack_anims[ self.perk.script_noteworthy ][ "right_top" ];
}
}
if ( !isdefined( perk_attack_anim ) )
{
perk_attack_anim = level.monkey_perk_attack_anims[ choose ];
}
time = getAnimLength( perk_attack_anim );
self thread monkey_wait_to_drop();
while ( 1 )
{
monkey_pack_flash_perk( self.perk.script_noteworthy );
self animscripted( "perk_attack_anim", self.attack.origin, self.attack.angles, perk_attack_anim, "normal", %body, 1, 0.2 );
self thread play_attack_impacts( time );
if ( self monkey_zombie_perk_damage( self.machine_damage ) )
{
break;
}
wait( time );
}
self notify( "stop_machine_watch" );
self monkey_zombie_set_state( "attack_perk_done" );
}
monkey_wait_to_drop()
{
self endon( "death" );
wait( 0.2 );
self.dropped = false;
self.perk_attack_origin = self.attack.origin;
while ( true )
{
diff = abs( self.perk_attack_origin[2] - self.origin[2] );
if ( diff < 8 )
{
break;
}
wait_network_frame();
}
self.dropped = true;
monkey_print( "close to ground" );
}
play_player_perk_theft_vox( perk, monkey )
{
force_quit = 0;
if( !IsDefined( level.perk_theft_vox ) )
level.perk_theft_vox = [];
if( !IsDefined( level.perk_theft_vox[perk] ) )
level.perk_theft_vox[perk] = false;
if( level.perk_theft_vox[perk] )
return;
level.perk_theft_vox[perk] = true;
while(1)
{
player = getplayers();
rand = RandomIntRange(0, player.size );
if ( monkey monkey_zombie_perk_damage( monkey.machine_damage ) )
{
level.perk_theft_vox[perk] = false;
return;
}
if( ( IsAlive( player[rand] ) ) && ( !player[rand] maps\_laststand::player_is_in_laststand() ) && ( player[rand] HasPerk( perk ) ) )
{
player[rand] maps\_zombiemode_audio::create_and_play_dialog( "perk", "steal_" + perk );
break;
}
else if( force_quit >= 6 )
{
break;
}
force_quit ++;
wait(.05);
}
while( !monkey monkey_zombie_perk_damage( monkey.machine_damage ) )
{
wait(1);
}
level.perk_theft_vox[perk] = false;
}
play_attack_impacts( time )
{
self endon( "death" );
for(i=0;i<time;i++)
{
if( RandomIntRange(0,100) >= 41 )
self PlaySound( "zmb_monkey_attack_machine" );
wait(RandomFloatRange(.7,1.1));
}
}
monkey_zombie_destroy_perk()
{
self endon( "death" );
self endon( "stop_perk_attack" );
if ( isdefined( self.perk ) )
{
self monkey_zombie_set_state( "destroy_perk" );
monkey_print( "goto " + self.perk.script_noteworthy );
self monkey_zombie_get_perk_pos();
if ( isdefined( self.attack ) )
{
self SetGoalPos( self.attack.origin );
self waittill( "goal" );
self SetGoalPos( self.origin );
self thread monkey_zombie_watch_machine_damage();
self thread monkey_zombie_attack_perk();
}
}
}
monkey_zombie_default_spawn_heuristic( spawner )
{
if( !isDefined( spawner.script_noteworthy ) )
{
return -1;
}
if( !isDefined( level.zones ) || !isDefined( level.zones[ spawner.script_noteworthy ] ) || !level.zones[ spawner.script_noteworthy ].is_enabled )
{
return -1;
}
score = 0;
players = get_players();
for( i = 0; i < players.size; i++ )
{
score = int( distanceSquared( spawner.origin, players[i].origin ) );
}
return score;
}
monkey_zombie_ground_hit()
{
self endon( "death" );
if ( self.ground_hit )
{
return;
}
self monkey_zombie_set_state( "ground_pound" );
self.ground_hit = true;
self thread groundhit_watcher( "groundhit_anim" );
choose = RandomInt( level.monkey_groundpound_anims.size );
groundpound_anim = level.monkey_groundpound_anims[ choose ];
self animscripted( "groundhit_anim", self.origin, self.angles, groundpound_anim );
animscripts\traverse\zombie_shared::wait_anim_length(groundpound_anim, .02);
self.ground_hit = false;
self monkey_zombie_set_state( "ground_pound_done" );
self.nextGroundHit = GetTime() + level.monkey_ground_attack_delay;
if ( self.chest_beat )
{
choose = RandomInt( level._zombie_board_taunt["monkey_zombie"].size );
taunt_anim = level._zombie_board_taunt["monkey_zombie"][ choose ];
self animscripted( "taunt_anim", self.origin, self.angles, taunt_anim );
time = getAnimLength( taunt_anim );
wait( time );
self.chest_beat = false;
}
self thread animscripts\zombie_combat::main();
}
monkey_pack_ready_to_detonate( claymore )
{
for ( i = 0; i < self.monkeys.size; i++ )
{
if ( self.monkeys[i] == self )
{
continue;
}
ready = self.monkeys[i].force_detonate;
if ( isdefined( ready ) )
{
for ( j = 0; j < ready.size; j++ )
{
if ( claymore == ready[j] )
{
return true;
}
}
}
}
return false;
}
monkey_zombie_force_groundhit()
{
if ( !isdefined( level.claymores ) )
{
return false;
}
claymore_dist = 216*216;
height_max = 12;
self.force_detonate = [];
for ( i = 0; i < level.claymores.size; i++ )
{
if ( self.pack monkey_pack_ready_to_detonate( level.claymores[i] ) )
{
continue;
}
height_diff = abs( self.origin[2] - level.claymores[i].origin[2] );
if ( height_diff < height_max )
{
if ( DistanceSquared( self.origin, level.claymores[i].origin ) < claymore_dist )
{
self.force_detonate[ self.force_detonate.size ] = level.claymores[i];
}
}
}
return self.force_detonate.size > 0;
}
monkey_zombie_ground_hit_think()
{
self endon( "death" );
self.ground_hit = false;
self.nextGroundHit = GetTime() + level.monkey_ground_attack_delay;
while( 1 )
{
if ( self.state == "attack_perk" )
{
wait_network_frame();
continue;
}
if ( !self.dropped )
{
wait( 1 );
continue;
}
if ( !self.ground_hit && self monkey_zombie_force_groundhit() )
{
self.pack monkey_pack_update_ground_hit( self );
self animcustom( ::monkey_zombie_ground_hit );
}
else if ( !self.ground_hit && self monkey_zombie_check_ground_hit() )
{
players = GetPlayers();
closeEnough = false;
origin = self GetEye();
for ( i = 0; i < players.size; i++ )
{
if ( players[i] maps\_laststand::player_is_in_laststand() )
{
continue;
}
test_origin = players[i] GetEye();
d = DistanceSquared( origin, test_origin );
if ( d > level.monkey_zombie_groundhit_trigger_radius * level.monkey_zombie_groundhit_trigger_radius )
{
continue;
}
if ( !BulletTracePassed( origin, test_origin, false, undefined ) )
{
continue;
}
closeEnough = true;
break;
}
if ( closeEnough )
{
self.pack monkey_pack_update_ground_hit( self );
self animcustom( ::monkey_zombie_ground_hit );
}
}
wait_network_frame();
}
}
groundhit_watcher( animname )
{
self endon( "death" );
self waittillmatch( animname, "fire" );
playfxontag( level._effect["monkey_groundhit"], self, "tag_origin" );
origin = self.origin + ( 0, 0, 40 );
zombies_axis = get_array_of_closest( origin, GetAiSpeciesArray( "axis", "all" ), undefined, undefined, level.monkey_zombie_groundhit_damage_radius );
dogs = get_array_of_closest( origin, GetAiSpeciesArray( "allies", "zombie_dog" ), undefined, undefined, level.monkey_zombie_groundhit_damage_radius );
zombies = array_combine( zombies_axis, dogs );
if ( IsDefined( zombies ) )
{
for ( i = 0; i < zombies.size; i++ )
{
if ( !IsDefined( zombies[i] ) )
{
continue;
}
if ( is_magic_bullet_shield_enabled( zombies[i] ) )
{
continue;
}
test_origin = zombies[i] GetEye();
if ( !BulletTracePassed( origin, test_origin, false, undefined ) )
{
continue;
}
if ( zombies[i] == self )
{
continue;
}
if ( zombies[i].animname == "monkey_zombie" )
{
continue;
}
refs = [];
refs[refs.size] = "guts";
refs[refs.size] = "right_arm";
refs[refs.size] = "left_arm";
refs[refs.size] = "right_leg";
refs[refs.size] = "left_leg";
refs[refs.size] = "no_legs";
refs[refs.size] = "head";
if( refs.size )
{
zombies[i].a.gib_ref = random( refs );
}
zombies[i] DoDamage( zombies[i].health * 10, self.origin, self );
}
}
players = get_players();
affected_players = [];
for( i = 0; i < players.size; i++ )
{
if ( !is_player_valid( players[i] ) )
{
continue;
}
test_origin = players[i] GetEye();
if( distanceSquared( origin, test_origin ) > level.monkey_zombie_groundhit_damage_radius * level.monkey_zombie_groundhit_damage_radius )
{
continue;
}
if ( !BulletTracePassed( origin, test_origin, false, undefined ) )
{
continue;
}
affected_players = array_add( affected_players, players[i] );
}
self.chest_beat = false;
for( i = 0; i < affected_players.size; i++ )
{
self.chest_beat = true;
player = affected_players[i];
if ( player IsOnGround() )
{
damage = player.maxhealth * 0.5;
player ShellShock( "electrocution", 1.5, true );
player DoDamage( damage, self.origin, self );
}
}
if ( isdefined( self.force_detonate ) )
{
for ( i = 0; i < self.force_detonate.size; i++ )
{
if ( isdefined( self.force_detonate[i] ) )
{
self.force_detonate[i] detonate( undefined );
}
}
}
}
monkey_zombie_grenade_pickup()
{
self endon( "death" );
pickup_dist_sq = 32*32;
picked_up = false;
while ( isdefined( self.monkey_grenade ) )
{
self SetGoalPos( self.monkey_grenade.origin );
grenade_dist_sq = DistanceSquared( self.origin, self.monkey_grenade.origin );
if ( grenade_dist_sq <= pickup_dist_sq )
{
self.monkey_thrower = self.monkey_grenade.thrower;
self.monkey_grenade delete();
self.monkey_grenade = undefined;
picked_up = true;
monkey_print( "deleting grenade" );
}
wait_network_frame();
}
if ( picked_up )
{
while ( 1 )
{
self SetGoalPos( self.monkey_thrower.origin );
target_dir = self.monkey_thrower.origin - self.origin;
monkey_dir = AnglesToForward( self.angles );
dot = VectorDot( VectorNormalize( target_dir ), VectorNormalize( monkey_dir ) );
if ( dot >= 0.5 )
{
break;
}
wait_network_frame();
}
self thread monkey_zombie_grenade_throw( self.monkey_thrower );
self waittill( "throw_done" );
}
}
monkey_zombie_grenade_response()
{
self endon( "death" );
monkey_print( "go for grenade" );
self notify( "stop_find_flesh" );
self notify( "zombie_acquire_enemy" );
self notify( "monkey_update_stop" );
self notify( "stop_perk_attack" );
self.following_player = false;
self monkey_zombie_set_state( "grenade_response" );
self monkey_zombie_clear_attack_pos();
self monkey_zombie_grenade_pickup();
self thread monkey_zombie_update();
self monkey_zombie_set_state( "grenade_response_done" );
}
monkey_zombie_grenade_watcher()
{
self endon( "death" );
grenade_respond_dist_sq = 120 * 120;
while ( 1 )
{
if ( self.state == "default" )
{
wait_network_frame();
continue;
}
if ( is_true( self.ground_hit ) )
{
wait_network_frame();
continue;
}
if ( is_true( self.monkey_grenade ) )
{
wait_network_frame();
continue;
}
if ( level.monkey_grenades.size > 0 )
{
for ( i = 0; i < level.monkey_grenades.size; i++ )
{
grenade = level.monkey_grenades[i];
if ( !isdefined( grenade ) || isdefined( grenade.monkey ) )
{
wait_network_frame();
continue;
}
grenade_dist_sq = DistanceSquared( self.origin, grenade.origin );
if ( grenade_dist_sq <= grenade_respond_dist_sq )
{
grenade.monkey = self;
self.monkey_grenade = grenade;
self monkey_zombie_grenade_response();
break;
}
}
}
wait_network_frame();
}
}
monkey_zombie_bhb_teleport()
{
self endon( "death" );
monkey_print( "bhb teleport" );
black_hole_teleport = getstructarray( "struct_black_hole_teleport", "targetname" );
assertex( black_hole_teleport.size > 0, "struct_black_hole_teleport not found" );
zone_name = self get_current_zone();
locations = [];
for ( i = 0; i < black_hole_teleport.size; i++ )
{
bhb_zone_name = black_hole_teleport[i].script_string;
if ( !isDefined( bhb_zone_name ) || !isDefined( zone_name ) )
{
continue;
}
if ( bhb_zone_name == zone_name )
{
continue;
}
if ( !level.zones[ bhb_zone_name ].is_enabled )
{
continue;
}
locations[ locations.size ] = black_hole_teleport[i];
}
self StopAnimScripted();
wait_network_frame();
so = spawn( "script_origin", self.origin );
so.angles = self.angles;
self linkto( so );
if ( locations.size > 0 )
{
locations = array_randomize( locations );
so.origin = locations[0].origin;
so.angles = locations[0].angles;
}
else
{
so.origin = self.spawn_origin;
so.angles = self.spawn_angles;
}
wait_network_frame();
self unlink();
so delete();
maps\_zombiemode_weap_black_hole_bomb::black_hole_bomb_create_exit_portal( self.origin );
}
monkey_zombie_bhb_failsafe()
{
self endon( "death" );
self endon( "bhb_old_failsafe" );
prev_origin = self.origin;
min_movement = 16*16;
while ( true )
{
wait( 1 );
dist = DistanceSquared( prev_origin, self.origin );
if ( dist < min_movement )
{
break;
}
prev_origin = self.origin;
}
if ( self.state == "ground_pound" )
{
return;
}
self.safeToChangeScript = true;
self animmode( "none" );
}
monkey_zombie_bhb_run()
{
self endon( "death" );
jump_dist_sq = 64*64;
jump = false;
wait_network_frame();
if ( !isdefined( self.monkey_bhb ) || !isdefined( self.monkey_bhb.origin ) )
{
return;
}
self.safeToChangeScript = false;
self SetGoalPos( self.monkey_bhb.origin );
while ( isdefined( self.monkey_bhb ) )
{
bhb_dist_sq = DistanceSquared( self.origin, self.monkey_bhb.origin );
if ( bhb_dist_sq <= jump_dist_sq )
{
jump = true;
break;
}
wait_network_frame();
}
if ( jump )
{
jump_anim = %ai_zombie_monkey_portal_jump_01;
self animscripted( "jump_anim", self.origin, self.angles, jump_anim );
jump_length = getanimlength( jump_anim );
pre_jump = jump_length * 0.625;
post_jump = jump_length * 0.375;
wait( pre_jump );
self stopanimscripted();
wait_network_frame();
self monkey_zombie_bhb_teleport();
}
wait_network_frame();
self.safeToChangeScript = true;
self SetGoalPos( self.origin );
self waittill_any_or_timeout( 0.5, "goal" );
self notify( "bhb_old_failsafe" );
wait_network_frame();
self thread monkey_zombie_bhb_failsafe();
}
monkey_zombie_clear_attack_pos()
{
if ( isDefined( self.attack ) )
{
if ( isDefined( self.pack.attack ) )
{
for ( i = 0; i < self.pack.attack.size; i++ )
{
if ( self == self.pack.attack[i] )
{
self.pack.attack = array_remove( self.pack.attack, self );
self.attack = undefined;
return;
}
}
}
}
}
monkey_zombie_bhb_response()
{
self endon( "death" );
monkey_print( "bhb response" );
self notify( "stop_find_flesh" );
self notify( "zombie_acquire_enemy" );
self notify( "monkey_update_stop" );
self notify( "stop_perk_attack" );
self.following_player = false;
self monkey_zombie_set_state( "bhb_response" );
self monkey_zombie_clear_attack_pos();
self monkey_zombie_bhb_run();
self thread monkey_zombie_update();
self monkey_zombie_set_state( "bhb_response_done" );
}
monkey_zombie_bhb_watcher()
{
self endon( "death" );
bhb_respond_dist_sq = 512 * 512;
while ( 1 )
{
if ( self.state == "default" ||
self.state == "ground_pound" || self.state == "ground_pound_taunt" ||
self.state == "grenade_reponse" || self.state == "bhb_response" ||
self.state == "attack_perk" || !self.dropped )
{
wait_network_frame();
continue;
}
if ( level.monkey_bhbs.size > 0 )
{
for ( i = 0; i < level.monkey_bhbs.size; i++ )
{
bhb = level.monkey_bhbs[i];
if ( is_true( bhb.is_valid ) )
{
if ( !isDefined( bhb ) || !isDefined( bhb.origin ) || !isDefined( self.origin ) )
{
continue;
}
bhb_dist_sq = DistanceSquared( self.origin, bhb.origin );
if ( bhb_dist_sq <= bhb_respond_dist_sq )
{
self.monkey_bhb = bhb;
self monkey_zombie_bhb_response();
}
}
}
}
wait_network_frame();
}
}
monkey_remove_from_pack()
{
for ( i = 0; i < level.monkey_pack.size; i++ )
{
pack = level.monkey_pack[i];
for ( j = 0; j < pack.monkeys.size; j++ )
{
if ( self == pack.monkeys[j] )
{
pack.monkeys = array_remove( pack.monkeys, self );
if ( pack.monkeys.size == 0 && pack.spawning_done )
{
if ( isdefined( pack.perk ) )
{
pack.perk.targeted = 0;
}
level.monkey_packs_killed++;
flag_set( "monkey_pack_down" );
level.monkey_pack = array_remove( level.monkey_pack, pack );
}
}
}
}
if ( level.monkey_packs_killed >= level.monkey_pack_max )
{
flag_set( "last_monkey_down" );
if ( self monkey_zombie_can_drop_free_perk() )
{
forward = VectorNormalize( AnglesToForward( self.angles ) );
end_pos = self.origin - vector_scale( forward, 32 );
level thread maps\_zombiemode_powerups::specific_powerup_drop( "free_perk", end_pos );
}
drop_pos = self.origin;
if ( self.state == "attack_perk" || !self.dropped )
{
drop_pos = self.attack.origin;
}
level thread maps\_zombiemode_powerups::specific_powerup_drop( "full_ammo", drop_pos );
}
}
monkey_zombie_can_drop_free_perk()
{
if ( !flag( "monkey_free_perk" ) )
{
return false;
}
max_perks = level.max_perks;
if ( flag( "solo_game" ) )
{
if ( level.solo_lives_given >= level.max_solo_lives )
{
players = getplayers();
if ( !players[0] HasPerk( "specialty_quickrevive" ) )
{
max_perks--;
}
}
}
players = getplayers();
vending_triggers = getentarray( "zombie_vending", "targetname" );
for ( i = 0; i < players.size; i++ )
{
num_perks = 0;
for ( j = 0; j < vending_triggers.size; j++ )
{
perk = vending_triggers[j].script_noteworthy;
if ( players[i] HasPerk( perk ) )
{
num_perks++;
}
}
if ( num_perks < max_perks )
{
return true;
}
}
return false;
}
monkey_zombie_die()
{
self maps\_zombiemode_spawner::reset_attack_spot();
self.grenadeAmmo = 0;
self thread maps\_zombiemode_audio::do_zombies_playvocals( "death", self.animname );
self thread maps\_zombiemode_spawner::zombie_eye_glow_stop();
PlayFX( level._effect["monkey_death"], self.origin );
level maps\_zombiemode_spawner::zombie_death_points( self.origin, self.damagemod, self.damagelocation, self.attacker,self );
if( RandomIntRange(0,100) >= 75 )
{
if( IsDefined( self.attacker ) && IsPlayer( self.attacker ) )
self.attacker maps\_zombiemode_audio::create_and_play_dialog( "kill", "space_monkey" );
}
if( self.damagemod == "MOD_BURNED" )
{
self thread animscripts\zombie_death::flame_death_fx();
}
level.monkey_death++;
level.monkey_death_total++;
self monkey_remove_from_pack();
return false;
}
monkey_custom_damage( player )
{
self endon( "death" );
damage = self.meleeDamage;
if ( isDefined( self.ground_hit ) && self.ground_hit )
{
damage = int( player.maxhealth * 0.25 );
}
return damage;
}
monkey_zombie_default_enter_level()
{
Playfx( level._effect["monkey_spawn"], self.origin );
playsoundatposition( "zmb_bolt", self.origin );
PlayRumbleOnPosition("explosion_generic", self.origin);
}
monkey_pathing()
{
self endon( "death" );
while ( 1 )
{
if( IsDefined( self.favoriteenemy ) )
{
self.ignoreall = false;
self OrientMode( "face default" );
self SetGoalPos( self.favoriteenemy.origin );
}
wait_network_frame();
}
}
monkey_find_flesh()
{
self endon( "death" );
level endon( "intermission" );
self endon( "stop_find_flesh" );
if( level.intermission )
{
return;
}
self maps\_zombiemode_spawner::zombie_history( "monkey find flesh -> start" );
self.goalradius = 48;
players = getplayers();
self.ignore_player = [];
player = get_closest_valid_player( self.origin, self.ignore_player );
if( !isDefined( player ) )
{
self maps\_zombiemode_spawner::zombie_history( "monkey find flesh -> can't find player, continue" );
}
self.favoriteenemy = player;
while( 1 )
{
if ( isdefined( self.pack ) && isdefined( self.pack.enemy ) )
{
if ( !isdefined( self.favoriteenemy ) || self.favoriteenemy != self.pack.enemy )
{
self.favoriteenemy = self.pack.enemy;
}
}
if ( isdefined( level.user_ryan_monkey_pathing ) )
{
self thread maps\_zombiemode_ai_monkey::monkey_pathing();
}
else
{
self thread maps\_zombiemode_spawner::zombie_pathing();
}
self.zombie_path_timer = GetTime() + ( RandomFloatRange( 1, 3 ) * 1000 );
while( GetTime() < self.zombie_path_timer )
{
wait( 0.1 );
}
self maps\_zombiemode_spawner::zombie_history( "monkey find flesh -> bottom of loop" );
debug_print( "Zombie is re-acquiring enemy, ending breadcrumb search" );
self notify( "zombie_acquire_enemy" );
}
}
monkey_zombie_setup_perks()
{
vending_triggers = getentarray( "zombie_vending", "targetname" );
for ( i = 0; i < vending_triggers.size; i++ )
{
vending_triggers[i] monkey_zombie_perk_init();
}
}
monkey_zombie_perk_init()
{
self.targeted = 0;
machine = undefined;
targets = getentarray( self.target, "targetname" );
for ( i = 0; i < targets.size; i++ )
{
if ( targets[i].classname == "script_model" )
{
machine = targets[i];
break;
}
}
assertex( isdefined( machine ), "no machine found for " + self.target );
if ( isdefined( machine ) )
{
machine.monkey_health = 100;
}
}
monkey_zombie_perk_damage( amount )
{
if ( !isdefined( self.perk ) )
{
return true;
}
machine = self.pack.machine;
machine.monkey_health -= amount;
if ( machine.monkey_health < 0 )
{
machine.monkey_health = 0;
}
return machine.monkey_health == 0;
}
monkey_pack_take_perk()
{
players = getplayers();
self.perk.targeted = 0;
perk = self.perk.script_noteworthy;
for ( i = 0; i < players.size; i++ )
{
if ( players[i] HasPerk( perk ) )
{
perk_str = perk + "_stop";
players[i] notify( perk_str );
if ( flag( "solo_game" ) && perk == "specialty_quickrevive" )
{
players[i].lives--;
}
}
}
}
monkey_perk_lost( perk )
{
if ( perk == "specialty_armorvest" )
{
if ( self.health > self.maxhealth )
{
self.health = self.maxhealth;
}
}
if ( isdefined( self.perk_hud ) )
{
keys = getarraykeys( self.perk_hud );
for ( i = 0; i < self.perk_hud.size; i++ )
{
self.perk_hud[ keys[i] ].x = i * 30;
}
}
}
monkey_perk_bought( perk )
{
flag_set( "perk_bought" );
level.perk_bought_func = undefined;
}
monkey_pack_flash_perk( perk )
{
if ( !isdefined( perk ) )
{
return;
}
players = getplayers();
for ( i = 0; i < players.size; i++ )
{
players[i] maps\_zombiemode_perks::perk_hud_start_flash( perk );
}
}
monkey_pack_stop_flash( perk, taken )
{
players = getplayers();
for ( i = 0; i < players.size; i++ )
{
players[i] maps\_zombiemode_perks::perk_hud_stop_flash( perk, taken );
}
}
monkey_get_zone()
{
zone = undefined;
keys = getarraykeys( level.zones );
for ( i = 0; i < keys.size; i++ )
{
zone = level.zones[ keys[i] ];
for ( j = 0; j < zone.volumes.size; j++ )
{
if ( self isTouching( zone.volumes[j] ) )
{
return zone;
}
}
}
assertex( isdefined( zone ), "monkey is NOT in a zone" );
return zone;
}
monkey_fling( player )
{
monkey_print( "fling monkey damage" );
damage = int( level.monkey_zombie_health * 0.5 );
self DoDamage( damage, self.origin, self );
forward = VectorNormalize( AnglesToForward( self.angles ) );
attack_dir = VectorNormalize( self.origin - player.origin );
dot = VectorDot( attack_dir, forward );
if ( dot < 0 )
{
end_pos = self.origin - vector_scale( forward, 120 );
if ( sightTracePassed( self.origin, end_pos, false, self ) )
{
recordLine( self.origin, end_pos, (0,1,0), "Script", self );
roll_anim = [];
roll_anim[ roll_anim.size ] = %ai_zombie_monkey_thundergun_roll_01;
roll_anim[ roll_anim.size ] = %ai_zombie_monkey_thundergun_roll_02;
roll_anim[ roll_anim.size ] = %ai_zombie_monkey_thundergun_roll_03;
roll_anim[ roll_anim.size ] = %ai_zombie_monkey_thundergun_roll_04;
rollback_anim = roll_anim[ RandomInt( roll_anim.size ) ];
self animscripted( "rollback_anim", self.origin, self.angles, rollback_anim );
animscripts\traverse\zombie_shared::wait_anim_length( rollback_anim, .02 );
}
else
{
recordLine( self.origin, end_pos, (1,0,0), "Script", self );
}
}
self.thundergun_fling_func = undefined;
}
monkey_revive_solo_fx()
{
vending_triggers = getentarray( "zombie_vending", "targetname" );
for ( i = 0; i < vending_triggers.size; i++ )
{
if ( vending_triggers[i].script_noteworthy == "specialty_quickrevive" )
{
vending_triggers[i] delete();
break;
}
}
}
monkey_print( str )
{
}
play_random_monkey_vox()
{
self endon( "death" );
while(1)
{
self thread maps\_zombiemode_audio::do_zombies_playvocals( "ambient", "monkey_zombie" );
wait(RandomFloatRange(1.25,3));
}
}