1 #using scripts\codescripts\struct;
3 #using scripts\shared\aat_shared;
4 #using scripts\shared\array_shared;
5 #using scripts\shared\flag_shared;
6 #using scripts\shared\spawner_shared;
7 #using scripts\shared\system_shared;
8 #using scripts\shared\trigger_shared;
9 #using scripts\shared\util_shared;
10 #using scripts\shared\vehicle_shared;
11 #using scripts\shared\vehicle_ai_shared;
12 #using scripts\shared\vehicles\_raps;
13 #using scripts\shared\clientfield_shared;
14 #using scripts\shared\visionset_mgr_shared;
16 #insert scripts\shared\shared.gsh;
17 #insert scripts\shared\weapons\grapple.gsh;
19 #using scripts\zm\_util;
20 #using scripts\zm\_zm;
21 #using scripts\zm\_zm_audio;
22 #using scripts\zm\_zm_net;
23 #using scripts\zm\_zm_powerups;
24 #using scripts\zm\_zm_score;
25 #using scripts\zm\_zm_spawner;
26 #using scripts\zm\_zm_stats;
27 #using scripts\zm\_zm_utility;
29 #using scripts\shared\ai\zombie_utility;
31 #insert scripts\shared\aat_zm.gsh;
32 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
33 #insert scripts\zm\_zm_utility.gsh;
34 #insert scripts\shared\version.gsh;
35 #insert scripts\zm\_zm_ai_raps.gsh;
37 #precache( "fx", "zombie/fx_meatball_trail_sky_zod_zmb" );
38 #precache( "fx", "zombie/fx_meatball_impact_ground_tell_zod_zmb" );
39 #precache( "fx", "zombie/fx_meatball_portal_sky_zod_zmb" );
41 #precache( "fx", "zombie/fx_meatball_impact_ground_zod_zmb" );
42 #precache( "fx", "zombie/fx_meatball_trail_ground_zod_zmb" );
43 #precache( "fx", "zombie/fx_meatball_explo_zod_zmb" );
46 #define N_NUM_RAPS_PER_ROUND_1PLAYER 10 // 10
47 #define N_NUM_RAPS_PER_ROUND_2PLAYER 18 // 18
48 #define N_NUM_RAPS_PER_ROUND_3PLAYER 28 // 34
49 #define N_NUM_RAPS_PER_ROUND_4PLAYER 34 // 44
51 #define N_RAPS_HEALTH_INCREASE 50 // Amount to increase RAPS health
52 #define N_RAPS_HEALTH_MAX 1600 // Maximum health
53 #define N_RAPS_KILL_POINTS 70 // Points per kill
55 #define N_RAPS_DROP_HEIGHT_MAX 720 // Maximum height to fall from
56 #define N_RAPS_DROP_SPEED 720 // Fall speed Units/sec
58 #define N_RAPS_SPAWN_DELAY_1P 2.25 // Delay between spawns 1st round
59 #define N_RAPS_SPAWN_DELAY_2P 1.75 // Delay between spawns 2nd round
60 #define N_RAPS_SPAWN_DELAY_3P 1.25 // Delay between spawns 3rd round
61 #define N_RAPS_SPAWN_DELAY_4P 0.75 // Delay between spawns thereafter
64 #namespace zm_ai_raps;
72 level.raps_enabled =
true;
73 level.raps_rounds_enabled =
false;
74 level.raps_round_count = 1;
76 level.raps_spawners = [];
81 level.melee_range_sav = GetDvarString(
"ai_meleeRange" );
82 level.melee_width_sav = GetDvarString(
"ai_meleeWidth" );
83 level.melee_height_sav = GetDvarString(
"ai_meleeHeight" );
92 level._effect[
"raps_meteor_fire" ] =
"zombie/fx_meatball_trail_sky_zod_zmb";
93 level._effect[
"raps_ground_spawn" ] =
"zombie/fx_meatball_impact_ground_tell_zod_zmb";
94 level._effect[
"raps_portal" ] =
"zombie/fx_meatball_portal_sky_zod_zmb";
95 level._effect[
"raps_gib" ] =
"zombie/fx_meatball_explo_zod_zmb";
96 level._effect[
"raps_trail_blood" ] =
"zombie/fx_meatball_trail_ground_zod_zmb";
97 level._effect[
"raps_impact" ] =
"zombie/fx_meatball_impact_ground_zod_zmb";
119 level.raps_rounds_enabled =
true;
121 if( !isdefined( level.raps_round_track_override ) )
126 level thread [[level.raps_round_track_override]]();
136 level.raps_spawners = getEntArray(
"zombie_raps_spawner",
"script_noteworthy" );
137 later_raps = getentarray(
"later_round_raps_spawners",
"script_noteworthy" );
138 level.raps_spawners = ArrayCombine( level.raps_spawners, later_raps,
true,
false );
140 if( level.raps_spawners.size == 0 )
145 for( i = 0; i < level.raps_spawners.size; i++ )
149 level.raps_spawners[i].is_enabled =
false;
153 level.raps_spawners[i].is_enabled =
true;
154 level.raps_spawners[i].script_forcespawn =
true;
158 assert( level.raps_spawners.size > 0 );
159 level.n_raps_health = 100;
161 vehicle::add_main_callback(
"spawner_enemy_zombie_vehicle_raps_suicide", &
raps_init );
171 level.raps_round_count = 1;
175 level.n_next_raps_round = RandomIntRange( 9, 11 );
178 old_spawn_func = level.round_spawn_func;
179 old_wait_func = level.round_wait_func;
183 level waittill (
"between_round_over" );
186 if( GetDvarInt(
"force_raps" ) > 0 )
188 level.n_next_raps_round= level.round_number;
192 if( level.round_number == level.n_next_raps_round )
194 level.sndMusicSpecialRound =
true;
195 old_spawn_func = level.round_spawn_func;
196 old_wait_func = level.round_wait_func;
204 if( isdefined(level.zm_custom_get_next_raps_round) )
206 level.n_next_raps_round = [[level.zm_custom_get_next_raps_round]]();
211 level.n_next_raps_round = 10 + (level.raps_round_count * 10) + RandomIntRange( -1, 1 );
215 GetPlayers()[0] iprintln(
"Next raps round: " + level.n_next_raps_round);
221 level.round_spawn_func = old_spawn_func;
222 level.round_wait_func = old_wait_func;
223 level.raps_round_count++;
237 if(!isdefined (level.rapsround_nomusic))
239 level.rapsround_nomusic = 0;
241 level.rapsround_nomusic = 1;
242 level notify(
"raps_round_starting" );
245 if(isdefined(level.raps_melee_range))
247 SetDvar(
"ai_meleeRange", level.raps_melee_range );
251 SetDvar(
"ai_meleeRange", 100 );
265 if(!isdefined (level.rapsround_nomusic))
267 level.rapsround_nomusic = 0;
269 level.rapsround_nomusic = 0;
270 level notify(
"raps_round_ending" );
272 SetDvar(
"ai_meleeRange", level.melee_range_sav );
273 SetDvar(
"ai_meleeWidth", level.melee_width_sav );
274 SetDvar(
"ai_meleeHeight", level.melee_height_sav );
283 level endon(
"intermission" );
284 level endon(
"raps_round" );
286 level.raps_targets = GetPlayers();
287 for( i = 0 ; i < level.raps_targets.size; i++ )
289 level.raps_targets[i].hunted_by = 0;
292 level endon(
"restart_round" );
293 level endon(
"kill_round" );
296 if ( GetDvarInt(
"zombie_cheat" ) == 2 || GetDvarInt(
"zombie_cheat" ) >= 4 )
302 if( level.intermission )
315 level.zombie_total = Int( n_wave_count );
318 if( GetDvarString(
"force_raps" ) !=
"" && GetDvarInt(
"force_raps" ) > 0 )
320 level.zombie_total = GetDvarInt(
"force_raps" );
321 SetDvar(
"force_raps", 0 );
329 PlaySoundAtPosition(
"vox_zmba_event_rapsstart_0", ( 0, 0, 0 ) );
338 level endon(
"last_ai_down" );
344 while( level.zombie_total > 0 )
346 if(
IS_TRUE( level.bzm_worldPaused ) )
352 if( isdefined(level.zm_mixed_wasp_raps_spawning) )
354 [[level.zm_mixed_wasp_raps_spawning]]();
378 s_spawn_loc = undefined;
382 if( !IsDefined( favorite_enemy ) )
388 if ( isdefined( level.raps_spawn_func ) )
390 s_spawn_loc = [[level.raps_spawn_func]]( favorite_enemy );
398 if ( !isdefined( s_spawn_loc ) )
405 if( isdefined( ai ) )
407 ai.favoriteenemy = favorite_enemy;
408 ai.favoriteenemy.hunted_by++;
410 level.zombie_total--;
422 switch( level.players.size )
442 return( n_wave_count );
451 level endon(
"restart_round" );
452 level endon(
"kill_round" );
461 level.sndMusicSpecialRound =
false;
471 raps = GetEntArray(
"zombie_raps",
"targetname" );
472 num_alive_raps = raps.size;
473 foreach( rapsAI
in raps )
475 if( !IsAlive( rapsAI ) )
480 return num_alive_raps;
489 foreach ( player
in level.players )
502 if ( isdefined(
self ) && isdefined(
self.hud_damagefeedback ) )
504 self.hud_damagefeedback SetShader(
"damage_feedback", 24, 48 );
505 self.hud_damagefeedback.alpha = 1;
506 self.hud_damagefeedback FadeOverTime(1);
507 self.hud_damagefeedback.alpha = 0;
515 function rapsDamage( inflictor, attacker,
damage, dFlags, mod, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex )
517 if( isdefined(attacker) )
536 if( b_raps_count_at_max || b_raps_count_per_player_at_max || !( level
flag::get(
"spawn_zombies" ) ) )
549 switch( level.players.size )
565 wait( n_default_wait );
574 level waittill(
"last_ai_down", e_enemy_ai );
578 if( isdefined(level.zm_override_ai_aftermath_powerup_drop) )
580 [[level.zm_override_ai_aftermath_powerup_drop]]( e_enemy_ai, level.last_ai_origin );
584 power_up_origin = level.last_ai_origin;
585 trace = GroundTrace(power_up_origin + (0, 0, 100), power_up_origin + (0, 0, -1000),
false, undefined);
586 power_up_origin =
trace[
"position"];
588 if( isdefined( power_up_origin ) )
595 level.sndMusicSpecialRound =
false;
611 if ( !isdefined(ent) )
620 raps_impact_location =
trace[
"position" ];
623 angle = VectorToAngles( ai.favoriteenemy.origin - ent.origin );
624 angles = ( ai.angles[0], angle[1], ai.angles[2] );
626 ai.origin = raps_impact_location;
633 if ( !bullettracepassed( ent.origin, pos,
false, ai) )
635 trace = bullettrace( ent.origin, pos,
false, ai );
638 portal_fx_location =
spawn(
"script_model" , pos );
639 portal_fx_location SetModel(
"tag_origin" );
640 playfxontag( level._effect[
"raps_portal"], portal_fx_location,
"tag_origin" );
642 ground_tell_location =
spawn(
"script_model" , raps_impact_location );
643 ground_tell_location SetModel(
"tag_origin" );
644 playfxontag( level._effect[
"raps_ground_spawn"], ground_tell_location,
"tag_origin" );
645 ground_tell_location playsound(
"zmb_meatball_spawn_tell" );
646 playsoundatposition(
"zmb_meatball_spawn_rise", pos );
652 raps_meteor =
spawn(
"script_model", pos);
654 raps_meteor SetModel( model );
655 raps_meteor.angles = angles;
656 raps_meteor playloopsound(
"zmb_meatball_spawn_loop", .25 );
659 playfxontag( level._effect[
"raps_meteor_fire" ], raps_meteor,
"tag_origin" );
661 fall_dist = sqrt( DistanceSquared( pos, raps_impact_location ));
664 raps_meteor MoveTo(raps_impact_location, fall_time);
670 raps_meteor
delete();
672 if( isdefined (portal_fx_location ))
674 portal_fx_location
delete();
677 if ( isdefined( ground_tell_location ) )
679 ground_tell_location
delete();
686 ai.origin = raps_impact_location;
689 Playfx( level._effect[
"raps_impact" ], raps_impact_location );
690 playsoundatposition(
"zmb_meatball_spawn_impact", raps_impact_location );
692 Earthquake( 0.3, 0.75, raps_impact_location, 512);
694 assert( isdefined( ai ),
"Ent isn't defined." );
695 assert( IsAlive( ai ),
"Ent is dead." );
700 ai SetVisibleToAll();
702 ai notify(
"visible" );
707 self endon(
"death" );
709 self.ai waittill(
"death" );
716 self waittill(
"death" );
718 if ( isdefined( portal_fx ) )
723 if ( isdefined( ground_tell ) )
725 ground_tell
delete();
734 if( !isdefined(level.enemy_raps_global_locations) )
736 level.enemy_raps_global_locations = [];
737 keys = GetArrayKeys( level.zones );
738 for( i=0; i<keys.size; i++ )
740 zone = level.zones[keys[i]];
743 foreach( loc
in zone.a_locs[
"raps_location" ] )
745 ARRAY_ADD( level.enemy_raps_global_locations, loc );
758 closest_distance_squared = DistanceSquared( level.enemy_raps_global_locations[index_to_use].origin, favorite_enemy.origin );
759 for( i = 0; i < level.enemy_raps_global_locations.size; i++ )
761 if( level.enemy_raps_global_locations[i].is_enabled )
763 dist_squared = DistanceSquared( level.enemy_raps_global_locations[i].origin, favorite_enemy.origin );
764 if( dist_squared<closest_distance_squared )
767 closest_distance_squared = dist_squared;
771 return level.enemy_raps_global_locations[index_to_use];
781 position = favorite_enemy.last_valid_position;
782 if( !IsDefined( position ) )
784 position = favorite_enemy.origin;
788 if( level.players.size == 1 )
790 N_RAPS_SPAWN_DIST_MIN = 450;
791 N_RAPS_SPAWN_DIST_MAX = 900;
793 else if( level.players.size == 2 )
795 N_RAPS_SPAWN_DIST_MIN = 450;
796 N_RAPS_SPAWN_DIST_MAX = 850;
801 else if( level.players.size == 3 )
803 N_RAPS_SPAWN_DIST_MIN = 700;
804 N_RAPS_SPAWN_DIST_MAX = 1000;
808 N_RAPS_SPAWN_DIST_MIN = 800;
809 N_RAPS_SPAWN_DIST_MAX = 1200;
813 query_result = PositionQuery_Source_Navigation(
815 N_RAPS_SPAWN_DIST_MIN,
816 N_RAPS_SPAWN_DIST_MAX,
822 if ( query_result.data.size )
824 a_s_locs = array::randomize( query_result.data );
826 if ( isdefined( a_s_locs ) )
828 foreach( s_loc
in a_s_locs )
832 s_loc.origin += (0,0,16);
848 raps_targets = GetPlayers();
849 e_least_hunted = undefined;
851 for( i=0; i<raps_targets.size; i++ )
868 if( IsDefined( level.is_player_accessible_to_raps ) && ![[level.is_player_accessible_to_raps]](
e_target ) )
874 if( !isdefined(e_least_hunted) )
878 else if(
e_target.hunted_by < e_least_hunted.hunted_by )
884 return e_least_hunted;
893 players = GetPlayers();
909 self playlocalsound(
"zmb_raps_round_start" );
914 players = GetPlayers();
915 num = RandomIntRange(0,players.size);
929 self.targetname =
"zombie_raps";
930 self.script_noteworthy = undefined;
931 self.animname =
"zombie_raps";
932 self.ignoreme =
true;
933 self.allowdeath =
true;
934 self.allowpain =
false;
936 self.is_zombie =
true;
939 self.head_gibbed =
false;
940 self.default_goalheight = 40;
941 self.ignore_inert =
true;
942 self.no_eye_glow =
true;
944 self.lightning_chain_immune =
true;
946 self.holdfire =
true;
950 self.grenadeawareness = 0;
951 self.badplaceawareness = 0;
953 self.ignoreSuppression =
true;
954 self.suppressionThreshold = 1;
955 self.noDodgeMove =
true;
956 self.dontShootWhileMoving =
true;
957 self.pathenemylookahead = 0;
958 self.test_failed_path =
true;
960 self.badplaceawareness = 0;
961 self.chatInitialized =
false;
962 self.missingLegs =
false;
964 self.teslafxtag =
"tag_origin";
969 self SetGrapplableType(
self.grapple_type );
971 self.team = level.zombie_team;
974 health_multiplier = 1.0;
975 if ( GetDvarString(
"scr_raps_health_walk_multiplier" ) !=
"" )
977 health_multiplier = GetDvarFloat(
"scr_raps_health_walk_multiplier" );
980 self.maxhealth = int( level.n_raps_health * health_multiplier );
981 if( isdefined(level.a_zombie_respawn_health[
self.archetype ] ) && level.a_zombie_respawn_health[
self.archetype ].size > 0 )
983 self.health = level.a_zombie_respawn_health[
self.archetype ][0];
984 ArrayRemoveValue(level.a_zombie_respawn_health[
self.archetype ], level.a_zombie_respawn_health[
self.archetype ][0]);
988 self.health = int( level.n_raps_health * health_multiplier );
993 self SetInvisibleToAll();
1003 if ( isdefined(level.achievement_monitor_func) )
1005 self [[level.achievement_monitor_func]]();
1015 self endon(
"death" );
1017 self DoDamage(
self.health + 100,
self.origin,
self, undefined,
"none",
"MOD_UNKNOWN" );
1026 self waittill(
"death", attacker );
1031 if( ( !isdefined(level.zm_ai_round_over) || [[level.zm_ai_round_over]]() ) )
1033 level.last_ai_origin =
self.origin;
1034 level notify(
"last_ai_down",
self );
1039 if( IsPlayer( attacker ) )
1042 if( !
IS_TRUE(
self.deathpoints_already_given ) )
1048 if( isdefined(level.hero_power_update))
1050 [[level.hero_power_update]](attacker,
self);
1054 if( RandomIntRange(0,100) >= 80 )
1066 if( isdefined( attacker ) && isai( attacker ) )
1068 attacker notify(
"killed",
self );
1071 if ( isdefined(
self ) )
1074 self stoploopsound();
1086 if( mod ==
"MOD_EXPLOSIVE" )
1096 #define N_RAPS_SHELLSHOCK_HIT_LIMIT 4
1100 self endon(
"death");
1101 DEFAULT(
self.raps_recent_explosions, 0);
1102 self.raps_recent_explosions++;
1105 self ShellShock(
"explosion_elementals", 2.0 );
1108 self.raps_recent_explosions--;
1117 PlayFX( level._effect[
"raps_gib"], origin );
1130 self.ignoreall =
false;
1133 self.meleeAttackDist = 64;
1136 self.disableArrivals =
true;
1137 self.disableExits =
true;
1148 self waittill(
"death");
1159 raps = GetEntArray(
"zombie_raps",
"targetname" );
1161 if ( isdefined( raps ) && raps.size >= 9 )
1167 while ( count < n_to_spawn )
1170 players = GetPlayers();
1173 if( !IsDefined( favorite_enemy ) )
1179 if ( isdefined( level.raps_spawn_func ) )
1181 s_spawn_loc = [[level.raps_spawn_func]]( favorite_enemy );
1189 if ( !isdefined( s_spawn_loc ) )
1196 if( isdefined( ai ) )
1198 ai.favoriteenemy = favorite_enemy;
1199 ai.favoriteenemy.hunted_by++;
1203 if ( isdefined( fn_on_spawned ) )
1205 ai thread [[fn_on_spawned]]();
1221 self endon(
"death" );
1223 self waittill(
"visible" );
1226 if (
self.health > level.n_raps_health )
1228 self.maxhealth = level.n_raps_health;
1229 self.health = level.n_raps_health;
1239 if( IsDefined( potential_target ) )
1241 self.favoriteenemy = potential_target;
1242 self.favoriteenemy.hunted_by++;
1243 self.raps_force_patrol_behavior = undefined;
1247 self.raps_force_patrol_behavior =
true;
1260 if( IsDefined( level.raps_can_reach_inaccessible_location ) &&
self [[level.raps_can_reach_inaccessible_location]]() )
1264 if( IsDefined( level.is_player_accessible_to_raps ) && ![[level.is_player_accessible_to_raps]]( player ) )
1277 self endon(
"death" );
1281 self playsound(
"zmb_hellhound_vocals_amb" );
1282 wait randomfloatrange(3,6);
1292 self endon(
"death" );
1294 damage = int(
self.maxhealth * 0.5 );
1295 self DoDamage(
damage, player.origin, player, undefined,
"none",
"MOD_UNKNOWN" );