2164 lines
58 KiB
Plaintext
2164 lines
58 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include common_scripts\utility;
|
|
#include maps\mp\alien\_utility;
|
|
#include maps\mp\gametypes\_hud_util;
|
|
#include maps\mp\agents\_agent_utility;
|
|
#include maps\mp\alien\_perk_utility;
|
|
|
|
CONST_DRILL_HEALTH = 150; // health: of planted bomb to withstand alien attack
|
|
CONST_DRILL_HEALTH_HARDCORE = 1250; // bomb health in hardcore mode
|
|
CONST_DRILL_HEALTH_HARDCORE_SOLO= 2000; // bomb health in hardcore mode
|
|
CONST_HEALTH_INVULNERABLE = 20000;
|
|
|
|
CONST_DRILL_THREATBIAS_MIN = -3000;// min threat - starting threat, threat while players are in range
|
|
CONST_DRILL_THREATBIAS_MAX = -1000; // max threat
|
|
CONST_DRILL_THREAT_RADIUS_MIN = 1000; // radius before threat is increased based on distance
|
|
CONST_DRILL_THREAT_RADIUS_MAX = 2500; // radius where threat increased is maxed
|
|
|
|
CONST_DRILL_MODEL = "mp_laser_drill";
|
|
CONST_DRILL_MODEL_OBJ = "mp_laser_drill";
|
|
|
|
CONST_DRILL_OUTLINE_COLOR_INDEX = 3;
|
|
|
|
// drill overheat constants
|
|
CONST_DRILL_OVERHEAT_TIMER = 45; // seconds
|
|
CONST_DRILL_OVERHEAT_TIMER_DECREASE = 5;
|
|
CONST_DRILL_OVERHEAT_TIMER_MIN = 25;
|
|
CONST_DRILL_OVERHEAT_TIMER_WARN_1 = 20;
|
|
CONST_DRILL_OVERHEAT_TIMER_WARN_2 = 10;
|
|
|
|
init_drill()
|
|
{
|
|
// state flags
|
|
flag_init( "drill_detonated" );
|
|
flag_init( "drill_destroyed" );
|
|
flag_init ( "drill_drilling" );
|
|
|
|
level.drill_use_trig = getent( "drill_pickup_trig", "targetname" ); // needs to exist in map, and needs to be placed in an unreachable location
|
|
if ( isdefined( level.drill_use_trig ) )
|
|
level.drill_use_trig.original_origin = level.drill_use_trig.origin;
|
|
|
|
level.drill_id = 0;
|
|
level.drill_marker_id = 1;
|
|
|
|
// carried drill
|
|
level.drill = undefined;
|
|
level.drill_carrier = undefined;
|
|
|
|
// inits
|
|
init_fx(); // fx
|
|
init_drill_drop_loc(); // drill start location
|
|
|
|
// drill device loop
|
|
thread drill_think();
|
|
|
|
//drill gets dropped out of playable area
|
|
level thread drill_out_of_playable();
|
|
}
|
|
|
|
drill_out_of_playable()
|
|
{
|
|
level endon( "game_ended" );
|
|
out_of_playable_areas = getentarray( "trigger_hurt","classname" );
|
|
while ( 1 )
|
|
{
|
|
if ( !isDefined ( level.drill ) )
|
|
{
|
|
wait ( .5 );
|
|
continue;
|
|
}
|
|
|
|
foreach ( area in out_of_playable_areas )
|
|
{
|
|
if ( !isDefined ( area.script_noteworthy ) || area.script_noteworthy != "out_of_playable" )
|
|
continue;
|
|
|
|
if ( level.drill istouching ( area ) )
|
|
{
|
|
level.drill delete();
|
|
|
|
//AssertEx ( isDefined ( level.last_drill_pickup_origin ) && isDefined ( level.last_drill_pickup_angles ),"Last drill pickup spot was not defined" );
|
|
playfx( level._effect[ "alien_teleport" ] , level.last_drill_pickup_origin );
|
|
playfx ( level._effect[ "alien_teleport_dist" ], level.last_drill_pickup_origin );
|
|
|
|
drop_drill ( level.last_drill_pickup_origin, level.last_drill_pickup_angles );
|
|
|
|
foreach ( player in level.players )
|
|
{
|
|
player setLowerMessage( "drill_overboard",&"ALIEN_COLLECTIBLES_DRILL_OUTOFPLAY",4 );
|
|
}
|
|
}
|
|
}
|
|
wait( 0.1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//=======================================================
|
|
// Inits
|
|
//=======================================================
|
|
|
|
init_drill_drop_loc()
|
|
{
|
|
level.drill_locs = [];
|
|
level.drill_locs = getstructarray( "bomb_drop_loc", "targetname" );
|
|
}
|
|
|
|
init_fx()
|
|
{
|
|
// fx
|
|
level._effect[ "drill_laser_contact" ] = loadfx( "vfx/gameplay/alien/vfx_alien_drill_laser_contact" );
|
|
level._effect[ "drill_laser" ] = loadfx( "vfx/gameplay/alien/vfx_alien_drill_laser" );
|
|
level._effect[ "stronghold_explode_med" ] = loadfx( "vfx/gameplay/mp/killstreaks/vfx_sentry_gun_explosion" );
|
|
level._effect[ "stronghold_explode_large" ] = loadfx( "fx/explosions/aerial_explosion" );
|
|
level._effect[ "alien_hive_explode" ] = loadfx( "fx/explosions/alien_hive_explosion" );
|
|
|
|
level.spawnGlowModel["friendly"] = "mil_emergency_flare_mp";
|
|
level.spawnGlow["friendly"] = loadfx( "fx/misc/flare_ambient_green" );
|
|
}
|
|
|
|
//=======================================================
|
|
// Drill object loop
|
|
//=======================================================
|
|
|
|
// loop to respawn drill object
|
|
drill_think()
|
|
{
|
|
level endon( "game_ended" );
|
|
|
|
//wait 1;
|
|
while ( !isdefined( level.players ) || level.players.size < 1 )
|
|
wait 0.05;
|
|
|
|
level.drill_health_hardcore = CONST_DRILL_HEALTH_HARDCORE;
|
|
if ( isPlayingSolo() )
|
|
level.drill_health_hardcore = CONST_DRILL_HEALTH_HARDCORE_SOLO;
|
|
|
|
level thread drill_threat_think();
|
|
|
|
// drill initial drop location
|
|
//drop_loc = ( 2801, -117, 595 ); // default for "mp_alien_town"
|
|
drop_loc = ( 2822.27, -196, 524.068 ); // default to match drill animation in "mp_alien_town"
|
|
drop_loc_struct = getstruct( "drill_loc", "targetname" );
|
|
|
|
if ( isdefined( drop_loc_struct ) )
|
|
drop_loc = drop_loc_struct.origin;
|
|
|
|
//drop_angles = ( 0, 0, 0 );
|
|
drop_angles = ( 1.287, 0.995, -103.877 ); //default to match drill animation in "mp_alien_town"
|
|
if ( isdefined( drop_loc_struct ) && isdefined( drop_loc_struct.angles ) )
|
|
drop_angles = drop_loc_struct.angles;
|
|
|
|
/#
|
|
drop_loc = maps\mp\alien\_debug::adjust_drill_loc( drop_loc );
|
|
#/
|
|
|
|
level waittill( "spawn_intro_drill" ,spawnpos,spawnang );
|
|
|
|
// overrides of drill origin and angles, ex: intro animation end frame
|
|
drop_to_ground = true;
|
|
if ( isdefined( level.initial_drill_origin ) && isdefined( level.initial_drill_angles ) )
|
|
{
|
|
drop_loc = level.initial_drill_origin;
|
|
drop_angles = level.initial_drill_angles;
|
|
drop_to_ground = false;
|
|
}
|
|
|
|
if ( isDefined( spawnpos ) && isDefined( spawnang ) )
|
|
{
|
|
drop_loc = spawnpos;
|
|
drop_angles = spawnang;
|
|
drop_to_ground = false;
|
|
}
|
|
|
|
// TODO: remove after new model is in, and carry object is setup,
|
|
// currently is to remove the vest model dropped on ground when dropping drill
|
|
marker = undefined;
|
|
|
|
while ( true )
|
|
{
|
|
spawn_drill_raw( CONST_DRILL_MODEL_OBJ, drop_loc, drop_angles, marker, drop_to_ground );
|
|
drop_to_ground = true;
|
|
level waittill( "new_drill", drop_loc, drop_angles, marker );
|
|
assertex( isdefineD( drop_loc ), "Drill dropped at invalid position" );
|
|
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
// drop drill spawns new drill
|
|
drop_drill( pos, angles, marker )
|
|
{
|
|
level notify( "new_drill", pos, angles, marker );
|
|
}
|
|
|
|
// spawns the drill and listens for pickup
|
|
spawn_drill_raw( model, pos, angles, marker, drop_to_ground )
|
|
{
|
|
if ( !isdefined( drop_to_ground ) )
|
|
drop_to_ground = true;
|
|
|
|
level.drill_carrier = undefined; // means no one is carrying drill as drill is spawned
|
|
|
|
// remove previous version, <safe>
|
|
if ( isdefined( level.drill ) )
|
|
{
|
|
level.drill delete();
|
|
level.drill = undefined;
|
|
}
|
|
|
|
// drill object
|
|
level.drill = spawn( "script_model", pos );
|
|
level.drill setmodel( model );
|
|
level.drill set_drill_icon();
|
|
level.drill.state = "idle"; // idle meaning it can be picked up/planted
|
|
if ( drop_to_ground )
|
|
level.drill thread angles_to_ground( pos, angles, ( 0, 0, -4 ) );
|
|
else
|
|
level.drill.angles = angles;
|
|
|
|
// wait until intro sequence is complete
|
|
if ( flag_exist( "intro_sequence_complete" ) && !flag( "intro_sequence_complete" ) )
|
|
flag_wait( "intro_sequence_complete" );
|
|
|
|
if ( alien_mode_has( "outline" ) )
|
|
maps\mp\alien\_outline_proto::add_to_drill_preplant_watch_list( level.drill );
|
|
|
|
//using marker to kill the dropped alien drill model.
|
|
//TODO: remove "marker" when we get a proper drill model and the tags are correct for makeusable
|
|
if ( !is_true( level.automatic_drill ) )
|
|
level.drill thread drill_pickup_listener( marker );
|
|
|
|
level notify( "drill_spawned" );
|
|
|
|
}
|
|
|
|
enable_alt_drill_pickup( drill )
|
|
{
|
|
assert( isdefined( level.drill_use_trig ) );
|
|
level.drill_use_trig.origin = drill.origin + ( 0, 0, 24 );
|
|
}
|
|
|
|
disable_alt_drill_pickup()
|
|
{
|
|
assert( isdefined( level.drill_use_trig ) );
|
|
level.drill_use_trig.origin = level.drill_use_trig.original_origin;
|
|
}
|
|
|
|
// listen for pickup, updates icon from drill to carrier
|
|
drill_pickup_listener( marker )
|
|
{
|
|
// self is level.drill, the script model
|
|
self endon( "death" );
|
|
|
|
level endon( "game_ended" );
|
|
level endon( "new_drill" );
|
|
|
|
if ( isdefined( level.drill_use_trig ) )
|
|
use_trig = level.drill_use_trig;
|
|
else
|
|
use_trig= self;
|
|
|
|
if ( !is_true( level.prevent_drill_pickup ) )
|
|
{
|
|
// ======= SETUP FOR PICKUP =======
|
|
if ( isdefined( level.drill_use_trig ) )
|
|
{
|
|
level.drill_use_trig enable_alt_drill_pickup( self );
|
|
}
|
|
else
|
|
{
|
|
use_trig MakeUsable();
|
|
}
|
|
}
|
|
|
|
use_trig SetCursorHint( "HINT_ACTIVATE" );
|
|
use_trig SetHintString( &"ALIEN_COLLECTIBLES_PICKUP_BOMB" );
|
|
|
|
// ======= WAIT FOR PICKUP =======
|
|
while( true )
|
|
{
|
|
use_trig waittill( "trigger", owner );
|
|
|
|
if ( owner is_holding_deployable() )
|
|
{
|
|
owner setLowerMessage( "cant_buy", &"ALIEN_COLLECTIBLES_PLAYER_HOLDING", 3 );
|
|
continue;
|
|
}
|
|
|
|
if ( owner GetStance() == "prone" || owner GetStance() == "crouch" )
|
|
{
|
|
owner setLowerMessage( "change_stance", &"ALIENS_PATCH_CHANGE_STANCE", 3 );
|
|
continue;
|
|
}
|
|
if ( is_true ( owner.picking_up_item ) )
|
|
continue;
|
|
|
|
if ( is_true ( owner.isCarrying ) )
|
|
continue;
|
|
|
|
owner.has_special_weapon = true;
|
|
|
|
owner _disableUsability();
|
|
owner thread delayed_enable_usability();
|
|
|
|
if( isPlayer( owner ) )
|
|
break;
|
|
}
|
|
|
|
// ======= PICKED UP =======
|
|
// tell the world who picked up the drill
|
|
if ( alien_mode_has( "outline" ) )
|
|
maps\mp\alien\_outline_proto::remove_from_drill_preplant_watch_list( level.drill );
|
|
|
|
// move alternate drill pickup trigger far away
|
|
if ( isdefined( level.drill_use_trig ) )
|
|
level.drill_use_trig disable_alt_drill_pickup();
|
|
|
|
level notify( "drill_pickedup", owner );
|
|
self PlaySound( "extinction_item_pickup" );
|
|
|
|
level.drill_carrier = owner;
|
|
level.last_drill_pickup_origin = drop_to_ground( self.origin, 16, -32 ); // trace to ground, to prevent cascading offset
|
|
level.last_drill_pickup_angles = self.angles;
|
|
level.drill_carrier set_drill_icon( true );
|
|
self.state = "carried";
|
|
|
|
// player setup
|
|
owner thread drop_drill_on_death();
|
|
owner thread drop_drill_on_disconnect();
|
|
|
|
owner.lastweapon = owner GetCurrentWeapon();
|
|
owner _giveWeapon( "alienbomb_mp" );
|
|
|
|
owner SwitchToWeapon( "alienbomb_mp" );
|
|
owner DisableWeaponSwitch();
|
|
owner _disableOffhandWeapons();
|
|
|
|
// ======= CLEAN UP =======
|
|
// clean up drill marker model after pickup
|
|
if (IsDefined (marker) )
|
|
marker delete();
|
|
|
|
owner notify( "kill_spendhint" );
|
|
owner notify( "dpad_cancel" );
|
|
// removed from the world, also ends threads running on the pickupable object
|
|
self delete();
|
|
|
|
}
|
|
|
|
delayed_enable_usability()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
wait ( 1 );
|
|
self _enableUsability();
|
|
}
|
|
|
|
|
|
// drop drill when player so others can pick it up
|
|
drop_drill_on_death()
|
|
{
|
|
// self is player
|
|
level endon( "game_ended" );
|
|
level endon( "new_drill" ); // new drill was requested, old drill will be removed
|
|
level endon( "drill_planted" ); // drill left hand of owner
|
|
level endon( "drill_dropping" ); // drill left hand of owner
|
|
|
|
// only one instance of this per player
|
|
self notify( "watching_drop_drill_on_death" );
|
|
self endon( "watching_drop_drill_on_death" );
|
|
|
|
// either death or last stand mode
|
|
self waittill_either( "death", "last_stand" );
|
|
|
|
self Takeweapon( "alienbomb_mp" );
|
|
self EnableWeaponSwitch();
|
|
self SwitchToWeapon( self.lastWeapon );
|
|
self _enableOffhandWeapons();
|
|
level.drill_carrier = undefined;
|
|
|
|
assert( isdefined( self.last_death_pos ) );
|
|
|
|
//make sure the last_death_pos is actually on the ground
|
|
groundpos = GetGroundPosition( self.last_death_pos + (0,0,4 ),8 );
|
|
angles = self.angles;
|
|
|
|
if ( is_true ( self.kill_trigger_event_processed ) ) //player killed by kill trigger, don't drop the drill here
|
|
{
|
|
drill_spot = getClosest ( self.origin, level.killTriggerSpawnLocs );
|
|
groundpos = GetGroundPosition ( drill_spot.origin + ( 0,0,4 ),8 );
|
|
if ( !isDefined( drill_spot.angles ) )
|
|
drill_spot.angles = ( 0,0,0 );
|
|
angles = drill_spot.angles;
|
|
}
|
|
drop_drill( groundpos, angles );
|
|
}
|
|
|
|
//drop the drill when the owner disconnects while holding it
|
|
drop_drill_on_disconnect()
|
|
{
|
|
level endon( "drill_dropping" );
|
|
level endon( "game_ended" );
|
|
self endon( "death" );
|
|
self endon ( "last_stand" );
|
|
|
|
self waittill( "disconnect" );
|
|
|
|
playfx( level._effect[ "alien_teleport" ] , level.last_drill_pickup_origin );
|
|
playfx ( level._effect[ "alien_teleport_dist" ], level.last_drill_pickup_origin );
|
|
drop_drill ( level.last_drill_pickup_origin, level.last_drill_pickup_angles );
|
|
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( !isAlive ( player ) )
|
|
continue;
|
|
|
|
if ( player == self )
|
|
continue;
|
|
|
|
player setLowerMessage( "drill_overboard",&"ALIEN_COLLECTIBLES_DRILL_OUTOFPLAY",4 );
|
|
}
|
|
|
|
}
|
|
|
|
// teleport the drill if not near blocker
|
|
CONST_DRILL_TELEPORT_RANGE = 1250;
|
|
|
|
teleport_drill( pos )
|
|
{
|
|
wait 5; // padding, so hive destruction fx can finish
|
|
|
|
// only if drill is not carried and out of set range
|
|
if ( isdefined( level.drill ) && !isdefined( level.drill_carrier ) && ( distance( pos, level.drill.origin ) > CONST_DRILL_TELEPORT_RANGE ) )
|
|
{
|
|
pos = drop_to_ground( pos, 16, -64 ); // in case the struct is floating
|
|
level.drill angles_to_ground( pos, level.drill.angles, ( 0, 0, -4 ) ); // spawn drill oriented to ground normal
|
|
level.drill set_drill_icon();
|
|
enable_alt_drill_pickup( level.drill );
|
|
}
|
|
}
|
|
|
|
// loops until drilling is complete, handles being offline
|
|
drilling( pos, owner )
|
|
{
|
|
if ( isDefined( level.set_drill_state_drilling_override ) )
|
|
{
|
|
self thread [[level.set_drill_state_drilling_override]]( pos,owner );
|
|
return;
|
|
}
|
|
|
|
// self is hive location struct drill is drilling
|
|
self endon( "stop_listening" );
|
|
self endon( "drill_complete" );
|
|
|
|
// =======[STATE: PLANT]======= //
|
|
self thread set_drill_state_plant( pos, owner );
|
|
|
|
level.drill endon( "death" );
|
|
level.drill.owner = owner;
|
|
level.encounter_name = self.target;
|
|
level.drill.start_time = gettime(); // initial start time, in case drill is killed before it started
|
|
|
|
flag_set( "drill_drilling" );
|
|
|
|
// wait till unfold animation completes
|
|
level.drill waittill_any_timeout( 5, "drill_finished_plant_anim" );
|
|
|
|
// set timing parameters ( ex. depth, layers etc. )
|
|
self init_drilling_parameters();
|
|
|
|
// =======[STATE: RUN]======= //
|
|
level.drill.start_time = gettime(); // updated start time
|
|
self thread set_drill_state_run( owner );
|
|
|
|
self maps\mp\alien\_hive::hive_play_drill_planted_animations();
|
|
|
|
// wait till offline
|
|
level.drill waittill( "offline", attacker, damage );
|
|
|
|
// =======[STATE: OFF]======= //
|
|
self thread set_drill_state_offline();
|
|
|
|
flag_set( "drill_destroyed" );
|
|
|
|
wait 2;
|
|
maps\mp\gametypes\aliens::AlienEndGame( "axis", maps\mp\alien\_hud::get_end_game_string_index( "drill_destroyed" ) );
|
|
return;
|
|
}
|
|
|
|
set_drill_attack_setup()
|
|
{
|
|
synchDirections = [];
|
|
synchDirections["brute"][0] = set_attack_sync_direction( ( 0, 1, 0 ), "alien_drill_attack_drill_F_enter", "alien_drill_attack_drill_F_loop", "alien_drill_attack_drill_F_exit", "attack_drill_front", "attack_drill" );
|
|
synchDirections["brute"][1] = set_attack_sync_direction( ( -1, 0, 0 ), "alien_drill_attack_drill_R_enter", "alien_drill_attack_drill_R_loop", "alien_drill_attack_drill_R_exit", "attack_drill_right", "attack_drill" );
|
|
synchDirections["brute"][2] = set_attack_sync_direction( ( 1, 0, 0 ), "alien_drill_attack_drill_L_enter", "alien_drill_attack_drill_L_loop", "alien_drill_attack_drill_L_exit", "attack_drill_left", "attack_drill" );
|
|
synchDirections["goon"][0] = set_attack_sync_direction( ( 0, 1, 0 ), "alien_goon_drill_attack_drill_F_enter", "alien_goon_drill_attack_drill_F_loop", "alien_goon_drill_attack_drill_F_exit", "attack_drill_front", "attack_drill" );
|
|
synchDirections["goon"][1] = set_attack_sync_direction( ( -1, 0, 0 ), "alien_goon_drill_attack_drill_R_enter", "alien_goon_drill_attack_drill_R_loop", "alien_goon_drill_attack_drill_R_exit", "attack_drill_right", "attack_drill" );
|
|
synchDirections["goon"][2] = set_attack_sync_direction( ( 1, 0, 0 ), "alien_goon_drill_attack_drill_L_enter", "alien_goon_drill_attack_drill_L_loop", "alien_goon_drill_attack_drill_L_exit", "attack_drill_left", "attack_drill" );
|
|
|
|
endNotifies[0] = "offline";
|
|
endNotifies[1] = "death";
|
|
endNotifies[2] = "drill_complete";
|
|
endNotifies[3] = "destroyed";
|
|
|
|
self set_synch_attack_setup( synchDirections, true, endNotifies, undefined, ::drill_synch_attack_play_anim, ::drill_synch_attack_play_anim, ::drill_synch_attack_exit, "drill" );
|
|
}
|
|
|
|
drill_synch_attack_play_anim( anim_name )
|
|
{
|
|
level.drill ScriptModelClearAnim();
|
|
level.drill ScriptModelPlayAnim( anim_name );
|
|
}
|
|
|
|
drill_synch_attack_exit( anim_name, anim_length )
|
|
{
|
|
if ( IsDefined( anim_name ) )
|
|
{
|
|
level.drill ScriptModelClearAnim();
|
|
level.drill ScriptModelPlayAnim( anim_name );
|
|
wait anim_length;
|
|
}
|
|
|
|
if ( IsAlive( level.drill ) && !flag( "drill_detonated" ) )
|
|
{
|
|
level.drill ScriptModelClearAnim();
|
|
level.drill ScriptModelPlayAnim( "alien_drill_loop" );
|
|
}
|
|
}
|
|
|
|
use_alternate_drill()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
watch_to_repair( hive_struct )
|
|
{
|
|
self endon( "drill_complete" );
|
|
self endon( "death" );
|
|
hive_struct endon( "hive_dying" );
|
|
|
|
wait 5.0;
|
|
|
|
self MakeUnUsable();
|
|
|
|
CONST_DRILL_REPAIR_PAYMENT = 100;
|
|
CONST_DRILL_HEALTH_REPAIRED = 1000;
|
|
CONST_DRILL_REPAIR_BASE_TIME = 4000; // Time in ms for solo mode to repair drill
|
|
CONST_DRILL_PER_PLAYER_ADDITIONAL_TIME = 2000; //10 seconds total for 4 players
|
|
while ( 1 )
|
|
{
|
|
self MakeUnusable();
|
|
|
|
while ( 1 )
|
|
{
|
|
drill_health = ( self.health - CONST_HEALTH_INVULNERABLE ) / level.drill_health_hardcore;
|
|
|
|
if ( drill_health < 0.75 )
|
|
break;
|
|
|
|
wait ( 1 );
|
|
}
|
|
|
|
self MakeUsable();
|
|
|
|
if ( isDefined( level.drill_repair ) )
|
|
self SetHintString( level.drill_repair );
|
|
else
|
|
self SetHintString( &"ALIEN_COLLECTIBLES_DRILL_REPAIR" );
|
|
self waittill( "trigger", player );
|
|
|
|
if ( is_true ( player.iscarrying ) )
|
|
continue;
|
|
|
|
self SetHintString( "" );
|
|
|
|
player_count = level.players.size;
|
|
player.isRepairing = true;
|
|
level notify ("dlc_vo_notify","drill_repair", player);
|
|
use_time = int( CONST_DRILL_REPAIR_BASE_TIME * player perk_GetDrillTimeScalar() * player.drillSpeedModifier );
|
|
|
|
if( player_count > 1 )
|
|
use_time = int( ( CONST_DRILL_REPAIR_BASE_TIME + (( player_count - 1 ) * CONST_DRILL_PER_PLAYER_ADDITIONAL_TIME ) ) * player perk_GetDrillTimeScalar() * player.drillSpeedModifier );
|
|
|
|
|
|
result = self useHoldThink( player, use_time );
|
|
|
|
if( !result )
|
|
{
|
|
player.isRepairing = false;
|
|
continue;
|
|
}
|
|
|
|
if ( isdefined( level.drill_sfx_lp ) )
|
|
{
|
|
if ( isdefined( level.drill_overheat_lp_02 ))
|
|
level.drill_overheat_lp_02 StopLoopSound();
|
|
|
|
if ( !hive_struct is_door() && !hive_struct is_door_hive() && level.script != "mp_alien_dlc3" )
|
|
{
|
|
if( level.script == "mp_alien_last" )
|
|
level.drill_sfx_lp PlayLoopSound( "alien_conduit_on_lp" );
|
|
else
|
|
level.drill_sfx_lp PlayLoopSound( "alien_laser_drill_lp" );
|
|
}
|
|
}
|
|
|
|
level notify( "dlc_vo_notify","drill_repaired" , player);
|
|
level notify( "drill_repaired");
|
|
player.isRepairing = false;
|
|
|
|
// black box print
|
|
hive_struct thread drill_reset_BBPrint( player );
|
|
|
|
player maps\mp\alien\_persistence::give_player_currency( CONST_DRILL_REPAIR_PAYMENT );
|
|
self.health = level.drill_health_hardcore + CONST_HEALTH_INVULNERABLE;
|
|
level.drill_last_health = level.drill_health_hardcore + CONST_HEALTH_INVULNERABLE;
|
|
|
|
update_drill_health_HUD();
|
|
|
|
player.isRepairing = false;
|
|
|
|
// EoG tracking: drill restarts
|
|
player maps\mp\alien\_persistence::eog_player_update_stat( "drillrestarts", 1 );
|
|
|
|
wait 1.0;
|
|
}
|
|
|
|
}
|
|
|
|
// [!] function not to be used to reset drills not yet planted
|
|
set_drill_state_plant( pos, owner )
|
|
{
|
|
// self is hive location struct
|
|
// reset drill
|
|
if ( isdefined( level.drill ) )
|
|
{
|
|
level.drill delete();
|
|
level.drill = undefined;
|
|
}
|
|
|
|
// TODO: Replace with animated drill model
|
|
level.drill = spawn( "script_model", pos );
|
|
level.drill setmodel( CONST_DRILL_MODEL );
|
|
level.drill.state = "planted";
|
|
level.drill.angles = self.angles;
|
|
|
|
// Only allow synced attack when drilling a hive
|
|
if( !is_door())
|
|
level.drill set_drill_attack_setup();
|
|
|
|
if ( isDefined( level.drill_attack_setup_override ) ) //for overriding the default sync animations if necessary
|
|
level.drill [[level.drill_attack_setup_override ]]();
|
|
|
|
//level.drill thread angles_to_ground( pos, self.angles, ( 0, 0, 0 ) );
|
|
|
|
health = CONST_DRILL_HEALTH;
|
|
if ( use_alternate_drill() )
|
|
{
|
|
health = level.drill_health_hardcore;
|
|
level.drill thread watch_to_repair( self );
|
|
}
|
|
level.drill.maxhealth = CONST_HEALTH_INVULNERABLE + health;
|
|
level.drill.health = int( CONST_HEALTH_INVULNERABLE + ( health * owner perk_GetDrillHealthScalar() ) );
|
|
level.drill thread watch_drill_health_for_challenge();
|
|
|
|
if ( alien_mode_has( "outline" ) )
|
|
maps\mp\alien\_outline_proto::add_to_outline_drill_watch_list ( level.drill, 0 );
|
|
|
|
thread sfx_drill_plant();
|
|
|
|
// init depth marker
|
|
self.depth_marker = gettime();
|
|
|
|
level thread maps\mp\alien\_music_and_dialog::playVOForBombPlant(owner );
|
|
|
|
// remove drill icon
|
|
destroy_drill_icon();
|
|
|
|
// Normal drill enter anim
|
|
if( !is_door() && !is_door_hive() )
|
|
{
|
|
level.drill ScriptModelPlayAnim( "alien_drill_enter" );
|
|
wait 4;
|
|
}
|
|
else
|
|
{
|
|
//small wait here since there isn't a seperate unfolding/folding animation for the door drilling
|
|
wait .5;
|
|
}
|
|
|
|
level.drill notify( "drill_finished_plant_anim" );
|
|
}
|
|
watch_drill_health_for_challenge()
|
|
{
|
|
self endon( "drill_complete" );
|
|
self endon( "death" );
|
|
while ( 1 )
|
|
{
|
|
drill_health = ( level.drill.health - CONST_HEALTH_INVULNERABLE ) / level.drill_health_hardcore;
|
|
|
|
if ( drill_health < 0.5 )
|
|
{
|
|
maps\mp\alien\_challenge::update_challenge ( "no_stuck_drill" , false);
|
|
break;
|
|
}
|
|
wait ( 1 );
|
|
}
|
|
}
|
|
drill_threat_think()
|
|
{
|
|
// self is stronghold_loc struct
|
|
level endon( "game_ended" );
|
|
|
|
|
|
interval = 1; // seconds
|
|
while ( 1 )
|
|
{
|
|
if ( !isdefined( level.drill ) || !IsSentient( level.drill ) || !isAlive( level.drill ) )
|
|
{
|
|
wait interval;
|
|
continue;
|
|
}
|
|
|
|
if ( use_alternate_drill() )
|
|
{
|
|
self.drill.threatbias = -1000;
|
|
wait interval;
|
|
continue;
|
|
}
|
|
|
|
total_dist = 0;
|
|
players_available = 0;
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( isdefined( player ) && isalive( player ) )
|
|
{
|
|
players_available++;
|
|
total_dist += distance2D( player.origin, level.drill.origin );
|
|
}
|
|
}
|
|
|
|
// not enough players
|
|
if ( players_available == 0 )
|
|
{
|
|
// reset
|
|
level.drill.threatbias = int( CONST_DRILL_THREATBIAS_MIN );
|
|
wait interval;
|
|
continue;
|
|
}
|
|
|
|
average_dist = total_dist / max( 1, players_available );
|
|
|
|
if ( average_dist < CONST_DRILL_THREAT_RADIUS_MIN )
|
|
{
|
|
level.drill.threatbias = int( CONST_DRILL_THREATBIAS_MIN );
|
|
}
|
|
else if ( average_dist > CONST_DRILL_THREAT_RADIUS_MAX )
|
|
{
|
|
level.drill.threatbias = int( CONST_DRILL_THREATBIAS_MAX );
|
|
}
|
|
else
|
|
{
|
|
radius_value_range = CONST_DRILL_THREAT_RADIUS_MAX - CONST_DRILL_THREAT_RADIUS_MIN;
|
|
threat_value_range = CONST_DRILL_THREATBIAS_MAX - CONST_DRILL_THREATBIAS_MIN;
|
|
|
|
dist_ratio = ( average_dist - CONST_DRILL_THREAT_RADIUS_MIN ) / radius_value_range;
|
|
threat_delta = dist_ratio * threat_value_range;
|
|
|
|
level.drill.threatbias = int( CONST_DRILL_THREATBIAS_MIN + threat_delta );
|
|
}
|
|
|
|
wait interval;
|
|
}
|
|
}
|
|
|
|
set_drill_state_run( owner )
|
|
{
|
|
if ( isDefined( level.set_drill_state_run_override ) )
|
|
{
|
|
self thread [[level.set_drill_state_run_override]]( owner );
|
|
return;
|
|
}
|
|
// self is stronghold_loc struct
|
|
self endon( "death" );
|
|
self endon( "stop_listening" );
|
|
|
|
level.drill.state = "online";
|
|
level.drill notify( "online" );
|
|
|
|
// setup for attackable
|
|
level.drill setCanDamage( true );
|
|
level.drill MakeUnUsable();
|
|
level.drill SetHintString( "" );
|
|
|
|
health = CONST_DRILL_HEALTH;
|
|
if ( use_alternate_drill() )
|
|
{
|
|
health = level.drill_health_hardcore;
|
|
}
|
|
|
|
// reset attributes
|
|
level.drill.maxhealth = CONST_HEALTH_INVULNERABLE + health;
|
|
level.drill.health = int( CONST_HEALTH_INVULNERABLE + ( health * level.drill.owner perk_GetDrillHealthScalar() ) );
|
|
level.drill.threatbias = CONST_DRILL_THREATBIAS_MIN;
|
|
level.drill MakeEntitySentient( "allies" );
|
|
level.drill SetThreatBiasGroup( "drill" );
|
|
|
|
update_drill_health_HUD();
|
|
|
|
// tell aliens drill is up for attack!
|
|
foreach ( agent in level.agentArray )
|
|
{
|
|
if ( isdefined( agent.wave_spawned ) && agent.wave_spawned )
|
|
agent GetEnemyInfo( level.drill );
|
|
}
|
|
// play fx on drill when armed
|
|
laser_fx_tag_angles = level.drill GetTagAngles( "tag_laser" );
|
|
laser_fx_dir_forward = AnglesToForward( laser_fx_tag_angles );
|
|
laser_fx_dir_up = AnglesToUp( laser_fx_tag_angles );
|
|
|
|
laser_offset_dir = VectorCross(laser_fx_dir_forward,(0,0,1));
|
|
fx_loc = level.drill GetTagOrigin( "tag_laser_end" ) - ( 0, 0, 16 ) + (laser_offset_dir * 4 * -1) + (laser_fx_dir_forward * 1.0 * -1 );
|
|
laser_fx_loc = level.drill GetTagOrigin( "tag_laser" ) - ( 0, 0, 8 ) ;
|
|
|
|
level.drill.fxEnt = SpawnFx( level._effect[ "drill_laser_contact" ], fx_loc );
|
|
level.drill.fxLaserEnt = SpawnFx( level._effect[ "drill_laser" ], laser_fx_loc, laser_fx_dir_forward, laser_fx_dir_up );
|
|
// play loop sfx
|
|
door = ( self is_door() || self is_door_hive() );
|
|
thread sfx_drill_on(door);
|
|
|
|
// Play door drilling anim
|
|
if( is_door())
|
|
{
|
|
level notify( "drill_start_door_fx" );
|
|
level.drill ScriptModelPlayAnim( "alien_drill_open_door" ); // Door drilling anim
|
|
}
|
|
else if ( isDefined( level.custom_hive_logic ) )
|
|
{
|
|
level [[level.custom_hive_logic]]();
|
|
}
|
|
|
|
// Play drilling loop anim
|
|
else
|
|
{
|
|
TriggerFx( level.drill.fxEnt );
|
|
TriggerFx( level.drill.fxLaserEnt );
|
|
level.drill ScriptModelPlayAnim( "alien_drill_loop" );
|
|
}
|
|
|
|
// friendly fire and offline catch
|
|
self thread handle_bomb_damage();
|
|
|
|
// update time marker, to track running time, so it can be subtracted from total when it runs again
|
|
self.depth_marker = gettime();
|
|
|
|
// thread to watch for end of drilling
|
|
self thread monitor_drill_complete( self.depth );
|
|
self thread maps\mp\alien\_hive::hive_pain_monitor();
|
|
|
|
// set waypoint to defend location
|
|
self thread maps\mp\alien\_hive::set_hive_icon( "waypoint_alien_defend" );
|
|
|
|
// remove drill icon
|
|
destroy_drill_icon();
|
|
|
|
maps\mp\alien\_hud::turn_on_drill_meter_HUD( self.depth );
|
|
|
|
level thread watch_drill_depth_for_vo( self.depth );
|
|
}
|
|
|
|
watch_drill_depth_for_vo ( time )
|
|
{
|
|
level endon( "drill_detonated");
|
|
level endon( "game_ended" );
|
|
wait ( time/2 );
|
|
level thread maps\mp\alien\_music_and_dialog::playVOForDrillHalfway();
|
|
}
|
|
|
|
monitor_drill_complete( depth )
|
|
{
|
|
// self is stronghold_loc struct
|
|
self endon( "death" );
|
|
self endon( "stop_listening" );
|
|
|
|
level.drill endon( "offline" );
|
|
|
|
while ( self.layers.size > 0 )
|
|
{
|
|
layer_depth = self.layers[ self.layers.size - 1 ];
|
|
is_last_layer = self.layers.size == 1;
|
|
|
|
remaining_depth_to_layer = depth - layer_depth;
|
|
|
|
if ( is_last_layer )
|
|
self childthread maps\mp\alien\_music_and_dialog::playMusicBeforeReachLayer( remaining_depth_to_layer );
|
|
|
|
msg = "remaining_depth_to_layer is negative, ";
|
|
msg = msg + "[depth=" + depth + "][layer_depth="+ layer_depth +"][layer index="+ (self.layers.size - 1) +"]";
|
|
msg = msg + "[hive.origin=" + self.origin + "]";
|
|
assertex( remaining_depth_to_layer >= 0, msg );
|
|
|
|
self waittill_any_timeout( remaining_depth_to_layer, "force_drill_complete" );
|
|
|
|
// layer is reached
|
|
self.layer_completed++;
|
|
SetOmnvar( "ui_alien_drill_layer_completed", self.layer_completed );
|
|
self.layers = array_remove( self.layers, layer_depth );
|
|
depth = layer_depth;
|
|
reach_layer_earthquake();
|
|
if ( !self is_door() )
|
|
{
|
|
reach_layer_spawn_event( is_last_layer );
|
|
}
|
|
}
|
|
|
|
self notify( "drill_complete" );
|
|
level.drill notify( "drill_complete" );
|
|
level.encounter_name = undefined;
|
|
|
|
flag_clear( "drill_drilling" );
|
|
flag_set( "drill_detonated" );
|
|
//clear any repair progress bars leftover on the players
|
|
foreach ( player in level.players )
|
|
{
|
|
//ignore players who are in the process of reviving
|
|
if ( !isAlive ( player ) || is_true ( player.isReviving ) || is_true( player.being_revived ) )
|
|
continue;
|
|
|
|
player SetClientOmnvar( "ui_securing_progress",0 );
|
|
player SetClientOmnvar( "ui_securing",0);
|
|
}
|
|
SetOmnvar( "ui_alien_drill_state", 0 );
|
|
}
|
|
|
|
reach_layer_earthquake()
|
|
{
|
|
earthquake_intensity = 0.4;
|
|
warn_delay = 1.75;
|
|
|
|
if ( self is_door() )
|
|
{
|
|
earthquake_intensity = 0.15;
|
|
}
|
|
|
|
thread maps\mp\alien\_hive::warn_all_players( warn_delay, earthquake_intensity );
|
|
}
|
|
|
|
reach_layer_spawn_event( is_last_layer )
|
|
{
|
|
if ( is_last_layer )
|
|
return;
|
|
|
|
notify_msg = "reached_layer_" + self.layer_completed;
|
|
|
|
//TODO: re-enable when table tweaked
|
|
maps\mp\alien\_spawn_director::activate_spawn_event( notify_msg );
|
|
|
|
/#
|
|
if ( GetDvarInt( "alien_debug_director" ) > 0 )
|
|
IPrintLnBold( "activate_spawn_event: " + notify_msg );
|
|
#/
|
|
}
|
|
|
|
init_drilling_parameters()
|
|
{
|
|
if ( self is_door() )
|
|
{
|
|
//layers_info = level.cycle_data.cycle_drill_layers[level.current_cycle_num + 1];
|
|
self.depth = 30;//layers_info[ layers_info.size - 1 ]; // last entry in the layers
|
|
self.total_depth = self.depth; // .depth changes as we drill, total_depth never changes
|
|
self.layer_completed = 0;
|
|
|
|
self.layers[0] = 0;
|
|
|
|
// Send the table line info to LUA
|
|
SetOmnvar( "ui_alien_drill_layers_table_line", ( 599 + level.current_cycle_num + 1 ) );
|
|
SetOmnvar( "ui_alien_drill_layer_completed", self.layer_completed );
|
|
}
|
|
else
|
|
{
|
|
// init depths and layers
|
|
layers_info = level.cycle_data.cycle_drill_layers[level.current_cycle_num + 1];
|
|
self.depth = layers_info[ layers_info.size - 1 ]; // last entry in the layers
|
|
self.total_depth = self.depth; // .depth changes as we drill, total_depth never changes
|
|
self.layer_completed = 0;
|
|
|
|
self.layers[0] = 0;
|
|
for ( i = 0; i <= layers_info.size - 2; i++ )
|
|
self.layers[ self.layers.size ] = layers_info[ i ];
|
|
|
|
// Send the table line info to LUA
|
|
SetOmnvar( "ui_alien_drill_layers_table_line", ( 599 + level.current_cycle_num + 1 ) );
|
|
SetOmnvar( "ui_alien_drill_layer_completed", self.layer_completed );
|
|
}
|
|
}
|
|
|
|
set_drill_state_offline()
|
|
{
|
|
// self is stronghold_loc struct
|
|
self endon( "death" );
|
|
self endon( "stop_listening" );
|
|
|
|
level.drill.state = "offline";
|
|
//level.drill notify( "offline" ); // already notified by damage monitor
|
|
|
|
// delete flare fx
|
|
if ( Isdefined( level.drill.fxEnt) )
|
|
level.drill.fxEnt Delete();
|
|
|
|
if ( Isdefined( level.drill.fxLaserEnt) )
|
|
level.drill.fxLaserEnt Delete();
|
|
|
|
if( is_door())
|
|
{
|
|
level notify( "drill_stop_door_fx" );
|
|
}
|
|
|
|
// stop sfx loop
|
|
thread sfx_drill_offline();
|
|
|
|
// mark time
|
|
depth_delta = ( gettime() - self.depth_marker )/1000;
|
|
self.depth = max( 0, self.depth - depth_delta );
|
|
|
|
// plays non operate anim
|
|
level.drill ScriptModelPlayAnim( "alien_drill_operate_end" );
|
|
wait 1.4;
|
|
level.drill ScriptModelPlayAnim( "alien_drill_nonoperate" );
|
|
|
|
level.drill MakeUsable();
|
|
level.drill SetCursorHint( "HINT_ACTIVATE" );
|
|
level.drill SetHintString( &"ALIEN_COLLECTIBLES_PLANT_BOMB" );
|
|
|
|
level.drill setCanDamage( false );
|
|
level.drill FreeEntitySentient();
|
|
|
|
// rid the defend icon
|
|
self maps\mp\alien\_hive::destroy_hive_icon();
|
|
|
|
// set drill icon to signal player for reactivation
|
|
level.drill set_drill_icon();
|
|
|
|
// Make drill meter stop
|
|
SetOmnvar( "ui_alien_drill_state", 2 );
|
|
}
|
|
|
|
handle_bomb_damage()
|
|
{
|
|
// self is stronghold_loc struct
|
|
self endon( "death" );
|
|
self endon( "stop_listening" );
|
|
level endon( "hives_cleared" );
|
|
|
|
level.drill endon( "death" );
|
|
level.drill endon( "offline" ); // no need to monitor damages if offline
|
|
|
|
//setting this to 0 since it conflicts with the delay in the vo script itself
|
|
DRILL_HEALTH_VO_SPAM_DELAY = 0;
|
|
|
|
last_damage_time = GetTime();
|
|
level.drill_last_health = level.drill.health;
|
|
repair_hint1_given = false;
|
|
repair_hint2_given = false;
|
|
repair_hint3_given = false;
|
|
|
|
while ( 1 )
|
|
{
|
|
level.drill waittill( "damage", amount, attacker, direction_vec, point, meansOfDeath, modelName, tagName, partName, iDFlags, weapon );
|
|
|
|
if ( isDefined ( attacker ) && isAi( attacker ) )
|
|
{
|
|
level.drill_last_health = level.drill_last_health - amount;
|
|
}
|
|
else if ( isDefined ( weapon ) && weapon == "alien_minion_explosion" )
|
|
{
|
|
level.drill_last_health = level.drill_last_health - amount;
|
|
}
|
|
else
|
|
{
|
|
level.drill.health = level.drill_last_health;
|
|
continue;
|
|
}
|
|
|
|
if ( IsDefined( level.level_drill_damage_adjust_function ))
|
|
[[ level.level_drill_damage_adjust_function ]]( amount, attacker, weapon );
|
|
|
|
level.drill.health = level.drill_last_health;
|
|
|
|
/#
|
|
if ( GetDvarInt( "scr_debugdrilldamage", 0 ) == 1 )
|
|
{
|
|
if ( !isdefined( meansOfDeath ) )
|
|
meansOfDeath = "MOD_NONE";
|
|
|
|
if ( !isDefined( weapon ) )
|
|
weapon = "weapon_none";
|
|
|
|
if ( !isDefined( attacker ) )
|
|
atkr = "no_atkr";
|
|
else if ( isDefined( attacker ) && isDefined( attacker.model ) )
|
|
atkr = attacker.model;
|
|
else
|
|
atkr = "no_model";
|
|
|
|
println( "Drill damaged. MOD: " + meansOfDeath + " Wpn: " + weapon + " atkr: " + atkr + " dmg: " + amount + " remain: " + level.drill.health );
|
|
}
|
|
#/
|
|
|
|
//PlayFxOnTag( level._effect[ "bomb_impact" ], level.drill, "tag_origin" );
|
|
|
|
maps\mp\alien\_gamescore::update_team_encounter_performance( maps\mp\alien\_gamescore::get_drill_score_component_name(), "drill_damage_taken", amount );
|
|
|
|
maps\mp\alien\_alien_matchdata::inc_drill_heli_damages( amount );
|
|
|
|
|
|
// Play alien hit sound for DLC4 conduits [IWSIX-186485]
|
|
//if( IsDefined( attacker.team ) && attacker.team == "allies" )
|
|
if( level.script == "mp_alien_last" )
|
|
{
|
|
if( isDefined( attacker ) && (( !IsDefined( attacker.team ) || attacker.team == "axis" )))
|
|
{
|
|
//level notify("dlc_vo_notify", "conduit_attack");
|
|
self PlaySound("scn_dscnt_alien_pod_hit");
|
|
}
|
|
}
|
|
|
|
if ( level.drill.health < CONST_HEALTH_INVULNERABLE )
|
|
{
|
|
maps\mp\alien\_hud::update_drill_health( 0 );
|
|
// offline
|
|
level.drill notify( "offline", attacker, amount ); // this call ends this thread! aka return;
|
|
}
|
|
else
|
|
{
|
|
if ( !isdefined( self.icon ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// color scales to red when health is low
|
|
health_ratio = ( level.drill.health - CONST_HEALTH_INVULNERABLE ) / CONST_DRILL_HEALTH;
|
|
health_ratio = max( 0, min( 1, health_ratio ) );
|
|
health_ratio_sqr= health_ratio * health_ratio; // shows red earlier
|
|
green = health_ratio_sqr;
|
|
blue = green;
|
|
self.icon.color = ( 1, green, blue );
|
|
|
|
if ( use_alternate_drill() )
|
|
{
|
|
hardcore_ratio = ( level.drill.health - CONST_HEALTH_INVULNERABLE ) / level.drill_health_hardcore;
|
|
update_drill_health_HUD();
|
|
//maps\mp\alien\_hud::update_drill_health( int( hardcore_ratio * 100 ) );
|
|
if ( hardcore_ratio <= 0.75 && !repair_hint1_given )
|
|
{
|
|
if ( isDefined( level.drill_repair_hint ) )
|
|
IPrintLnBold ( level.drill_repair_hint );
|
|
else
|
|
iprintlnbold( &"ALIEN_COLLECTIBLES_DRILL_REPAIR_HINT" );
|
|
|
|
repair_hint1_given = true;
|
|
}
|
|
else if ( hardcore_ratio <= 0.5 && !repair_hint2_given )
|
|
{
|
|
if ( isDefined( level.drill_repair_hint ) )
|
|
IPrintLnBold ( level.drill_repair_hint );
|
|
else
|
|
iprintlnbold( &"ALIEN_COLLECTIBLES_DRILL_REPAIR_HINT" );
|
|
|
|
repair_hint2_given = true;
|
|
}
|
|
else if ( hardcore_ratio <= 0.25 && !repair_hint3_given)
|
|
{
|
|
if ( isDefined( level.drill_repair_hint_urgent ) )
|
|
IPrintLnBold ( level.drill_repair_hint_urgent );
|
|
else
|
|
IPrintLnbold( &"ALIEN_COLLECTIBLES_REACT_DRILL" );
|
|
|
|
repair_hint3_given = true;
|
|
}
|
|
|
|
if ( hardcore_ratio <= 0.25 )
|
|
self thread sfx_overheat();
|
|
|
|
if ( hardcore_ratio < 0.5 && ( GetTime() - last_damage_time > DRILL_HEALTH_VO_SPAM_DELAY ) )
|
|
level thread maps\mp\alien\_music_and_dialog::playVOforDrillHot();
|
|
else if ( GetTime() - last_damage_time > DRILL_HEALTH_VO_SPAM_DELAY )
|
|
level thread maps\mp\alien\_music_and_dialog::playVOForDrillDamaged();
|
|
|
|
last_damage_time = GetTime();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sfx_overheat()
|
|
{
|
|
if ( !is_door() && !is_door_hive() && level.script != "mp_alien_dlc3")
|
|
level.drill_sfx_lp StopLoopSound( "alien_laser_drill_lp" );
|
|
|
|
if (!IsDefined(level.drill_overheat_lp_02))
|
|
{
|
|
level.drill_overheat_lp_02 = Spawn( "script_origin", level.drill.origin );
|
|
level.drill_overheat_lp_02 LinkTo(level.drill);
|
|
|
|
// Turn off the normal loop, and play the damaged loop
|
|
if( level.script == "mp_alien_last" )
|
|
{
|
|
level.drill_sfx_lp StopLoopSound( "alien_conduit_on_lp" );
|
|
level.drill_overheat_lp_02 PlayLoopSound( "alien_conduit_damaged_lp" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
// FIXME: These should probably be moved up into the above if, but I dont want to modify previous levels
|
|
if ( level.script == "mp_alien_dlc3" )
|
|
level.drill_overheat_lp_02 PlayLoopSound( "alien_drill_scanner_overheat_lp" );
|
|
else
|
|
level.drill_overheat_lp_02 PlayLoopSound( "alien_laser_drill_overheat_lp" );
|
|
}
|
|
|
|
drill_detonate()
|
|
{
|
|
if ( isDefined( level.drill_detonate_override ) )
|
|
{
|
|
self thread [[level.drill_detonate_override]]();
|
|
return;
|
|
}
|
|
// rid hive icon if active
|
|
self maps\mp\alien\_hive::destroy_hive_icon();
|
|
|
|
self MakeUnusable();
|
|
self SetHintString( "" );
|
|
|
|
// to stop monitoring of drill layers
|
|
if ( alien_mode_has( "outline" ) )
|
|
maps\mp\alien\_outline_proto::remove_from_outline_drill_watch_list ( level.drill );
|
|
|
|
if ( !is_door() && !is_door_hive() ) //only play the death FX for normal hives
|
|
{
|
|
// Stop SFX
|
|
thread sfx_drill_off(false);
|
|
// final kill sequence
|
|
self thread kill_sequence();
|
|
}
|
|
|
|
// delete flare fx
|
|
if ( Isdefined( level.drill.fxEnt) )
|
|
level.drill.fxEnt Delete();
|
|
// delete laser fx
|
|
if ( Isdefined( level.drill.fxLaserEnt) )
|
|
level.drill.fxLaserEnt Delete();
|
|
|
|
if( is_door())
|
|
{
|
|
level notify( "drill_stop_door_fx" );
|
|
}
|
|
|
|
// plays non operate anim
|
|
level.drill ScriptModelClearAnim();
|
|
|
|
if( !is_door())
|
|
{
|
|
level.drill ScriptModelPlayAnim( "alien_drill_end" );
|
|
wait 3.8;
|
|
}
|
|
|
|
if ( !isdefined( self.last_hive ) || !self.last_hive )
|
|
{
|
|
org = level.drill.origin + ( 0, 0, 8 ); // this is the make sure drill trace starts above the ground
|
|
drop_drill( org, self.angles - ( 0, 90, 0 ) ); // rotation offset because static model is not the same orientation as the animated model... why?
|
|
}
|
|
|
|
if ( is_door() || is_door_hive() )
|
|
{
|
|
self delaythread( 3,::open_door );
|
|
}
|
|
else
|
|
self thread maps\mp\alien\_hive::delete_removables();
|
|
|
|
self thread remove_spawner();
|
|
self thread fx_ents_playfx();
|
|
|
|
self maps\mp\alien\_hive::show_dead_hive_model();
|
|
|
|
self thread do_radius_damage(); // To clean up any items stuck on top of hive
|
|
|
|
// drill self destruct if last hive
|
|
if ( isdefined( self.last_hive ) && self.last_hive )
|
|
{
|
|
flag_set( "hives_cleared" );
|
|
level thread detonate_drill_when_nuke_goes_off( self );
|
|
}
|
|
|
|
flag_clear( "drill_detonated" );
|
|
wait 8;
|
|
level thread maps\mp\alien\_music_and_dialog::playVOForBombDetonate( self );
|
|
}
|
|
|
|
do_radius_damage()
|
|
{
|
|
HIVE_EXPLODE_DAMAGE_RADIUS = 300;
|
|
|
|
foreach ( scriptable in self.scriptables )
|
|
{
|
|
RadiusDamage( scriptable.origin, HIVE_EXPLODE_DAMAGE_RADIUS, 0, 0, scriptable );
|
|
waitframe();
|
|
}
|
|
}
|
|
|
|
detonate_drill_when_nuke_goes_off( hive )
|
|
{
|
|
if ( isdefined( level.drill ) )
|
|
{
|
|
level.drill setCanDamage( false );
|
|
level.drill FreeEntitySentient();
|
|
level.drill MakeUnusable();
|
|
}
|
|
|
|
level waittill( "nuke_went_off" );
|
|
wait 1.5; // padding
|
|
|
|
// drill destroyed fx
|
|
destroyed_fx = level._effect[ "stronghold_explode_med" ];
|
|
fx_loc = hive.origin;
|
|
if ( isdefined( level.drill ) )
|
|
fx_loc = level.drill.origin;
|
|
|
|
playfx( destroyed_fx, fx_loc );
|
|
|
|
if ( isdefined( level.drill ) )
|
|
{
|
|
level.drill_carrier = undefined;
|
|
level.drill delete();
|
|
}
|
|
}
|
|
|
|
kill_sequence()
|
|
{
|
|
PlayFX( level._effect[ "stronghold_explode_large" ], self.origin );
|
|
if (!is_door())
|
|
{
|
|
self thread maps\mp\alien\_hive::sfx_destroy_hive();
|
|
}
|
|
|
|
if ( isAlive( level.drill ) )
|
|
{
|
|
foreach ( scriptable in self.scriptables )
|
|
{
|
|
scriptable thread maps\mp\alien\_hive::hive_explode(1);
|
|
waitframe();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
createUseEnt()
|
|
{
|
|
useEnt = Spawn( "script_origin", self.origin );
|
|
useEnt.curProgress = 0;
|
|
useEnt.useTime = 0;
|
|
useEnt.useRate = 1;
|
|
useEnt.inUse = false;
|
|
useEnt thread deleteUseEnt( self );
|
|
return useEnt;
|
|
}
|
|
|
|
deleteUseEnt( owner )
|
|
{
|
|
self endon ( "death" );
|
|
owner waittill( "death" );
|
|
self delete();
|
|
}
|
|
|
|
cancel_repair_on_hive_death( player )
|
|
{
|
|
player endon( "disconnect" );
|
|
|
|
self notify ( "cancel_repair_on_hive_death" );
|
|
self endon( "cancel_repair_on_hive_death" );
|
|
level endon ( "drill_repaired" );
|
|
|
|
self waittill( "drill_complete" );
|
|
|
|
|
|
if ( isAlive( player ) )
|
|
{
|
|
player notify( "drill_repair_weapon_management" );
|
|
|
|
if ( player.disabledWeapon > 0 )
|
|
player _enableWeapon();
|
|
|
|
if ( is_true ( player.hasprogressbar ) )
|
|
player.hasprogressbar = false;
|
|
|
|
player.isRepairing = false;
|
|
}
|
|
|
|
}
|
|
|
|
DRILL_USE_DISTANCE = 18496; // 136*136
|
|
useHoldThink( player, useTime )
|
|
{
|
|
// if ( IsPlayer( player ) )
|
|
// player playerLinkTo( self );
|
|
// else
|
|
// player LinkTo( self );
|
|
// player playerLinkedOffsetEnable();
|
|
|
|
self thread cancel_repair_on_hive_death( player );
|
|
|
|
self.curProgress = 0;
|
|
self.inUse = true;
|
|
self.useRate = 1;
|
|
|
|
if ( IsDefined( useTime ) )
|
|
self.useTime = useTime;
|
|
else
|
|
self.useTime = 3000;
|
|
|
|
//player _disableWeapon();
|
|
|
|
if( !player maps\mp\alien\_perk_utility::has_perk( "perk_rigger", [ 0,1,2,3,4 ] ) )
|
|
player disable_weapon_timeout( ( useTime + 0.05 ), "drill_repair_weapon_management" );
|
|
|
|
player thread personalUseBar( self );
|
|
|
|
player.hasprogressbar = true;
|
|
|
|
result = useHoldThinkLoop( player, self, DRILL_USE_DISTANCE );
|
|
|
|
assert ( IsDefined( result ) );
|
|
|
|
if ( isAlive( player ) )
|
|
{
|
|
player.hasprogressbar = false;
|
|
if( !player maps\mp\alien\_perk_utility::has_perk( "perk_rigger", [ 0,1,2,3,4 ] ) )
|
|
player enable_weapon_wrapper( "drill_repair_weapon_management" );
|
|
}
|
|
|
|
if ( !IsDefined( self ) )
|
|
return false;
|
|
|
|
self.inUse = false;
|
|
self.curProgress = 0;
|
|
|
|
return ( result );
|
|
}
|
|
|
|
personalUseBar( object )
|
|
{
|
|
UI_DRILL_REPAIR = 2;
|
|
if ( level.script == "mp_alien_last" )
|
|
UI_DRILL_REPAIR = 7; //indexes defined & explained in AlienCapturingHud.lua
|
|
|
|
self endon( "disconnect" );
|
|
self SetClientOmnvar( "ui_securing",UI_DRILL_REPAIR );
|
|
|
|
lastRate = -1;
|
|
while ( isReallyAlive( self ) && IsDefined( object ) && object.inUse && !level.gameEnded )
|
|
{
|
|
if ( lastRate != object.useRate )
|
|
{
|
|
if( object.curProgress > object.useTime)
|
|
object.curProgress = object.useTime;
|
|
}
|
|
|
|
lastRate = object.useRate;
|
|
self SetClientOmnvar( "ui_securing_progress",object.curProgress / object.useTime );
|
|
wait ( 0.05 );
|
|
}
|
|
|
|
self SetClientOmnvar( "ui_securing_progress",0 );
|
|
self SetClientOmnvar( "ui_securing",0);
|
|
}
|
|
|
|
useHoldThinkLoop( player,ent, dist_check )
|
|
{
|
|
while( !level.gameEnded && IsDefined( self ) && isReallyAlive( player ) && player useButtonPressed() && ( !isdefined( player.lastStand ) || !player.lastStand ) && self.curProgress < self.useTime )
|
|
{
|
|
drill_health = ( self.health - CONST_HEALTH_INVULNERABLE ) / level.drill_health_hardcore;
|
|
if ( drill_health <= 0 )
|
|
return false;
|
|
|
|
if ( isDefined ( ent ) && isDefined ( dist_check) )
|
|
{
|
|
if ( distancesquared ( player.origin,ent.origin ) > dist_check )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
self.curProgress += (50 * self.useRate);
|
|
self.useRate = 1;
|
|
|
|
if ( self.curProgress >= self.useTime )
|
|
return ( isReallyAlive( player ) );
|
|
|
|
wait 0.05;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// ================= utilities ==================
|
|
|
|
draw_line( from, to, color, frames )
|
|
{
|
|
//level endon( "helicopter_done" );
|
|
if( isdefined( frames ) )
|
|
{
|
|
for( i=0; i<frames; i++ )
|
|
{
|
|
line( from, to, color );
|
|
wait 0.05;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( ;; )
|
|
{
|
|
line( from, to, color );
|
|
wait 0.05;
|
|
}
|
|
}
|
|
}
|
|
|
|
angles_to_ground( pos, ang, offset )
|
|
{
|
|
start = pos + ( 0, 0, 16 );
|
|
end = pos - ( 0, 0, 64 );
|
|
trace = BulletTrace( start, end, false, self );
|
|
trace_vec = trace[ "normal" ] * ( -1 ); // face up
|
|
|
|
trace_angles = VectorToAngles( trace_vec );
|
|
angle_delta = VectorToAngles( AnglesToUp( trace_angles ) )[ 1 ] - VectorToAngles( AnglesToForward( ang ) )[ 1 ];
|
|
|
|
// rotate around entity's local Z axis
|
|
up = VectorNormalize( trace_vec );
|
|
forward = VectorNormalize( AnglesToUp( VectorToAngles( trace_vec ) ) );
|
|
right = VectorNormalize( AnglesToRight( VectorToAngles( trace_vec ) ) );
|
|
forward = RotatePointAroundVector( up, forward, angle_delta - 90 ); // -90 for the drill
|
|
right = RotatePointAroundVector( up, right, angle_delta - 90 );
|
|
|
|
/*
|
|
/#
|
|
thread draw_line( pos, pos + forward*32, (1,0,0), 20000 );
|
|
thread draw_line( pos, pos + right*32, (0,1,0), 20000 );
|
|
#/
|
|
*/
|
|
|
|
self.angles = AxisToAngles( forward, right, up );
|
|
if ( abs ( self.angles[2] ) > 45 )
|
|
{
|
|
self.angles = ( self.angles[0], self.angles[1], 0 );
|
|
}
|
|
if ( abs ( self.angles[0] ) > 45 )
|
|
{
|
|
self.angles = ( 0, self.angles[1], self.angles[2] );
|
|
}
|
|
|
|
|
|
self.origin = pos + offset;
|
|
}
|
|
|
|
//==============================================================================
|
|
// Bomb viewmodel carry and replace weapons when bomb is planted or dropped
|
|
//==============================================================================
|
|
//
|
|
watchBomb()
|
|
{
|
|
level endon( "game_ended" );
|
|
self endon( "death" );
|
|
self endon( "disconnect" );
|
|
|
|
// remove bomb on player spawn, no way they can spawn with one by default currently
|
|
if ( self hasweapon( "alienbomb_mp" ) )
|
|
{
|
|
self TakeWeapon( "alienbomb_mp" );
|
|
self EnableWeaponSwitch();
|
|
}
|
|
|
|
while ( 1 )
|
|
{
|
|
self waittill( "grenade_fire", alienbomb, weapname );
|
|
if ( weapname == "alienbomb" || weapname == "alienbomb_mp" )
|
|
{
|
|
alienbomb.owner = self;
|
|
alienbomb SetOtherEnt(self);
|
|
alienbomb.team = self.team;
|
|
|
|
alienbomb thread watchBombStuck( self );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//Watcher for the dropped bomb to stick then spawns a new script_model bomb at the location of the dropped bomb
|
|
watchBombStuck( owner )
|
|
{
|
|
// self == alienbomb projectile
|
|
level endon( "game_ended" );
|
|
//self endon( "death" ); // if deleted or died
|
|
|
|
owner endon( "death" );
|
|
owner endon( "disconnect" );
|
|
|
|
self Hide();
|
|
self waittill_any_timeout( .05, "missile_stuck" );
|
|
|
|
//try to put it on the ground
|
|
//secTrace = bulletTrace( owner.origin + (0,0,8 ) , owner.origin - (0, 0, 16 ), false, self , true ,false, true );
|
|
secTrace = self AIPhysicsTrace ( owner.origin + ( 0,0,8 ),owner.origin - ( 0,0,12 ),undefined,undefined,true,true );
|
|
if( secTrace["fraction"] == 1 )
|
|
{
|
|
owner TakeWeapon( "alienbomb_mp" );
|
|
owner GiveWeapon( "alienbomb_mp" );
|
|
// there's nothing under us so don't place the drill up in the air
|
|
owner SetWeaponAmmoStock( "alienbomb_mp", owner GetWeaponAmmoStock( "alienbomb_mp" ) + 1 );
|
|
owner SwitchToWeapon( "alienbomb_mp" );
|
|
self delete();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
self.origin = secTrace["position"];
|
|
parent = secTrace["entity"];
|
|
}
|
|
|
|
self.angles *= (0,1,1);
|
|
//self.origin = self.origin;
|
|
level notify( "drill_dropping" );
|
|
|
|
// auto plant if dropped close to target
|
|
foreach ( destroy_loc in level.stronghold_hive_locs )
|
|
{
|
|
if ( destroy_loc maps\mp\alien\_hive::is_blocker_hive() )
|
|
continue;
|
|
|
|
if ( !destroy_loc maps\mp\alien\_hive::dependent_hives_removed() )
|
|
continue;
|
|
|
|
if ( distance( destroy_loc.origin, self.origin ) < 80 )
|
|
{
|
|
// auto plant
|
|
destroy_loc notify( "trigger", owner );
|
|
Earthquake( .25,.5,self.origin,128 );
|
|
owner TakeWeapon( "alienbomb_mp" );
|
|
if ( !owner has_special_weapon() )
|
|
owner EnableWeaponSwitch();
|
|
|
|
owner restore_last_weapon();
|
|
owner _enableOffhandWeapons();
|
|
|
|
self delete();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( isDefined( level.watch_bomb_stuck_override ) ) //for checking when the drill is dropped near *other* things that may not be a hive struct ( like the platform bot in Beacon )
|
|
{
|
|
if ( [[level.watch_bomb_stuck_override]]( owner ) )
|
|
return;
|
|
}
|
|
|
|
drop_drill( self.origin, self.angles, self );
|
|
Earthquake( .25,.5,self.origin,128 );
|
|
|
|
owner TakeWeapon( "alienbomb_mp" );
|
|
if ( !owner has_special_weapon() )
|
|
owner EnableWeaponSwitch();
|
|
|
|
owner restore_last_weapon();
|
|
owner _enableOffhandWeapons();
|
|
|
|
level thread maps\mp\alien\_outline_proto::update_drill_outline();
|
|
|
|
self delete();
|
|
|
|
}
|
|
|
|
restore_last_weapon()
|
|
{
|
|
if ( self.lastweapon != "aliendeployable_crate_marker_mp" )
|
|
self SwitchToWeapon( self.lastweapon );
|
|
else
|
|
self SwitchToWeapon ( self GetWeaponsListPrimaries()[0] );
|
|
}
|
|
|
|
//=======================================================
|
|
// HUD - Icons
|
|
//=======================================================
|
|
|
|
// player bomb carry init on player spawn - No longer used TODO : Remove this
|
|
player_carry_bomb_init()
|
|
{
|
|
// self is player
|
|
if ( !isdefined( self.carryIcon ) )
|
|
{
|
|
if ( level.splitscreen )
|
|
{
|
|
self.carryIcon = createIcon( "hud_suitcase_bomb", 33, 33 );
|
|
self.carryIcon setPoint( "BOTTOM RIGHT", "BOTTOM RIGHT", -50, -78 );
|
|
}
|
|
else
|
|
{
|
|
self.carryIcon = createIcon( "hud_suitcase_bomb", 50, 50 );
|
|
self.carryIcon setPoint( "BOTTOM RIGHT", "BOTTOM RIGHT", -50, -65 );
|
|
}
|
|
|
|
self.carryIcon.hidewheninmenu = true;
|
|
self thread hideCarryIconOnGameEnd();
|
|
}
|
|
|
|
self.carryIcon.alpha = 0;
|
|
}
|
|
|
|
hideCarryIconOnGameEnd()
|
|
{
|
|
self endon( "disconnect" );
|
|
|
|
level waittill( "game_ended" );
|
|
|
|
if ( isDefined( self.carryIcon ) )
|
|
self.carryIcon.alpha = 0;
|
|
}
|
|
|
|
set_drill_icon( link )
|
|
{
|
|
level notify( "new_bomb_icon" );
|
|
|
|
// destroy in case we used to link
|
|
destroy_drill_icon( self );
|
|
|
|
if ( !isDefined ( link ) || !link )
|
|
{
|
|
level.drill_icon = NewHudElem();
|
|
level.drill_icon SetShader( "waypoint_alien_drill", 14, 14 );
|
|
level.drill_icon.color = ( 1, 1, 1 );
|
|
level.drill_icon SetWayPoint( true, true );
|
|
level.drill_icon.sort = 1;
|
|
level.drill_icon.foreground = true;
|
|
level.drill_icon.alpha = 0.5;
|
|
level.drill_icon.x = self.origin[ 0 ];
|
|
level.drill_icon.y = self.origin[ 1 ];
|
|
level.drill_icon.z = self.origin[ 2 ] + 72;
|
|
}
|
|
else
|
|
{
|
|
self maps\mp\_entityheadIcons::setHeadIcon( self.team, "waypoint_alien_drill", (0,0,72), 4, 4, undefined, undefined, undefined, true, undefined, false );
|
|
}
|
|
}
|
|
|
|
destroy_drill_icon( ent )
|
|
{
|
|
if ( isdefined( level.drill_icon ) )
|
|
level.drill_icon Destroy();
|
|
|
|
if ( !isDefined ( ent ) )
|
|
return;
|
|
|
|
remove_headicons_from_players();
|
|
}
|
|
|
|
remove_headicons_from_players()
|
|
{
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( isDefined ( player.entityHeadIcons ) )
|
|
{
|
|
foreach ( key, headIcon in player.entityHeadIcons ) //remove any head icons
|
|
{
|
|
// TODO: remove and fix properly after ship
|
|
if( !isDefined(headIcon) ) //needed for FFA host migration (when host has active head icons)
|
|
continue;
|
|
|
|
headIcon destroy();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//=======================================================
|
|
// Helpers
|
|
//=======================================================
|
|
|
|
remove_spawner()
|
|
{
|
|
if ( IsDefined( self.script_linkto ) )
|
|
maps\mp\alien\_spawn_director::remove_spawn_location( self.script_linkto );
|
|
}
|
|
|
|
fx_ents_playfx()
|
|
{
|
|
// self is stronghold_loc script model
|
|
assert( isdefined( self.fx_ents ) );
|
|
|
|
foreach ( fx_ent in self.fx_ents )
|
|
{
|
|
playfx( level._effect[ "stronghold_explode_med" ], fx_ent.origin );
|
|
fx_ent delete();
|
|
}
|
|
}
|
|
|
|
//=======================================================
|
|
// Audio
|
|
//=======================================================
|
|
sfx_drill_plant()
|
|
{
|
|
drill = get_drill_entity();
|
|
//wait 0.1;
|
|
drill PlaySound( "alien_laser_drill_plant" );
|
|
}
|
|
|
|
sfx_drill_on(door)
|
|
{
|
|
wait 0.1;
|
|
|
|
drill = get_drill_entity();
|
|
|
|
if (!IsDefined(level.drill_sfx_lp))
|
|
{
|
|
level.drill_sfx_lp = Spawn( "script_origin", drill.origin );
|
|
level.drill_sfx_lp LinkTo(drill);
|
|
}
|
|
|
|
if (!IsDefined(level.drill_sfx_dist_lp))
|
|
{
|
|
level.drill_sfx_dist_lp = Spawn( "script_origin", drill.origin );
|
|
level.drill_sfx_dist_lp LinkTo( drill );
|
|
}
|
|
|
|
wait 0.1;
|
|
|
|
if (door)
|
|
{
|
|
wait 3.76;
|
|
//IPrintLnBold("Drilling a door");
|
|
if ( isDefined ( level.drill_sfx_lp ) )
|
|
level.drill_sfx_lp PlayLoopSound("alien_laser_drill_door_lp");
|
|
|
|
if ( isDefined ( level.drill_sfx_dist_lp ) )
|
|
level.drill_sfx_dist_lp PlayLoopSound("alien_laser_drill_door_dist_lp");
|
|
}
|
|
else
|
|
{
|
|
//IPrintLnBold("Drilling a hive");
|
|
if ( isDefined ( level.drill_sfx_lp ) )
|
|
level.drill_sfx_lp PlayLoopSound("alien_laser_drill_lp");
|
|
|
|
if ( isDefined ( level.drill_sfx_dist_lp ) )
|
|
level.drill_sfx_dist_lp PlayLoopSound("alien_laser_drill_dist_lp");
|
|
}
|
|
}
|
|
|
|
sfx_drill_off(door)
|
|
{
|
|
drill = get_drill_entity();
|
|
coord = drill.origin;
|
|
|
|
if (!door)
|
|
drill PlaySound("alien_laser_drill_stop");
|
|
else
|
|
playSoundAtPos( coord, "alien_laser_drill_stop");
|
|
|
|
if (IsDefined(level.drill_sfx_lp))
|
|
level.drill_sfx_lp delete();
|
|
|
|
if (IsDefined(level.drill_sfx_dist_lp))
|
|
level.drill_sfx_dist_lp delete();
|
|
|
|
if (IsDefined(level.drill_overheat_lp))
|
|
level.drill_overheat_lp delete();
|
|
|
|
if (IsDefined(level.drill_overheat_lp_02))
|
|
level.drill_overheat_lp_02 delete();
|
|
|
|
if (door)
|
|
{
|
|
wait 2.7;
|
|
playSoundAtPos( coord, "alien_laser_drill_door_open");
|
|
}
|
|
}
|
|
|
|
sfx_drill_offline()
|
|
{
|
|
drill = get_drill_entity();
|
|
|
|
if ( level.script == "mp_alien_dlc3" )
|
|
level.drill PlaySound("alien_drill_scanner_shutdown");
|
|
else
|
|
drill PlaySound("alien_laser_drill_shutdown");
|
|
|
|
if (IsDefined(level.drill_sfx_lp))
|
|
level.drill_sfx_lp delete();
|
|
|
|
if (IsDefined(level.drill_sfx_dist_lp))
|
|
level.drill_sfx_dist_lp delete();
|
|
|
|
if (IsDefined(level.drill_overheat_lp_02))
|
|
level.drill_overheat_lp_02 delete();
|
|
}
|
|
|
|
// ===============================================================================
|
|
// Black box prints for drill
|
|
// ===============================================================================
|
|
|
|
drill_plant_BBprint( player )
|
|
{
|
|
// self is hive struct
|
|
self drill_generic_BBPrint( "aliendrillplant", player );
|
|
}
|
|
|
|
drill_reset_BBPrint( player )
|
|
{
|
|
// self is hive struct
|
|
self drill_generic_BBPrint( "aliendrillreset", player );
|
|
}
|
|
|
|
drill_generic_BBPrint( BBprint_string, player )
|
|
{
|
|
// self is hive struct
|
|
cyclenum = level.current_cycle_num;
|
|
|
|
hivename = "unknown hive";
|
|
if ( isdefined( self.target ) )
|
|
hivename = self.target;
|
|
|
|
playtime = gettime() - level.startTime;
|
|
|
|
planter = "unknown player";
|
|
if ( isdefined( player.name ) )
|
|
planter = player.name;
|
|
|
|
playernum = level.players.size;
|
|
|
|
planterperk0 = player maps\mp\alien\_persistence::get_selected_perk_0();
|
|
planterperk0level = player maps\mp\alien\_persistence::get_perk_0_level();
|
|
|
|
planterperk1 = player maps\mp\alien\_persistence::get_selected_perk_1();
|
|
planterperk1level = player maps\mp\alien\_persistence::get_perk_1_level();
|
|
|
|
healthratio = -1;
|
|
if ( isdefined( level.drill ) && isdefined( level.drill.health ) && isdefined( level.drill_health_hardcore ) )
|
|
healthratio = ( level.drill.health - CONST_HEALTH_INVULNERABLE ) / level.drill_health_hardcore;
|
|
|
|
/#
|
|
if ( GetDvarInt( "alien_bbprint_debug" ) > 0 )
|
|
{
|
|
IPrintLnBold( "^8bbprint: " + BBprint_string + "\n" +
|
|
" cyclenum=" + cyclenum +
|
|
" hivename=" + hivename +
|
|
" playtime=" + playtime +
|
|
" drillhealth=" + healthratio +
|
|
" repairer=" + planter +
|
|
" repairerperk0=" + planterperk0 +
|
|
" repairerperk1=" + planterperk1 +
|
|
" repairerperk0level=" + planterperk0level +
|
|
" repairerperk1level=" + planterperk1level +
|
|
" playernum=" + playernum );
|
|
}
|
|
#/
|
|
|
|
bbprint( BBprint_string,
|
|
"cyclenum %i hivename %s playtime %f drillhealth %f repairer %s repairerperk0 %s repairerperk1 %s repairerperk0level %s repairerperk1level %s playernum %i ",
|
|
cyclenum,
|
|
hivename,
|
|
playtime,
|
|
healthratio,
|
|
planter,
|
|
planterperk0,
|
|
planterperk1,
|
|
planterperk0level,
|
|
planterperk1level,
|
|
playernum );
|
|
}
|
|
|
|
check_for_player_near_hive_with_drill()
|
|
{
|
|
/#
|
|
if ( alien_mode_has( "nogame" ) )
|
|
return;
|
|
#/
|
|
|
|
if ( is_true ( level.automatic_drill ) ) //break out of this if not needed
|
|
return;
|
|
|
|
self endon( "disconnect" );
|
|
check_distance = 80*80;
|
|
while ( 1 )
|
|
{
|
|
while ( !flag( "drill_drilling" ) )
|
|
{
|
|
if ( ( isDefined ( self.inlaststand ) && self.inlaststand ) || flag ( "drill_drilling" ) || isDefined ( self.usingRemote ) || is_true ( self.isCarrying ) )
|
|
{
|
|
wait ( .05 );
|
|
continue;
|
|
}
|
|
|
|
foreach ( destroy_loc in level.stronghold_hive_locs )
|
|
{
|
|
if ( destroy_loc maps\mp\alien\_hive::is_blocker_hive() )
|
|
continue;
|
|
|
|
if ( !destroy_loc maps\mp\alien\_hive::dependent_hives_removed() )
|
|
continue;
|
|
|
|
if ( distancesquared( destroy_loc.origin, self.origin ) < check_distance )
|
|
{
|
|
if ( ( !isDefined ( level.drill_carrier ) ) || isDefined ( level.drill_carrier ) && level.drill_carrier != self )
|
|
{
|
|
self setLowerMessage( "need_drill",&"ALIEN_COLLECTIBLES_NEED_DRILL",undefined,10 );
|
|
while( player_should_see_drill_hint( destroy_loc,check_distance,true ) )
|
|
{
|
|
wait ( .05 );
|
|
}
|
|
self clearLowerMessage ( "need_drill" );
|
|
}
|
|
else
|
|
{
|
|
self setLowerMessage( "plant_drill",&"ALIEN_COLLECTIBLES_PLANT_BOMB",undefined,10 );
|
|
while( player_should_see_drill_hint( destroy_loc,check_distance,false ) )
|
|
{
|
|
wait ( .05 );
|
|
}
|
|
self clearLowerMessage( "plant_drill" );
|
|
}
|
|
}
|
|
}
|
|
wait ( .05 );
|
|
}
|
|
|
|
flag_waitopen( "drill_drilling" );
|
|
}
|
|
}
|
|
|
|
player_should_see_drill_hint( destroy_loc,check_distance, ignore_carrying_check )
|
|
{
|
|
if ( distancesquared( destroy_loc.origin, self.origin ) > check_distance )
|
|
return false;
|
|
|
|
if ( flag ( "drill_drilling" ) )
|
|
return false;
|
|
|
|
if ( self.inlaststand )
|
|
return false;
|
|
|
|
if ( isDefined ( self.usingRemote ) )
|
|
return false;
|
|
|
|
if ( is_true ( ignore_carrying_check ) )
|
|
return true;
|
|
else if ( is_true ( self.isCarrying ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
get_drill_entity()
|
|
{
|
|
|
|
if ( isDefined( level.drill.vehicle ) )
|
|
return level.drill.vehicle;
|
|
else
|
|
return level.drill;
|
|
}
|
|
|
|
open_door()
|
|
{
|
|
level notify( "door_opening" , self.target );
|
|
foreach ( ent in self.removeables )
|
|
{
|
|
if ( isdefined( ent ) )
|
|
{
|
|
if( ent.classname == "script_model" )
|
|
{
|
|
ent thread slide_open();
|
|
}
|
|
else
|
|
{
|
|
if( ent.classname == "script_brushmodel" )
|
|
{
|
|
ent ConnectPaths();
|
|
}
|
|
ent delete();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
slide_open()
|
|
{
|
|
if ( !isDefined( self.script_angles ) )
|
|
self delete();
|
|
else
|
|
self moveto ( self.origin + self.script_angles, 1 );
|
|
}
|
|
|
|
wait_for_drill_plant()
|
|
{
|
|
// self is hive location struct, where we allow planting of drill
|
|
self endon( "stop_listening" );
|
|
|
|
//self MakeUsable();
|
|
//self SetCursorHint( "HINT_NOICON" );
|
|
//self SetHintString( "" );
|
|
|
|
while( true )
|
|
{
|
|
self waittill( "trigger", player );
|
|
|
|
if ( !is_true ( level.automatic_drill ) && ( !isdefined( level.drill_carrier ) || level.drill_carrier != player ) )
|
|
{
|
|
player setLowerMessage( "no_bomb", &"ALIEN_COLLECTIBLES_NO_BOMB", 5 );
|
|
wait 0.05;
|
|
continue;
|
|
}
|
|
|
|
if( isPlayer( player ) )
|
|
{
|
|
if( !is_true ( level.automatic_drill ) )
|
|
{
|
|
// clear lower message hint to plant bomb
|
|
player clearLowerMessage( "go_plant" );
|
|
|
|
// remove the bomb and give the player back his last weapon
|
|
player TakeWeapon( "alienbomb_mp" );
|
|
if ( !player has_special_weapon() )
|
|
{
|
|
player EnableWeaponSwitch();
|
|
}
|
|
|
|
if(!isdefined(level.non_player_drill_plant_check) || ![[level.non_player_drill_plant_check]]())
|
|
{
|
|
player SwitchToWeapon( player.lastweapon );
|
|
}
|
|
|
|
self MakeUnusable();
|
|
self SetHintString( "" );
|
|
maps\mp\alien\_drill::remove_headicons_from_players();
|
|
}
|
|
|
|
earthquake_intensity = 0.4;
|
|
warn_delay = 1.75;
|
|
thread maps\mp\alien\_hive::warn_all_players( warn_delay, earthquake_intensity );
|
|
|
|
// EoG tracking: drill plants
|
|
player maps\mp\alien\_persistence::eog_player_update_stat( "drillplants", 1 );
|
|
|
|
level notify( "drill_planted", player, self );
|
|
|
|
return player;
|
|
}
|
|
}
|
|
}
|
|
|
|
update_drill_health_HUD()
|
|
{
|
|
drill_health = int( ( level.drill.health - CONST_HEALTH_INVULNERABLE ) / level.drill_health_hardcore * 100 );
|
|
maps\mp\alien\_hud::update_drill_health( drill_health );
|
|
} |