1 #using scripts\codescripts\struct;
3 #using scripts\shared\laststand_shared;
4 #using scripts\shared\math_shared;
5 #using scripts\shared\util_shared;
7 #insert scripts\shared\shared.gsh;
9 #using scripts\shared\ai\systems\animation_state_machine_mocomp;
10 #using scripts\shared\ai\systems\animation_state_machine_notetracks;
11 #using scripts\shared\ai\systems\animation_state_machine_utility;
12 #using scripts\shared\ai\systems\behavior_tree_utility;
13 #using scripts\shared\ai\zombie_shared;
14 #using scripts\shared\ai\zombie_utility;
16 #using scripts\zm\_zm_laststand;
17 #using scripts\zm\_zm_spawner;
18 #using scripts\zm\_zm_utility;
20 #insert scripts\shared\ai\systems\animation_state_machine.gsh;
21 #insert scripts\shared\ai\systems\behavior.gsh;
22 #insert scripts\shared\ai\systems\behavior_tree.gsh;
24 #define DEFAULT_DIST_SQ_VISIBLE ( 1000 * 1000 )
25 #define FALLER_DIST_SQ_VISIBLE ( 1500 * 1500 )
27 #define ASM_FALLER_MELEE_NOTETRACK "faller_melee"
28 #define ASM_FALLER_DEATHOUT_NOTETRACK "deathout"
30 #namespace zm_ai_faller;
67 if( entity.origin[2] - ground_pos[2] < 20)
77 entity.faller_drop =
false;
84 if (
IS_TRUE( entity.faller_drop ) )
107 function private mocompFallerDrop( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
112 function private mocompCeilingDeath( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
122 level.zombie_total++;
124 if ( isdefined(
self.zombie_faller_location ) )
126 self.zombie_faller_location.is_enabled =
true;
127 self.zombie_faller_location = undefined;
134 if ( isdefined(
self.script_parameters ) )
136 parms = strtok(
self.script_parameters,
";" );
137 if ( isdefined( parms ) && parms.size > 0 )
139 for ( i = 0; i < parms.size; i++ )
141 if ( parms[i] ==
"drop_now" )
143 self.drop_now =
true;
146 if ( parms[i] ==
"drop_not_occupied" )
148 self.drop_not_occupied =
true;
151 if(parms[i] ==
"emerge_top" )
153 self.emerge_top =
true;
155 if(parms[i] ==
"emerge_bottom" )
157 self.emerge_bottom =
true;
166 self endon(
"death" );
168 while ( !
IS_TRUE(
self.zombie_init_done ) )
173 if(isDefined(func_name))
175 self.deathFunction = func_name;
177 else if(IsDefined(level.custom_faller_death))
179 self.deathFunction = level.custom_faller_death;
192 if ( !
IS_TRUE( level.faller_init ) )
194 level.faller_init =
true;
196 faller_anim =
self AnimMappingSearch( IString(
"anim_faller_emerge" ) );
197 level.faller_emerge_time = GetAnimLength( faller_anim );
199 faller_anim =
self AnimMappingSearch( IString(
"anim_faller_attack_01" ) );
200 level.faller_attack_01_time = GetAnimLength( faller_anim );
202 faller_anim =
self AnimMappingSearch( IString(
"anim_faller_attack_02" ) );
203 level.faller_attack_02_time = GetAnimLength( faller_anim );
205 faller_anim =
self AnimMappingSearch( IString(
"anim_faller_fall" ) );
206 level.faller_fall_time = GetAnimLength( faller_anim );
209 self.zombie_faller_location = spot;
212 self.zombie_faller_location.is_enabled =
false;
215 if(
IS_TRUE(
self.zombie_faller_location.emerge_bottom) ||
IS_TRUE(
self.zombie_faller_location.emerge_top ) )
223 self.no_powerups =
true;
224 self.in_the_ceiling =
true;
226 self.anchor =
spawn(
"script_origin",
self.origin);
227 self.anchor.angles =
self.angles;
228 self linkto(
self.anchor);
230 if( !isdefined( spot.angles ) )
232 spot.angles = (0, 0, 0);
235 anim_org = spot.origin;
236 anim_ang = spot.angles;
239 self.anchor moveto(anim_org, .05);
240 self.anchor waittill(
"movedone");
244 if (isdefined(target_org))
246 anim_ang = VectorToAngles(target_org -
self.origin);
247 self.anchor RotateTo((0, anim_ang[1], 0), .05);
248 self.anchor waittill(
"rotatedone");
252 if(isdefined(
self.anchor))
254 self.anchor
delete();
265 self.no_powerups =
false;
266 self notify(
"risen", spot.script_string );
274 self AnimScripted(
"fall_anim",
self.origin,
self.zombie_faller_location.angles,
"ai_zm_dlc5_zombie_ceiling_emerge_01" );
275 wait( level.faller_emerge_time );
278 self.zombie_faller_wait_start = GetTime();
279 self.zombie_faller_should_drop =
false;
282 while ( !
self.zombie_faller_should_drop )
288 self AnimScripted(
"fall_anim",
self.origin,
self.zombie_faller_location.angles,
"ai_zm_dlc5_zombie_ceiling_attack_01" );
289 wait( level.faller_attack_01_time );
293 self AnimScripted(
"fall_anim",
self.origin,
self.zombie_faller_location.angles,
"ai_zm_dlc5_zombie_ceiling_attack_02" );
294 wait( level.faller_attack_02_time );
301 self.zombie_faller_should_drop =
true;
309 self.zombie_faller_should_drop =
true;
313 else if ( GetTime() >=
self.zombie_faller_wait_start + 20000 )
317 self.zombie_faller_should_drop =
true;
322 self.zombie_faller_should_drop =
true;
330 self AnimScripted(
"fall_anim",
self.origin,
self.zombie_faller_location.angles,
"ai_zm_dlc5_zombie_ceiling_attack_01" );
331 wait( level.faller_attack_01_time );
335 self AnimScripted(
"fall_anim",
self.origin,
self.zombie_faller_location.angles,
"ai_zm_dlc5_zombie_ceiling_attack_02" );
336 wait( level.faller_attack_02_time );
342 self notify(
"falling");
344 spot =
self.zombie_faller_location;
347 self AnimScripted(
"fall_anim",
self.origin, spot.angles,
"ai_zm_dlc5_zombie_ceiling_dropdown_01" );
348 wait( level.faller_fall_time );
352 self.normal_death =
true;
354 self notify(
"fall_anim_finished");
355 spot notify(
"stop_zombie_fall_fx");
358 self StopAnimScripted();
364 physDist =
self.origin[2] - ground_pos[2] + landAnimDelta;
368 self.faller_drop =
true;
376 self waittill(
"zombie_land_done" );
379 self.in_the_ceiling =
false;
380 self traverseMode(
"gravity" );
382 self.no_powerups =
false;
389 self SetAnimStateFromASD(
"zm_faller_fall_loop" );
394 if(
self.origin[2] - ground_pos[2] < 20)
396 self notify(
"faller_on_ground");
405 self SetAnimStateFromASD(
"zm_faller_land" );
408 self notify(
"zombie_land_done" );
414 if (
IS_TRUE(
self.zombie_faller_location.drop_now ) )
423 if (
IS_TRUE(
self.zombie_faller_location.drop_not_occupied) )
425 if( isdefined(
self.zone_name) && isdefined(level.zones[
self.zone_name ]) )
427 return !level.zones[
self.zone_name ].is_occupied;
436 players = GetPlayers();
437 for(i=0; i<players.size; i++)
445 self endon(
"falling");
447 player endon(
"disconnect");
451 rangeSqr = range*range;
460 closeRangeSqr = closeRange*closeRange;
461 dirToPlayerEnter = (0,0,0);
462 inCloseRange =
false;
467 distSqr = distance2dsquared(
self.origin, player.origin);
468 if(distSqr < rangeSqr)
472 if(inRangeTime+
timer < GetTime())
474 self.zombie_faller_should_drop =
true;
481 inRangeTime = GetTime();
490 if(distSqr<closeRangeSqr)
495 dirToPlayerEnter = player.origin -
self.origin;
496 dirToPlayerEnter = (dirToPlayerEnter[0], dirToPlayerEnter[1], 0.0);
497 dirToPlayerEnter = vectornormalize(dirToPlayerEnter);
507 dirToPlayerExit = player.origin -
self.origin;
508 dirToPlayerExit = (dirToPlayerExit[0], dirToPlayerExit[1], 0.0);
509 dirToPlayerExit = vectornormalize(dirToPlayerExit);
511 if(vectordot(dirToPlayerEnter, dirToPlayerExit) < 0)
513 self.zombie_faller_should_drop =
true;
518 inCloseRange =
false;
527 self endon(
"falling");
530 if ( isdefined(
self.zone_name ) )
532 if ( isdefined(level.zones) && isdefined(level.zones[
self.zone_name ] ) )
534 zone = level.zones[
self.zone_name ];
539 if ( (!zone.is_enabled ||!zone.is_active) )
543 if (
self.health != level.zombie_health )
547 self.zombie_faller_should_drop =
true;
567 return victims.size > 0;
573 players = GetPlayers();
576 checkDist2 *= checkDist2;
577 for ( i = 0; i < players.size; i++ )
587 stance = player GetStance();
588 if ( stance ==
"crouch" || stance ==
"prone" )
594 zCheck =
self.origin[2] - player.origin[2];
595 if ( zCheck < 0.0 || zCheck > 120.0 )
600 dist2 = Distance2DSquared(player.origin,
self.origin);
601 if ( dist2 < checkDist2 )
603 ret[ret.size] = player;
612 return level._zombie_fall_anims[
self.animname][
"fall"];
617 if ( isdefined(
self.zombie_faller_location ) )
619 self.zombie_faller_location.is_enabled =
true;
620 self.zombie_faller_location = undefined;
627 self endon(
"falling" );
628 if(isDefined(endon_notify))
630 self endon(endon_notify);
632 self waittill(
"death" );
640 self animmode(
"noclip" );
641 self.deathanim =
"zm_faller_emerge_death";
654 self endon(
"fall_anim_finished");
656 while (
self.health > 1)
658 self waittill(
"damage", amount, attacker, dir, p, type);
661 self StopAnimScripted();
662 spot notify(
"stop_zombie_fall_fx");
667 toks = strtok(type,
"_");
676 for(i=2;i<toks.size;i++)
678 returnStr += toks[i];
681 returnStr = tolower(returnStr);
693 playsoundatposition (
"zmb_zombie_spawn", spot.origin);
695 spot endon(
"stop_zombie_fall_fx");
697 if (
self.zombie_move_speed !=
"sprint")
706 self endon(
"stop_zombie_fall_fx");
707 self endon(
"fall_anim_finished");
709 playfx(level._effect[
"rise_burst"],
self.origin + ( 0,0,randomintrange(5,10) ) );
711 playfx(level._effect[
"rise_billow"],
self.origin + ( randomintrange(-10,10),randomintrange(-10,10),randomintrange(5,10) ) );
716 dust_tag =
"J_SpineUpper";
718 self endon(
"stop_zombie_fall_dust_fx");
724 for (t = 0; t < dust_time; t += dust_interval)
726 PlayfxOnTag(level._effect[
"rise_dust"], zombie, dust_tag);
733 zombie waittill(
"death");
734 self notify(
"stop_zombie_fall_dust_fx");
742 self.in_the_ceiling =
false;
759 for ( i = 0; i < victims.size; i++ )
761 victims[i] DoDamage( entity.meleeDamage, entity.origin,
self,
self,
"none",
"MOD_MELEE" );
763 entity.zombie_faller_should_drop =
true;
770 self launchragdoll((0, 0, -1));
778 playerAngles = player getplayerangles();
779 playerForwardVec = AnglesToForward( playerAngles );
780 playerUnitForwardVec = VectorNormalize( playerForwardVec );
782 banzaiPos =
self.origin;
783 playerPos = player GetOrigin();
784 playerToBanzaiVec = banzaiPos - playerPos;
785 playerToBanzaiUnitVec = VectorNormalize( playerToBanzaiVec );
787 forwardDotBanzai = VectorDot( playerUnitForwardVec, playerToBanzaiUnitVec );
788 angleFromCenter = ACos( forwardDotBanzai );
790 playerFOV = GetDvarFloat(
"cg_fov" );
791 banzaiVsPlayerFOVBuffer = GetDvarFloat(
"g_banzai_player_fov_buffer" );
792 if ( banzaiVsPlayerFOVBuffer <= 0 )
794 banzaiVsPlayerFOVBuffer = 0.2;
797 inPlayerFov = ( angleFromCenter <= ( playerFOV * 0.5 * ( 1 - banzaiVsPlayerFOVBuffer ) ) );
809 if ( !isdefined( how_close ) )
813 potentiallyVisible =
false;
815 players = getplayers();
816 for ( i = 0; i < players.size; i++ )
818 dist = DistanceSquared(
self.origin, players[i].origin);
824 potentiallyVisible =
true;
831 return potentiallyVisible;
841 self.no_powerups =
true;
842 self.in_the_ceiling =
true;
844 anim_org = spot.origin;
845 anim_ang = spot.angles;
849 if(isDefined(level.custom_faller_entrance_logic))
851 self thread [[level.custom_faller_entrance_logic]]();
855 self.create_eyes = 1;
857 self notify(
"risen", spot.script_string );
866 if (
IS_TRUE(
self.zombie_faller_location.emerge_bottom))
868 self AnimScripted(
"fall_anim",
self.zombie_faller_location.origin,
self.zombie_faller_location.angles,
"zombie_riser_elevator_from_floor");
872 self AnimScripted(
"fall_anim",
self.zombie_faller_location.origin,
self.zombie_faller_location.angles,
"zombie_riser_elevator_from_ceiling" );
880 self.in_the_ceiling =
false;
881 self.no_powerups =
false;
889 playsoundatposition (
"zmb_zombie_spawn", spot.origin);
891 spot endon(
"stop_zombie_fall_fx");
899 dust_tag =
"J_SpineUpper";
901 self endon(
"stop_zombie_fall_dust_fx");
907 for (t = 0; t < dust_time; t += dust_interval)
909 PlayfxOnTag(level._effect[
"rise_dust"], zombie, dust_tag);
916 zombie waittill(
"death");
917 self notify(
"stop_zombie_fall_dust_fx");