#include maps/mp/gametypes/_dev; #include maps/mp/gametypes/_hud; #include maps/mp/killstreaks/_radar; #include maps/mp/killstreaks/_dogs; #include maps/mp/_scoreevents; #include maps/mp/_challenges; #include maps/mp/killstreaks/_remote_weapons; #include maps/mp/gametypes/_spawning; #include maps/mp/_entityheadicons; #include maps/mp/killstreaks/_emp; #include maps/mp/killstreaks/_killstreakrules; #include maps/mp/gametypes/_spawnlogic; #include maps/mp/killstreaks/_airsupport; #include maps/mp/killstreaks/_supplydrop; #include maps/mp/killstreaks/_killstreaks; #include common_scripts/utility; #include maps/mp/gametypes/_weapons; #include maps/mp/_utility; #using_animtree( "mp_vehicles" ); init() { precachevehicle( "ai_tank_drone_mp" ); precachemodel( "veh_t6_drone_tank" ); precachemodel( "veh_t6_drone_tank_alt" ); precacheitem( "ai_tank_drone_rocket_mp" ); precacheitem( "killstreak_ai_tank_mp" ); precacheshader( "mech_check_line" ); precacheshader( "mech_check_fill" ); precacheshader( "mech_flame_bar" ); precacheshader( "mech_flame_arrow_flipped" ); loadfx( "vehicle/treadfx/fx_treadfx_talon_dirt" ); loadfx( "vehicle/treadfx/fx_treadfx_talon_concrete" ); loadfx( "light/fx_vlight_talon_eye_grn" ); loadfx( "light/fx_vlight_talon_eye_red" ); loadfx( "weapon/talon/fx_talon_emp_stun" ); level.ai_tank_minigun_flash_3p = loadfx( "weapon/talon/fx_muz_talon_rocket_flash_1p" ); registerkillstreak( "inventory_ai_tank_drop_mp", "inventory_ai_tank_drop_mp", "killstreak_ai_tank_drop", "ai_tank_drop_used", ::usekillstreakaitankdrop ); registerkillstreakaltweapon( "inventory_ai_tank_drop_mp", "ai_tank_drone_gun_mp" ); registerkillstreakaltweapon( "inventory_ai_tank_drop_mp", "ai_tank_drone_rocket_mp" ); registerkillstreakremoteoverrideweapon( "inventory_ai_tank_drop_mp", "killstreak_ai_tank_mp" ); registerkillstreakstrings( "inventory_ai_tank_drop_mp", &"KILLSTREAK_EARNED_AI_TANK_DROP", &"KILLSTREAK_AI_TANK_NOT_AVAILABLE", &"KILLSTREAK_AI_TANK_INBOUND" ); registerkillstreakdialog( "inventory_ai_tank_drop_mp", "mpl_killstreak_ai_tank", "kls_aitank_used", "", "kls_aitank_enemy", "", "kls_aitank_ready" ); registerkillstreakdevdvar( "inventory_ai_tank_drop_mp", "scr_giveaitankdrop" ); registerkillstreak( "ai_tank_drop_mp", "ai_tank_drop_mp", "killstreak_ai_tank_drop", "ai_tank_drop_used", ::usekillstreakaitankdrop ); registerkillstreakaltweapon( "ai_tank_drop_mp", "ai_tank_drone_gun_mp" ); registerkillstreakaltweapon( "ai_tank_drop_mp", "ai_tank_drone_rocket_mp" ); registerkillstreakremoteoverrideweapon( "ai_tank_drop_mp", "killstreak_ai_tank_mp" ); registerkillstreakstrings( "ai_tank_drop_mp", &"KILLSTREAK_EARNED_AI_TANK_DROP", &"KILLSTREAK_AI_TANK_NOT_AVAILABLE", &"KILLSTREAK_AI_TANK_INBOUND" ); registerkillstreakdialog( "ai_tank_drop_mp", "mpl_killstreak_ai_tank", "kls_aitank_used", "", "kls_aitank_enemy", "", "kls_aitank_ready" ); level.ai_tank_fov = cos( 160 ); level.ai_tank_turret_fire_rate = weaponfiretime( "ai_tank_drone_gun_mp" ); level.ai_tank_valid_locations = []; spawns = maps/mp/gametypes/_spawnlogic::getspawnpointarray( "mp_tdm_spawn" ); level.ai_tank_damage_fx = loadfx( "weapon/talon/fx_talon_damage_state" ); level.ai_tank_explode_fx = loadfx( "weapon/talon/fx_talon_exp" ); level.ai_tank_crate_explode_fx = loadfx( "weapon/talon/fx_talon_drop_box" ); _a73 = spawns; _k73 = getFirstArrayKey( _a73 ); while ( isDefined( _k73 ) ) { spawn = _a73[ _k73 ]; level.ai_tank_valid_locations[ level.ai_tank_valid_locations.size ] = spawn.origin; _k73 = getNextArrayKey( _a73, _k73 ); } anims = []; anims[ anims.size ] = %o_drone_tank_missile1_fire; anims[ anims.size ] = %o_drone_tank_missile2_fire; anims[ anims.size ] = %o_drone_tank_missile3_fire; anims[ anims.size ] = %o_drone_tank_missile_full_reload; setdvar( "scr_ai_tank_no_timeout", 0 ); /# level thread tank_devgui_think(); #/ } register() { registerclientfield( "vehicle", "ai_tank_death", 1, 1, "int" ); registerclientfield( "vehicle", "ai_tank_hack_spawned", 1, 1, "int" ); registerclientfield( "vehicle", "ai_tank_hack_rebooting", 1, 1, "int" ); registerclientfield( "vehicle", "ai_tank_missile_fire", 1, 3, "int" ); } usekillstreakaitankdrop( hardpointtype ) { team = self.team; if ( !self maps/mp/killstreaks/_supplydrop::issupplydropgrenadeallowed( hardpointtype ) ) { return 0; } killstreak_id = self maps/mp/killstreaks/_killstreakrules::killstreakstart( hardpointtype, team, 0, 0 ); if ( killstreak_id == -1 ) { return 0; } result = self maps/mp/killstreaks/_supplydrop::usesupplydropmarker( killstreak_id ); self notify( "supply_drop_marker_done" ); if ( !isDefined( result ) || !result ) { maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointtype, team, killstreak_id ); return 0; } return result; } crateland( crate, weaponname, owner, team ) { if ( crate valid_location() && isDefined( owner ) || team != owner.team && owner maps/mp/killstreaks/_emp::isenemyempkillstreakactive() ) { maps/mp/killstreaks/_killstreakrules::killstreakstop( weaponname, team, crate.package_contents_id ); wait 10; crate delete(); return; } origin = crate.origin; cratebottom = bullettrace( origin, origin + vectorScale( ( 0, 0, 1 ), 50 ), 0, crate ); if ( isDefined( cratebottom ) ) { origin = cratebottom[ "position" ] + ( 0, 0, 1 ); } playfx( level.ai_tank_crate_explode_fx, origin, ( 0, 0, 1 ), ( 0, 0, 1 ) ); playsoundatposition( "veh_talon_crate_exp", crate.origin ); level thread ai_tank_killstreak_start( owner, origin, crate.package_contents_id, weaponname ); crate delete(); } valid_location() { node = getnearestnode( self.origin ); if ( !isDefined( node ) ) { return 0; } start = self getcentroid(); end = node.origin + vectorScale( ( 0, 0, 1 ), 8 ); trace = physicstrace( start, end, ( 0, 0, 1 ), ( 0, 0, 1 ), self, level.physicstracecontentsvehicleclip ); if ( trace[ "fraction" ] < 1 ) { return 0; } origin = self.origin + vectorScale( ( 0, 0, 1 ), 32 ); level.ai_tank_valid_locations = array_randomize( level.ai_tank_valid_locations ); count = min( level.ai_tank_valid_locations.size, 5 ); i = 0; while ( i < count ) { if ( findpath( origin, level.ai_tank_valid_locations[ i ], self, 0, 1 ) ) { return 1; } i++; } return 0; } ai_tank_killstreak_start( owner, origin, killstreak_id, weaponname ) { waittillframeend; drone = spawnvehicle( "veh_t6_drone_tank", "talon", "ai_tank_drone_mp", origin, ( 0, 0, 1 ) ); drone setenemymodel( "veh_t6_drone_tank_alt" ); drone playloopsound( "veh_talon_idle_npc", 0,2 ); drone setvehicleavoidance( 1 ); drone setclientfield( "ai_tank_missile_fire", 4 ); drone setowner( owner ); drone.owner = owner; drone.team = owner.team; drone.aiteam = owner.team; drone.killstreak_id = killstreak_id; drone.type = "tank_drone"; if ( level.teambased ) { drone setteam( owner.team ); } else { drone setteam( "free" ); } drone maps/mp/_entityheadicons::setentityheadicon( drone.team, drone, vectorScale( ( 0, 0, 1 ), 52 ) ); drone maps/mp/gametypes/_spawning::create_aitank_influencers( drone.team ); drone.controlled = 0; drone makevehicleunusable(); drone.numberrockets = 3; drone.warningshots = 3; drone setdrawinfrared( 1 ); if ( !isDefined( drone.owner.numtankdrones ) ) { drone.owner.numtankdrones = 1; } else { drone.owner.numtankdrones++; } drone.ownernumber = drone.owner.numtankdrones; target_set( drone, vectorScale( ( 0, 0, 1 ), 20 ) ); target_setturretaquire( drone, 0 ); drone thread tank_move_think(); drone thread tank_aim_think(); drone thread tank_combat_think(); drone thread tank_death_think( weaponname ); drone thread tank_damage_think(); drone thread tank_abort_think(); drone thread tank_team_kill(); drone thread tank_ground_abort_think(); drone thread tank_riotshield_think(); drone thread tank_rocket_think(); owner maps/mp/killstreaks/_remote_weapons::initremoteweapon( drone, "killstreak_ai_tank_mp" ); drone thread deleteonkillbrush( drone.owner ); level thread tank_game_end_think( drone ); /# #/ } tank_team_kill() { self endon( "death" ); self.owner waittill( "teamKillKicked" ); self notify( "death" ); } tank_abort_think() { self endon( "death" ); self.owner wait_endon( 120, "disconnect", "joined_team", "joined_spectators", "emp_jammed" ); shouldtimeout = getDvar( "scr_ai_tank_no_timeout" ); if ( shouldtimeout == "1" ) { return; } self notify( "death" ); } tank_game_end_think( drone ) { drone endon( "death" ); level waittill( "game_ended" ); drone notify( "death" ); } stop_remote() { if ( !isDefined( self ) ) { return; } self clearusingremote(); self.killstreak_waitamount = undefined; self destroy_remote_hud(); self clientnotify( "nofutz" ); } tank_damage_think() { self endon( "death" ); self.maxhealth = 999999; self.health = self.maxhealth; self.isstunned = 0; low_health = 0; damage_taken = 0; for ( ;; ) { self waittill( "damage", damage, attacker, dir, point, mod, model, tag, part, weapon, flags ); self.maxhealth = 999999; self.health = self.maxhealth; /# self.damage_debug = ( damage + " (" ) + weapon + ")"; #/ if ( weapon == "emp_grenade_mp" && mod == "MOD_GRENADE_SPLASH" ) { damage_taken += 400; damage = 0; if ( !self.isstunned ) { maps/mp/_challenges::stunnedtankwithempgrenade( attacker ); self thread tank_stun( 4 ); self.isstunned = 1; } } if ( !self.isstunned ) { if ( weapon != "proximity_grenade_mp" && weapon == "proximity_grenade_aoe_mp" || mod == "MOD_GRENADE_SPLASH" && mod == "MOD_GAS" ) { self thread tank_stun( 1,5 ); self.isstunned = 1; } } if ( mod != "MOD_RIFLE_BULLET" && mod != "MOD_PISTOL_BULLET" || weapon == "hatchet_mp" && mod == "MOD_PROJECTILE_SPLASH" && isexplosivebulletweapon( weapon ) ) { if ( isplayer( attacker ) ) { if ( attacker hasperk( "specialty_armorpiercing" ) ) { damage += int( damage * level.cac_armorpiercing_data ); } } if ( weaponclass( weapon ) == "spread" ) { damage *= 4,5; } damage *= 0,3; } if ( mod != "MOD_PROJECTILE" && mod != "MOD_GRENADE_SPLASH" && mod == "MOD_PROJECTILE_SPLASH" && damage != 0 && weapon != "emp_grenade_mp" && !isexplosivebulletweapon( weapon ) ) { damage *= 1,5; } if ( self.controlled ) { self.owner sendkillstreakdamageevent( int( damage ) ); } damage_taken += damage; if ( damage_taken >= 800 ) { self notify( "death" ); return; } if ( !low_health && damage_taken > 444,4445 ) { self thread tank_low_health_fx(); low_health = 1; } if ( isDefined( attacker ) && isplayer( attacker ) && self tank_is_idle() && !self.isstunned ) { self.aim_entity.origin = attacker getcentroid(); self.aim_entity.delay = 8; self notify( "aim_updated" ); } } } tank_low_health_fx() { self endon( "death" ); self.damage_fx = spawn( "script_model", self gettagorigin( "tag_origin" ) + vectorScale( ( 0, 0, 1 ), 14 ) ); self.damage_fx setmodel( "tag_origin" ); self.damage_fx linkto( self, "tag_turret", vectorScale( ( 0, 0, 1 ), 14 ), ( 0, 0, 1 ) ); wait 0,1; playfxontag( level.ai_tank_damage_fx, self.damage_fx, "tag_origin" ); } deleteonkillbrush( player ) { player endon( "disconnect" ); self endon( "death" ); killbrushes = getentarray( "trigger_hurt", "classname" ); while ( 1 ) { i = 0; while ( i < killbrushes.size ) { if ( self istouching( killbrushes[ i ] ) ) { if ( isDefined( self ) ) { self notify( "death" ); } return; } i++; } wait 0,1; } } tank_stun( duration ) { self endon( "death" ); self notify( "stunned" ); self clearvehgoalpos(); forward = anglesToForward( self.angles ); forward = self.origin + ( forward * 128 ); forward -= vectorScale( ( 0, 0, 1 ), 64 ); self setturrettargetvec( forward ); self disablegunnerfiring( 0, 1 ); self laseroff(); if ( self.controlled ) { self.owner freezecontrols( 1 ); self.owner sendkillstreakdamageevent( 400 ); } if ( isDefined( self.owner.fullscreen_static ) ) { self.owner thread maps/mp/killstreaks/_remote_weapons::stunstaticfx( duration ); } self setclientflag( 3 ); wait duration; self clearclientflag( 3 ); if ( self.controlled ) { self.owner freezecontrols( 0 ); } if ( self.controlled == 0 ) { self thread tank_move_think(); self thread tank_aim_think(); self thread tank_combat_think(); } self disablegunnerfiring( 0, 0 ); self.isstunned = 0; } emp_crazy_death() { self setclientflag( 3 ); wait 1; self notify( "death" ); time = 0; randomangle = randomint( 360 ); while ( time < 1,45 ) { self setturrettargetvec( self.origin + ( anglesToForward( ( randomintrange( 305, 315 ), int( randomangle + ( time * 180 ) ), 0 ) ) * 100 ) ); if ( time > 0,2 ) { self fireweapon(); if ( randomint( 100 ) > 85 ) { rocket = self firegunnerweapon( 0 ); if ( isDefined( rocket ) ) { rocket.from_ai = 1; } } } time += 0,05; wait 0,05; } self setclientfield( "ai_tank_death", 1 ); playfx( level.ai_tank_explode_fx, self.origin, ( 0, 0, 1 ) ); playsoundatposition( "wpn_agr_explode", self.origin ); wait 0,05; self hide(); } tank_death_think( hardpointname ) { team = self.team; self waittill( "death", attacker, type, weapon ); self.dead = 1; self laseroff(); self clearvehgoalpos(); if ( self.controlled == 1 && isDefined( self.owner ) ) { self.owner sendkillstreakdamageevent( 600 ); self.owner destroy_remote_hud(); } if ( self.isstunned ) { stunned = 1; self thread emp_crazy_death(); wait 1,55; } else { self setclientfield( "ai_tank_death", 1 ); stunned = 0; playfx( level.ai_tank_explode_fx, self.origin, ( 0, 0, 1 ) ); playsoundatposition( "wpn_agr_explode", self.origin ); wait 0,05; self hide(); if ( isDefined( self.damage_fx ) ) { self.damage_fx delete(); } } if ( isDefined( attacker ) && isplayer( attacker ) && isDefined( self.owner ) && attacker != self.owner ) { if ( self.owner isenemyplayer( attacker ) ) { maps/mp/_scoreevents::processscoreevent( "destroyed_aitank", attacker, self.owner, weapon ); attacker addweaponstat( weapon, "destroyed_aitank", 1 ); if ( isDefined( self.wascontrollednowdead ) && self.wascontrollednowdead ) { attacker addweaponstat( weapon, "destroyed_controlled_killstreak", 1 ); } } } wait 2; maps/mp/killstreaks/_killstreakrules::killstreakstop( hardpointname, team, self.killstreak_id ); self.aim_entity delete(); self delete(); } tank_move_think() { self endon( "death" ); self endon( "stunned" ); self endon( "remote_start" ); level endon( "game_ended" ); /# self endon( "debug_patrol" ); #/ do_wait = 1; for ( ;; ) { if ( do_wait ) { wait randomfloatrange( 1, 4 ); } do_wait = 1; if ( !tank_is_idle() ) { enemy = tank_get_target(); if ( valid_target( enemy, self.team, self.owner ) ) { if ( distancesquared( self.origin, enemy.origin ) < 65536 ) { self clearvehgoalpos(); wait 1; } else if ( findpath( self.origin, enemy.origin, self, 0 ) ) { self setvehgoalpos( enemy.origin, 1, 2 ); self wait_endon( 3, "reached_end_node" ); } else { self clearvehgoalpos(); wait 1; } if ( valid_target( enemy, self.team, self.owner ) ) { do_wait = 0; } continue; } } else avg_position = tank_compute_enemy_position(); if ( isDefined( avg_position ) ) { nodes = getnodesinradiussorted( avg_position, 256, 0 ); } else { nodes = getnodesinradiussorted( self.owner.origin, 1024, 256, 128 ); } if ( nodes.size > 0 ) { node = nodes[ 0 ]; } else { } if ( self setvehgoalpos( node.origin, 1, 2 ) ) { event = self waittill_any_timeout( 45, "reached_end_node", "force_movement_wake" ); if ( event != "reached_end_node" ) { do_wait = 0; } continue; } else self clearvehgoalpos(); } } tank_riotshield_think() { self endon( "death" ); self endon( "remote_start" ); for ( ;; ) { level waittill( "riotshield_planted", owner ); if ( owner == self.owner || owner.team == self.team ) { if ( distancesquared( owner.riotshieldentity.origin, self.origin ) < 262144 ) { self clearvehgoalpos(); } self notify( "force_movement_wake" ); } } } tank_ground_abort_think() { self endon( "death" ); ground_trace_fail = 0; for ( ;; ) { wait 1; nodes = getnodesinradius( self.origin, 256, 0, 128, "Path" ); if ( nodes.size <= 0 ) { ground_trace_fail++; } else { ground_trace_fail = 0; } if ( ground_trace_fail >= 4 ) { self notify( "death" ); } } } tank_aim_think() { self endon( "death" ); self endon( "stunned" ); self endon( "remote_start" ); if ( !isDefined( self.aim_entity ) ) { self.aim_entity = spawn( "script_model", ( 0, 0, 1 ) ); } self.aim_entity.delay = 0; self tank_idle(); for ( ;; ) { self wait_endon( randomfloatrange( 1, 3 ), "aim_updated" ); if ( self.aim_entity.delay > 0 ) { wait self.aim_entity.delay; self.aim_entity.delay = 0; continue; } else if ( !tank_is_idle() ) { continue; } else if ( self getspeed() <= 1 ) { enemies = tank_get_player_enemies( 0 ); if ( enemies.size ) { enemy = enemies[ 0 ]; node = getvisiblenode( self.origin, enemy.origin, self ); if ( isDefined( node ) ) { self.aim_entity.origin = node.origin + vectorScale( ( 0, 0, 1 ), 16 ); continue; } } } else { yaw = ( 0, self.angles[ 1 ] + randomintrange( -75, 75 ), 0 ); forward = anglesToForward( yaw ); origin = self.origin + ( forward * 1024 ); self.aim_entity.origin = ( origin[ 0 ], origin[ 1 ], origin[ 2 ] + 20 ); } } } tank_combat_think() { self endon( "death" ); self endon( "stunned" ); self endon( "remote_start" ); level endon( "game_ended" ); for ( ;; ) { wait 0,5; self laseroff(); origin = self.origin + vectorScale( ( 0, 0, 1 ), 32 ); forward = vectornormalize( self.target_entity.origin - self.origin ); players = tank_get_player_enemies( 0 ); self tank_target_evaluate( players, origin, forward ); if ( level.gametype != "hack" ) { dogs = maps/mp/killstreaks/_dogs::dog_manager_get_dogs(); self tank_target_evaluate( dogs, origin, forward ); tanks = getentarray( "talon", "targetname" ); self tank_target_evaluate( tanks, origin, forward ); rcbombs = getentarray( "rcbomb", "targetname" ); self tank_target_evaluate( rcbombs, origin, forward ); turrets = getentarray( "auto_turret", "classname" ); self tank_target_evaluate( turrets, origin, forward ); shields = getentarray( "riotshield_mp", "targetname" ); self tank_target_evaluate( shields, origin, forward ); } } } tank_target_evaluate( targets, origin, forward ) { _a802 = targets; _k802 = getFirstArrayKey( _a802 ); while ( isDefined( _k802 ) ) { target = _a802[ _k802 ]; if ( !valid_target( target, self.team, self.owner ) ) { } else delta = target.origin - origin; delta = vectornormalize( delta ); dot = vectordot( forward, delta ); if ( dot < level.ai_tank_fov ) { } else if ( !bullettracepassed( origin, target getcentroid(), 0, target ) ) { } else { self tank_engage( target ); break; } _k802 = getNextArrayKey( _a802, _k802 ); } self tank_idle(); } tank_engage( enemy ) { do_fire_delay = 1; warning_shots = self.warningshots; self laseron(); for ( ;; ) { if ( !valid_target( enemy, self.team, self.owner ) ) { return; } if ( warning_shots <= 2 ) { fire_rocket = self tank_should_fire_rocket( enemy ); } self tank_set_target( enemy, fire_rocket ); if ( fire_rocket ) { self clearvehgoalpos(); } event = self waittill_any_return( "turret_on_vistarget", "turret_no_vis" ); if ( !valid_target( enemy, self.team, self.owner ) ) { return; } self.aim_entity.origin = enemy getcentroid(); distsq = distancesquared( self.origin, enemy.origin ); if ( distsq > 4096 && event == "turret_no_vis" ) { self tank_target_lost(); if ( self tank_is_idle() ) { return; } continue; } else self notify( "force_movement_wake" ); if ( event == "turret_no_vis" ) { warning_shots = self.warningshots; } if ( do_fire_delay ) { self playsound( "wpn_metalstorm_lock_on" ); wait randomfloatrange( 0,4, 0,8 ); do_fire_delay = 0; if ( !valid_target( enemy, self.team, self.owner ) ) { return; } } if ( fire_rocket ) { rocket = self firegunnerweapon( 0, self.owner ); self notify( "missile_fire" ); if ( isDefined( rocket ) ) { rocket.from_ai = 1; rocket.killcament = self; rocket wait_endon( randomfloatrange( 0,5, 1 ), "death" ); continue; } } else { self fireweapon(); warning_shots--; wait level.ai_tank_turret_fire_rate; while ( isDefined( enemy ) && !isalive( enemy ) ) { bullets = randomintrange( 8, 15 ); i = 0; while ( i < bullets ) { self fireweapon(); wait level.ai_tank_turret_fire_rate; i++; } } } } } tank_target_lost() { self endon( "turret_on_vistarget" ); wait 5; self tank_idle(); } tank_should_fire_rocket( enemy ) { if ( self.numberrockets <= 0 ) { return 0; } if ( distancesquared( self.origin, enemy.origin ) < 147456 ) { return 0; } origin = self gettagorigin( "tag_flash_gunner1" ); if ( !bullettracepassed( origin, enemy.origin + vectorScale( ( 0, 0, 1 ), 10 ), 0, enemy ) ) { return 0; } return 1; } tank_rocket_think() { self endon( "death" ); self endon( "remote_start" ); if ( self.numberrockets <= 0 ) { self disablegunnerfiring( 0, 1 ); wait 2; self setclientfield( "ai_tank_missile_fire", 4 ); self.numberrockets = 3; wait 0,4; if ( !self.isstunned ) { self disablegunnerfiring( 0, 0 ); } } while ( 1 ) { self waittill( "missile_fire" ); self.numberrockets--; self setclientfield( "ai_tank_missile_fire", self.numberrockets ); angles = self gettagangles( "tag_flash_gunner1" ); dir = anglesToForward( angles ); self launchvehicle( dir * -30, self.origin + vectorScale( ( 0, 0, 1 ), 50 ), 0 ); earthquake( 0,4, 0,5, self.origin, 200 ); if ( self.numberrockets <= 0 ) { self disablegunnerfiring( 0, 1 ); wait 2; self setclientfield( "ai_tank_missile_fire", 4 ); self.numberrockets = 3; wait 0,4; if ( !self.isstunned ) { self disablegunnerfiring( 0, 0 ); } } } } tank_set_target( entity, use_rocket ) { if ( !isDefined( use_rocket ) ) { use_rocket = 0; } self.target_entity = entity; if ( use_rocket ) { angles = self gettagangles( "tag_barrel" ); right = anglesToRight( angles ); offset = vectorScale( right, 8 ); velocity = entity getvelocity(); speed = length( velocity ); forward = anglesToForward( entity.angles ); origin = offset + vectorScale( forward, speed ); self setturrettargetent( entity, origin ); } else { self setturrettargetent( entity ); } } tank_get_target() { return self.target_entity; } tank_idle() { tank_set_target( self.aim_entity ); } tank_is_idle() { return tank_get_target() == self.aim_entity; } tank_has_radar() { if ( level.teambased ) { if ( !maps/mp/killstreaks/_radar::teamhasspyplane( self.team ) ) { return maps/mp/killstreaks/_radar::teamhassatellite( self.team ); } } if ( isDefined( self.owner.hasspyplane ) && !self.owner.hasspyplane ) { if ( isDefined( self.owner.hassatellite ) ) { return self.owner.hassatellite; } } } tank_get_player_enemies( on_radar ) { enemies = []; if ( !isDefined( on_radar ) ) { on_radar = 0; } if ( on_radar ) { time = getTime(); } _a1077 = level.aliveplayers; teamkey = getFirstArrayKey( _a1077 ); while ( isDefined( teamkey ) ) { team = _a1077[ teamkey ]; if ( level.teambased && teamkey == self.team ) { } else { _a1084 = team; _k1084 = getFirstArrayKey( _a1084 ); while ( isDefined( _k1084 ) ) { player = _a1084[ _k1084 ]; if ( !valid_target( player, self.team, self.owner ) ) { } else if ( on_radar ) { if ( ( time - player.lastfiretime ) > 3000 && !tank_has_radar() ) { } } else { enemies[ enemies.size ] = player; } _k1084 = getNextArrayKey( _a1084, _k1084 ); } } teamkey = getNextArrayKey( _a1077, teamkey ); } return enemies; } tank_compute_enemy_position() { enemies = tank_get_player_enemies( 0 ); position = undefined; if ( enemies.size ) { x = 0; y = 0; z = 0; _a1117 = enemies; _k1117 = getFirstArrayKey( _a1117 ); while ( isDefined( _k1117 ) ) { enemy = _a1117[ _k1117 ]; x += enemy.origin[ 0 ]; y += enemy.origin[ 1 ]; z += enemy.origin[ 2 ]; _k1117 = getNextArrayKey( _a1117, _k1117 ); } x /= enemies.size; y /= enemies.size; z /= enemies.size; position = ( x, y, z ); } return position; } valid_target( target, team, owner ) { if ( !isDefined( target ) ) { return 0; } if ( !isalive( target ) ) { return 0; } if ( target == owner ) { return 0; } if ( isplayer( target ) ) { if ( target.sessionstate != "playing" ) { return 0; } if ( isDefined( target.lastspawntime ) && ( getTime() - target.lastspawntime ) < 3000 ) { return 0; } /# if ( target isinmovemode( "ufo", "noclip" ) ) { return 0; #/ } } if ( level.teambased ) { if ( isDefined( target.team ) && team == target.team ) { return 0; } if ( isDefined( target.aiteam ) && team == target.aiteam ) { return 0; } } if ( isDefined( target.owner ) && target.owner == owner ) { return 0; } if ( isDefined( target.script_owner ) && target.script_owner == owner ) { return 0; } if ( isDefined( target.dead ) && target.dead ) { return 0; } if ( isDefined( target.targetname ) && target.targetname == "riotshield_mp" ) { if ( isDefined( target.damagetaken ) && target.damagetaken >= getDvarInt( "riotshield_deployed_health" ) ) { return 0; } } return 1; } starttankremotecontrol( drone ) { self.killstreak_waitamount = 120000; drone makevehicleusable(); drone clearvehgoalpos(); drone clearturrettarget(); drone laseroff(); drone usevehicle( self, 0 ); drone makevehicleunusable(); drone setbrake( 0 ); self create_weapon_hud(); drone update_weapon_hud( self ); self thread tank_fire_watch( drone ); drone thread tank_rocket_watch( self ); } endtankremotecontrol( drone, isdead ) { drone makevehicleunusable(); if ( !isdead ) { drone thread tank_move_think(); drone thread tank_riotshield_think(); drone thread tank_aim_think(); drone thread tank_combat_think(); drone thread tank_rocket_think(); } } end_remote_control_ai_tank( drone ) { if ( !isDefined( drone.dead ) || !drone.dead ) { self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,25, 0,1, 0,25 ); wait 0,3; } else { wait 0,75; self thread maps/mp/gametypes/_hud::fadetoblackforxsec( 0, 0,25, 0,1, 0,25 ); wait 0,3; } drone makevehicleusable(); drone.controlled = 0; drone notify( "remote_stop" ); self unlink(); drone makevehicleunusable(); self stop_remote(); drone showpart( "tag_pov_hide" ); if ( isDefined( self.hud_prompt_control ) || !isDefined( drone.dead ) && !drone.dead ) { self.hud_prompt_control settext( "HOLD [{+activate}] TO CONTROL A.G.R." ); self.hud_prompt_exit settext( "" ); } self switchtolastnonkillstreakweapon(); wait 0,5; self takeweapon( "killstreak_ai_tank_mp" ); if ( !isDefined( drone.dead ) || !drone.dead ) { drone thread tank_move_think(); drone thread tank_riotshield_think(); drone thread tank_aim_think(); drone thread tank_combat_think(); } } tank_fire_watch( drone ) { self endon( "disconnect" ); self endon( "stopped_using_remote" ); drone endon( "death" ); level endon( "game_ended" ); while ( 1 ) { drone waittill( "turret_fire" ); while ( drone.isstunned ) { continue; } drone fireweapon(); earthquake( 0,2, 0,2, drone.origin, 200 ); angles = drone gettagangles( "tag_barrel" ); dir = anglesToForward( angles ); drone launchvehicle( dir * -5, drone.origin + vectorScale( ( 0, 0, 1 ), 10 ), 0 ); wait level.ai_tank_turret_fire_rate; } } tank_rocket_watch( player ) { self endon( "death" ); player endon( "stopped_using_remote" ); if ( self.numberrockets <= 0 ) { self disablegunnerfiring( 0, 1 ); wait 2; self setclientfield( "ai_tank_missile_fire", 4 ); self.numberrockets = 3; wait 0,4; if ( !self.isstunned ) { self disablegunnerfiring( 0, 0 ); } self update_weapon_hud( player ); } if ( !self.isstunned ) { self disablegunnerfiring( 0, 0 ); } while ( 1 ) { player waittill( "missile_fire" ); self.numberrockets--; self setclientfield( "ai_tank_missile_fire", self.numberrockets ); angles = self gettagangles( "tag_flash_gunner1" ); dir = anglesToForward( angles ); if ( !self.controlled ) { self launchvehicle( dir * -30, self.origin + vectorScale( ( 0, 0, 1 ), 50 ), 0 ); } else { self launchvehicle( dir * -30, self.origin + vectorScale( ( 0, 0, 1 ), 50 ), 0 ); player playrumbleonentity( "sniper_fire" ); } earthquake( 0,4, 0,5, self.origin, 200 ); self update_weapon_hud( player ); if ( self.numberrockets <= 0 ) { self disablegunnerfiring( 0, 1 ); wait 2; self setclientfield( "ai_tank_missile_fire", 4 ); self.numberrockets = 3; wait 0,4; if ( !self.isstunned ) { self disablegunnerfiring( 0, 0 ); } self update_weapon_hud( player ); } } } create_weapon_hud() { self.tank_rocket_1 = newclienthudelem( self ); self.tank_rocket_1.alignx = "right"; self.tank_rocket_1.aligny = "bottom"; self.tank_rocket_1.horzalign = "user_center"; self.tank_rocket_1.vertalign = "user_bottom"; self.tank_rocket_1.font = "small"; self.tank_rocket_1 setshader( "mech_check_fill", 32, 16 ); self.tank_rocket_1.hidewheninmenu = 0; self.tank_rocket_1.immunetodemogamehudsettings = 1; self.tank_rocket_1.x = -250; self.tank_rocket_1.y = -75; self.tank_rocket_1.fontscale = 1,25; self.tank_rocket_2 = newclienthudelem( self ); self.tank_rocket_2.alignx = "right"; self.tank_rocket_2.aligny = "bottom"; self.tank_rocket_2.horzalign = "user_center"; self.tank_rocket_2.vertalign = "user_bottom"; self.tank_rocket_2.font = "small"; self.tank_rocket_2 setshader( "mech_check_fill", 32, 16 ); self.tank_rocket_2.hidewheninmenu = 0; self.tank_rocket_2.immunetodemogamehudsettings = 1; self.tank_rocket_2.x = -250; self.tank_rocket_2.y = -65; self.tank_rocket_2.fontscale = 1,25; self.tank_rocket_3 = newclienthudelem( self ); self.tank_rocket_3.alignx = "right"; self.tank_rocket_3.aligny = "bottom"; self.tank_rocket_3.horzalign = "user_center"; self.tank_rocket_3.vertalign = "user_bottom"; self.tank_rocket_3.font = "small"; self.tank_rocket_3 setshader( "mech_check_fill", 32, 16 ); self.tank_rocket_3.hidewheninmenu = 0; self.tank_rocket_3.immunetodemogamehudsettings = 1; self.tank_rocket_3.x = -250; self.tank_rocket_3.y = -55; self.tank_rocket_3.fontscale = 1,25; self thread fade_out_weapon_hud(); } fade_out_weapon_hud() { self endon( "death" ); wait 8; time = 0; while ( time < 2 ) { if ( !isDefined( self.tank_rocket_hint ) ) { return; } self.tank_rocket_hint.alpha -= 0,025; self.tank_mg_hint.alpha -= 0,025; time += 0,05; wait 0,05; } self.tank_rocket_hint.alpha = 0; self.tank_mg_hint.alpha = 0; } update_weapon_hud( player ) { if ( isDefined( player.tank_rocket_3 ) ) { player.tank_rocket_3 setshader( "mech_check_fill", 32, 16 ); player.tank_rocket_2 setshader( "mech_check_fill", 32, 16 ); player.tank_rocket_1 setshader( "mech_check_fill", 32, 16 ); switch( self.numberrockets ) { case 0: player.tank_rocket_3 setshader( "mech_check_line", 32, 16 ); case 1: player.tank_rocket_2 setshader( "mech_check_line", 32, 16 ); case 2: player.tank_rocket_1 setshader( "mech_check_line", 32, 16 ); break; return; } } } } } destroy_remote_hud() { self useservervisionset( 0 ); self setinfraredvision( 0 ); if ( isDefined( self.fullscreen_static ) ) { self.fullscreen_static destroy(); } if ( isDefined( self.remote_hud_reticle ) ) { self.remote_hud_reticle destroy(); } if ( isDefined( self.remote_hud_bracket_right ) ) { self.remote_hud_bracket_right destroy(); } if ( isDefined( self.remote_hud_bracket_left ) ) { self.remote_hud_bracket_left destroy(); } if ( isDefined( self.remote_hud_arrow_right ) ) { self.remote_hud_arrow_right destroy(); } if ( isDefined( self.remote_hud_arrow_left ) ) { self.remote_hud_arrow_left destroy(); } if ( isDefined( self.tank_rocket_1 ) ) { self.tank_rocket_1 destroy(); } if ( isDefined( self.tank_rocket_2 ) ) { self.tank_rocket_2 destroy(); } if ( isDefined( self.tank_rocket_3 ) ) { self.tank_rocket_3 destroy(); } if ( isDefined( self.tank_rocket_hint ) ) { self.tank_rocket_hint destroy(); } if ( isDefined( self.tank_mg_bar ) ) { self.tank_mg_bar destroy(); } if ( isDefined( self.tank_mg_arrow ) ) { self.tank_mg_arrow destroy(); } if ( isDefined( self.tank_mg_hint ) ) { self.tank_mg_hint destroy(); } } tank_devgui_think() { /# setdvar( "devgui_tank", "" ); for ( ;; ) { wait 0,25; level.ai_tank_turret_fire_rate = weaponfiretime( "ai_tank_drone_gun_mp" ); if ( getDvar( "devgui_tank" ) == "routes" ) { devgui_debug_route(); setdvar( "devgui_tank", "" ); } #/ } } tank_debug_patrol( node1, node2 ) { /# self endon( "death" ); self endon( "debug_patrol" ); for ( ;; ) { self setvehgoalpos( node1.origin, 1, 2 ); self waittill( "reached_end_node" ); wait 1; self setvehgoalpos( node2.origin, 1, 2 ); self waittill( "reached_end_node" ); wait 1; #/ } } devgui_debug_route() { /# iprintln( "Choose nodes with 'A' or press 'B' to cancel" ); nodes = maps/mp/gametypes/_dev::dev_get_node_pair(); if ( !isDefined( nodes ) ) { iprintln( "Route Debug Cancelled" ); return; } iprintln( "Sending talons to chosen nodes" ); tanks = getentarray( "talon", "targetname" ); _a1611 = tanks; _k1611 = getFirstArrayKey( _a1611 ); while ( isDefined( _k1611 ) ) { tank = _a1611[ _k1611 ]; tank notify( "debug_patrol" ); tank thread tank_debug_patrol( nodes[ 0 ], nodes[ 1 ] ); _k1611 = getNextArrayKey( _a1611, _k1611 ); #/ } } tank_debug_hud_init() { /# host = gethostplayer(); while ( !isDefined( host ) ) { wait 0,25; host = gethostplayer(); } x = 80; y = 40; level.ai_tank_bar = newclienthudelem( host ); level.ai_tank_bar.x = x + 80; level.ai_tank_bar.y = y + 2; level.ai_tank_bar.alignx = "left"; level.ai_tank_bar.aligny = "top"; level.ai_tank_bar.horzalign = "fullscreen"; level.ai_tank_bar.vertalign = "fullscreen"; level.ai_tank_bar.alpha = 0; level.ai_tank_bar.foreground = 0; level.ai_tank_bar setshader( "black", 1, 8 ); level.ai_tank_text = newclienthudelem( host ); level.ai_tank_text.x = x + 80; level.ai_tank_text.y = y; level.ai_tank_text.alignx = "left"; level.ai_tank_text.aligny = "top"; level.ai_tank_text.horzalign = "fullscreen"; level.ai_tank_text.vertalign = "fullscreen"; level.ai_tank_text.alpha = 0; level.ai_tank_text.fontscale = 1; level.ai_tank_text.foreground = 1; #/ } tank_debug_health() { /# self.damage_debug = ""; level.ai_tank_bar.alpha = 1; level.ai_tank_text.alpha = 1; for ( ;; ) { wait 0,05; if ( !isDefined( self ) || !isalive( self ) ) { level.ai_tank_bar.alpha = 0; level.ai_tank_text.alpha = 0; return; } width = ( self.health / self.maxhealth ) * 300; width = int( max( width, 1 ) ); level.ai_tank_bar setshader( "black", width, 8 ); str = ( self.health + " Last Damage: " ) + self.damage_debug; level.ai_tank_text settext( str ); #/ } }