#include maps\_utility; #include common_scripts\utility; #include maps\_zombiemode_utility; #using_animtree("generic_human"); faller_init() { level._zombie_fall_anims["zombie"] = []; level._zombie_fall_anims["zombie"]["default"] = %ai_zombie_jump_down_72; level._zombie_fall_anims["zombie"]["emerge"] = %ai_zombie_ceiling_emerge_01; level._zombie_fall_anims["zombie"]["fall"] = %ai_zombie_ceiling_dropdown_01; level._zombie_fall_anims["zombie"]["fall_loop"] = %ai_zombie_ceiling_fall_loop; level._zombie_fall_anims["zombie"]["land"][0] = %ai_zombie_ceiling_fall_land; level._zombie_fall_anims["zombie"]["land"][1] = %ai_zombie_ceiling_fall_land_02; level._zombie_fall_anims["zombie"]["attack"][0] = %ai_zombie_ceiling_attack_01; level._zombie_fall_anims["zombie"]["attack"][1] = %ai_zombie_ceiling_attack_02; level._zombie_fall_anims["zombie"]["emerge_death"] = %ai_zombie_ceiling_death; level.zombie_custom_think_logic = ::check_do_zombie_fall; level thread setup_faller_locations(); } setup_faller_locations() { flag_wait("zones_initialized"); zkeys = GetArrayKeys(level.zones); for ( i = 0; i < level.zones.size; i++ ) { zone = level.zones[ zkeys[i] ]; if ( IsDefined( zone.volumes[0].target ) ) { zone.fall_locations = GetStructArray(zone.volumes[0].target + "_fall", "targetname"); for ( x = 0; x < zone.fall_locations.size; x++ ) { zone.fall_locations[x].is_enabled = true; } } } } get_available_fall_locations() { level.zombie_fall_spawners = []; zone = level.zones[ self.zone_name ]; if ( IsDefined( zone ) ) { for(x=0; x 0 ) { for ( i = 0; i < parms.size; i++ ) { if ( parms[i] == "drop_now" ) { self.drop_now = true; } if ( parms[i] == "drop_not_occupied" ) { self.drop_not_occupied = true; } } } } } setup_deathfunc() { self endon( "death" ); while ( !is_true( self.zombie_init_done ) ) { wait_network_frame(); } self.deathFunction = ::zombie_fall_death_func; } do_zombie_fall() { self endon("death"); self thread setup_deathfunc(); self.no_powerups = true; self.in_the_ceiling = true; self.anchor = spawn("script_origin", self.origin); self.anchor.angles = self.angles; self linkto(self.anchor); if ( !IsDefined( self.zone_name ) ) { self.zone_name = self get_current_zone(); } spots = get_available_fall_locations(); if( spots.size < 1 ) { self unlink(); self.anchor delete(); self Hide(); self delayThread( 0.1, ::zombie_faller_delete ); return; } else if ( GetDvarInt(#"zombie_fall_test") ) { player = GetPlayers()[0]; spot = undefined; bestDist = 0.0; for ( i = 0; i < spots.size; i++ ) { checkDist = DistanceSquared(spots[i].origin, player.origin); if ( !IsDefined(spot) || checkDist < bestDist ) { spot = spots[i]; bestDist = checkDist; } } } else { spot = random(spots); } self.zombie_faller_location = spot; self.zombie_faller_location.is_enabled = false; self.zombie_faller_location parse_script_parameters(); if( !isDefined( spot.angles ) ) { spot.angles = (0, 0, 0); } anim_org = spot.origin; anim_ang = spot.angles; self Hide(); self.anchor moveto(anim_org, .05); self.anchor waittill("movedone"); target_org = maps\_zombiemode_spawner::get_desired_origin(); if (IsDefined(target_org)) { anim_ang = VectorToAngles(target_org - self.origin); self.anchor RotateTo((0, anim_ang[1], 0), .05); self.anchor waittill("rotatedone"); } self unlink(); self.anchor delete(); self thread hide_pop(); level thread zombie_fall_death(self, spot); spot thread zombie_fall_fx(self); self thread zombie_faller_death_wait(); self thread zombie_faller_do_fall(); } zombie_faller_do_fall() { self endon("death"); emerge_anim = self get_fall_emerge_anim(); self AnimScripted("fall_emerge", self.origin, self.zombie_faller_location.angles, emerge_anim); self animscripts\zombie_shared::DoNoteTracks("fall_emerge", ::handle_fall_notetracks, undefined, self.zombie_faller_location); self.zombie_faller_wait_start = GetTime(); self.zombie_faller_should_drop = false; self thread zombie_fall_wait(); self thread zombie_faller_watch_all_players(); while ( !self.zombie_faller_should_drop ) { if ( self zombie_fall_should_attack(self.zombie_faller_location) ) { attack_anim = self get_attack_anim(self.zombie_faller_location); self AnimScripted("attack", self.origin, self.zombie_faller_location.angles, attack_anim); self animscripts\zombie_shared::DoNoteTracks("attack", ::handle_fall_notetracks, undefined, self.zombie_faller_location); if ( !(self zombie_faller_always_drop()) && randomfloat(1) > 0.5 ) { self.zombie_faller_should_drop = true; } } else { if ( (self zombie_faller_always_drop()) ) { self.zombie_faller_should_drop = true; break; } else if ( GetTime() >= self.zombie_faller_wait_start + 20000 ) { self.zombie_faller_should_drop = true; break; } else if ( self zombie_faller_drop_not_occupied() ) { self.zombie_faller_should_drop = true; break; } else { attack_anim = self get_attack_anim(self.zombie_faller_location); self AnimScripted("attack", self.origin, self.zombie_faller_location.angles, attack_anim); self animscripts\zombie_shared::DoNoteTracks("attack", ::handle_fall_notetracks, undefined, self.zombie_faller_location); } } } self notify("falling"); spot = self.zombie_faller_location; self zombie_faller_enable_location(); fall_anim = self get_fall_anim(spot); self AnimScripted("fall", self.origin, spot.angles, fall_anim); self animscripts\zombie_shared::DoNoteTracks("fall", ::handle_fall_notetracks, undefined, spot); self.deathFunction = maps\_zombiemode_spawner::zombie_death_animscript; self notify("fall_anim_finished"); spot notify("stop_zombie_fall_fx"); self StopAnimScripted(); landAnim = random(level._zombie_fall_anims["zombie"]["land"]); landAnimDelta = 15; ground_pos = groundpos_ignore_water_new( self.origin ); physDist = self.origin[2] - ground_pos[2] + landAnimDelta; if ( physDist > 0 ) { fallAnim = level._zombie_fall_anims["zombie"]["fall_loop"]; if ( IsDefined( fallAnim ) ) { self.fall_anim = fallAnim; self animcustom(::zombie_fall_loop); self waittill("faller_on_ground"); } self.landAnim = landAnim; self animcustom(::zombie_land); wait( GetAnimLength( landAnim ) ); } self.in_the_ceiling = false; self traverseMode( "gravity" ); self SetAnimKnobAllRestart( animscripts\zombie_run::GetRunAnim(), %body, 1, 0.2, 1 ); self.no_powerups = false; self notify("zombie_custom_think_done", spot.script_noteworthy ); } zombie_fall_loop() { self endon("death"); self setFlaggedAnimKnobRestart( "fall_loop", self.fall_anim, 1, 0.20, 1.0 ); while(1) { ground_pos = groundpos_ignore_water_new( self.origin ); if( self.origin[2] - ground_pos[2] < 20) { self notify("faller_on_ground"); break; } wait .05; } } zombie_land() { self setFlaggedAnimKnobRestart( "land", self.landAnim, 1, 0.20, 1.0 ); wait( GetAnimLength( self.landAnim ) ); } zombie_faller_always_drop() { if ( IsDefined(self.zombie_faller_location.drop_now) ) { if ( self.zombie_faller_location.drop_now == true ) { return true; } } return false; } zombie_faller_drop_not_occupied() { if ( is_true(self.zombie_faller_location.drop_not_occupied) ) { if( isDefined(self.zone_name) && isDefined(level.zones[ self.zone_name ]) ) { return !level.zones[ self.zone_name ].is_occupied; } } return false; } zombie_faller_watch_all_players() { players = get_players(); for(i=0; i 0; } zombie_fall_get_vicitims(spot) { ret = []; players = GetPlayers(); checkDist2 = 40.0; checkDist2 *= checkDist2; for ( i = 0; i < players.size; i++ ) { player = players[i]; if ( player maps\_laststand::player_is_in_laststand() ) { continue; } stance = player GetStance(); if ( stance == "crouch" || stance == "prone" ) { continue; } zCheck = self.origin[2] - player.origin[2]; if ( zCheck < 0.0 || zCheck > 120.0 ) { continue; } dist2 = Distance2DSquared(player.origin, self.origin); if ( dist2 < checkDist2 ) { ret[ret.size] = player; } } return ret; } get_fall_emerge_anim(spot) { return level._zombie_fall_anims[self.animname]["emerge"]; } get_fall_anim(spot) { return level._zombie_fall_anims[self.animname]["fall"]; } get_attack_anim(spot) { return random(level._zombie_fall_anims[self.animname]["attack"]); } zombie_faller_enable_location() { if ( IsDefined( self.zombie_faller_location ) ) { self.zombie_faller_location.is_enabled = true; self.zombie_faller_location = undefined; } } zombie_faller_death_wait() { self waittill( "death" ); self endon( "falling" ); self zombie_faller_enable_location(); } zombie_fall_death_func() { self animmode( "noclip" ); self.deathanim = level._zombie_fall_anims["zombie"]["emerge_death"]; return self maps\_zombiemode_spawner::zombie_death_animscript(); } zombie_fall_death(zombie, spot) { zombie endon("fall_anim_finished"); while (zombie.health > 1) { zombie waittill("damage", amount, attacker, dir, p, type); } zombie StopAnimScripted(); spot notify("stop_zombie_fall_fx"); } _damage_mod_to_damage_type(type) { toks = strtok(type, "_"); if(toks.size<2) { return type; } returnStr = toks[1]; for(i=2;i