diff --git a/zm_ai_pack/clientscripts/mp/zombies/_zm_ai_leaper.csc b/zm_ai_pack/clientscripts/mp/zombies/_zm_ai_leaper.csc new file mode 100644 index 0000000..7d0331d --- /dev/null +++ b/zm_ai_pack/clientscripts/mp/zombies/_zm_ai_leaper.csc @@ -0,0 +1,14 @@ +// T6 GSC SOURCE +// Generated by https://github.com/xensik/gsc-tool +#include clientscripts\mp\_utility; +#include clientscripts\mp\zombies\_zm_utility; + +precache() +{ + +} + +init() +{ + +} diff --git a/zm_ai_pack/maps/mp/zm_highrise.d3dbsp b/zm_ai_pack/maps/mp/zm_highrise.d3dbsp index ebd62ab..e9a19d6 100644 --- a/zm_ai_pack/maps/mp/zm_highrise.d3dbsp +++ b/zm_ai_pack/maps/mp/zm_highrise.d3dbsp @@ -31328,4 +31328,243 @@ "origin" "2771.15 1400 2728.13" "classname" "node_pathnode" "guid" "CC9CDDB8" -} \ No newline at end of file +} +{ +"origin" "0 0 -500" +"export" "1" +"model" "veh_t6_dlc_zm_mech" +"classname" "actor_zm_tomb_mech_zombie" +"script_noteworthy" "mechz_spawner" +"spawnflags" "1" +} +{ +"targetname" "zone_green_start_spawners" +"script_noteworthy" "mechz_location" +"origin" "1543.26 1403.97 3392.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_green_level1_spawners" +"script_noteworthy" "mechz_location" +"origin" "2203.56 1565.42 3398.49" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_green_level2a_spawners" +"script_noteworthy" "mechz_location" +"origin" "2057.82 1292.39 3219.26" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_green_level2b_spawners" +"script_noteworthy" "mechz_location" +"origin" "1452.33 1627.78 3216.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_green_level3a_spawners" +"script_noteworthy" "mechz_location" +"origin" "1685.17 2067.07 3046.09" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_orange_level1_spawners" +"script_noteworthy" "mechz_location" +"origin" "2971.25 1990.43 2955.24" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_orange_level1_spawners" +"script_noteworthy" "mechz_location" +"origin" "2618.8 1747.15 2852.12" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_orange_level2_spawners" +"script_noteworthy" "mechz_location" +"origin" "2646.38 1274.17 2654.02" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_orange_elevator_shaft_middle_1_spawners" +"script_noteworthy" "mechz_location" +"origin" "3431.56 2073.77 2490.93" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_orange_elevator_shaft_middle_2_spawners" +"script_noteworthy" "mechz_location" +"origin" "3726.62 1772.9 2229.33" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_orange_level3a_spawners" +"script_noteworthy" "mechz_location" +"origin" "4334.71 1649 1720.64" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_orange_level3b_spawners" +"script_noteworthy" "mechz_location" +"origin" "4011.17 1344.05 1651.87" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_orange_level3b_spawners" +"script_noteworthy" "mechz_location" +"origin" "3260.03 1386.41 1316.37" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level4a_spawners" +"script_noteworthy" "mechz_location" +"origin" "3126.67 498.965 1296.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level4a_spawners" +"script_noteworthy" "mechz_location" +"origin" "2014.02 526.034 1296.46" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level4c_spawners" +"script_noteworthy" "mechz_location" +"origin" "2650.14 -459.034 1296.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level4b_spawners" +"script_noteworthy" "mechz_location" +"origin" "1516.2 -438.535 1296.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level5_spawners" +"script_noteworthy" "mechz_location" +"origin" "1985.01 -199.889 1120.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level5_spawners" +"script_noteworthy" "mechz_location" +"origin" "1520.7 -454.917 1120.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level5_spawners" +"script_noteworthy" "mechz_location" +"origin" "2019.77 770.722 1120.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level5_spawners" +"script_noteworthy" "mechz_location" +"origin" "2830.01 845.753 1120.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level1a_spawners" +"script_noteworthy" "mechz_location" +"origin" "2528.77 -519.947 2880.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level1a_spawners" +"script_noteworthy" "mechz_location" +"origin" "2100.78 385.804 2880.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level2b_spawners" +"script_noteworthy" "mechz_location" +"origin" "2036.23 392.668 2704.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level2b_spawners" +"script_noteworthy" "mechz_location" +"origin" "2435.87 590.875 2704.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level2a_spawners" +"script_noteworthy" "mechz_location" +"origin" "2662.58 175.902 2704.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level2c_spawners" +"script_noteworthy" "mechz_location" +"origin" "2910.82 81.4468 2704.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level2d_spawners" +"script_noteworthy" "mechz_location" +"origin" "3098.91 307.819 2714.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level1c_spawners" +"script_noteworthy" "mechz_location" +"origin" "2034.18 696.061 3136.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level1a_spawners" +"script_noteworthy" "mechz_location" +"origin" "2723.02 194.534 3016.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_blue_level1b_spawners" +"script_noteworthy" "mechz_location" +"origin" "2973.15 201.932 2880.13" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_green_level3b_spawners" +"script_noteworthy" "mechz_location" +"origin" "2058.92 1448.33 3047.39" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_green_level3c_spawners" +"script_noteworthy" "mechz_location" +"origin" "1659.98 1308.56 3047.23" +"classname" "script_struct" +"angles" "0 0 0" +} diff --git a/zm_ai_pack/maps/mp/zombies/_zm_ai_avogadro.gsc b/zm_ai_pack/maps/mp/zombies/_zm_ai_avogadro.gsc index e8977ae..7e96000 100644 --- a/zm_ai_pack/maps/mp/zombies/_zm_ai_avogadro.gsc +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_avogadro.gsc @@ -130,6 +130,8 @@ avogadro_prespawn() self endon( "death" ); level endon( "intermission" ); level.avogadro = self; + self.ignore_distance_tracking = true; + self.exclude_distance_cleanup_adding_to_total = true; self.immune_to_slowgun = true; self.has_legs = 1; self.no_gib = 1; diff --git a/zm_ai_pack/maps/mp/zombies/_zm_ai_brutus.gsc b/zm_ai_pack/maps/mp/zombies/_zm_ai_brutus.gsc index 6919c83..3f31c73 100644 --- a/zm_ai_pack/maps/mp/zombies/_zm_ai_brutus.gsc +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_brutus.gsc @@ -402,6 +402,8 @@ brutus_spawn( starting_health, has_helmet, helmet_hits, explosive_dmg_taken, zon self.ignore_inert = true; self.ignore_lava_damage = true; self.ignore_electric_trap = true; + self.ignore_distance_tracking = true; + self.exclude_distance_cleanup_adding_to_total = true; self.zombie_init_done = 1; self notify( "zombie_init_done" ); self.allowpain = 0; diff --git a/zm_ai_pack/maps/mp/zombies/_zm_ai_dogs.gsc b/zm_ai_pack/maps/mp/zombies/_zm_ai_dogs.gsc index 92bb361..f70eef5 100644 --- a/zm_ai_pack/maps/mp/zombies/_zm_ai_dogs.gsc +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_dogs.gsc @@ -398,6 +398,8 @@ dog_init() self.script_noteworthy = undefined; self.animname = "zombie_dog"; self.no_gib = true; + self.ignore_distance_tracking = false; + self.exclude_distance_cleanup_adding_to_total = false; self.ignoreall = 1; self.ignoreme = 1; self.allowdeath = 1; diff --git a/zm_ai_pack/maps/mp/zombies/_zm_ai_ghost.gsc b/zm_ai_pack/maps/mp/zombies/_zm_ai_ghost.gsc index 972c2e3..d8e6cb9 100644 --- a/zm_ai_pack/maps/mp/zombies/_zm_ai_ghost.gsc +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_ghost.gsc @@ -625,6 +625,8 @@ prespawn() self.ignore_inert = true; self.ignore_lava_damage = true; self.ignore_electric_trap = true; + self.ignore_distance_tracking = false; + self.exclude_distance_cleanup_adding_to_total = false; self maps\mp\zombies\_zm_ai_ghost_ffotd::prespawn_start(); self.startinglocation = self.origin; self.animname = "ghost_zombie"; diff --git a/zm_ai_pack/maps/mp/zombies/_zm_ai_leaper.gsc b/zm_ai_pack/maps/mp/zombies/_zm_ai_leaper.gsc new file mode 100644 index 0000000..a71d9cc --- /dev/null +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_leaper.gsc @@ -0,0 +1,1282 @@ +// T6 GSC SOURCE +// Generated by https://github.com/xensik/gsc-tool +#include common_scripts\utility; +#include maps\mp\_utility; +#include maps\mp\zombies\_zm_utility; +#include maps\mp\animscripts\zm_utility; +#include maps\mp\zombies\_zm_spawner; +#include maps\mp\zombies\_zm_score; +#include maps\mp\animscripts\zm_shared; +#include maps\mp\zombies\_zm_ai_basic; +#include maps\mp\zombies\_zm_zonemgr; +#include maps\mp\gametypes_zm\_globallogic_score; +#include maps\mp\zombies\_zm_powerups; +#include maps\mp\zombies\_zm_audio; +#include maps\mp\zm_highrise_elevators; + +precache() +{ + precache_fx(); +} + +precache_fx() +{ + level._effect["leaper_death"] = loadfx( "maps/zombie/fx_zmb_leaper_death" ); + level._effect["leaper_spawn"] = loadfx( "maps/zombie/fx_zmb_leaper_spawn" ); + level._effect["leaper_trail"] = loadfx( "maps/zombie/fx_zmb_leaper_trail" ); + level._effect["leaper_walk"] = loadfx( "maps/zombie/fx_zmb_leaper_walk" ); + level._effect["leaper_wall_impact"] = loadfx( "maps/zombie/fx_zmb_leaper_wall_impact" ); +} + +init() +{ + leaper_spawner_init(); + leaper_calc_anim_offsets(); + + if ( !isdefined( level.leapers_per_player ) ) + level.leapers_per_player = 2; + + level.no_jump_triggers = getentarray( "leaper_no_jump_trigger", "targetname" ); +} + +leaper_calc_anim_offsets() +{ + leaper = spawn_zombie( level.leaper_spawners[0] ); + + if ( isdefined( leaper ) ) + { + level.leaper_anim = spawnstruct(); + asd = "zm_wall_up"; + anim_id = leaper getanimfromasd( asd, 0 ); + level.leaper_anim.up_mid = getmovedelta( anim_id, 0, 0.488 ) + vectorscale( ( 0, 0, 1 ), 6.0 ); + level.leaper_anim.up_end = getmovedelta( anim_id, 0, 1 ); + asd = "zm_wall_left"; + anim_id = leaper getanimfromasd( asd, 0 ); + wallhit_time = getnotetracktimes( anim_id, "wallhit" ); + level.leaper_anim.left_mid = getmovedelta( anim_id, 0, wallhit_time[0] ) + vectorscale( ( 0, 0, 1 ), 48.0 ); + level.leaper_anim.left_end = getmovedelta( anim_id, 0, 1 ); + asd = "zm_wall_left_large"; + anim_id = leaper getanimfromasd( asd, 0 ); + wallhit_time = getnotetracktimes( anim_id, "wallhit" ); + level.leaper_anim.left_large_mid = getmovedelta( anim_id, 0, wallhit_time[0] ) + vectorscale( ( 0, 0, 1 ), 48.0 ); + level.leaper_anim.left_large_end = getmovedelta( anim_id, 0, 1 ); + asd = "zm_wall_right"; + anim_id = leaper getanimfromasd( asd, 0 ); + wallhit_time = getnotetracktimes( anim_id, "wallhit" ); + level.leaper_anim.right_mid = getmovedelta( anim_id, 0, wallhit_time[0] ) + vectorscale( ( 0, 0, 1 ), 48.0 ); + level.leaper_anim.right_end = getmovedelta( anim_id, 0, 1 ); + asd = "zm_wall_right_large"; + anim_id = leaper getanimfromasd( asd, 0 ); + wallhit_time = getnotetracktimes( anim_id, "wallhit" ); + level.leaper_anim.right_large_mid = getmovedelta( anim_id, 0, wallhit_time[0] ) + vectorscale( ( 0, 0, 1 ), 48.0 ); + level.leaper_anim.right_large_end = getmovedelta( anim_id, 0, 1 ); + leaper delete(); + } +} + +leaper_spawner_init() +{ + level.leaper_spawners = getentarray( "leaper_zombie_spawner", "script_noteworthy" ); + + if ( level.leaper_spawners.size == 0 ) + return; + + for ( i = 0; i < level.leaper_spawners.size; i++ ) + { + level.leaper_spawners[i].is_enabled = 1; + level.leaper_spawners[i].script_forcespawn = 1; + } + + assert( level.leaper_spawners.size > 0 ); + level.leaper_health = 100; + array_thread( level.leaper_spawners, ::add_spawn_function, ::leaper_init ); +/# + if ( isdefined( level.leaper_rounds_enabled ) && level.leaper_rounds_enabled ) + level thread leaper_spawner_zone_check(); +#/ +} + +leaper_spawner_zone_check() +{ + flag_wait( "zones_initialized" ); + str_zone_list = ""; + str_spawn_count_list = ""; + n_zones_missing_spawners = 0; + a_zones = getarraykeys( level.zones ); + + for ( i = 0; i < a_zones.size; i++ ) + { + if ( level.zones[a_zones[i]].leaper_locations.size == 0 ) + { + n_zones_missing_spawners++; + str_zone_list = str_zone_list + "\\n " + a_zones[i]; + } + + str_spawn_count_list = str_spawn_count_list + a_zones[i] + ": " + level.zones[a_zones[i]].leaper_locations.size + "\\n"; + } + + assert( n_zones_missing_spawners == 0, "All zones require at least one leaper spawn point." + n_zones_missing_spawners + " zones are missing leaper spawners. They are: " + str_zone_list ); +/# + println( "========== LEAPER SPAWN COUNT PER ZONE ===========" ); + println( str_spawn_count_list ); + println( "==================================================" ); +#/ +} + +leaper_init() +{ + self endon( "death" ); + level endon( "intermission" ); + self.animname = "leaper_zombie"; + self.audio_type = "leaper"; + self.has_legs = 1; + self.ignore_all_poi = 1; + self.is_leaper = 1; + self.melee_anim_func = ::melee_anim_func; + self.meleedamage = 30; + self.ignore_distance_tracking = false; + self.exclude_distance_cleanup_adding_to_total = false; + recalc_zombie_array(); + + if ( isdefined( self.spawn_point ) ) + { + spot = self.spawn_point; + + if ( !isdefined( spot.angles ) ) + spot.angles = ( 0, 0, 0 ); + + self forceteleport( spot.origin, spot.angles ); + } + + self playsound( "zmb_vocals_leaper_spawn" ); + self set_zombie_run_cycle( "run" ); + self.state = "init"; + self thread leaper_think(); + self thread leaper_spawn_failsafe(); + self thread leaper_traverse_watcher(); + self.maxhealth = level.leaper_health; + self.health = level.leaper_health; + self setphysparams( 15, 0, 24 ); + self.zombie_init_done = 1; + self notify( "zombie_init_done" ); + self.allowpain = 0; + self thread play_ambient_leaper_vocals(); + self animmode( "normal" ); + self orientmode( "face enemy" ); + self maps\mp\zombies\_zm_spawner::zombie_setup_attack_properties(); + self maps\mp\zombies\_zm_spawner::zombie_complete_emerging_into_playable_area(); + self setfreecameralockonallowed( 0 ); + + if ( isdefined( self.spawn_point.script_parameters ) && ( self.spawn_point.script_parameters == "emerge_bottom" || self.spawn_point.script_parameters == "emerge_top" ) ) + self thread do_leaper_emerge( self.spawn_point ); + + self thread leaper_death(); + self thread leaper_check_zone(); + self thread leaper_check_no_jump(); + self thread leaper_watch_enemy(); + self.combat_animmode = ::leaper_combat_animmode; + level thread maps\mp\zombies\_zm_spawner::zombie_death_event( self ); + self thread maps\mp\zombies\_zm_spawner::enemy_death_detection(); + self thread leaper_elevator_failsafe(); +} + +play_ambient_leaper_vocals() +{ + self endon( "death" ); + wait( randomintrange( 2, 4 ) ); + + while ( true ) + { + if ( isdefined( self ) ) + { + if ( isdefined( self.favoriteenemy ) && distance( self.origin, self.favoriteenemy.origin ) <= 150 ) + { + + } + else + self playsound( "zmb_vocals_leaper_ambience" ); + } + + wait( randomfloatrange( 1, 1.5 ) ); + } +} + +leaper_death() +{ + self endon( "leaper_cleanup" ); + self waittill( "death" ); + self leaper_stop_trail_fx(); + self playsound( "zmb_vocals_leaper_death" ); + playfx( level._effect["leaper_death"], self.origin ); + + if ( get_current_zombie_count() == 0 && level.zombie_total == 0 ) + { + level.last_leaper_origin = self.origin; + level notify( "last_leaper_down" ); + } + + if ( isplayer( self.attacker ) ) + { + event = "death"; + + if ( issubstr( self.damageweapon, "knife_ballistic_" ) ) + event = "ballistic_knife_death"; + + self.attacker thread do_player_general_vox( "general", "leaper_killed", 20, 20 ); + self.attacker maps\mp\zombies\_zm_score::player_add_points( event, self.damagemod, self.damagelocation, 1 ); + } +} + +leaper_think() +{ + self endon( "death" ); + + while ( true ) + { + switch ( self.state ) + { + case "init": + leaper_building_jump(); + break; + case "chasing": + leaper_check_wall(); + break; + case "leaping": + break; + } + + wait 0.1; + } +} + +leaper_can_use_anim( local_mid, local_end, dir ) +{ + start = self.origin; + mid = self localtoworldcoords( local_mid ); + end = self localtoworldcoords( local_end ); + real_mid = mid; + forward_dist = length( end - start ) * 0.5; + forward_vec = vectornormalize( end - start ); + temp_org = start + vectorscale( forward_vec, forward_dist ); + forward_org = ( temp_org[0], temp_org[1], real_mid[2] ); + end_top = end + vectorscale( ( 0, 0, 1 ), 24.0 ); + end_bottom = end + vectorscale( ( 0, 0, -1 ), 60.0 ); + trace = bullettrace( start, mid, 1, self ); + + if ( isdefined( trace["entity"] ) ) + return false; + + if ( isdefined( trace["fraction"] ) && trace["fraction"] < 1 ) + { + if ( trace["fraction"] < 0.2 ) + { +/# + if ( getdvarint( #"_id_5B4FE0B3" ) == 1 ) + line( start, mid, ( 1, 0, 0 ), 1, 0, 100 ); +#/ + return false; + } + + if ( dir == "up" ) + { + if ( trace["fraction"] < 0.9 ) + return false; + } + + mid = trace["position"]; +/# + if ( getdvarint( #"_id_5B4FE0B3" ) >= 1 ) + line( start, mid, ( 0, 1, 0 ), 1, 0, 100 ); +#/ + + if ( dir != "up" ) + { + trace = bullettrace( forward_org, real_mid, 1, self ); + + if ( isdefined( trace["entity"] ) ) + return false; + + if ( isdefined( trace["fraction"] ) && trace["fraction"] < 1 ) + { +/# + if ( getdvarint( #"_id_5B4FE0B3" ) == 1 ) + line( forward_org, real_mid, ( 1, 0, 0 ), 1, 0, 100 ); +#/ + } + else + { +/# + if ( getdvarint( #"_id_5B4FE0B3" ) == 1 ) + line( forward_org, real_mid, ( 0, 1, 0 ), 1, 0, 100 ); +#/ + return false; + } + } + } + else + { +/# + if ( getdvarint( #"_id_5B4FE0B3" ) == 1 ) + line( start, mid, ( 1, 0, 0 ), 1, 0, 100 ); +#/ + return false; + } + + trace = bullettrace( mid, end, 1, self ); + + if ( isdefined( trace["fraction"] ) && trace["fraction"] < 1 ) + { +/# + if ( getdvarint( #"_id_5B4FE0B3" ) == 1 ) + line( mid, end, ( 1, 0, 0 ), 1, 0, 100 ); +#/ + return false; + } + else + { +/# + if ( getdvarint( #"_id_5B4FE0B3" ) >= 1 ) + line( mid, end, ( 0, 1, 0 ), 1, 0, 100 ); +#/ + } + + trace = bullettrace( end_top, end_bottom, 1, self ); + + if ( isdefined( trace["fraction"] ) && trace["fraction"] >= 1 ) + { +/# + if ( getdvarint( #"_id_5B4FE0B3" ) == 1 ) + line( end_top, end_bottom, ( 1, 0, 0 ), 1, 0, 100 ); +#/ + return false; + } + else + { +/# + if ( getdvarint( #"_id_5B4FE0B3" ) >= 1 ) + line( end_top, end_bottom, ( 0, 1, 0 ), 1, 0, 100 ); +#/ + } + + return true; +} + +leaper_building_jump() +{ + self endon( "death" ); + + if ( isdefined( self.spawn_point.script_string ) && self.spawn_point.script_string != "find_flesh" ) + { + self animscripted( self.spawn_point.origin, self.spawn_point.angles, "zm_building_leap", self.spawn_point.script_string ); + self maps\mp\animscripts\zm_shared::donotetracks( "building_leap_anim" ); + } + + self thread leaper_playable_area_failsafe(); + self thread maps\mp\zombies\_zm_ai_basic::find_flesh(); + self.state = "chasing"; +} + +leaper_check_wall() +{ + self endon( "death" ); + + if ( !isdefined( self.next_leap_time ) ) + self.next_leap_time = gettime() + 500; + + if ( is_true( self.sliding_on_goo ) || is_true( self.is_leaping ) ) + return; + + if ( gettime() > self.next_leap_time && !is_true( self.no_jump ) ) + { + wall_anim = []; + + if ( self leaper_can_use_anim( level.leaper_anim.up_mid, level.leaper_anim.up_end, "up" ) ) + wall_anim[wall_anim.size] = "zm_wall_up"; + + if ( self leaper_can_use_anim( level.leaper_anim.left_mid, level.leaper_anim.left_end, "left" ) ) + wall_anim[wall_anim.size] = "zm_wall_left"; + else if ( self leaper_can_use_anim( level.leaper_anim.left_large_mid, level.leaper_anim.left_large_end, "left_large" ) ) + wall_anim[wall_anim.size] = "zm_wall_left_large"; + + if ( self leaper_can_use_anim( level.leaper_anim.right_mid, level.leaper_anim.right_end, "right" ) ) + wall_anim[wall_anim.size] = "zm_wall_right"; + else if ( self leaper_can_use_anim( level.leaper_anim.right_large_mid, level.leaper_anim.right_large_end, "right_large" ) ) + wall_anim[wall_anim.size] = "zm_wall_right_large"; + + b_should_play_wall_jump_anim = !self isinscriptedstate() && wall_anim.size > 0; + + if ( b_should_play_wall_jump_anim && isdefined( self.enemy ) && ( self cansee( self.enemy ) || is_true( self.in_player_zone ) ) ) + { + wall_anim = array_randomize( wall_anim ); + self.leap_anim = wall_anim[0]; + self leaper_start_trail_fx(); + self.ignoreall = 1; + self.is_leaping = 1; + self notify( "stop_find_flesh" ); + self notify( "zombie_acquire_enemy" ); + self animcustom( ::leaper_play_anim ); + self waittill( "leap_anim_done" ); + self leaper_stop_trail_fx(); + self.ignoreall = 0; + self.is_leaping = 0; + self thread maps\mp\zombies\_zm_ai_basic::find_flesh(); + self.next_leap_time = gettime() + 500; + } + } +} + +leaper_check_zone() +{ + self endon( "death" ); + self.in_player_zone = 0; + + while ( true ) + { + self.in_player_zone = 0; + + foreach ( zone in level.zones ) + { + if ( !isdefined( zone.volumes ) || zone.volumes.size == 0 ) + continue; + + zone_name = zone.volumes[0].targetname; + + if ( self maps\mp\zombies\_zm_zonemgr::entity_in_zone( zone_name ) ) + { + if ( is_true( zone.is_occupied ) ) + { + self.in_player_zone = 1; + break; + } + } + } + + wait 0.2; + } +} + +leaper_check_no_jump() +{ + self endon( "death" ); + + while ( true ) + { + self.no_jump = 0; + + foreach ( trigger in level.no_jump_triggers ) + { + if ( self istouching( trigger ) ) + { + self.no_jump = 1; + break; + } + } + + wait 0.2; + } +} + +melee_anim_func() +{ + self.next_leap_time = gettime() + 1500; + self animmode( "gravity" ); +} + +leaper_start_trail_fx() +{ + self endon( "death" ); + self leaper_stop_trail_fx(); + self.trail_fx = spawn( "script_model", self.origin ); + self.trail_fx setmodel( "tag_origin" ); + self.trail_fx linkto( self ); + wait 0.1; + playfxontag( level._effect["leaper_trail"], self.trail_fx, "tag_origin" ); +} + +leaper_stop_trail_fx() +{ + if ( isdefined( self.trail_fx ) ) + self.trail_fx delete(); +} + +leaper_play_anim() +{ + self endon( "death" ); + self animmode( "nogravity" ); + self setanimstatefromasd( self.leap_anim ); + self thread leaper_handle_fx_notetracks( "wall_anim" ); + maps\mp\animscripts\zm_shared::donotetracks( "wall_anim" ); + self animmode( "normal" ); + self notify( "leap_anim_done" ); +} + +leaper_handle_fx_notetracks( animname ) +{ + self endon( "death" ); + self endon( "leap_anim_done" ); + + if ( isdefined( self.leap_anim ) && self getanimhasnotetrackfromasd( "wallhit" ) ) + { + self waittillmatch( animname, "wallhit" ); + playfx( level._effect["leaper_wall_impact"], self.origin ); + } +} + +leaper_notetracks( animname ) +{ + self endon( "death" ); + self endon( "leap_anim_done" ); + self waittillmatch( animname, "gravity on" ); + self animmode( "normal" ); +} + +enable_leaper_rounds() +{ + level.leaper_rounds_enabled = 1; + flag_init( "leaper_round" ); + level thread leaper_round_tracker(); +} + +leaper_round_tracker() +{ + level.leaper_round_count = 1; + level.next_leaper_round = level.round_number + randomintrange( 4, 7 ); + old_spawn_func = level.round_spawn_func; + old_wait_func = level.round_wait_func; + + while ( true ) + { + level waittill( "between_round_over" ); + + if ( level.round_number == level.next_leaper_round ) + { + level.music_round_override = 1; + old_spawn_func = level.round_spawn_func; + old_wait_func = level.round_wait_func; + leaper_round_start(); + level.round_spawn_func = ::leaper_round_spawning; + level.round_wait_func = ::leaper_round_wait; + level.next_leaper_round = level.round_number + randomintrange( 4, 6 ); + } + else if ( flag( "leaper_round" ) ) + { + leaper_round_stop(); + level.round_spawn_func = old_spawn_func; + level.round_wait_func = old_wait_func; + level.music_round_override = 0; + level.leaper_round_count = level.leaper_round_count + 1; + } + } +} + +leaper_round_spawning() +{ + level endon( "intermission" ); + level endon( "leaper_round_ending" ); + level.leaper_targets = getplayers(); + + for ( i = 0; i < level.leaper_targets.size; i++ ) + level.leaper_targets[i].hunted_by = 0; + +/# + level endon( "kill_round" ); + + if ( getdvarint( #"zombie_cheat" ) == 2 || getdvarint( #"zombie_cheat" ) >= 4 ) + return; +#/ + + if ( level.intermission ) + return; + + level.leaper_intermission = 1; + level thread leaper_round_accuracy_tracking(); + level thread leaper_round_aftermath(); + players = get_players(); + wait 1; + playsoundatposition( "vox_zmba_event_dogstart_0", ( 0, 0, 0 ) ); + wait 1; + + if ( level.leaper_round_count < 3 ) + max = players.size * level.leapers_per_player; + else + max = players.size * level.leapers_per_player; + + level.zombie_total = max; + leaper_health_increase(); + level.leaper_count = 0; + + while ( true ) + { + b_hold_spawning_when_leapers_are_all_dead = 1; +/# + n_test_mode_active = getdvarint( #"_id_298DD9A4" ); + + if ( isdefined( n_test_mode_active ) && n_test_mode_active == 1 ) + { + level.zombie_total = 9999; + b_hold_spawning_when_leapers_are_all_dead = 0; + } + else + { + n_remaining_leapers_this_round = max - level.leaper_count; + level.zombie_total = clamp( n_remaining_leapers_this_round, 0, max ); + } +#/ + + if ( level.leaper_count >= max && b_hold_spawning_when_leapers_are_all_dead ) + { + wait 0.5; + continue; + } + + num_player_valid = get_number_of_valid_players(); + per_player = 2; +/# + if ( getdvarint( #"_id_5A273E4B" ) == 2 ) + per_player = 1; +#/ + + while ( get_current_zombie_count() >= num_player_valid * per_player ) + { + wait 2; + num_player_valid = get_number_of_valid_players(); + } + + players = get_players(); + favorite_enemy = get_favorite_enemy(); + spawn_point = leaper_spawn_logic( level.enemy_dog_spawns, favorite_enemy ); + ai = spawn_zombie( level.leaper_spawners[0] ); + + if ( isdefined( ai ) ) + { + ai.favoriteenemy = favorite_enemy; + ai.spawn_point = spawn_point; + spawn_point thread leaper_spawn_fx( ai, spawn_point ); + level.zombie_total--; + level.leaper_count++; + } + + waiting_for_next_leaper_spawn( level.leaper_count, max ); + } +} + +leaper_round_accuracy_tracking() +{ + players = getplayers(); + level.leaper_round_accurate_players = 0; + + for ( i = 0; i < players.size; i++ ) + { + players[i].total_shots_start_leaper_round = players[i] maps\mp\gametypes_zm\_globallogic_score::getpersstat( "total_shots" ); + players[i].total_hits_start_leaper_round = players[i] maps\mp\gametypes_zm\_globallogic_score::getpersstat( "hits" ); + } + + level waittill( "last_leaper_down" ); + players = getplayers(); + + for ( i = 0; i < players.size; i++ ) + { + total_shots_end_leaper_round = players[i] maps\mp\gametypes_zm\_globallogic_score::getpersstat( "total_shots" ) - players[i].total_shots_start_leaper_round; + total_hits_end_leaper_round = players[i] maps\mp\gametypes_zm\_globallogic_score::getpersstat( "hits" ) - players[i].total_hits_start_leaper_round; + + if ( total_shots_end_leaper_round == total_hits_end_leaper_round ) + level.leaper_round_accurate_players++; + } + + if ( level.leaper_round_accurate_players == players.size ) + { + for ( i = 0; i < players.size; i++ ) + players[i] maps\mp\zombies\_zm_score::add_to_player_score( 2000 ); + + if ( isdefined( level.last_leaper_origin ) ) + { + trace = groundtrace( level.last_leaper_origin + vectorscale( ( 0, 0, 1 ), 10.0 ), level.last_leaper_origin + vectorscale( ( 0, 0, -1 ), 150.0 ), 0, undefined, 1 ); + power_up_origin = trace["position"]; + level thread maps\mp\zombies\_zm_powerups::specific_powerup_drop( "free_perk", power_up_origin + vectorscale( ( 1, 1, 0 ), 30.0 ) ); + } + } +} + +leaper_round_wait() +{ + level endon( "restart_round" ); +/# + if ( getdvarint( #"zombie_cheat" ) == 2 || getdvarint( #"zombie_cheat" ) >= 4 ) + level waittill( "forever" ); +#/ + wait 1; + + if ( flag( "leaper_round" ) ) + { + wait 7; + + while ( level.leaper_intermission ) + wait 0.5; + } +} + +leaper_health_increase() +{ + players = getplayers(); + + if ( level.leaper_round_count == 1 ) + level.leaper_health = 400; + else if ( level.leaper_round_count == 2 ) + level.leaper_health = 900; + else if ( level.leaper_round_count == 3 ) + level.leaper_health = 1300; + else if ( level.leaper_round_count == 4 ) + level.leaper_health = 1600; + + if ( level.leaper_health > 1600 ) + level.leaper_health = 1600; +} + +get_favorite_enemy() +{ + leaper_targets = getplayers(); + least_hunted = leaper_targets[0]; + + for ( i = 0; i < leaper_targets.size; i++ ) + { + if ( !isdefined( leaper_targets[i].hunted_by ) ) + leaper_targets[i].hunted_by = 0; + + if ( !is_player_valid( leaper_targets[i] ) ) + continue; + + if ( !is_player_valid( least_hunted ) ) + least_hunted = leaper_targets[i]; + + if ( leaper_targets[i].hunted_by < least_hunted.hunted_by ) + least_hunted = leaper_targets[i]; + } + + least_hunted.hunted_by = least_hunted.hunted_by + 1; + return least_hunted; +} + +leaper_watch_enemy() +{ + self endon( "death" ); + + while ( true ) + { + if ( !is_player_valid( self.favoriteenemy ) ) + self.favoriteenemy = get_favorite_enemy(); + + wait 0.2; + } +} + +leaper_combat_animmode() +{ + self animmode( "gravity", 0 ); +} + +leaper_spawn_logic_old( leaper_array, favorite_enemy ) +{ + all_locs = getstructarray( "leaper_location", "script_noteworthy" ); + leaper_locs = array_randomize( all_locs ); + + for ( i = 0; i < leaper_locs.size; i++ ) + { + if ( leaper_locs.size > 1 ) + { + if ( isdefined( level.old_leaper_spawn ) && level.old_leaper_spawn == leaper_locs[i] ) + continue; + } + + dist_squared = distancesquared( leaper_locs[i].origin, favorite_enemy.origin ); + + if ( dist_squared > 160000 && dist_squared < 1000000 ) + { + level.old_leaper_spawn = leaper_locs[i]; + return leaper_locs[i]; + } + } + + return leaper_locs[0]; +} + +leaper_spawn_logic( leaper_array, favorite_enemy ) +{ + a_zones_active = level.active_zone_names; + a_zones_occupied = []; + + foreach ( zone in a_zones_active ) + { + if ( level.zones[zone].is_occupied ) + a_zones_occupied[a_zones_occupied.size] = zone; + } + + a_leaper_spawn_points = []; + + foreach ( zone in a_zones_occupied ) + a_leaper_spawn_points = arraycombine( a_leaper_spawn_points, level.zones[zone].leaper_locations, 0, 0 ); + + if ( a_leaper_spawn_points.size == 0 ) + { + foreach ( zone in a_zones_active ) + a_leaper_spawn_points = arraycombine( a_leaper_spawn_points, level.zones[zone].leaper_locations, 0, 0 ); + } + + if ( a_leaper_spawn_points.size == 0 ) + { + str_zone_list_occupied = ""; + a_keys_error = getarraykeys( a_zones_occupied ); + + foreach ( key in a_zones_occupied ) + str_zone_list_occupied = str_zone_list_occupied + " " + key; + + str_zone_list_active = ""; + a_keys_error = getarraykeys( a_zones_active ); + + foreach ( key in a_zones_active ) + str_zone_list_active = str_zone_list_active + " " + key; + +/# + assertmsg( "No leaper spawn locations were found in any of the occupied or active zones. Occupied zones: " + str_zone_list_occupied + ". Active zones: " + str_zone_list_active ); +#/ + } + +/# + if ( getdvarint( #"scr_zombie_spawn_in_view" ) ) + { + player = get_players()[0]; + a_spawn_points_in_view = []; + + for ( i = 0; i < a_leaper_spawn_points.size; i++ ) + { + player_vec = vectornormalize( anglestoforward( player.angles ) ); + player_spawn = vectornormalize( a_leaper_spawn_points[i].origin - player.origin ); + dot = vectordot( player_vec, player_spawn ); + + if ( dot > 0.707 ) + { + a_spawn_points_in_view[a_spawn_points_in_view.size] = a_leaper_spawn_points[i]; + debugstar( a_leaper_spawn_points[i].origin, 1000, ( 1, 1, 1 ) ); + } + } + + if ( a_spawn_points_in_view.size <= 0 ) + { + a_spawn_points_in_view[a_spawn_points_in_view.size] = a_leaper_spawn_points[0]; + iprintln( "no spawner in view" ); + } + + a_leaper_spawn_points = a_spawn_points_in_view; + } +#/ + s_leaper_spawn_point = select_leaper_spawn_point( a_leaper_spawn_points ); + return s_leaper_spawn_point; +} + +select_leaper_spawn_point( a_spawn_points ) +{ + a_valid_nodes = get_valid_spawner_array( a_spawn_points ); + + if ( a_valid_nodes.size == 0 ) + { +/# + iprintln( "All leaper spawns used...resetting" ); +#/ + + for ( i = 0; i < a_spawn_points.size; i++ ) + a_spawn_points[i].has_spawned_leaper_this_round = 0; + + a_valid_nodes = get_valid_spawner_array( a_spawn_points ); + } + + if ( a_valid_nodes.size > 0 ) + { + s_spawn_point = random( a_valid_nodes ); + s_spawn_point.has_spawned_leaper_this_round = 1; + } + else + { +/# + iprintln( "DEBUG: no valid leaper spawns available" ); +#/ + s_spawn_point = a_spawn_points[0]; + } + + return s_spawn_point; +} + +get_valid_spawner_array( a_spawn_points ) +{ + a_valid_nodes = []; + + for ( i = 0; i < a_spawn_points.size; i++ ) + { + if ( isdefined( a_spawn_points[i].is_blocked ) && a_spawn_points[i].is_blocked || !( isdefined( a_spawn_points[i].is_enabled ) && a_spawn_points[i].is_enabled ) || isdefined( a_spawn_points[i].is_spawning ) && a_spawn_points[i].is_spawning ) + continue; + + if ( !isdefined( a_spawn_points[i].has_spawned_leaper_this_round ) ) + a_spawn_points[i].has_spawned_leaper_this_round = 0; + + if ( !a_spawn_points[i].has_spawned_leaper_this_round ) + a_valid_nodes[a_valid_nodes.size] = a_spawn_points[i]; + } + + return a_valid_nodes; +} + +leaper_spawn_fx( ai, ent ) +{ + ai setfreecameralockonallowed( 0 ); + ai show(); + ai setfreecameralockonallowed( 1 ); + v_fx_origin = ai.spawn_point.origin; + + if ( isdefined( ai.spawn_point.script_string ) && ai.spawn_point.script_string != "find_flesh" ) + { + wait 0.1; + v_fx_origin = ai gettagorigin( "J_SpineLower" ); + } + + playfx( level._effect["leaper_spawn"], v_fx_origin ); + playsoundatposition( "zmb_leaper_spawn_fx", v_fx_origin ); +} + +waiting_for_next_leaper_spawn( count, max ) +{ + default_wait = 1.5; + + if ( level.leaper_round_count == 1 ) + default_wait = 3; + else if ( level.leaper_round_count == 2 ) + default_wait = 2.5; + else if ( level.leaper_round_count == 3 ) + default_wait = 2; + else + default_wait = 1.5; + + default_wait = default_wait - count / max; + default_wait = clamp( default_wait, 0, 3 ); + wait( default_wait ); +} + +leaper_round_aftermath() +{ + level waittill( "last_leaper_down" ); + level thread maps\mp\zombies\_zm_audio::change_zombie_music( "dog_end" ); + power_up_origin = undefined; + + if ( isdefined( level.last_leaper_origin ) ) + { + trace = groundtrace( level.last_leaper_origin + vectorscale( ( 0, 0, 1 ), 10.0 ), level.last_leaper_origin + vectorscale( ( 0, 0, -1 ), 150.0 ), 0, undefined, 1 ); + power_up_origin = trace["position"]; + } + + if ( isdefined( power_up_origin ) ) + level thread maps\mp\zombies\_zm_powerups::specific_powerup_drop( "full_ammo", power_up_origin ); + + wait 2; + clientnotify( "leaper_stop" ); + wait 6; + level.leaper_intermission = 0; +} + +leaper_round_start() +{ + flag_set( "leaper_round" ); + level thread maps\mp\zombies\_zm_audio::change_zombie_music( "dog_start" ); + level thread leaper_round_start_audio(); + level notify( "leaper_round_starting" ); + clientnotify( "leaper_start" ); +} + +leaper_round_stop() +{ + flag_clear( "leaper_round" ); + level notify( "leaper_round_ending" ); + clientnotify( "leaper_stop" ); +} + +leaper_traverse_watcher() +{ + self endon( "death" ); + + while ( true ) + { + if ( is_true( self.is_traversing ) ) + { + self.elevator_parent = undefined; + + if ( is_true( self maps\mp\zm_highrise_elevators::object_is_on_elevator() ) ) + { + if ( isdefined( self.elevator_parent ) ) + { + if ( is_true( self.elevator_parent.is_moving ) ) + { + playfx( level._effect["zomb_gib"], self.origin ); + self leaper_cleanup(); + self delete(); + return; + } + } + } + } + + wait 0.2; + } +} + +leaper_playable_area_failsafe() +{ + self endon( "death" ); + self.leaper_failsafe_start_time = gettime(); + playable_area = getentarray( "player_volume", "script_noteworthy" ); + b_outside_playable_space_this_frame = 0; + self.leaper_outside_playable_space_time = -2; + + while ( true ) + { + b_outside_playable_last_check = b_outside_playable_space_this_frame; + b_outside_playable_space_this_frame = is_leaper_outside_playable_space( playable_area ); + n_current_time = gettime(); + + if ( b_outside_playable_space_this_frame && !b_outside_playable_last_check ) + self.leaper_outside_playable_space_time = n_current_time; + else if ( !b_outside_playable_space_this_frame ) + self.leaper_outside_playable_space = -1; + + b_leaper_has_been_alive_long_enough = n_current_time - self.leaper_failsafe_start_time > 3000; + b_leaper_is_in_scripted_state = self isinscriptedstate(); + b_leaper_has_been_out_of_playable_space_long_enough_to_delete = b_outside_playable_space_this_frame && n_current_time - self.leaper_outside_playable_space_time > 2000; + b_can_delete = b_leaper_has_been_alive_long_enough && !b_leaper_is_in_scripted_state && b_leaper_has_been_out_of_playable_space_long_enough_to_delete; + + if ( b_can_delete ) + { + playsoundatposition( "zmb_vocals_leaper_fall", self.origin ); + self leaper_cleanup(); +/# + str_traversal_data = ""; + + if ( isdefined( self.traversestartnode ) ) + str_traversal_data = " Last traversal used = " + self.traversestartnode.animscript + " at " + self.traversestartnode.origin; + + iprintln( "leaper at " + self.origin + " with spawn point " + self.spawn_point.origin + " out of play space. DELETING!" + str_traversal_data ); +#/ + self delete(); + return; + } + + wait 1; + } +} + +is_leaper_outside_playable_space( playable_area ) +{ + b_outside_play_space = 1; + + foreach ( area in playable_area ) + { + if ( self istouching( area ) ) + b_outside_play_space = 0; + } + + return b_outside_play_space; +} + +leaper_cleanup() +{ + self leaper_stop_trail_fx(); + self notify( "leaper_cleanup" ); + wait 0.05; + level.leaper_count--; + level.zombie_total++; +} + +leaper_spawn_failsafe() +{ + self endon( "death" ); + + while ( true ) + { + prevorigin = self.origin; + dist_sq = 0; + + for ( i = 0; i < 3; i++ ) + { + if ( is_true( self.sliding_on_goo ) ) + dist_sq = dist_sq + 576; + + wait 1; + dist_sq = dist_sq + distancesquared( self.origin, prevorigin ); + prevorigin = self.origin; + } + + if ( dist_sq < 576 ) + { + if ( !is_true( self.melee_attack ) ) + { + self leaper_cleanup(); +/# + str_traversal_data = ""; + + if ( isdefined( self.traversestartnode ) ) + str_traversal_data = " Last traversal used = " + self.traversestartnode.animscript + " at " + self.traversestartnode.origin; + + iprintln( "leaper_spawn_failsafe() killing leaper at " + self.origin + " with spawn point " + self.spawn_point.origin + "!\\n" + str_traversal_data ); +#/ + self dodamage( self.health + 100, ( 0, 0, 0 ) ); + break; + } + else + { +/# + if ( getdvarint( #"_id_5A273E4B" ) == 1 ) + iprintln( "leaper tried melee" ); +#/ + self.melee_attack = 0; + } + } + } +} + +do_leaper_emerge( spot ) +{ + self endon( "death" ); + self.deathfunction = ::leaper_death_ragdoll; + self.no_powerups = 1; + self.in_the_ceiling = 1; + spot.is_spawning = 1; + anim_org = spot.origin; + anim_ang = spot.angles; + self ghost(); + self thread maps\mp\zombies\_zm_spawner::hide_pop(); + self thread leaper_death_wait( "spawn_anim" ); + + if ( isdefined( level.custom_faller_entrance_logic ) ) + self thread [[ level.custom_faller_entrance_logic ]](); + + self leaper_emerge(); + wait 0.1; + self notify( "spawn_anim_finished" ); + spot.is_spawning = 0; +} + +leaper_death_ragdoll() +{ + self startragdoll(); + self launchragdoll( ( 0, 0, -1 ) ); + return self maps\mp\zombies\_zm_spawner::zombie_death_animscript(); +} + +leaper_death_wait( endon_notify ) +{ + self endon( "spawn_anim_finished" ); + self waittill( "death" ); + self.spawn_point.is_spawning = 0; +} + +leaper_emerge() +{ + self endon( "death" ); + + if ( self.spawn_point.script_parameters == "emerge_bottom" ) + self animscripted( self.spawn_point.origin, self.spawn_point.angles, "zm_spawn_elevator_from_floor" ); + else + self animscripted( self.spawn_point.origin, self.spawn_point.angles, "zm_spawn_elevator_from_ceiling" ); + + self maps\mp\animscripts\zm_shared::donotetracks( "spawn_anim" ); + self.deathfunction = maps\mp\zombies\_zm_spawner::zombie_death_animscript; + self.in_the_ceiling = 0; +} + +leaper_round_start_audio() +{ + wait 2.5; + players = get_players(); + num = randomintrange( 0, players.size ); + players[num] maps\mp\zombies\_zm_audio::create_and_play_dialog( "general", "leaper_round" ); + array_thread( players, ::wait_for_player_to_see_leaper ); + array_thread( players, ::wait_for_leaper_attack ); +} + +wait_for_player_to_see_leaper() +{ + self endon( "disconnect" ); + level endon( "leaper_round_ending" ); + + while ( true ) + { + leapers = getaiarray( level.zombie_team ); + + foreach ( leaper in leapers ) + { + player_vec = vectornormalize( anglestoforward( self.angles ) ); + player_leaper = vectornormalize( leaper.origin - self.origin ); + dot = vectordot( player_vec, player_leaper ); + + if ( dot > 0.707 ) + { + if ( sighttracepassed( self.origin + vectorscale( ( 0, 0, 1 ), 40.0 ), leaper.origin + vectorscale( ( 0, 0, 1 ), 10.0 ), 0, self ) ) + { + self maps\mp\zombies\_zm_audio::create_and_play_dialog( "general", "leaper_seen" ); + return; + } + } + } + + wait 0.25; + } +} + +wait_for_leaper_attack() +{ + self endon( "disconnect" ); + level endon( "leaper_round_ending" ); + + while ( true ) + { + self waittill( "melee_swipe", enemy ); + + if ( isdefined( enemy.is_leaper ) && enemy.is_leaper ) + { + self thread do_player_general_vox( "general", "leaper_attack", 10, 5 ); + wait 5; + } + } +} + +leaper_elevator_failsafe() +{ + self endon( "death" ); + free_pos = ( 3780, 1750, 1887 ); + + while ( true ) + { + if ( self maps\mp\zombies\_zm_zonemgr::entity_in_zone( "zone_orange_elevator_shaft_bottom" ) ) + { + if ( self check_traverse_height() ) + { + wait 3; + + if ( self check_traverse_height() ) + { + self forceteleport( free_pos ); + wait 3; + } + } + } + + wait 0.2; + } +} + +check_traverse_height() +{ + if ( isdefined( self.traversestartnode ) ) + { + traverse_height = self.traversestartnode.origin[2] - self.origin[2]; + + if ( traverse_height > 300 ) + return true; + } + + return false; +} diff --git a/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz.gsc b/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz.gsc index 1686a19..ef87db6 100644 --- a/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz.gsc +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz.gsc @@ -630,6 +630,7 @@ mechz_spawn() self.meleedamage = 75; self.custom_item_dmg = 2000; self.ignore_distance_tracking = true; + self.exclude_distance_cleanup_adding_to_total = true; recalc_zombie_array(); width = 15; height = 60; diff --git a/zm_ai_pack/scripts/zm/zm_ai_pack_mod_main.gsc b/zm_ai_pack/scripts/zm/zm_ai_pack_mod_main.gsc index 9a05332..4b0eddd 100644 --- a/zm_ai_pack/scripts/zm/zm_ai_pack_mod_main.gsc +++ b/zm_ai_pack/scripts/zm/zm_ai_pack_mod_main.gsc @@ -1,6 +1,7 @@ #include maps\mp\zombies\_zm_utility; #include common_scripts\utility; #include maps\mp\_utility; +#include maps\mp\zombies\_zm_spawner; #include maps\mp\zombies\_zm_ai_avogadro; #include maps\mp\zombies\_zm_ai_screecher; @@ -18,7 +19,7 @@ main() replace_single_function( "maps/mp/zombies/_zm_weap_slowgun", "can_be_paralyzed", ::can_be_paralyzed_override ); replace_single_function( "maps/mp/zombies/_zm_ai_sloth", "watch_crash_trigger", ::watch_crash_trigger_override ); - + level.script = toLower( getDvar( "mapname" ) ); level.gametype = toLower( getDvar( "g_gametype" ) ); @@ -73,6 +74,45 @@ init() level [[ level.ai_data[ keys[ i ] ].init ]](); } } + + level thread add_spawn_functions_to_spawners(); +} + +watch_for_damage_from_players() +{ + self endon( "death" ); + + for (;;) + { + self waittill( "damage", amount, attacker, direction_vec, point, type ); + + if ( !isdefined( amount ) ) + continue; + + if ( !isalive( self ) || self.delayeddeath ) + return; + + if ( !player_attacker( attacker ) ) + continue; + + self.has_been_damaged_by_player = true; + + if ( is_true( self.is_ghost ) ) + { + continue; + } + self player_attacks_enemy( attacker, amount, type, point ); + } +} + +add_spawn_functions_to_spawners() +{ + flag_wait( "initial_blackscreen_passed" ); + + if ( isDefined( level.ghost_spawners ) ) + { + array_thread( level.ghost_spawners, ::add_spawn_function, ::watch_for_damage_from_players ); + } } add_visionset_callback( func ) @@ -329,4 +369,30 @@ check_solo_status() { level.is_forever_solo_game = 0; } +} + +increment_enemy_count( who ) +{ + if ( !is_true( who.has_been_damaged_by_player ) ) + { + return; + } + + if ( is_true( who.is_leaper ) ) + { + who thread [maps\mp\zombies\_zm_ai_leaper::leaper_cleanup](); + } + else if ( is_true( who.is_mechz ) ) + { + level.mechz_left_to_spawn++; + } + else if ( is_true( who.is_brutus ) ) + { + level.brutus_count++; + } + //Maybe add dog increment here when possible + else + { + level.zombie_total++; + } } \ No newline at end of file diff --git a/zm_ai_pack/scripts/zm/zm_buried/zm_ai_pack_mod_zm_buried_main.gsc b/zm_ai_pack/scripts/zm/zm_buried/zm_ai_pack_mod_zm_buried_main.gsc new file mode 100644 index 0000000..429601f --- /dev/null +++ b/zm_ai_pack/scripts/zm/zm_buried/zm_ai_pack_mod_zm_buried_main.gsc @@ -0,0 +1,33 @@ +#include maps\mp\zombies\_zm_utility; +#include common_scripts\utility; +#include maps\mp\_utility; + +#include maps\mp\zm_buried_classic; + +#include scripts\zm\zm_ai_pack_mod_main; + +main() +{ + +} + +squashed_death_init( kill_if_falling ) +{ + while ( true ) + { + self waittill( "trigger", who ); + + if ( !( isdefined( who.insta_killed ) && who.insta_killed ) ) + { + if ( isplayer( who ) ) + who thread insta_kill_player( 1, kill_if_falling ); + else if ( isai( who ) ) + { + who dodamage( who.health + 100, who.origin ); + who.insta_killed = 1; + + increment_enemy_count( who ); + } + } + } +} \ No newline at end of file diff --git a/zm_ai_pack/scripts/zm/zm_highrise/zm_ai_pack_mod_zm_highrise_main.gsc b/zm_ai_pack/scripts/zm/zm_highrise/zm_ai_pack_mod_zm_highrise_main.gsc new file mode 100644 index 0000000..416addb --- /dev/null +++ b/zm_ai_pack/scripts/zm/zm_highrise/zm_ai_pack_mod_zm_highrise_main.gsc @@ -0,0 +1,85 @@ +#include maps\mp\zombies\_zm_utility; +#include common_scripts\utility; +#include maps\mp\_utility; + +#include maps\mp\zm_highrise_classic; + +#include scripts\zm\zm_ai_pack_mod_main; + +main() +{ + replaceFunc( maps\mp\zm_highrise_classic::squashed_death_init, ::squashed_death_init_override ); + replaceFunc( maps\mp\zm_highrise::elevator_traverse_watcher, ::elevator_traverse_watcher_override ); +} + +squashed_death_init_override( kill_if_falling ) +{ + while ( true ) + { + self waittill( "trigger", who ); + + if ( !is_true( who.insta_killed ) ) + { + continue; + } + if ( isplayer( who ) ) + { + who thread elevator_black_screen_squash_check(); + who thread insta_kill_player( 1, kill_if_falling ); + } + else if ( isai( who ) ) + { + if ( is_true( who.in_the_ceiling ) ) + { + continue; + } + + if ( is_true( who.is_avogadro ) ) + { + continue; + } + who dodamage( who.health + 100, who.origin ); + who.insta_killed = 1; + + increment_enemy_count( who ); + } + } +} + +elevator_traverse_watcher_override() +{ + self endon( "death" ); + + while ( true ) + { + wait 0.2; + + if ( !is_true( self.is_traversing ) ) + { + continue; + } + + self.elevator_parent = undefined; + + if ( !is_true( self maps\mp\zm_highrise_elevators::object_is_on_elevator() ) ) + { + continue; + } + + if ( !isdefined( self.elevator_parent ) ) + { + continue; + } + if ( !is_true( self.elevator_parent.is_moving ) ) + { + continue; + } + + playfx( level._effect["zomb_gib"], self.origin ); + + increment_enemy_count( self ); + + self delete(); + return; + } +} \ No newline at end of file diff --git a/zm_ai_pack/scripts/zm/zm_transit/zm_ai_pack_mod_zm_transit_main.gsc b/zm_ai_pack/scripts/zm/zm_transit/zm_ai_pack_mod_zm_transit_main.gsc new file mode 100644 index 0000000..1c65d89 --- /dev/null +++ b/zm_ai_pack/scripts/zm/zm_transit/zm_ai_pack_mod_zm_transit_main.gsc @@ -0,0 +1,47 @@ +#include maps\mp\zombies\_zm_utility; +#include common_scripts\utility; +#include maps\mp\_utility; + +main() +{ + replaceFunc( maps\mp\zm_transit_power::killzombiesinpowerstation, ::killzombiesinpowerstation_override ); +} + +killzombiesinpowerstation_override() +{ + level endon( "power_on" ); + radiussq = 122500; + + while ( true ) + { + zombies = getaiarray( level.zombie_team ); + + foreach ( zombie in zombies ) + { + if ( !isdefined( zombie ) ) + continue; + + if ( isdefined( zombie.is_avogadro ) && zombie.is_avogadro ) + continue; + + if ( is_true( zombie.is_boss ) ) + { + continue; + } + + if ( distancesquared( ( 11344, 7590, -729 ), zombie.origin ) < radiussq ) + continue; + + if ( isdefined( zombie ) && zombie maps\mp\zombies\_zm_zonemgr::entity_in_zone( "zone_prr", 1 ) || isdefined( zombie.zone_name ) && zombie.zone_name == "zone_prr" ) + { + if ( !( isdefined( zombie.has_been_damaged_by_player ) && zombie.has_been_damaged_by_player ) ) + level.zombie_total++; + + zombie dodamage( zombie.health + 100, zombie.origin ); + wait( randomfloatrange( 0.05, 0.15 ) ); + } + } + + wait 1; + } +} \ No newline at end of file diff --git a/zm_ai_pack/zone_source/highrise/zm_highrise_leaper.zone b/zm_ai_pack/zone_source/highrise/zm_highrise_leaper.zone index 449f858..e288e41 100644 --- a/zm_ai_pack/zone_source/highrise/zm_highrise_leaper.zone +++ b/zm_ai_pack/zone_source/highrise/zm_highrise_leaper.zone @@ -147,4 +147,19 @@ material,mc/mtl_c_gen_gore_blend xmodel,c_zom_leaper_body_g_behead xmodel,c_zom_leaper_body_g_lowclean script,character/clientscripts/c_zom_leaper.csc -script,aitype/clientscripts/zm_highrise_leaper.csc \ No newline at end of file +script,aitype/clientscripts/zm_highrise_leaper.csc + +fx,maps/zombie/fx_zmb_leaper_walk +footstepfxtable,zm_leaper_footstepfxtable +material,gfx_fxt_env_electric_arc2_add_eo10 +material,,gfx_fxt_debris_clump_ds128_z10 +fx,maps/zombie/fx_zmb_leaper_death +techniqueset,effect_z096f2e2 +material,gfx_fxt_env_lightning_bolt_ground +image,,fxt_lensflare_stripe_white +material,gfx_fxt_lensflare_stripe_white +fx,maps/zombie/fx_zmb_leaper_spawn +image,fxt_smk_trail_wisp +material,gfx_fxt_smk_trail_wisp +fx,maps/zombie/fx_zmb_leaper_trail +fx,maps/zombie/fx_zmb_leaper_wall_impact \ No newline at end of file diff --git a/zm_ai_pack/zone_source/mod.zone b/zm_ai_pack/zone_source/mod.zone index 662a019..e40680d 100644 --- a/zm_ai_pack/zone_source/mod.zone +++ b/zm_ai_pack/zone_source/mod.zone @@ -56,6 +56,9 @@ script,clientscripts/mp/zombies/_zm_ai_avogadro.csc script,maps/mp/zombies/_zm_ai_screecher.gsc script,clientscripts/mp/zombies/_zm_ai_screecher.csc +script,maps/mp/zombies/_zm_ai_leaper.gsc +script,clientscripts/mp/zombies/_zm_ai_leaper.csc + script,scripts/zm/zm_ai_pack_mod_debug_main.csc script,scripts/zm/zm_ai_pack_mod_debug_main.gsc script,scripts/zm/zm_ai_pack_mod_main.csc