From 10915889b5dd630096f9ae5df809a3faacd1b07a Mon Sep 17 00:00:00 2001 From: JezuzLizard Date: Sun, 18 Feb 2024 21:02:52 -0800 Subject: [PATCH] Fix clientfield alt system. Add mechz to Buried. Add _zm_ai_dogs.gsc. Make multiple ai immune to paralyzer. Fix zm_all_basic.asd. --- zm_ai_pack/animstatedefs/zm_all_basic.asd | 2 +- zm_ai_pack/maps/mp/zm_buried.d3dbsp | 162 ++++ .../maps/mp/zombies/_zm_ai_avogadro.gsc | 1 + zm_ai_pack/maps/mp/zombies/_zm_ai_brutus.gsc | 3 +- zm_ai_pack/maps/mp/zombies/_zm_ai_dogs.gsc | 734 ++++++++++++++++++ zm_ai_pack/maps/mp/zombies/_zm_ai_ghost.gsc | 1 + zm_ai_pack/maps/mp/zombies/_zm_ai_mechz.gsc | 17 +- .../maps/mp/zombies/_zm_ai_mechz_claw.gsc | 11 +- zm_ai_pack/scripts/zm/clientfield_alt_sys.csc | 16 +- zm_ai_pack/scripts/zm/clientfield_alt_sys.gsc | 8 +- .../scripts/zm/zm_ai_pack_mod_debug_main.gsc | 6 +- zm_ai_pack/scripts/zm/zm_ai_pack_mod_main.gsc | 57 +- zm_ai_pack/zone_source/mod.zone | 2 + 13 files changed, 980 insertions(+), 40 deletions(-) create mode 100644 zm_ai_pack/maps/mp/zombies/_zm_ai_dogs.gsc diff --git a/zm_ai_pack/animstatedefs/zm_all_basic.asd b/zm_ai_pack/animstatedefs/zm_all_basic.asd index 90d22ce..de64f66 100644 --- a/zm_ai_pack/animstatedefs/zm_all_basic.asd +++ b/zm_ai_pack/animstatedefs/zm_all_basic.asd @@ -745,7 +745,7 @@ zm_traverse : aliased restart notify traverse_anim jump_across_120 ai_zombie_jump_across_120 jump_down_40 ai_zombie_jump_down_40 jump_down_fast_40 ai_zombie_jump_down_fast_40 -// jump_down_48 ai_zombie_jump_down_48 + jump_down_48 ai_zombie_jump_down_48 jump_down_72 ai_zombie_jump_down_72 jump_down_96 ai_zombie_jump_down_96 jump_down_120 ai_zombie_jump_down_120 diff --git a/zm_ai_pack/maps/mp/zm_buried.d3dbsp b/zm_ai_pack/maps/mp/zm_buried.d3dbsp index 109bd57..beafb1e 100644 --- a/zm_ai_pack/maps/mp/zm_buried.d3dbsp +++ b/zm_ai_pack/maps/mp/zm_buried.d3dbsp @@ -33003,4 +33003,166 @@ "targetname" "ee_warp_bar" "origin" "887 -1281 74" "guid" "BB6ECC38" +} +{ +"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_maze_spawners" +"script_noteworthy" "mechz_location" +"origin" "5028 455 4" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_mansion_backyard_spawners" +"script_noteworthy" "mechz_location" +"origin" "3992 583 4" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_start_lower_spawners" +"script_noteworthy" "mechz_location" +"origin" "-2586 -187 1224" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_start_spawners" +"script_noteworthy" "mechz_location" +"origin" "-2747 29 1344" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_tunnels_center_spawners" +"script_noteworthy" "mechz_location" +"origin" "-961 -225 288" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_stables_spawners" +"script_noteworthy" "mechz_location" +"origin" "-797 -115 101" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_street_lightwest_spawners" +"script_noteworthy" "mechz_location" +"origin" "-613 296 -27" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_street_darkeast_spawners" +"script_noteworthy" "mechz_location" +"origin" "168 -938 -21" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_street_fountain_spawners" +"script_noteworthy" "mechz_location" +"origin" "1007 541 -18" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_church_main_spawners" +"script_noteworthy" "mechz_location" +"origin" "1673 2299 40" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_mansion_lawn_spawners" +"script_noteworthy" "mechz_location" +"origin" "1772 553 0" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_underground_bar_spawners" +"script_noteworthy" "mechz_location" +"origin" "826 -1458 56" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_street_darkeast_nook_spawners" +"script_noteworthy" "mechz_location" +"origin" "309 -1686 160" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_gun_store_spawners" +"script_noteworthy" "mechz_location" +"origin" "-451 -1389 152" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_bank_spawners" +"script_noteworthy" "mechz_location" +"origin" "-407 -268 8" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_underground_courthouse2_spawners" +"script_noteworthy" "mechz_location" +"origin" "-1 721 176" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_underground_courthouse_spawners" +"script_noteworthy" "mechz_location" +"origin" "486 823 8" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_toy_store_floor2_spawners" +"script_noteworthy" "mechz_location" +"origin" "719 -602 142" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_candy_store_floor2_spawners" +"script_noteworthy" "mechz_location" +"origin" "574 -240 148" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_candy_store_spawners" +"script_noteworthy" "mechz_location" +"origin" "581 -132 8" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_toy_store_spawners" +"script_noteworthy" "mechz_location" +"origin" "660 -559 10" +"classname" "script_struct" +"angles" "0 0 0" +} +{ +"targetname" "zone_tunnels_north2_spawners" +"script_noteworthy" "mechz_location" +"origin" "-435 267 424" +"classname" "script_struct" +"angles" "0 0 0" } \ No newline at end of file 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 ac0b579..663479b 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,7 @@ avogadro_prespawn() self endon( "death" ); level endon( "intermission" ); level.avogadro = self; + self.immune_to_slowgun = true; self.has_legs = 1; self.no_gib = 1; self.is_avogadro = 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 5946dae..0f1d0d9 100644 --- a/zm_ai_pack/maps/mp/zombies/_zm_ai_brutus.gsc +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_brutus.gsc @@ -393,6 +393,7 @@ brutus_spawn( starting_health, has_helmet, helmet_hits, explosive_dmg_taken, zon width = 20; } self setphysparams( width, 0, 60 ); + self.immune_to_slowgun = true; self.zombie_init_done = 1; self notify( "zombie_init_done" ); self.allowpain = 0; @@ -2452,7 +2453,7 @@ brutus_lockdown_client_effects( delay ) self.brutus_lockdown_state = !self.brutus_lockdown_state; - if ( level.script == "zm_tomb" ) + if ( level.script == "zm_prison" ) { self setclientfield( "brutus_lock_down", self.brutus_lockdown_state ); } diff --git a/zm_ai_pack/maps/mp/zombies/_zm_ai_dogs.gsc b/zm_ai_pack/maps/mp/zombies/_zm_ai_dogs.gsc new file mode 100644 index 0000000..49cd793 --- /dev/null +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_dogs.gsc @@ -0,0 +1,734 @@ +// 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\zombies\_zm_spawner; +#include maps\mp\zombies\_zm_audio; +#include maps\mp\zombies\_zm_powerups; +#include maps\mp\zombies\_zm; +#include maps\mp\zombies\_zm_score; +#include maps\mp\zombies\_zm_stats; +#include maps\mp\zombies\_zm_net; + +init() +{ + level.dogs_enabled = 1; + level.dog_rounds_enabled = 0; + level.dog_round_count = 1; + level.dog_spawners = []; + level.enemy_dog_spawns = []; + level.enemy_dog_locations = []; + flag_init( "dog_clips" ); + precacherumble( "explosion_generic" ); + precacheshellshock( "dog_bite" ); + + if ( getdvar( #"zombie_dog_animset" ) == "" ) + setdvar( "zombie_dog_animset", "zombie" ); + + if ( getdvar( #"scr_dog_health_walk_multiplier" ) == "" ) + setdvar( "scr_dog_health_walk_multiplier", "4.0" ); + + if ( getdvar( #"scr_dog_run_distance" ) == "" ) + setdvar( "scr_dog_run_distance", "500" ); + + level.melee_range_sav = getdvar( #"ai_meleeRange" ); + level.melee_width_sav = getdvar( #"ai_meleeWidth" ); + level.melee_height_sav = getdvar( #"ai_meleeHeight" ); + setdvar( "dog_MeleeDamage", "100" ); + set_zombie_var( "dog_fire_trail_percent", 50 ); + level._effect["lightning_dog_spawn"] = loadfx( "maps/zombie/fx_zombie_dog_lightning_buildup" ); + level._effect["dog_eye_glow"] = loadfx( "maps/zombie/fx_zombie_dog_eyes" ); + level._effect["dog_gib"] = loadfx( "maps/zombie/fx_zombie_dog_explosion" ); + level._effect["dog_trail_fire"] = loadfx( "maps/zombie/fx_zombie_dog_fire_trail" ); + level._effect["dog_trail_ash"] = loadfx( "maps/zombie/fx_zombie_dog_ash_trail" ); + dog_spawner_init(); + level thread dog_clip_monitor(); +} + +enable_dog_rounds() +{ + level.dog_rounds_enabled = 1; + + if ( !isdefined( level.dog_round_track_override ) ) + level.dog_round_track_override = ::dog_round_tracker; + + level thread [[ level.dog_round_track_override ]](); +} + +dog_spawner_init() +{ + level.dog_spawners = getentarray( "zombie_dog_spawner", "script_noteworthy" ); + later_dogs = getentarray( "later_round_dog_spawners", "script_noteworthy" ); + level.dog_spawners = arraycombine( level.dog_spawners, later_dogs, 1, 0 ); + + if ( level.dog_spawners.size == 0 ) + return; + + for ( i = 0; i < level.dog_spawners.size; i++ ) + { + if ( maps\mp\zombies\_zm_spawner::is_spawner_targeted_by_blocker( level.dog_spawners[i] ) ) + { + level.dog_spawners[i].is_enabled = 0; + continue; + } + + level.dog_spawners[i].is_enabled = 1; + level.dog_spawners[i].script_forcespawn = 1; + } + + assert( level.dog_spawners.size > 0 ); + level.dog_health = 100; + array_thread( level.dog_spawners, ::add_spawn_function, ::dog_init ); + level.enemy_dog_spawns = getentarray( "zombie_spawner_dog_init", "targetname" ); +} + +dog_round_spawning() +{ + level endon( "intermission" ); + level.dog_targets = getplayers(); + + for ( i = 0; i < level.dog_targets.size; i++ ) + level.dog_targets[i].hunted_by = 0; + +/# + level endon( "kill_round" ); + + if ( getdvarint( #"zombie_cheat" ) == 2 || getdvarint( #"zombie_cheat" ) >= 4 ) + return; +#/ + + if ( level.intermission ) + return; + + level.dog_intermission = 1; + level thread dog_round_aftermath(); + players = get_players(); + array_thread( players, ::play_dog_round ); + wait 1; + playsoundatposition( "vox_zmba_event_dogstart_0", ( 0, 0, 0 ) ); + wait 6; + + if ( level.dog_round_count < 3 ) + max = players.size * 6; + else + max = players.size * 8; + +/# + if ( getdvar( #"force_dogs" ) != "" ) + max = getdvarint( #"force_dogs" ); +#/ + level.zombie_total = max; + dog_health_increase(); + count = 0; + + while ( count < max ) + { + for ( num_player_valid = get_number_of_valid_players(); get_current_zombie_count() >= num_player_valid * 2; num_player_valid = get_number_of_valid_players() ) + wait 2; + + players = get_players(); + favorite_enemy = get_favorite_enemy(); + + if ( isdefined( level.dog_spawn_func ) ) + { + spawn_loc = [[ level.dog_spawn_func ]]( level.dog_spawners, favorite_enemy ); + ai = spawn_zombie( level.dog_spawners[0] ); + + if ( isdefined( ai ) ) + { + ai.favoriteenemy = favorite_enemy; + spawn_loc thread dog_spawn_fx( ai, spawn_loc ); + level.zombie_total--; + count++; + } + } + else + { + spawn_point = dog_spawn_factory_logic( level.enemy_dog_spawns, favorite_enemy ); + ai = spawn_zombie( level.dog_spawners[0] ); + + if ( isdefined( ai ) ) + { + ai.favoriteenemy = favorite_enemy; + spawn_point thread dog_spawn_fx( ai, spawn_point ); + level.zombie_total--; + count++; + flag_set( "dog_clips" ); + } + } + + waiting_for_next_dog_spawn( count, max ); + } +} + +waiting_for_next_dog_spawn( count, max ) +{ + default_wait = 1.5; + + if ( level.dog_round_count == 1 ) + default_wait = 3; + else if ( level.dog_round_count == 2 ) + default_wait = 2.5; + else if ( level.dog_round_count == 3 ) + default_wait = 2; + else + default_wait = 1.5; + + default_wait = default_wait - count / max; + wait( default_wait ); +} + +dog_round_aftermath() +{ + level waittill( "last_dog_down" ); + level thread maps\mp\zombies\_zm_audio::change_zombie_music( "dog_end" ); + power_up_origin = level.last_dog_origin; + + if ( isdefined( power_up_origin ) ) + level thread maps\mp\zombies\_zm_powerups::specific_powerup_drop( "full_ammo", power_up_origin ); + + wait 2; + clientnotify( "dog_stop" ); + wait 6; + level.dog_intermission = 0; +} + +dog_spawn_fx( ai, ent ) +{ + ai endon( "death" ); + ai setfreecameralockonallowed( 0 ); + playfx( level._effect["lightning_dog_spawn"], ent.origin ); + playsoundatposition( "zmb_hellhound_prespawn", ent.origin ); + wait 1.5; + playsoundatposition( "zmb_hellhound_bolt", ent.origin ); + earthquake( 0.5, 0.75, ent.origin, 1000 ); + playrumbleonposition( "explosion_generic", ent.origin ); + playsoundatposition( "zmb_hellhound_spawn", ent.origin ); + angle = vectortoangles( ai.favoriteenemy.origin - ent.origin ); + angles = ( ai.angles[0], angle[1], ai.angles[2] ); + ai forceteleport( ent.origin, angles ); + assert( isdefined( ai ), "Ent isn't defined." ); + assert( isalive( ai ), "Ent is dead." ); + assert( ai.isdog, "Ent isn't a dog;" ); + assert( is_magic_bullet_shield_enabled( ai ), "Ent doesn't have a magic bullet shield." ); + ai zombie_setup_attack_properties_dog(); + ai stop_magic_bullet_shield(); + wait 0.1; + ai show(); + ai setfreecameralockonallowed( 1 ); + ai.ignoreme = 0; + ai notify( "visible" ); +} + +dog_spawn_sumpf_logic( dog_array, favorite_enemy ) +{ + assert( dog_array.size > 0, "Dog Spawner array is empty." ); + dog_array = array_randomize( dog_array ); + + for ( i = 0; i < dog_array.size; i++ ) + { + if ( isdefined( level.old_dog_spawn ) && level.old_dog_spawn == dog_array[i] ) + continue; + + if ( distancesquared( dog_array[i].origin, favorite_enemy.origin ) > 160000 && distancesquared( dog_array[i].origin, favorite_enemy.origin ) < 640000 ) + { + if ( distancesquared( ( 0, 0, dog_array[i].origin[2] ), ( 0, 0, favorite_enemy.origin[2] ) ) > 10000 ) + continue; + else + { + level.old_dog_spawn = dog_array[i]; + return dog_array[i]; + } + } + } + + return dog_array[0]; +} + +dog_spawn_factory_logic( dog_array, favorite_enemy ) +{ + dog_locs = array_randomize( level.enemy_dog_locations ); + + for ( i = 0; i < dog_locs.size; i++ ) + { + if ( isdefined( level.old_dog_spawn ) && level.old_dog_spawn == dog_locs[i] ) + continue; + + dist_squared = distancesquared( dog_locs[i].origin, favorite_enemy.origin ); + + if ( dist_squared > 160000 && dist_squared < 1000000 ) + { + level.old_dog_spawn = dog_locs[i]; + return dog_locs[i]; + } + } + + return dog_locs[0]; +} + +get_favorite_enemy() +{ + dog_targets = getplayers(); + least_hunted = dog_targets[0]; + + for ( i = 0; i < dog_targets.size; i++ ) + { + if ( !isdefined( dog_targets[i].hunted_by ) ) + dog_targets[i].hunted_by = 0; + + if ( !is_player_valid( dog_targets[i] ) ) + continue; + + if ( !is_player_valid( least_hunted ) ) + least_hunted = dog_targets[i]; + + if ( dog_targets[i].hunted_by < least_hunted.hunted_by ) + least_hunted = dog_targets[i]; + } + + least_hunted.hunted_by = least_hunted.hunted_by + 1; + return least_hunted; +} + +dog_health_increase() +{ + players = getplayers(); + + if ( level.dog_round_count == 1 ) + level.dog_health = 400; + else if ( level.dog_round_count == 2 ) + level.dog_health = 900; + else if ( level.dog_round_count == 3 ) + level.dog_health = 1300; + else if ( level.dog_round_count == 4 ) + level.dog_health = 1600; + + if ( level.dog_health > 1600 ) + level.dog_health = 1600; +} + +dog_round_tracker() +{ + level.dog_round_count = 1; + level.next_dog_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 ( getdvarint( #"force_dogs" ) > 0 ) + level.next_dog_round = level.round_number; +#/ + + if ( level.round_number == level.next_dog_round ) + { + level.music_round_override = 1; + old_spawn_func = level.round_spawn_func; + old_wait_func = level.round_wait_func; + dog_round_start(); + level.round_spawn_func = ::dog_round_spawning; + level.next_dog_round = level.round_number + randomintrange( 4, 6 ); +/# + get_players()[0] iprintln( "Next dog round: " + level.next_dog_round ); +#/ + } + else if ( flag( "dog_round" ) ) + { + dog_round_stop(); + level.round_spawn_func = old_spawn_func; + level.round_wait_func = old_wait_func; + level.music_round_override = 0; + level.dog_round_count = level.dog_round_count + 1; + } + } +} + +dog_round_start() +{ + flag_set( "dog_round" ); + flag_set( "dog_clips" ); + level thread maps\mp\zombies\_zm_audio::change_zombie_music( "dog_start" ); + + if ( !isdefined( level.doground_nomusic ) ) + level.doground_nomusic = 0; + + level.doground_nomusic = 1; + level notify( "dog_round_starting" ); + clientnotify( "dog_start" ); + + if ( isdefined( level.dog_melee_range ) ) + setdvar( "ai_meleeRange", level.dog_melee_range ); + else + setdvar( "ai_meleeRange", 100 ); +} + +dog_round_stop() +{ + flag_clear( "dog_round" ); + flag_clear( "dog_clips" ); + + if ( !isdefined( level.doground_nomusic ) ) + level.doground_nomusic = 0; + + level.doground_nomusic = 0; + level notify( "dog_round_ending" ); + clientnotify( "dog_stop" ); + setdvar( "ai_meleeRange", level.melee_range_sav ); + setdvar( "ai_meleeWidth", level.melee_width_sav ); + setdvar( "ai_meleeHeight", level.melee_height_sav ); +} + +play_dog_round() +{ + self playlocalsound( "zmb_dog_round_start" ); + variation_count = 5; + wait 4.5; + players = getplayers(); + num = randomintrange( 0, players.size ); + players[num] maps\mp\zombies\_zm_audio::create_and_play_dialog( "general", "dog_spawn" ); +} + +dog_init() +{ + self.immune_to_slowgun = false; + self.targetname = "zombie_dog"; + self.script_noteworthy = undefined; + self.animname = "zombie_dog"; + self.ignoreall = 1; + self.ignoreme = 1; + self.allowdeath = 1; + self.allowpain = 0; + self.force_gib = 1; + self.is_zombie = 1; + self.has_legs = 1; + self.gibbed = 0; + self.head_gibbed = 0; + self.default_goalheight = 40; + self.ignore_inert = 1; + self.grenadeawareness = 0; + self.badplaceawareness = 0; + self.ignoresuppression = 1; + self.suppressionthreshold = 1; + self.nododgemove = 1; + self.dontshootwhilemoving = 1; + self.pathenemylookahead = 0; + self.badplaceawareness = 0; + self.chatinitialized = 0; + self.team = level.zombie_team; + health_multiplier = 1.0; + + if ( getdvar( #"scr_dog_health_walk_multiplier" ) != "" ) + health_multiplier = getdvarfloat( #"scr_dog_health_walk_multiplier" ); + + self.maxhealth = int( level.dog_health * health_multiplier ); + self.health = int( level.dog_health * health_multiplier ); + self.freezegun_damage = 0; + self.zombie_move_speed = "sprint"; + self thread dog_run_think(); + self thread dog_stalk_audio(); + self thread maps\mp\zombies\_zm::round_spawn_failsafe(); + self ghost(); + self thread magic_bullet_shield(); + self dog_fx_eye_glow(); + self dog_fx_trail(); + self thread dog_death(); + level thread maps\mp\zombies\_zm_spawner::zombie_death_event( self ); + self thread maps\mp\zombies\_zm_spawner::enemy_death_detection(); + self.a.disablepain = 1; + self disable_react(); + self clearenemy(); + self cleargoalvolume(); + self.flame_damage_time = 0; + self.meleedamage = 40; + self.thundergun_knockdown_func = ::dog_thundergun_knockdown; + self maps\mp\zombies\_zm_spawner::zombie_history( "zombie_dog_spawn_init -> Spawned = " + self.origin ); + + if ( isdefined( level.achievement_monitor_func ) ) + self [[ level.achievement_monitor_func ]](); +} + +dog_fx_eye_glow() +{ + self.fx_dog_eye = spawn( "script_model", self gettagorigin( "J_EyeBall_LE" ) ); + assert( isdefined( self.fx_dog_eye ) ); + self.fx_dog_eye.angles = self gettagangles( "J_EyeBall_LE" ); + self.fx_dog_eye setmodel( "tag_origin" ); + self.fx_dog_eye linkto( self, "J_EyeBall_LE" ); +} + +dog_fx_trail() +{ + if ( !is_mature() || randomint( 100 ) > level.zombie_vars["dog_fire_trail_percent"] ) + { + self.fx_dog_trail_type = level._effect["dog_trail_ash"]; + self.fx_dog_trail_sound = "zmb_hellhound_loop_breath"; + } + else + { + self.a.nodeath = 1; + self.fx_dog_trail_type = level._effect["dog_trail_fire"]; + self.fx_dog_trail_sound = "zmb_hellhound_loop_fire"; + } + + self.fx_dog_trail = spawn( "script_model", self gettagorigin( "tag_origin" ) ); + assert( isdefined( self.fx_dog_trail ) ); + self.fx_dog_trail.angles = self gettagangles( "tag_origin" ); + self.fx_dog_trail setmodel( "tag_origin" ); + self.fx_dog_trail linkto( self, "tag_origin" ); +} + +dog_death() +{ + self waittill( "death" ); + + if ( get_current_zombie_count() == 0 && level.zombie_total == 0 ) + { + level.last_dog_origin = self.origin; + level notify( "last_dog_down" ); + } + + if ( isplayer( self.attacker ) ) + { + event = "death"; + + if ( issubstr( self.damageweapon, "knife_ballistic_" ) ) + event = "ballistic_knife_death"; + + self.attacker maps\mp\zombies\_zm_score::player_add_points( event, self.damagemod, self.damagelocation, 1 ); + + if ( randomintrange( 0, 100 ) >= 80 ) + self.attacker maps\mp\zombies\_zm_audio::create_and_play_dialog( "kill", "hellhound" ); + + self.attacker maps\mp\zombies\_zm_stats::increment_client_stat( "zdogs_killed" ); + self.attacker maps\mp\zombies\_zm_stats::increment_player_stat( "zdogs_killed" ); + } + + if ( isdefined( self.attacker ) && isai( self.attacker ) ) + self.attacker notify( "killed", self ); + + self stoploopsound(); + assert( isdefined( self.fx_dog_eye ) ); + self.fx_dog_eye delete(); + assert( isdefined( self.fx_dog_trail ) ); + self.fx_dog_trail delete(); + + if ( isdefined( self.a.nodeath ) ) + { + level thread dog_explode_fx( self.origin ); + self delete(); + } + else + self playsound( "zmb_hellhound_vocals_death" ); +} + +dog_explode_fx( origin ) +{ + playfx( level._effect["dog_gib"], origin ); + playsoundatposition( "zmb_hellhound_explode", origin ); +} + +zombie_setup_attack_properties_dog() +{ + self maps\mp\zombies\_zm_spawner::zombie_history( "zombie_setup_attack_properties()" ); + self thread dog_behind_audio(); + self.ignoreall = 0; + self.pathenemyfightdist = 64; + self.meleeattackdist = 64; + self.disablearrivals = 1; + self.disableexits = 1; +} + +stop_dog_sound_on_death() +{ + self waittill( "death" ); + self stopsounds(); +} + +dog_behind_audio() +{ + self thread stop_dog_sound_on_death(); + self endon( "death" ); + self waittill_any( "dog_running", "dog_combat" ); + self playsound( "zmb_hellhound_vocals_close" ); + wait 3; + + while ( true ) + { + players = get_players(); + + for ( i = 0; i < players.size; i++ ) + { + dogangle = angleclamp180( vectortoangles( self.origin - players[i].origin )[1] - players[i].angles[1] ); + + if ( isalive( players[i] ) && !isdefined( players[i].revivetrigger ) ) + { + if ( abs( dogangle ) > 90 && distance2d( self.origin, players[i].origin ) > 100 ) + { + self playsound( "zmb_hellhound_vocals_close" ); + wait 3; + } + } + } + + wait 0.75; + } +} + +dog_clip_monitor() +{ + clips_on = 0; + level.dog_clips = getentarray( "dog_clips", "targetname" ); + + while ( true ) + { + for ( i = 0; i < level.dog_clips.size; i++ ) + { + level.dog_clips[i] trigger_off(); + level.dog_clips[i] connectpaths(); + } + + flag_wait( "dog_clips" ); + + if ( isdefined( level.no_dog_clip ) && level.no_dog_clip == 1 ) + return; + + for ( i = 0; i < level.dog_clips.size; i++ ) + { + level.dog_clips[i] trigger_on(); + level.dog_clips[i] disconnectpaths(); + wait_network_frame(); + } + + dog_is_alive = 1; + + while ( dog_is_alive || flag( "dog_round" ) ) + { + dog_is_alive = 0; + dogs = getentarray( "zombie_dog", "targetname" ); + + for ( i = 0; i < dogs.size; i++ ) + { + if ( isalive( dogs[i] ) ) + dog_is_alive = 1; + } + + wait 1; + } + + flag_clear( "dog_clips" ); + wait 1; + } +} + +special_dog_spawn( spawners, num_to_spawn ) +{ + dogs = getaispeciesarray( "all", "zombie_dog" ); + + if ( isdefined( dogs ) && dogs.size >= 9 ) + return false; + + if ( !isdefined( num_to_spawn ) ) + num_to_spawn = 1; + + spawn_point = undefined; + count = 0; + + while ( count < num_to_spawn ) + { + players = get_players(); + favorite_enemy = get_favorite_enemy(); + + if ( isdefined( spawners ) ) + { + spawn_point = spawners[randomint( spawners.size )]; + ai = spawn_zombie( spawn_point ); + + if ( isdefined( ai ) ) + { + ai.favoriteenemy = favorite_enemy; + spawn_point thread dog_spawn_fx( ai ); + count++; + flag_set( "dog_clips" ); + } + } + else if ( isdefined( level.dog_spawn_func ) ) + { + spawn_loc = [[ level.dog_spawn_func ]]( level.dog_spawners, favorite_enemy ); + ai = spawn_zombie( level.dog_spawners[0] ); + + if ( isdefined( ai ) ) + { + ai.favoriteenemy = favorite_enemy; + spawn_loc thread dog_spawn_fx( ai, spawn_loc ); + count++; + flag_set( "dog_clips" ); + } + } + else + { + spawn_point = dog_spawn_factory_logic( level.enemy_dog_spawns, favorite_enemy ); + ai = spawn_zombie( level.dog_spawners[0] ); + + if ( isdefined( ai ) ) + { + ai.favoriteenemy = favorite_enemy; + spawn_point thread dog_spawn_fx( ai, spawn_point ); + count++; + flag_set( "dog_clips" ); + } + } + + waiting_for_next_dog_spawn( count, num_to_spawn ); + } + + return true; +} + +dog_run_think() +{ + self endon( "death" ); + self waittill( "visible" ); + + if ( self.health > level.dog_health ) + { + self.maxhealth = level.dog_health; + self.health = level.dog_health; + } + + assert( isdefined( self.fx_dog_eye ) ); + maps\mp\zombies\_zm_net::network_safe_play_fx_on_tag( "dog_fx", 2, level._effect["dog_eye_glow"], self.fx_dog_eye, "tag_origin" ); + assert( isdefined( self.fx_dog_trail ) ); + maps\mp\zombies\_zm_net::network_safe_play_fx_on_tag( "dog_fx", 2, self.fx_dog_trail_type, self.fx_dog_trail, "tag_origin" ); + self playloopsound( self.fx_dog_trail_sound ); + + while ( true ) + { + if ( !is_player_valid( self.favoriteenemy ) ) + self.favoriteenemy = get_favorite_enemy(); + + wait 0.2; + } +} + +dog_stalk_audio() +{ + self endon( "death" ); + self endon( "dog_running" ); + self endon( "dog_combat" ); + + while ( true ) + { + self playsound( "zmb_hellhound_vocals_amb" ); + wait( randomfloatrange( 3, 6 ) ); + } +} + +dog_thundergun_knockdown( player, gib ) +{ + self endon( "death" ); + damage = int( self.maxhealth * 0.5 ); + self dodamage( damage, player.origin, player ); +} 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 58f3cd6..f2a60ef 100644 --- a/zm_ai_pack/maps/mp/zombies/_zm_ai_ghost.gsc +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_ghost.gsc @@ -616,6 +616,7 @@ prespawn() { self endon( "death" ); level endon( "intermission" ); + self.immune_to_slowgun = true; 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_mechz.gsc b/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz.gsc index 6c19179..1f3bcc1 100644 --- a/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz.gsc +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz.gsc @@ -221,7 +221,7 @@ clear_one_off_fx( fx_id ) } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } } @@ -251,7 +251,7 @@ traversal_booster_fx_watcher() } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } } } @@ -295,7 +295,7 @@ booster_fx_watcher() } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } } } @@ -319,7 +319,7 @@ flamethrower_fx_watcher() } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } } } @@ -333,7 +333,7 @@ fx_cleanup() } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } wait_network_frame(); } @@ -604,6 +604,7 @@ mechz_spawn() self mechz_setup_snd(); level notify( "sam_clue_mechz", self ); self.closest_player_override = maps\mp\zombies\_zm_ai_mechz::get_favorite_enemy; + self.immune_to_slowgun = true; self.animname = "mechz_zombie"; self.has_legs = 1; self.no_gib = 1; @@ -802,7 +803,7 @@ mechz_death() } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } self thread maps\mp\zombies\_zm_spawner::zombie_eye_glow_stop(); self mechz_interrupt(); @@ -1559,7 +1560,7 @@ mechz_launch_armor_piece() } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } if ( sndmechzisnetworksafe( "destruction" ) ) @@ -1696,7 +1697,7 @@ mechz_damage_override( inflictor, attacker, damage, flags, meansofdeath, weapon, } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } if ( !( isdefined( self.not_interruptable ) && self.not_interruptable ) && !( isdefined( self.is_traversing ) && self.is_traversing ) ) diff --git a/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz_claw.gsc b/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz_claw.gsc index 6735db0..1d30d93 100644 --- a/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz_claw.gsc +++ b/zm_ai_pack/maps/mp/zombies/_zm_ai_mechz_claw.gsc @@ -56,9 +56,8 @@ mechz_claw_release( bopenclaw ) } else { - self.e_grabbed set_clientfield_alt_toplayer( "toplayer", "mechz_grab", self.e_grabbed, 0 ); + self.e_grabbed set_clientfield_alt_toplayer( "mechz_grab", self.e_grabbed, 0 ); } - self.e_grabbed setclientfieldtoplayer( "mechz_grab", 0 ); self.e_grabbed allowcrouch( 1 ); self.e_grabbed allowprone( 1 ); } @@ -179,7 +178,7 @@ claw_grapple() } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } self.m_claw setanim( %ai_zombie_mech_grapple_arm_open_idle, 1, 0, 1 ); self.m_claw unlink(); @@ -234,7 +233,7 @@ claw_grapple() } else { - self.e_grabbed set_clientfield_alt_toplayer( "toplayer", "mechz_grab", self.e_grabbed, 1 ); + self.e_grabbed set_clientfield_alt_toplayer( "mechz_grab", self.e_grabbed, 1 ); } self.e_grabbed playerlinktodelta( self.m_claw, "tag_attach_player" ); self.e_grabbed setplayerangles( vectortoangles( self.origin - self.e_grabbed.origin ) ); @@ -315,7 +314,7 @@ claw_grapple() } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } flag_clear( "mechz_launching_claw" ); @@ -595,7 +594,7 @@ mechz_claw_cleanup() } else { - set_clientfield_alt_allplayers( "actor", "mechz_fx", self, self.fx_field ); + set_clientfield_alt_allplayers( "mechz_fx", self, self.fx_field ); } self mechz_claw_release(); diff --git a/zm_ai_pack/scripts/zm/clientfield_alt_sys.csc b/zm_ai_pack/scripts/zm/clientfield_alt_sys.csc index 2ea1039..78b49ec 100644 --- a/zm_ai_pack/scripts/zm/clientfield_alt_sys.csc +++ b/zm_ai_pack/scripts/zm/clientfield_alt_sys.csc @@ -1,20 +1,8 @@ execute_clientfield_alt_callback_internal( data, last_data, field_type, field_name ) { - entnum = data.entnum; - last_entnum = last_data.entnum; ent = undefined; field_data = level.clientfield_alts[ field_type ][ field_name ]; - switch ( field_type ) - { - case "actor": - assert( entnum >= 22 && entnum < 54, "Entnum " + entnum + " out of range for actor" ); - ent = getEntByNum( 0, entnum ); - break; - // case "toplayer": - // default: - // assertMsg( "Unhandled field type " + field_type ); - // break; - } + ent = getEntByNum( 0, entnum ); assert( isDefined( ent ) ); @@ -74,7 +62,7 @@ register_clientfield_alt( field_type, field_name, field_value_type, field_callba struct.callback = field_callback; level.clientfield_alts[ field_type ][ field_name ] = struct; - dvar_name = field_type + "." + field_name; + dvar_name = field_name; setDvar( dvar_name, "" ); level thread handle_clientfield_alt_callbacks( dvar_name, field_type, field_name ); diff --git a/zm_ai_pack/scripts/zm/clientfield_alt_sys.gsc b/zm_ai_pack/scripts/zm/clientfield_alt_sys.gsc index 3ad21cd..a079bc5 100644 --- a/zm_ai_pack/scripts/zm/clientfield_alt_sys.gsc +++ b/zm_ai_pack/scripts/zm/clientfield_alt_sys.gsc @@ -1,15 +1,15 @@ -set_clientfield_alt_toplayer( field_type, field_name, ent, value ) +set_clientfield_alt_toplayer( field_name, ent, value ) { entnum = ent getEntityNumber(); - self setClientDvar( field_type + "." + field_name, entnum + " " + value ); + self setClientDvar( field_name, entnum + " " + value ); } -set_clientfield_alt_allplayers( field_type, field_name, ent, value ) +set_clientfield_alt_allplayers(field_name, ent, value ) { foreach ( player in level.players ) { entnum = ent getEntityNumber(); - player setClientDvar( field_type + "." + field_name, entnum + " " + value ); + player setClientDvar( field_name, entnum + " " + value ); } } \ No newline at end of file diff --git a/zm_ai_pack/scripts/zm/zm_ai_pack_mod_debug_main.gsc b/zm_ai_pack/scripts/zm/zm_ai_pack_mod_debug_main.gsc index ebc7ab4..2de3513 100644 --- a/zm_ai_pack/scripts/zm/zm_ai_pack_mod_debug_main.gsc +++ b/zm_ai_pack/scripts/zm/zm_ai_pack_mod_debug_main.gsc @@ -164,7 +164,7 @@ location_hud() for ( i = 0; i < 3; i++ ) { loc_hud[ i ] = self new_debug_hud( x, y ); - x += 45; + x += 55; } loc_hud[ 0 ].label = &"x:"; @@ -240,6 +240,10 @@ draw_zombie_spawn_locations() { zone = level.zones[ zkeys[ z ] ]; + if ( getDvarInt( "zm_ai_pack_debug_show_only_active_spawns" ) && ( !zone.is_enabled || !zone.is_active || !zone.is_spawning_allowed ) ) + { + continue; + } draw_specific_zombie_spawn_locations( zone.spawn_locations, zkeys[ z ], ( 0.8, 0.8, 0.8 ), "zombie" ); draw_specific_zombie_spawn_locations( zone.inert_locations, zkeys[ z ], ( 0.8, 0, 0.8 ), "inert" ); 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 37b3d56..8b6db3b 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 @@ -13,12 +13,10 @@ main() { replaceFunc( maps\mp\_visionset_mgr::init, ::visionset_mgr_init_override ); replaceFunc( maps\mp\animscripts\traverse\zm_shared::dotraverse, ::dotraverse_override ); - perk_machine_knockdown_zombie_func = getFunction( "maps/mp/zm_nuked_perks", "perk_machine_knockdown_zombie" ); - if ( isDefined( perk_machine_knockdown_zombie_func ) ) - { - replaceFunc( perk_machine_knockdown_zombie_func, ::perk_machine_knockdown_zombie_override ); - } + replace_single_function( "maps/mp/zm_nuked_perks", "perk_machine_knockdown_zombie", ::perk_machine_knockdown_zombie_override ); + 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" ) ); @@ -263,4 +261,53 @@ get_idle_anim() } return idle_anim; +} + +replace_single_function( path, func_name, func_override ) +{ + func = getFunction( path, func_name ); + + if ( isDefined( func ) ) + { + replaceFunc( func, func_override ); + } +} + +can_be_paralyzed_override( zombie ) +{ + if ( is_true( zombie.immune_to_slowgun ) ) + { + return false; + } + + if ( is_true( zombie.is_ghost ) ) + { + return false; + } + + if ( is_true( zombie.guts_explosion ) ) + { + return false; + } + + if ( isdefined( zombie ) && zombie.health > 0 ) + { + return true; + } + + return false; +} + +watch_crash_trigger_override() +{ + while ( true ) + { + self waittill( "trigger", who ); + + if ( isDefined( who ) && isDefined( level.sloth ) && who == level.sloth && who.state == "berserk" ) + { + who setclientfield( "sloth_berserk", 0 ); + who sloth_set_state( "crash", 0 ); + } + } } \ 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 2ac8b85..3ea14e0 100644 --- a/zm_ai_pack/zone_source/mod.zone +++ b/zm_ai_pack/zone_source/mod.zone @@ -40,6 +40,8 @@ script,clientscripts/mp/zombies/_zm_ai_ghost.csc script,maps/mp/zombies/_zm_ai_brutus.gsc script,clientscripts/mp/zombies/_zm_ai_brutus.csc +script,maps/mp/zombies/_zm_ai_dogs.gsc + script,maps/mp/zombies/_zm_ai_mechz.gsc script,maps/mp/zombies/_zm_ai_mechz_ft.gsc script,maps/mp/zombies/_zm_ai_mechz_ffotd.gsc