1148 lines
30 KiB
Plaintext
1148 lines
30 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include common_scripts\utility;
|
|
#include maps\mp\alien\_utility;
|
|
|
|
DEFAULT_HIVE_WAYPOINT_DIST = 1300;
|
|
|
|
init_hives()
|
|
{
|
|
if ( !flag_exist( "hives_cleared" ) )
|
|
flag_init( "hives_cleared" );
|
|
|
|
if ( !flag_exist( "blocker_hive_destroyed" ) )
|
|
flag_init( "blocker_hive_destroyed" );
|
|
|
|
init_hive_locs();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Regular hive encounter
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
regular_hive( custom_get_score_component_list_func )
|
|
{
|
|
while ( 1 )
|
|
{
|
|
selected_regular_hives = select_hives( false );
|
|
|
|
AssertEx( selected_regular_hives.size > 0, "No regular hive is selected" );
|
|
|
|
level thread maps\mp\alien\_spawnlogic::encounter_cycle_spawn( "drill_planted", "door_planted" );
|
|
|
|
foreach( regular_hive in selected_regular_hives )
|
|
regular_hive thread regular_hive_listener( get_hive_score_component_list_func( custom_get_score_component_list_func ) );
|
|
|
|
result = level waittill_any_return( "regular_hive_destroyed", "regular_door_destroyed" );
|
|
if ( result == "regular_hive_destroyed" )
|
|
{
|
|
maps\mp\alien\_spawn_director::end_cycle();
|
|
level thread maps\mp\alien\_spawnlogic::remaining_alien_management();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// self is hive, hive is listening for a drill to be planted on self
|
|
regular_hive_listener( get_score_component_list_func )
|
|
{
|
|
// self is stronghold_loc struct
|
|
level endon( "game_ended" );
|
|
|
|
// only one instance of listener
|
|
self notify( "stop_listening" );
|
|
self endon( "stop_listening" );
|
|
|
|
// =========== WAIT FOR DRILL TO BE PICKED UP ===========
|
|
if ( isdefined( level.drill ) && !isdefined( level.drill_carrier ) && !is_true( level.automatic_drill ) )
|
|
level waittill( "drill_pickedup", player );
|
|
|
|
//[!] DURING THIS TIME, level.drill IS UNDEFINED AS IT IS CARRIED BY PLAYER
|
|
|
|
icon = "waypoint_alien_destroy";
|
|
waypoint_dist = get_hive_waypoint_dist( self, DEFAULT_HIVE_WAYPOINT_DIST );
|
|
|
|
if ( self is_door() || ( isDefined ( level.hive_icon_override ) && self [[level.hive_icon_override]]() ) ) //doors handled seperately
|
|
{
|
|
waypoint_dist = 1000;
|
|
icon = "waypoint_alien_door";
|
|
}
|
|
|
|
// show plant location icons after drill is picked up by a player
|
|
self thread set_hive_icon( icon, waypoint_dist );
|
|
|
|
// =========== WAIT FOR DRILL PLANTED ===================
|
|
planter = self maps\mp\alien\_drill::wait_for_drill_plant();
|
|
|
|
// update current selected hive name
|
|
level.current_hive_name = self.target;
|
|
|
|
if ( !is_true( level.automatic_drill ) )
|
|
{
|
|
// black box print
|
|
self thread maps\mp\alien\_drill::drill_plant_BBPrint( planter );
|
|
}
|
|
|
|
// Play this VO only for the first hive
|
|
if ( level.cycle_count == 1 )
|
|
level delaythread( 1, maps\mp\alien\_music_and_dialog::playVOForWaveStart );
|
|
|
|
if ( self is_door() )
|
|
{
|
|
level notify( "door_planted" ); //kill the encounter cycle spawn
|
|
level notify( "start_spawn_event",self.target ); // spawn the door hive cycle
|
|
if ( is_true ( level.current_cycle_started_by_timeout ) )
|
|
level.cycle_count --;
|
|
/#
|
|
if ( getdvarint ( "scr_debugcyclecount" ) == 1 )
|
|
{
|
|
if ( is_true ( level.current_cycle_started_by_timeout ) )
|
|
println( "CYCLE_COUNT_DEBUG -- > Cycle Count DECREMENTED to: " + level.cycle_count );
|
|
|
|
println( "CYCLE_COUNT_DEBUG -- > Spawning Door Event " + self.target );
|
|
}
|
|
#/
|
|
}
|
|
|
|
// spawn new challenge
|
|
if ( !self is_door() )
|
|
maps\mp\_utility::delaythread( 2, maps\mp\alien\_challenge::spawn_challenge );
|
|
|
|
// clear carrier
|
|
level.drill_carrier = undefined;
|
|
|
|
// ============ DRILLING LOOP ===========================
|
|
// setup drilling operation and for aliens to attack
|
|
self thread maps\mp\alien\_drill::drilling( self.origin, planter );
|
|
|
|
// kill other stronghold threads because this one is chosen
|
|
self disable_other_strongholds();
|
|
|
|
// reset hive score
|
|
maps\mp\alien\_gamescore::reset_encounter_performance();
|
|
|
|
// ======== CYCLE FORCE START FOR EXTERNAL WAITS ========
|
|
level notify( "force_cycle_start" );
|
|
|
|
// ============ WAIT TILL DRILLING COMPLETE =============
|
|
flag_wait( "drill_detonated" );
|
|
|
|
// ============ DRILL DETONATE ==========================
|
|
self hive_play_death_animations();
|
|
|
|
// end current challenge
|
|
maps\mp\alien\_challenge::end_current_challenge();
|
|
|
|
// remove all the remaining challenge cases
|
|
maps\mp\alien\_challenge::remove_all_challenge_cases();
|
|
|
|
// remove loc from stronghold_hive_locs
|
|
level.stronghold_hive_locs = array_remove( level.stronghold_hive_locs, self );
|
|
|
|
//stop health listener
|
|
self notify( "hive_dying" );
|
|
|
|
self thread maps\mp\alien\_drill::drill_detonate();
|
|
|
|
// trigger anything thats scene_trigger attached
|
|
if ( isdefined( self.scene_trig ) )
|
|
self.scene_trig notify( "trigger", level.players[ 0 ] );
|
|
|
|
level.current_hive_name += "_post";
|
|
|
|
if ( self is_door() )
|
|
{
|
|
give_door_score();
|
|
level notify( "regular_door_destroyed" );
|
|
}
|
|
else
|
|
{
|
|
level.num_hive_destroyed++;
|
|
give_players_rewards( false, get_score_component_list_func );
|
|
level notify( "regular_hive_destroyed" );
|
|
}
|
|
// kill everything else
|
|
self notify( "stop_listening" );
|
|
}
|
|
|
|
blocker_hive_explode_sequence( attackable_ent, blocker_hive )
|
|
{
|
|
attackable_ent delete();
|
|
|
|
//chopper awayyy
|
|
if ( isdefined( level.hive_heli ) )
|
|
{
|
|
level.hive_heli notify( "new_flight_path" );
|
|
level.hive_heli notify( "blocker_hive_destroyed" );
|
|
}
|
|
|
|
flag_set( "blocker_hive_destroyed" );
|
|
|
|
blocker_hive hive_play_death_animations();
|
|
blocker_hive delete_removables();
|
|
blocker_hive maps\mp\alien\_drill::remove_spawner();
|
|
blocker_hive maps\mp\alien\_drill::fx_ents_playfx();
|
|
blocker_hive show_dead_hive_model();
|
|
blocker_hive destroy_hive_icon();
|
|
|
|
blocker_hive thread blocker_kill_sequence();
|
|
blocker_hive thread maps\mp\alien\_drill::do_radius_damage();
|
|
|
|
level thread maps\mp\alien\_music_and_dialog::playVOforBlockerHive();
|
|
level thread maps\mp\alien\_spawnlogic::remaining_alien_management();
|
|
level.current_blocker_hive = undefined;
|
|
level.blocker_hive_active = undefined;
|
|
level.stronghold_hive_locs = array_remove( level.stronghold_hive_locs, blocker_hive );
|
|
level.current_hive_name += "_post";
|
|
level.num_hive_destroyed++;
|
|
|
|
if( isPlayingSolo() && !IsSplitScreen() )
|
|
maps\mp\alien\_laststand::give_lastStand( level.players[0], 1 );
|
|
|
|
if ( isdefined( blocker_hive.drill_teleport_structs ) && !is_true( level.automatic_drill ) )
|
|
level thread maps\mp\alien\_drill::teleport_drill( blocker_hive.drill_teleport_structs[ randomint( blocker_hive.drill_teleport_structs.size ) ].origin );
|
|
|
|
if ( isdefined( blocker_hive.scene_trig ) )
|
|
blocker_hive.scene_trig notify( "trigger", level.players[ 0 ] );
|
|
|
|
maps\mp\alien\_achievement::update_blocker_hive_achievements( blocker_hive.target );
|
|
level maps\mp\alien\_challenge_function::hide_barrier_hive_intel();
|
|
|
|
flag_clear( "blocker_hive_destroyed" );
|
|
|
|
blocker_hive notify( "hive_dying" );
|
|
blocker_hive notify( "stop_listening" );
|
|
}
|
|
|
|
blocker_kill_sequence()
|
|
{
|
|
PlayFX( level._effect[ "stronghold_explode_large" ], self.origin );
|
|
self thread maps\mp\alien\_hive::sfx_destroy_hive();
|
|
|
|
foreach ( scriptable in self.scriptables )
|
|
{
|
|
scriptable thread maps\mp\alien\_hive::hive_explode( 1 );
|
|
waitframe();
|
|
}
|
|
}
|
|
|
|
CONST_BLOCKER_HIVE_HP_MED = 100000;
|
|
CONST_BLOCKER_HIVE_HP_HIGH = 150000;
|
|
CONST_BLOCKER_HIVE_HP_SOLO_SCALE = 0.66;
|
|
create_attackable_ent( blocker_hive )
|
|
{
|
|
attackable_ent = spawn( "script_model", blocker_hive.origin );
|
|
attackable_ent setmodel( "mp_ext_alien_hive03_collision" );
|
|
attackable_ent hide();
|
|
attackable_ent.hive_target = blocker_hive.target;
|
|
|
|
// based on blocker hive idx, we adjust health, first blocker (id=1 has lower health)
|
|
if ( get_blocker_hive_index() == 1 )
|
|
{
|
|
// blocker index 1
|
|
attackable_ent.health = CONST_BLOCKER_HIVE_HP_MED;
|
|
attackable_ent.maxhealth = CONST_BLOCKER_HIVE_HP_MED;
|
|
}
|
|
else
|
|
{
|
|
// blocker index 2 and larger
|
|
attackable_ent.health = CONST_BLOCKER_HIVE_HP_HIGH;
|
|
attackable_ent.maxhealth = CONST_BLOCKER_HIVE_HP_HIGH;
|
|
}
|
|
|
|
// solo always scales down health for all hives
|
|
if ( isPlayingSolo() )
|
|
{
|
|
attackable_ent.health = int( CONST_BLOCKER_HIVE_HP_SOLO_SCALE * attackable_ent.health );
|
|
attackable_ent.maxhealth = int( CONST_BLOCKER_HIVE_HP_SOLO_SCALE * attackable_ent.maxhealth );
|
|
}
|
|
|
|
if ( isDefined( level.create_attackable_ent_override_func ) )
|
|
attackable_ent = [[level.create_attackable_ent_override_func]]( attackable_ent );
|
|
|
|
return attackable_ent;
|
|
}
|
|
|
|
|
|
|
|
hive_explode( fx_count )
|
|
{
|
|
if ( !isdefined( fx_count ) )
|
|
fx_count = 2;
|
|
|
|
for ( i = 0; i < fx_count; i ++ )
|
|
{
|
|
wait randomfloatrange( 0.5, 1 );
|
|
|
|
offset = 8;
|
|
_x = offset - randomintrange( 0, offset*2 );
|
|
_y = offset - randomintrange( 0, offset*2 );
|
|
|
|
self_forward = anglesToForward( self.angles );
|
|
self_up = anglesToUp( self.angles );
|
|
|
|
PlayFx( level._effect[ "alien_hive_explode" ], self.origin + ( _x, _y, 0 ), self_forward, self_up );
|
|
}
|
|
}
|
|
|
|
sfx_destroy_hive()
|
|
{
|
|
wait 0.1;
|
|
self PlaySound( "alien_hive_destroyed" );
|
|
}
|
|
|
|
CONST_DAMAGE_TRIGGER_THREAT = 400;
|
|
CONST_THREAT_INCREMENT = 100;
|
|
CONST_THREAT_COOL_DOWN = 10;
|
|
STAGE_ONE_THRESHOLD = 0.75;
|
|
STAGE_TWO_THRESHOLD = 0.5;
|
|
NEAR_DEATH_THRESHOLD = 0.25;
|
|
BLOCKER_HIVE_PAIN_EARTHQUAKE_INTENSITY = 0.4;
|
|
BLOCKER_HIVE_PAIN_WARN_DELAY = 0.1;
|
|
monitor_attackable_ent_damage( blocker_hive )
|
|
{
|
|
level endon( "blocker_hive_destroyed" );
|
|
level endon( "game_ended" );
|
|
|
|
level._effect[ "Fire_Cloud_Blocker_Hive" ] = loadfx( "vfx/gameplay/alien/vfx_alien_gas_fire");
|
|
|
|
stageOnePainThreshold = STAGE_ONE_THRESHOLD * self.maxhealth;
|
|
stageTwoPainThreshold = STAGE_TWO_THRESHOLD * self.maxhealth;
|
|
nearDeathPainThreshold = NEAR_DEATH_THRESHOLD * self.maxhealth;
|
|
|
|
stageOnePainReached = false;
|
|
stageTwoPainReached = false;
|
|
nearDeathReached = false;
|
|
|
|
while ( 1 )
|
|
{
|
|
self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, iDFlags, weapon );
|
|
|
|
if ( isdefined( weapon ) && weapon == "alienmortar_strike_mp" )
|
|
{
|
|
damage = int( damage / 3 ); //apply fixed damage if it's the mortar strike
|
|
self.health += damage; //give back health if its the mortar strike
|
|
}
|
|
// extra bonus damage from panzer
|
|
if ( isdefined( weapon ) && weapon == "iw6_alienpanzerfaust3_mp" )
|
|
self DoDamage( damage, self.origin, attacker, attacker, "MOD_PROJECTILE_SPLASH" );
|
|
|
|
if ( isdefined( attacker ) && isalive( attacker ) && isplayer( attacker ) )
|
|
{
|
|
if ( !IsDefined( attacker.hive_damage ) )
|
|
attacker.hive_damage = 0;
|
|
|
|
attacker.hive_damage += damage;
|
|
|
|
if (attacker.hive_damage > CONST_DAMAGE_TRIGGER_THREAT )
|
|
{
|
|
attacker.hive_damage = 0;
|
|
attacker.threatbias += CONST_THREAT_INCREMENT;
|
|
attacker thread cool_down_threat( CONST_THREAT_COOL_DOWN );
|
|
}
|
|
}
|
|
|
|
if ( !( isdefined( type ) && type == "MOD_UNKNOWN" ) && !( isdefined( self.is_burning ) && self.is_burning ) )
|
|
{
|
|
// burn
|
|
if ( ( isDefined( attacker.has_incendiary_ammo ) && attacker.has_incendiary_ammo )
|
|
|| ( isdefined( weapon ) && ( weapon == "iw6_alienmk324_mp" || weapon == "iw6_alienminigun4_mp" || weapon == "iw6_alienmk323_mp" ) ) )
|
|
{
|
|
self thread blocker_hive_burn( attacker );
|
|
}
|
|
}
|
|
|
|
// ================ draw damage feedback ===============
|
|
if ( isdefined( attacker.owner ) && isalive( attacker.owner ) && isplayer( attacker.owner ) )
|
|
attacker = attacker.owner;
|
|
|
|
if ( isdefined( attacker ) && isalive( attacker ) && isplayer( attacker ) )
|
|
attacker thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "standard" );
|
|
// =====================================================
|
|
|
|
if ( !stageOnePainReached && self.health < stageOnePainThreshold )
|
|
{
|
|
thread warn_all_players( BLOCKER_HIVE_PAIN_WARN_DELAY, BLOCKER_HIVE_PAIN_EARTHQUAKE_INTENSITY );
|
|
stageOnePainReached = true;
|
|
}
|
|
|
|
if ( !stageTwoPainReached && self.health < stageTwoPainThreshold )
|
|
{
|
|
thread warn_all_players( BLOCKER_HIVE_PAIN_WARN_DELAY, BLOCKER_HIVE_PAIN_EARTHQUAKE_INTENSITY );
|
|
blocker_hive hive_play_first_pain_animations();
|
|
if( isDefined( level.hive_heli ) )
|
|
level.hive_heli maps\mp\alien\_music_and_dialog::play_pilot_vo( "so_alien_plt_hivehalfdead" );
|
|
stageTwoPainReached = true;
|
|
}
|
|
|
|
if ( !nearDeathReached && self.health < nearDeathPainThreshold )
|
|
{
|
|
blocker_hive hive_play_second_pain_animations();
|
|
if( isDefined( level.hive_heli ) )
|
|
level.hive_heli maps\mp\alien\_music_and_dialog::play_pilot_vo( "so_alien_plt_hivealmostdead" );
|
|
nearDeathReached = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
blocker_hive_burn( attacker )
|
|
{
|
|
self endon( "death" );
|
|
|
|
self.is_burning = true;
|
|
|
|
// self is blocker hive .attackable_ent
|
|
burn_time = 3;
|
|
total_damage = 1200; // base burn
|
|
total_damage *= level.alien_health_per_player_scalar[ level.players.size ];
|
|
|
|
elapsed_time = 0;
|
|
samples = 6;
|
|
interval_wait = burn_time / samples;
|
|
interval_damage = total_damage / samples;
|
|
|
|
pos = self.origin + ( VectorNormalize( AnglesToForward( self.angles ) ) * 60 ) - ( 0, 0, 20 );
|
|
|
|
self.gasFire = SpawnFx( level._effect[ "Fire_Cloud_Blocker_Hive" ], pos );
|
|
triggerFx( self.gasFire );
|
|
|
|
self thread kill_hive_burning_on_death();
|
|
|
|
for ( i=0; i<samples; i++ )
|
|
{
|
|
wait ( interval_wait );
|
|
self DoDamage( interval_damage, self.origin, attacker, attacker, "MOD_UNKNOWN");
|
|
}
|
|
|
|
self.is_burning = false;
|
|
self.gasFire delete();
|
|
}
|
|
|
|
kill_hive_burning_on_death()
|
|
{
|
|
self notify( "kill_hive_burning_on_death" );
|
|
self endon( "kill_hive_burning_on_death" );
|
|
|
|
self waittill( "death" );
|
|
|
|
if ( isdefined( self.gasFire ) )
|
|
self.gasFire delete();
|
|
}
|
|
|
|
cool_down_threat( timer )
|
|
{
|
|
// self is player
|
|
|
|
level endon( "blocker_hive_destroyed" );
|
|
level endon( "game_ended" );
|
|
|
|
self endon( "death" );
|
|
self thread reset_threat_on_death();
|
|
self thread reset_threat_on_blocker_destroyed();
|
|
|
|
/#
|
|
if ( GetDvarInt( "alien_debug_director" ) > 0 )
|
|
IPrintLnBold( self.name + " threat: " + self.threatbias );
|
|
#/
|
|
|
|
wait timer;
|
|
|
|
self.threatbias = int( max( 0, self.threatbias - CONST_THREAT_INCREMENT ) );
|
|
|
|
/#
|
|
if ( GetDvarInt( "alien_debug_director" ) > 0 )
|
|
IPrintLnBold( self.name + " threat: " + self.threatbias );
|
|
#/
|
|
}
|
|
|
|
reset_threat_on_death()
|
|
{
|
|
self notify( "monitor_threat_on_death" );
|
|
self endon( "monitor_threat_on_death" );
|
|
|
|
// self is player
|
|
self waittill( "death" );
|
|
self.threatbias = 0;
|
|
}
|
|
|
|
reset_threat_on_blocker_destroyed()
|
|
{
|
|
self notify( "monitor_threat_on_blocker_destroyed" );
|
|
self endon( "monitor_threat_on_blocker_destroyed" );
|
|
|
|
// self is player
|
|
level waittill( "blocker_hive_destroyed" );
|
|
self.threatbias = 0;
|
|
}
|
|
/////////////////////////////////////////////////////////////////
|
|
// Helper function
|
|
/////////////////////////////////////////////////////////////////
|
|
give_door_score()
|
|
{
|
|
door_score_component_list = get_door_score_component_list();
|
|
maps\mp\alien\_gamescore::calculate_encounter_scores( level.players, door_score_component_list );
|
|
}
|
|
|
|
get_door_score_component_list()
|
|
{
|
|
if ( is_progression_door( self ) )
|
|
return ["progression_door"];
|
|
else
|
|
return ["side_area"];
|
|
}
|
|
|
|
is_progression_door( stronghold_struct )
|
|
{
|
|
if ( !isDefined( level.progression_doors ) || !isDefined( stronghold_struct.target ) )
|
|
return false;
|
|
|
|
return array_contains( level.progression_doors, stronghold_struct.target );
|
|
}
|
|
|
|
give_players_rewards( is_blocker_hive, get_score_component_list_func )
|
|
{
|
|
calculate_and_show_hive_scores( get_score_component_list_func );
|
|
|
|
foreach( player in level.players )
|
|
{
|
|
player maps\mp\alien\_persistence::eog_player_update_stat( "hivesdestroyed", 1 );
|
|
player thread wait_to_give_rewards();
|
|
|
|
if( is_blocker_hive )
|
|
player maps\mp\alien\_persistence::try_award_bonus_pool_token();
|
|
}
|
|
}
|
|
|
|
calculate_and_show_hive_scores( get_score_component_list_func )
|
|
{
|
|
score_component_name_list = [[get_score_component_list_func]]();
|
|
maps\mp\alien\_gamescore::calculate_and_show_encounter_scores( level.players, score_component_name_list );
|
|
}
|
|
|
|
get_blocker_hive_score_component_name_list()
|
|
{
|
|
if ( isPlayingSolo() )
|
|
return [ "personal_blocker" ];
|
|
else
|
|
return [ "team_blocker", "personal_blocker" ];
|
|
}
|
|
|
|
get_regular_hive_score_component_name_list()
|
|
{
|
|
if ( isPlayingSolo() )
|
|
return [ "drill", "personal", "challenge" ];
|
|
else
|
|
return [ "drill", "team", "personal", "challenge" ];
|
|
}
|
|
|
|
wait_to_give_rewards()
|
|
{
|
|
self endon( "disconnect" );
|
|
level endon( "game_ended" );
|
|
|
|
CONST_LUA_AFTER_HIVE_MENU_TIME = 4.0;
|
|
wait( CONST_LUA_AFTER_HIVE_MENU_TIME );
|
|
|
|
// give XP
|
|
xp_earned = int( self.encounter_score_earned );
|
|
self maps\mp\alien\_persistence::give_player_xp ( xp_earned );
|
|
|
|
/#
|
|
maps\mp\alien\_debug::print_hive_XP_earned( xp_earned );
|
|
#/
|
|
|
|
// give money
|
|
self maps\mp\alien\_persistence::give_player_currency ( self.encounter_cash_earned, undefined, undefined, true );
|
|
}
|
|
|
|
// disables all other strongholds when a bomb is planted on one
|
|
disable_other_strongholds()
|
|
{
|
|
foreach ( stronghold_loc in level.stronghold_hive_locs )
|
|
{
|
|
if ( self != stronghold_loc )
|
|
{
|
|
if ( isdefined( stronghold_loc.icon ) )
|
|
stronghold_loc.icon Destroy();
|
|
|
|
stronghold_loc MakeUnusable();
|
|
stronghold_loc SetHintString( "" );
|
|
stronghold_loc notify( "stop_listening" );
|
|
}
|
|
}
|
|
}
|
|
|
|
set_hive_icon( shader, coll_dist, icon_width, icon_height )
|
|
{
|
|
// self is stronghold_loc struct
|
|
level endon( "game_ended" );
|
|
|
|
self endon( "stop_listening" );
|
|
|
|
// ================= OPTMZ =================
|
|
// logic to not spawn new hudelems until players are close enough to see them
|
|
// default icon vis dist
|
|
if ( !isdefined( coll_dist ) )
|
|
coll_dist = 1000;
|
|
if ( isDefined( level.drill_icon_draw_dist_override ) ) //so that we can override this hardcoded value
|
|
coll_dist = level.drill_icon_draw_dist_override;
|
|
|
|
if ( !isdefined( icon_width ) )
|
|
icon_width = 14;
|
|
|
|
if ( !isdefined( icon_height ) )
|
|
icon_height = 14;
|
|
|
|
// wait till player is close before creating more hudelems
|
|
someone_is_close = false;
|
|
while ( !someone_is_close )
|
|
{
|
|
someone_is_close = false;
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( isalive( player ) && Distance( player.origin, self.origin ) <= coll_dist )
|
|
someone_is_close = true;
|
|
}
|
|
wait 0.05;
|
|
}
|
|
// ==========================================
|
|
|
|
// reset icon
|
|
self destroy_hive_icon();
|
|
|
|
self.icon = NewHudElem();
|
|
self.icon SetShader( shader, icon_width, icon_height );
|
|
self.icon.alpha = 0;
|
|
self.icon.color = ( 1, 1, 1 );
|
|
self.icon SetWayPoint( true, true );
|
|
self.icon.x = self.origin[ 0 ];
|
|
self.icon.y = self.origin[ 1 ];
|
|
self.icon.z = self.origin[ 2 ];
|
|
|
|
if ( !isdefined( coll_dist ) )
|
|
{
|
|
self.icon.alpha = 0.5;
|
|
return;
|
|
}
|
|
|
|
self.icon endon( "death" );
|
|
|
|
while ( isdefined( self.icon ) )
|
|
{
|
|
someone_is_close = false;
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( isalive( player ) && Distance( player.origin, self.origin ) <= coll_dist )
|
|
someone_is_close = true;
|
|
}
|
|
|
|
if ( someone_is_close )
|
|
icon_fade_in( self.icon ); // has wait already
|
|
else
|
|
icon_fade_out( self.icon ); // has wait already
|
|
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
icon_fade_in( icon )
|
|
{
|
|
if ( icon.alpha != 0 )
|
|
return;
|
|
|
|
icon FadeOverTime( 1 );
|
|
icon.alpha = .5;
|
|
wait( 1 );
|
|
}
|
|
|
|
icon_fade_out( icon )
|
|
{
|
|
if ( icon.alpha == 0 )
|
|
return;
|
|
|
|
icon FadeOverTime( 1 );
|
|
icon.alpha = 0;
|
|
wait( 1 );
|
|
}
|
|
|
|
destroy_hive_icon()
|
|
{
|
|
// self is hive loc struct
|
|
if ( isdefined( self.icon ) )
|
|
self.icon Destroy();
|
|
}
|
|
|
|
hive_pain_monitor()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "stop_listening" );
|
|
|
|
maps\mp\alien\_drill::get_drill_entity() endon ( "offline" );
|
|
|
|
if ( !IsDefined( self.scriptables ) )
|
|
return;
|
|
|
|
stageTwoPainThreshold = STAGE_TWO_THRESHOLD * self.total_depth;
|
|
nearDepthPainThreshold = NEAR_DEATH_THRESHOLD * self.total_depth;
|
|
currentDepth = self.depth;
|
|
|
|
if ( currentDepth > stageTwoPainThreshold )
|
|
{
|
|
wait ( self.depth - stageTwoPainThreshold );
|
|
self hive_play_first_pain_animations();
|
|
currentDepth = stageTwoPainThreshold;
|
|
}
|
|
|
|
if ( currentDepth > nearDepthPainThreshold )
|
|
{
|
|
wait ( currentDepth - nearDepthPainThreshold );
|
|
self hive_play_second_pain_animations();
|
|
}
|
|
}
|
|
|
|
get_hive_score_component_list_func( custom_func )
|
|
{
|
|
if ( isDefined( custom_func ) )
|
|
return custom_func;
|
|
|
|
return ::get_regular_hive_score_component_name_list;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Hive animation
|
|
////////////////////////////////////////////////////////
|
|
|
|
hive_play_first_pain_animations()
|
|
{
|
|
STAGE_TWO_PAIN_STATE = 3;
|
|
|
|
self thread play_hive_scriptable_animations( undefined, undefined, STAGE_TWO_PAIN_STATE, true );
|
|
}
|
|
|
|
hive_play_second_pain_animations()
|
|
{
|
|
NEAR_DEATH_DELAY = 0.4;
|
|
|
|
self thread play_hive_scriptable_animations( "start_near_death", NEAR_DEATH_DELAY, "loop_near_death", true );
|
|
}
|
|
|
|
hive_play_drill_planted_animations( delay_override )
|
|
{
|
|
START_PAIN_DELAY = 0.2;
|
|
if ( isdefined( delay_override ) )
|
|
START_PAIN_DELAY = delay_override;
|
|
|
|
self thread play_hive_scriptable_animations( "start_pain", START_PAIN_DELAY, "loop_pain1", true );
|
|
}
|
|
|
|
hive_play_death_animations()
|
|
{
|
|
DEATH_PAIN_DELAY = 1.5;
|
|
|
|
self thread play_hive_scriptable_animations( "death", DEATH_PAIN_DELAY, "remove", true );
|
|
}
|
|
|
|
play_hive_scriptable_animations( start_anim, time_delay, secondary_anim, use_interval_delay )
|
|
{
|
|
MIN_DELAY = 0.15;
|
|
MAX_DELAY = 0.25;
|
|
|
|
if ( !IsDefined( self.scriptables ) )
|
|
return;
|
|
|
|
foreach ( ent in self.scriptables )
|
|
{
|
|
ent thread play_hive_anim( start_anim, time_delay, secondary_anim );
|
|
|
|
if ( use_interval_delay )
|
|
wait RandomFloatRange( MIN_DELAY, MAX_DELAY );
|
|
}
|
|
}
|
|
|
|
play_hive_anim( start_anim, time_delay, secondary_anim )
|
|
{
|
|
if ( IsDefined( start_anim ) )
|
|
self SetScriptablePartState( 0, start_anim );
|
|
|
|
if ( IsDefined( time_delay ) )
|
|
wait time_delay;
|
|
|
|
if ( IsDefined( secondary_anim ) )
|
|
self SetScriptablePartState( 0, secondary_anim );
|
|
}
|
|
|
|
dependent_hives_removed()
|
|
{
|
|
if ( !isDefined( self.target ) || !isDefined( level.hive_dependencies ) || !isDefined( level.hive_dependencies[ self.target ] ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
dependencies = level.hive_dependencies[ self.target ];
|
|
|
|
foreach ( hive in level.stronghold_hive_locs )
|
|
{
|
|
if ( IsDefined( hive.target ) )
|
|
{
|
|
if ( array_contains( dependencies, hive.target ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
select_hives( select_blocker_hive )
|
|
{
|
|
selected_hives = [];
|
|
current_area_name = get_current_area_name();
|
|
|
|
foreach ( stronghold_loc in level.stronghold_hive_locs )
|
|
{
|
|
is_blocker_hive = stronghold_loc is_blocker_hive();
|
|
|
|
if ( select_blocker_hive && !is_blocker_hive )
|
|
continue;
|
|
|
|
if ( !select_blocker_hive && is_blocker_hive )
|
|
continue;
|
|
|
|
if ( !( stronghold_loc.area_name == current_area_name ) && !stronghold_loc is_door() )
|
|
continue;
|
|
|
|
if ( !stronghold_loc dependent_hives_removed() )
|
|
continue;
|
|
|
|
selected_hives[selected_hives.size] = stronghold_loc;
|
|
}
|
|
|
|
return selected_hives;
|
|
}
|
|
|
|
remove_unused_hives( removed_hives )
|
|
{
|
|
foreach ( hive in removed_hives )
|
|
{
|
|
location_ent = getent( hive, "target" );
|
|
assertEx( IsDefined( location_ent ), "Invalid hive chosen to remove: " + hive );
|
|
location_ent notify( "stop_listening" );
|
|
location_ent thread play_hive_scriptable_animations( "remove", undefined, undefined, false );
|
|
location_ent thread delete_removables();
|
|
location_ent destroy_hive_icon();
|
|
foreach ( ent in location_ent.fx_ents )
|
|
{
|
|
ent delete();
|
|
}
|
|
|
|
if ( isDefined( location_ent.dead_hive_model ) )
|
|
{
|
|
location_ent show_dead_hive_model();
|
|
}
|
|
|
|
location_ent delete();
|
|
}
|
|
}
|
|
|
|
delete_removables()
|
|
{
|
|
// self is stronghold_loc script model
|
|
assert( isdefined( self.removeables ) );
|
|
|
|
foreach ( ent in self.removeables )
|
|
{
|
|
if ( isdefined( ent ) )
|
|
ent delete();
|
|
}
|
|
}
|
|
|
|
show_dead_hive_model()
|
|
{
|
|
/#
|
|
if ( !isDefined( self.dead_hive_model ) )
|
|
return;
|
|
#/
|
|
foreach ( piece in self.dead_hive_model )
|
|
piece show();
|
|
}
|
|
|
|
is_blocker_hive()
|
|
{
|
|
if ( !isdefined( level.blocker_hives ) || !isdefined( self.target ) )
|
|
return false;
|
|
|
|
foreach( hive_struct in level.blocker_hives )
|
|
{
|
|
if ( hive_struct == self.target )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
warn_all_players( warn_delay, earthquake_intensity )
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
wait warn_delay;
|
|
|
|
foreach ( player in level.players )
|
|
{
|
|
player thread warn_player( earthquake_intensity );
|
|
}
|
|
}
|
|
|
|
warn_player( earthquake_intensity )
|
|
{
|
|
Earthquake( earthquake_intensity, 3, self.origin, 300 );
|
|
self PlayLocalSound( "pre_quake_mtl_groan" );
|
|
self PlayRumbleOnEntity( "heavygun_fire" );
|
|
}
|
|
|
|
init_hive_locs()
|
|
{
|
|
level.stronghold_hive_locs = [];
|
|
level.current_hive_name = "before_first_hive"; // This is for black box
|
|
|
|
stronghold_hive_locs = getentarray( "stronghold_bomb_loc", "targetname" );
|
|
|
|
door_locs = GetEntArray( "stronghold_door_loc", "targetname" );
|
|
if ( isDefined( door_locs ) && door_locs.size > 0 )
|
|
stronghold_hive_locs = array_combine( stronghold_hive_locs,door_locs );
|
|
|
|
foreach ( location_ent in stronghold_hive_locs )
|
|
{
|
|
// location struct targets stuff to remove
|
|
if ( isdefined( location_ent.target ) )
|
|
{
|
|
targeted_ents = getentarray( location_ent.target, "targetname" );
|
|
assert( isdefined( targeted_ents ) && targeted_ents.size > 0 );
|
|
location_ent.scriptables = GetScriptableArray( location_ent.target, "targetname" );
|
|
|
|
foreach ( scriptable in location_ent.scriptables )
|
|
scriptable.is_hive = true;
|
|
|
|
removeables = [];
|
|
fx_ents = [];
|
|
|
|
foreach ( ent in targeted_ents )
|
|
{
|
|
if ( isdefined( ent.script_noteworthy ) && ent.script_noteworthy == "fx_ent" )
|
|
fx_ents[ fx_ents.size ] = ent;
|
|
else if ( isdefined( ent.script_noteworthy ) && IsSubStr( ent.script_noteworthy, "waypointdist" ) )
|
|
{
|
|
tok = StrTok( ent.script_noteworthy, " " );
|
|
if ( isdefined( tok ) && tok.size && tok[ 0 ] == "waypointdist" )
|
|
{
|
|
assert( tok.size == 2 );
|
|
location_ent.waypoint_dist = int( tok[ 1 ] );
|
|
}
|
|
}
|
|
else
|
|
removeables[ removeables.size ] = ent;
|
|
}
|
|
|
|
// scene triggers
|
|
if ( isdefined( level.scene_trigs ) )
|
|
{
|
|
foreach( trig in level.scene_trigs )
|
|
{
|
|
if ( isdefined( trig.script_noteworthy ) && trig.script_noteworthy == location_ent.target )
|
|
{
|
|
location_ent.scene_trig = trig;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// blocker hive's drill teleport struct
|
|
drill_teleport_targetname = location_ent.target + "_drill_teleport_loc";
|
|
location_ent.drill_teleport_structs = getstructarray( drill_teleport_targetname, "targetname" );
|
|
|
|
location_ent.removeables = removeables;
|
|
location_ent.fx_ents = fx_ents;
|
|
|
|
if ( location_ent.target == level.last_hive )
|
|
{
|
|
location_ent.last_hive = true;
|
|
}
|
|
|
|
dead_hive_targetname = location_ent.target + "_dead";
|
|
location_ent.dead_hive_model = GetEntArray( dead_hive_targetname, "targetname" );
|
|
|
|
if ( isDefined ( location_ent.dead_hive_model ) )
|
|
{
|
|
foreach ( piece in location_ent.dead_hive_model )
|
|
piece hide();
|
|
}
|
|
|
|
if ( location_ent is_blocker_hive() )
|
|
{
|
|
location_ent thread init_blocker_hive_animation_state();
|
|
// not usabe!
|
|
location_ent MakeUnusable();
|
|
location_ent SetHintString( "" );
|
|
}
|
|
}
|
|
|
|
if ( !array_contains( level.removed_hives, location_ent.target ) )
|
|
{
|
|
location_ent.area_name = location_ent get_in_world_area();
|
|
level.stronghold_hive_locs[ level.stronghold_hive_locs.size ] = location_ent;
|
|
}
|
|
}
|
|
}
|
|
|
|
init_blocker_hive_animation_state()
|
|
{
|
|
// self is stronghold_loc struct
|
|
level endon( "game_ended" );
|
|
self endon( "death" );
|
|
|
|
if ( !isdefined( self.scriptables ) )
|
|
return;
|
|
|
|
wait 5; // delay for bad scriptible state sync between server and clients
|
|
|
|
foreach ( ent in self.scriptables )
|
|
{
|
|
wait RandomFloatRange( 0.15, 0.25 );
|
|
ent SetScriptablePartState( 0, "loop_pain1" );
|
|
}
|
|
}
|
|
|
|
get_hive_waypoint_dist( hive, default_waypoint_dist )
|
|
{
|
|
if ( isdefined( hive.waypoint_dist ) )
|
|
return hive.waypoint_dist;
|
|
|
|
if ( isdefined( level.waypoint_dist_override ) )
|
|
return level.waypoint_dist_override;
|
|
|
|
return default_waypoint_dist;
|
|
}
|
|
|
|
// returns blocker hive index: 1, 2, 3 etc...
|
|
get_blocker_hive_index()
|
|
{
|
|
assertex( isdefined( level.cycle_end_area_list ) && level.cycle_end_area_list.size, "level.cycle_end_area_list is not defined at this point." );
|
|
|
|
index_1 = level.cycle_end_area_list[ 0 ]; // as of 7/24/2013, value = 5
|
|
index_2 = level.cycle_end_area_list[ 1 ]; // as of 7/24/2013, value = 9
|
|
|
|
if ( level.cycle_count == ( index_1 - 1 ) || level.cycle_count == index_1 )
|
|
return 1;
|
|
else
|
|
return 2;
|
|
}
|
|
|
|
skip_hive()
|
|
{
|
|
/#
|
|
if ( !isDefined( level.cycle_count ) )
|
|
level.cycle_count = maps\mp\alien\_spawnlogic::init_cycle_count();
|
|
|
|
level.cycle_count++;
|
|
level.num_hive_destroyed++;
|
|
#/
|
|
}
|
|
|
|
beat_regular_hive()
|
|
{
|
|
/#
|
|
selected_hive = get_selected_hive();
|
|
|
|
if ( !flag( "drill_drilling" ) )
|
|
beat_pre_drilling_sequence( selected_hive );
|
|
|
|
beat_drilling_sequence( selected_hive );
|
|
#/
|
|
}
|
|
|
|
beat_blocker_hive()
|
|
{
|
|
/#
|
|
if ( !is_true( level.blocker_hive_active ) )
|
|
{
|
|
iprintlnBold( "Blocker hive is not active yet" );
|
|
return;
|
|
}
|
|
|
|
level.current_blocker_hive.attackable_ent notify ( "death" );
|
|
#/
|
|
}
|
|
|
|
/#
|
|
beat_pre_drilling_sequence( selected_hive )
|
|
{
|
|
level notify( "drill_pickedup" );
|
|
waitframe(); // Allow the "drill_pickedup" notify time to process
|
|
|
|
if( !isDefined( level.drill_carrier ) )
|
|
set_fake_drill_carrier();
|
|
|
|
selected_hive notify( "trigger", level.drill_carrier );
|
|
wait 7.5; // wait for the challenge to be activated and the drill finishes planting
|
|
}
|
|
|
|
set_fake_drill_carrier()
|
|
{
|
|
level.drill_carrier = level.players[0];
|
|
|
|
if ( !isDefined( level.drill_carrier.lastweapon ) )
|
|
level.drill_carrier.lastweapon = level.drill_carrier getWeaponsListAll()[0];
|
|
}
|
|
|
|
beat_drilling_sequence( selected_hive )
|
|
{
|
|
selected_hive.layers = [];
|
|
selected_hive notify( "force_drill_complete" );
|
|
wait 1.0; // wait for the hive destroy sequence to complete
|
|
}
|
|
|
|
get_selected_hive()
|
|
{
|
|
regular_hives_in_area = select_hives( false );
|
|
|
|
if ( flag( "drill_drilling" ) )
|
|
{
|
|
foreach( regular_hive in regular_hives_in_area )
|
|
{
|
|
if ( regular_hive.target == level.current_hive_name )
|
|
return regular_hive;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
random_hive_index = randomIntRange( 0, regular_hives_in_area.size );
|
|
return( regular_hives_in_area[random_hive_index] );
|
|
}
|
|
}
|
|
|
|
debug_spitter_population()
|
|
{
|
|
level endon( "blocker_hive_destroyed" );
|
|
level endon( "game_ended" );
|
|
|
|
while( 1 )
|
|
{
|
|
level.spitters_against_chopper = [];
|
|
level.spitters_against_players = [];
|
|
level.spitters_array = [];
|
|
|
|
foreach ( agent in level.agentArray )
|
|
{
|
|
if ( !IsDefined( agent.isActive ) || !agent.isActive || !isalive( agent ) || !isdefined( agent.alien_type ) || agent.alien_type != "spitter" )
|
|
continue;
|
|
|
|
level.spitters_array[ level.spitters_array.size ] = agent;
|
|
|
|
if ( agent GetThreatBiasGroup() == "spitters" )
|
|
level.spitters_against_chopper[ level.spitters_against_chopper.size ] = agent;
|
|
else
|
|
level.spitters_against_players[ level.spitters_against_players.size ] = agent;
|
|
}
|
|
wait 0.5;
|
|
}
|
|
}
|
|
#/ |