mirror of
https://github.com/JezuzLizard/Recompilable-gscs-for-BO2-zombies-and-multiplayer.git
synced 2025-07-04 14:37:52 -05:00
1836 lines
44 KiB
Plaintext
1836 lines
44 KiB
Plaintext
#include maps/mp/zombies/_zm_spawner;
|
|
#include maps/mp/zombies/_zm_weap_staff_fire;
|
|
#include maps/mp/zombies/_zm_ai_basic;
|
|
#include maps/mp/gametypes_zm/_hud;
|
|
#include maps/mp/zombies/_zm_zonemgr;
|
|
#include maps/mp/zombies/_zm_score;
|
|
#include maps/mp/zm_tomb_amb;
|
|
#include maps/mp/zombies/_zm_powerups;
|
|
#include maps/mp/zombies/_zm_audio;
|
|
#include maps/mp/zm_tomb_vo;
|
|
#include maps/mp/zm_tomb_utility;
|
|
#include maps/mp/zombies/_zm_utility;
|
|
#include maps/mp/zombies/_zm_weapons;
|
|
#include maps/mp/zombies/_zm_craftables;
|
|
#include maps/mp/_utility;
|
|
#include common_scripts/utility;
|
|
|
|
#using_animtree( "zm_tomb_tank" );
|
|
|
|
tank_precache()
|
|
{
|
|
}
|
|
|
|
init()
|
|
{
|
|
registerclientfield( "vehicle", "tank_tread_fx", 14000, 1, "int" );
|
|
registerclientfield( "vehicle", "tank_flamethrower_fx", 14000, 2, "int" );
|
|
registerclientfield( "vehicle", "tank_cooldown_fx", 14000, 2, "int" );
|
|
tank_precache();
|
|
onplayerconnect_callback( ::onplayerconnect );
|
|
level.enemy_location_override_func = ::enemy_location_override;
|
|
level.adjust_enemyoverride_func = ::adjust_enemyoverride;
|
|
level.zm_mantle_over_40_move_speed_override = ::zm_mantle_over_40_move_speed_override;
|
|
level.vh_tank = getent( "tank", "targetname" );
|
|
level.vh_tank tank_setup();
|
|
level.vh_tank thread tankuseanimtree();
|
|
level.vh_tank thread tank_discovery_vo();
|
|
level thread maps/mp/zm_tomb_vo::watch_occasional_line( "tank", "tank_flame_zombie", "vo_tank_flame_zombie" );
|
|
level thread maps/mp/zm_tomb_vo::watch_occasional_line( "tank", "tank_leave", "vo_tank_leave" );
|
|
level thread maps/mp/zm_tomb_vo::watch_occasional_line( "tank", "tank_cooling", "vo_tank_cooling" );
|
|
}
|
|
|
|
onplayerconnect()
|
|
{
|
|
self thread onplayerspawned();
|
|
}
|
|
|
|
onplayerspawned()
|
|
{
|
|
self endon( "disconnect" );
|
|
for ( ;; )
|
|
{
|
|
self waittill( "spawned_player" );
|
|
self.b_already_on_tank = 0;
|
|
}
|
|
}
|
|
|
|
tank_discovery_vo()
|
|
{
|
|
max_dist_sq = 640000;
|
|
flag_wait( "activate_zone_village_0" );
|
|
while ( 1 )
|
|
{
|
|
a_players = getplayers();
|
|
_a89 = a_players;
|
|
_k89 = getFirstArrayKey( _a89 );
|
|
while ( isDefined( _k89 ) )
|
|
{
|
|
e_player = _a89[ _k89 ];
|
|
dist_sq = distance2dsquared( level.vh_tank.origin, e_player.origin );
|
|
height_diff = abs( level.vh_tank.origin[ 2 ] - e_player.origin[ 2 ] );
|
|
if ( dist_sq < max_dist_sq && height_diff < 150 && isDefined( e_player.isspeaking ) && !e_player.isspeaking )
|
|
{
|
|
e_player maps/mp/zombies/_zm_audio::create_and_play_dialog( "tank", "discover_tank" );
|
|
return;
|
|
}
|
|
_k89 = getNextArrayKey( _a89, _k89 );
|
|
}
|
|
wait 0,1;
|
|
}
|
|
}
|
|
|
|
tank_drop_powerups()
|
|
{
|
|
flag_wait( "start_zombie_round_logic" );
|
|
a_drop_nodes = [];
|
|
i = 0;
|
|
while ( i < 3 )
|
|
{
|
|
drop_num = i + 1;
|
|
a_drop_nodes[ i ] = getvehiclenode( "tank_powerup_drop_" + drop_num, "script_noteworthy" );
|
|
a_drop_nodes[ i ].next_drop_round = level.round_number + i;
|
|
s_drop = getstruct( "tank_powerup_drop_" + drop_num, "targetname" );
|
|
a_drop_nodes[ i ].drop_pos = s_drop.origin;
|
|
i++;
|
|
}
|
|
a_possible_powerups = array( "nuke", "full_ammo", "zombie_blood", "insta_kill", "fire_sale", "double_points" );
|
|
while ( 1 )
|
|
{
|
|
self ent_flag_wait( "tank_moving" );
|
|
_a129 = a_drop_nodes;
|
|
_k129 = getFirstArrayKey( _a129 );
|
|
while ( isDefined( _k129 ) )
|
|
{
|
|
node = _a129[ _k129 ];
|
|
dist_sq = distance2dsquared( node.origin, self.origin );
|
|
if ( dist_sq < 250000 )
|
|
{
|
|
a_players = get_players_on_tank( 1 );
|
|
if ( a_players.size > 0 )
|
|
{
|
|
if ( level.staff_part_count[ "elemental_staff_lightning" ] == 0 && level.round_number >= node.next_drop_round )
|
|
{
|
|
str_powerup = random( a_possible_powerups );
|
|
level thread maps/mp/zombies/_zm_powerups::specific_powerup_drop( str_powerup, node.drop_pos );
|
|
node.next_drop_round = level.round_number + randomintrange( 8, 12 );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
level notify( "sam_clue_tank" );
|
|
}
|
|
}
|
|
}
|
|
_k129 = getNextArrayKey( _a129, _k129 );
|
|
}
|
|
wait 2;
|
|
}
|
|
}
|
|
|
|
zm_mantle_over_40_move_speed_override()
|
|
{
|
|
traversealias = "barrier_walk";
|
|
switch( self.zombie_move_speed )
|
|
{
|
|
case "chase_bus":
|
|
traversealias = "barrier_sprint";
|
|
break;
|
|
default:
|
|
/#
|
|
assertmsg( "Zombie move speed of '" + self.zombie_move_speed + "' is not supported for mantle_over_40." );
|
|
#/
|
|
}
|
|
return traversealias;
|
|
}
|
|
|
|
init_animtree()
|
|
{
|
|
scriptmodelsuseanimtree( -1 );
|
|
}
|
|
|
|
tankuseanimtree()
|
|
{
|
|
self useanimtree( -1 );
|
|
}
|
|
|
|
drawtag( tag, opcolor )
|
|
{
|
|
/#
|
|
org = self gettagorigin( tag );
|
|
ang = self gettagangles( tag );
|
|
box( org, vectorScale( ( 0, 0, 1 ), 8 ), vectorScale( ( 0, 0, 1 ), 8 ), ang[ 1 ], opcolor, 1, 0, 1 );
|
|
#/
|
|
}
|
|
|
|
draw_tank_tag( tag, opcolor )
|
|
{
|
|
/#
|
|
self endon( "death" );
|
|
for ( ;; )
|
|
{
|
|
if ( self tank_tag_is_valid( tag ) )
|
|
{
|
|
drawtag( tag.str_tag, vectorScale( ( 0, 0, 1 ), 255 ) );
|
|
}
|
|
else
|
|
{
|
|
drawtag( tag.str_tag, vectorScale( ( 0, 0, 1 ), 255 ) );
|
|
}
|
|
wait 0,05;
|
|
#/
|
|
}
|
|
}
|
|
|
|
tank_debug_tags()
|
|
{
|
|
/#
|
|
setdvar( "debug_tank", "off" );
|
|
adddebugcommand( "devgui_cmd "Zombies:2/Tomb:1/Tank Debug:5" "debug_tank on"\n" );
|
|
flag_wait( "start_zombie_round_logic" );
|
|
a_spots = getstructarray( "tank_jump_down_spots", "script_noteworthy" );
|
|
while ( 1 )
|
|
{
|
|
while ( getDvar( "debug_tank" ) == "on" )
|
|
{
|
|
if ( isDefined( self.tags_drawing ) && !self.tags_drawing )
|
|
{
|
|
_a224 = self.a_tank_tags;
|
|
_k224 = getFirstArrayKey( _a224 );
|
|
while ( isDefined( _k224 ) )
|
|
{
|
|
s_tag = _a224[ _k224 ];
|
|
self thread draw_tank_tag( s_tag );
|
|
_k224 = getNextArrayKey( _a224, _k224 );
|
|
}
|
|
self.tags_drawing = 1;
|
|
}
|
|
ang = self.angles;
|
|
_a232 = a_spots;
|
|
_k232 = getFirstArrayKey( _a232 );
|
|
while ( isDefined( _k232 ) )
|
|
{
|
|
s_spot = _a232[ _k232 ];
|
|
org = self tank_get_jump_down_offset( s_spot );
|
|
box( org, vectorScale( ( 0, 0, 1 ), 4 ), vectorScale( ( 0, 0, 1 ), 4 ), ang[ 1 ], vectorScale( ( 0, 0, 1 ), 128 ), 1, 0, 1 );
|
|
_k232 = getNextArrayKey( _a232, _k232 );
|
|
}
|
|
a_zombies = get_round_enemy_array();
|
|
_a239 = a_zombies;
|
|
_k239 = getFirstArrayKey( _a239 );
|
|
while ( isDefined( _k239 ) )
|
|
{
|
|
e_zombie = _a239[ _k239 ];
|
|
if ( isDefined( e_zombie.tank_state ) )
|
|
{
|
|
print3d( e_zombie.origin + vectorScale( ( 0, 0, 1 ), 60 ), e_zombie.tank_state, vectorScale( ( 0, 0, 1 ), 255 ), 1 );
|
|
}
|
|
_k239 = getNextArrayKey( _a239, _k239 );
|
|
}
|
|
}
|
|
wait 0,05;
|
|
#/
|
|
}
|
|
}
|
|
|
|
tank_jump_down_store_offset( s_pos )
|
|
{
|
|
v_up = anglesToUp( self.angles );
|
|
v_right = anglesToRight( self.angles );
|
|
v_fwd = anglesToForward( self.angles );
|
|
offset = s_pos.origin - self.origin;
|
|
s_pos.tank_offset = ( vectordot( v_fwd, offset ), vectordot( v_right, offset ), vectordot( v_up, offset ) );
|
|
}
|
|
|
|
tank_get_jump_down_offset( s_pos )
|
|
{
|
|
v_up = anglesToUp( self.angles );
|
|
v_right = anglesToRight( self.angles );
|
|
v_fwd = anglesToForward( self.angles );
|
|
v_offset = s_pos.tank_offset;
|
|
return ( ( self.origin + ( v_offset[ 0 ] * v_fwd ) ) + ( v_offset[ 1 ] * v_right ) ) + ( v_offset[ 2 ] * v_up );
|
|
}
|
|
|
|
tank_setup()
|
|
{
|
|
self ent_flag_init( "tank_moving" );
|
|
self ent_flag_init( "tank_activated" );
|
|
self ent_flag_init( "tank_cooldown" );
|
|
level.tank_boxes_enabled = 0;
|
|
self.tag_occupied = [];
|
|
self.health = 1000;
|
|
self.n_players_on = 0;
|
|
self.chase_pos_time = 0;
|
|
self hidepart( "tag_flamethrower" );
|
|
self setmovingplatformenabled( 1 );
|
|
self.e_roof = getent( "vol_on_tank_watch", "targetname" );
|
|
self.e_roof enablelinkto();
|
|
self.e_roof linkto( self );
|
|
self.t_use = getent( "trig_use_tank", "targetname" );
|
|
self.t_use enablelinkto();
|
|
self.t_use linkto( self );
|
|
self.t_use sethintstring( &"ZM_TOMB_X2AT", 500 );
|
|
self.t_kill = spawn( "trigger_box", ( -8192, -4300, 0 ), 0, 200, 150, 128 );
|
|
self.t_kill enablelinkto();
|
|
self.t_kill linkto( self );
|
|
m_tank_path_blocker = getent( "tank_path_blocker", "targetname" );
|
|
m_tank_path_blocker delete();
|
|
a_tank_jump_down_spots = getstructarray( "tank_jump_down_spots", "script_noteworthy" );
|
|
_a312 = a_tank_jump_down_spots;
|
|
_k312 = getFirstArrayKey( _a312 );
|
|
while ( isDefined( _k312 ) )
|
|
{
|
|
s_spot = _a312[ _k312 ];
|
|
self tank_jump_down_store_offset( s_spot );
|
|
_k312 = getNextArrayKey( _a312, _k312 );
|
|
}
|
|
self thread players_on_tank_update();
|
|
self thread zombies_watch_tank();
|
|
self thread tank_station();
|
|
self thread tank_run_flamethrowers();
|
|
self thread do_treadfx();
|
|
self thread do_cooldown_fx();
|
|
self thread tank_drop_powerups();
|
|
/#
|
|
self thread tank_debug_tags();
|
|
#/
|
|
self playloopsound( "zmb_tank_idle", 0,5 );
|
|
}
|
|
|
|
do_cooldown_fx()
|
|
{
|
|
self endon( "death" );
|
|
flag_wait( "start_zombie_round_logic" );
|
|
while ( 1 )
|
|
{
|
|
self setclientfield( "tank_cooldown_fx", 2 );
|
|
self ent_flag_wait( "tank_moving" );
|
|
self setclientfield( "tank_cooldown_fx", 0 );
|
|
self ent_flag_wait( "tank_cooldown" );
|
|
self setclientfield( "tank_cooldown_fx", 1 );
|
|
self ent_flag_waitopen( "tank_cooldown" );
|
|
}
|
|
}
|
|
|
|
do_treadfx()
|
|
{
|
|
self endon( "death" );
|
|
while ( 1 )
|
|
{
|
|
self ent_flag_wait( "tank_moving" );
|
|
self setclientfield( "tank_tread_fx", 1 );
|
|
self ent_flag_waitopen( "tank_moving" );
|
|
self setclientfield( "tank_tread_fx", 0 );
|
|
}
|
|
}
|
|
|
|
disconnect_reconnect_paths( vh_tank )
|
|
{
|
|
self endon( "death" );
|
|
while ( 1 )
|
|
{
|
|
self disconnectpaths();
|
|
wait 1;
|
|
while ( vh_tank getspeedmph() < 1 )
|
|
{
|
|
wait 0,05;
|
|
}
|
|
self connectpaths();
|
|
wait 0,5;
|
|
}
|
|
}
|
|
|
|
tank_rumble_update()
|
|
{
|
|
while ( self.b_already_on_tank )
|
|
{
|
|
if ( level.vh_tank ent_flag( "tank_moving" ) )
|
|
{
|
|
self setclientfieldtoplayer( "player_rumble_and_shake", 6 );
|
|
}
|
|
else
|
|
{
|
|
self setclientfieldtoplayer( "player_rumble_and_shake", 0 );
|
|
}
|
|
wait 1;
|
|
}
|
|
self setclientfieldtoplayer( "player_rumble_and_shake", 0 );
|
|
}
|
|
|
|
players_on_tank_update()
|
|
{
|
|
flag_wait( "start_zombie_round_logic" );
|
|
self thread tank_disconnect_paths();
|
|
while ( 1 )
|
|
{
|
|
a_players = getplayers();
|
|
_a422 = a_players;
|
|
_k422 = getFirstArrayKey( _a422 );
|
|
while ( isDefined( _k422 ) )
|
|
{
|
|
e_player = _a422[ _k422 ];
|
|
if ( is_player_valid( e_player ) )
|
|
{
|
|
if ( isDefined( e_player.b_already_on_tank ) && !e_player.b_already_on_tank && e_player entity_on_tank() )
|
|
{
|
|
e_player.b_already_on_tank = 1;
|
|
self.n_players_on++;
|
|
if ( self ent_flag( "tank_cooldown" ) )
|
|
{
|
|
level notify( "vo_tank_cooling" );
|
|
}
|
|
e_player thread tank_rumble_update();
|
|
e_player thread tank_rides_around_map_achievement_watcher();
|
|
e_player thread tank_force_crouch_from_prone_after_on_tank();
|
|
e_player allowcrouch( 1 );
|
|
e_player allowprone( 0 );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if ( isDefined( e_player.b_already_on_tank ) && e_player.b_already_on_tank && !e_player entity_on_tank() )
|
|
{
|
|
e_player.b_already_on_tank = 0;
|
|
self.n_players_on--;
|
|
|
|
level notify( "vo_tank_leave" );
|
|
e_player notify( "player_jumped_off_tank" );
|
|
e_player setclientfieldtoplayer( "player_rumble_and_shake", 0 );
|
|
e_player allowprone( 1 );
|
|
}
|
|
}
|
|
}
|
|
_k422 = getNextArrayKey( _a422, _k422 );
|
|
}
|
|
wait 0,05;
|
|
}
|
|
}
|
|
|
|
tank_force_crouch_from_prone_after_on_tank()
|
|
{
|
|
self endon( "disconnect" );
|
|
self endon( "bled_out" );
|
|
wait 1;
|
|
if ( self getstance() == "prone" )
|
|
{
|
|
self setstance( "crouch" );
|
|
}
|
|
}
|
|
|
|
tank_rides_around_map_achievement_watcher()
|
|
{
|
|
self endon( "death_or_disconnect" );
|
|
self endon( "player_jumped_off_tank" );
|
|
if ( level.vh_tank ent_flag( "tank_moving" ) )
|
|
{
|
|
level.vh_tank ent_flag_waitopen( "tank_moving" );
|
|
}
|
|
str_starting_location = level.vh_tank.str_location_current;
|
|
level.vh_tank ent_flag_wait( "tank_moving" );
|
|
level.vh_tank ent_flag_waitopen( "tank_moving" );
|
|
self notify( "rode_tank_around_map" );
|
|
}
|
|
|
|
entity_on_tank()
|
|
{
|
|
if ( self istouching( level.vh_tank.e_roof ) )
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
tank_station()
|
|
{
|
|
self thread tank_watch_use();
|
|
self thread tank_movement();
|
|
a_call_boxes = getentarray( "trig_tank_station_call", "targetname" );
|
|
_a518 = a_call_boxes;
|
|
_k518 = getFirstArrayKey( _a518 );
|
|
while ( isDefined( _k518 ) )
|
|
{
|
|
t_call_box = _a518[ _k518 ];
|
|
t_call_box thread tank_call_box();
|
|
_k518 = getNextArrayKey( _a518, _k518 );
|
|
}
|
|
self.t_use waittill( "trigger" );
|
|
level.tank_boxes_enabled = 1;
|
|
}
|
|
|
|
tank_left_behind()
|
|
{
|
|
wait 4;
|
|
n_valid_dist_sq = 1000000;
|
|
a_riders = get_players_on_tank( 1 );
|
|
if ( a_riders.size == 0 )
|
|
{
|
|
return;
|
|
}
|
|
e_rider = random( a_riders );
|
|
a_players = getplayers();
|
|
a_victims = [];
|
|
v_tank_fwd = anglesToForward( self.angles );
|
|
_a547 = a_players;
|
|
_k547 = getFirstArrayKey( _a547 );
|
|
while ( isDefined( _k547 ) )
|
|
{
|
|
e_player = _a547[ _k547 ];
|
|
if ( isDefined( e_player.b_already_on_tank ) && e_player.b_already_on_tank )
|
|
{
|
|
}
|
|
else
|
|
{
|
|
if ( distance2dsquared( e_player.origin, self.origin ) > n_valid_dist_sq )
|
|
{
|
|
break;
|
|
}
|
|
else v_to_tank = self.origin - e_player.origin;
|
|
v_to_tank = vectornormalize( v_to_tank );
|
|
if ( vectordot( v_to_tank, v_tank_fwd ) < 0 )
|
|
{
|
|
break;
|
|
}
|
|
else v_player_fwd = anglesToForward( e_player.angles );
|
|
if ( vectordot( v_player_fwd, v_to_tank ) < 0 )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
a_victims[ a_victims.size ] = e_player;
|
|
}
|
|
}
|
|
_k547 = getNextArrayKey( _a547, _k547 );
|
|
}
|
|
if ( a_victims.size == 0 )
|
|
{
|
|
return;
|
|
}
|
|
e_victim = random( a_victims );
|
|
maps/mp/zm_tomb_vo::tank_left_behind_vo( e_victim, e_rider );
|
|
}
|
|
|
|
tank_watch_use()
|
|
{
|
|
while ( 1 )
|
|
{
|
|
self.t_use waittill( "trigger", e_player );
|
|
level thread maps/mp/zm_tomb_amb::sndplaystingerwithoverride( "mus_event_tank_ride", 70 );
|
|
cooling_down = self ent_flag( "tank_cooldown" );
|
|
if ( is_player_valid( e_player ) && e_player.score >= 500 && !cooling_down )
|
|
{
|
|
self ent_flag_set( "tank_activated" );
|
|
self ent_flag_set( "tank_moving" );
|
|
e_player thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "tank", "tank_buy" );
|
|
self thread tank_left_behind();
|
|
e_player maps/mp/zombies/_zm_score::minus_to_player_score( 500 );
|
|
self waittill( "tank_stop" );
|
|
self playsound( "zmb_tank_stop" );
|
|
self stoploopsound( 1,5 );
|
|
if ( isDefined( self.b_call_box_used ) && self.b_call_box_used )
|
|
{
|
|
self.b_call_box_used = 0;
|
|
self activate_tank_wait_with_no_cost();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
activate_tank_wait_with_no_cost()
|
|
{
|
|
self endon( "call_box_used" );
|
|
self.b_no_cost = 1;
|
|
self.t_use waittill( "trigger", e_player );
|
|
self ent_flag_set( "tank_activated" );
|
|
self ent_flag_set( "tank_moving" );
|
|
self.b_no_cost = 0;
|
|
}
|
|
|
|
tank_call_box()
|
|
{
|
|
while ( 1 )
|
|
{
|
|
self waittill( "trigger", e_player );
|
|
cooling_down = level.vh_tank ent_flag( "tank_cooldown" );
|
|
if ( !level.vh_tank ent_flag( "tank_activated" ) && e_player.score >= 500 && !cooling_down )
|
|
{
|
|
level.vh_tank notify( "call_box_used" );
|
|
level.vh_tank.b_call_box_used = 1;
|
|
e_switch = getent( self.target, "targetname" );
|
|
self setinvisibletoall();
|
|
wait 0,05;
|
|
e_switch rotatepitch( -180, 0,5 );
|
|
e_switch waittill( "rotatedone" );
|
|
e_switch rotatepitch( 180, 0,5 );
|
|
level.vh_tank.t_use useby( e_player );
|
|
level.vh_tank waittill( "tank_stop" );
|
|
}
|
|
}
|
|
}
|
|
|
|
tank_call_boxes_update()
|
|
{
|
|
str_loc = level.vh_tank.str_location_current;
|
|
a_trigs = getentarray( "trig_tank_station_call", "targetname" );
|
|
moving = level.vh_tank ent_flag( "tank_moving" );
|
|
cooling = level.vh_tank ent_flag( "tank_cooldown" );
|
|
_a683 = a_trigs;
|
|
_k683 = getFirstArrayKey( _a683 );
|
|
while ( isDefined( _k683 ) )
|
|
{
|
|
trig = _a683[ _k683 ];
|
|
at_this_station = trig.script_noteworthy == ( "call_box_" + str_loc );
|
|
if ( moving )
|
|
{
|
|
trig setvisibletoall();
|
|
trig sethintstring( &"ZM_TOMB_TNKM" );
|
|
}
|
|
else if ( !level.tank_boxes_enabled || at_this_station )
|
|
{
|
|
trig setinvisibletoall();
|
|
}
|
|
else
|
|
{
|
|
if ( cooling )
|
|
{
|
|
trig setvisibletoall();
|
|
trig sethintstring( &"ZM_TOMB_TNKC" );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
trig setvisibletoall();
|
|
trig sethintstring( &"ZM_TOMB_X2CT", 500 );
|
|
}
|
|
}
|
|
_k683 = getNextArrayKey( _a683, _k683 );
|
|
}
|
|
}
|
|
|
|
tank_movement()
|
|
{
|
|
n_path_start = getvehiclenode( "tank_start", "targetname" );
|
|
self attachpath( n_path_start );
|
|
self startpath();
|
|
self thread follow_path( n_path_start );
|
|
self setspeedimmediate( 0 );
|
|
self.a_locations = array( "village", "bunkers" );
|
|
n_location_index = 0;
|
|
self.str_location_current = self.a_locations[ n_location_index ];
|
|
tank_call_boxes_update();
|
|
while ( 1 )
|
|
{
|
|
self ent_flag_wait( "tank_activated" );
|
|
/#
|
|
iprintln( "The tank is moving." );
|
|
#/
|
|
self thread tank_connect_paths();
|
|
self playsound( "evt_tank_call" );
|
|
self setspeedimmediate( 8 );
|
|
self.t_use setinvisibletoall();
|
|
tank_call_boxes_update();
|
|
self thread tank_kill_players();
|
|
self thread tank_cooldown_timer();
|
|
self waittill( "tank_stop" );
|
|
self ent_flag_set( "tank_cooldown" );
|
|
self.t_use setvisibletoall();
|
|
self.t_use sethintstring( &"ZM_TOMB_TNKC" );
|
|
self ent_flag_clear( "tank_moving" );
|
|
self thread tank_disconnect_paths();
|
|
self setspeedimmediate( 0 );
|
|
n_location_index++;
|
|
if ( n_location_index == self.a_locations.size )
|
|
{
|
|
n_location_index = 0;
|
|
}
|
|
self.str_location_current = self.a_locations[ n_location_index ];
|
|
tank_call_boxes_update();
|
|
self wait_for_tank_cooldown();
|
|
self ent_flag_clear( "tank_cooldown" );
|
|
if ( isDefined( self.b_no_cost ) && self.b_no_cost )
|
|
{
|
|
self.t_use sethintstring( &"ZM_TOMB_X2ATF" );
|
|
}
|
|
else
|
|
{
|
|
self.t_use sethintstring( &"ZM_TOMB_X2AT", 500 );
|
|
}
|
|
self ent_flag_clear( "tank_activated" );
|
|
tank_call_boxes_update();
|
|
}
|
|
}
|
|
|
|
tank_disconnect_paths()
|
|
{
|
|
self endon( "death" );
|
|
while ( self getspeedmph() > 0 )
|
|
{
|
|
wait 0,05;
|
|
}
|
|
self disconnectpaths();
|
|
}
|
|
|
|
tank_connect_paths()
|
|
{
|
|
self endon( "death" );
|
|
self connectpaths();
|
|
}
|
|
|
|
tank_kill_players()
|
|
{
|
|
self endon( "tank_cooldown" );
|
|
while ( 1 )
|
|
{
|
|
self.t_kill waittill( "trigger", player );
|
|
player thread tank_ran_me_over();
|
|
wait 0,05;
|
|
}
|
|
}
|
|
|
|
tank_ran_me_over()
|
|
{
|
|
self disableinvulnerability();
|
|
self dodamage( self.health + 1000, self.origin );
|
|
a_nodes = getnodesinradiussorted( self.origin, 256, 0, 72, "path", 15 );
|
|
_a838 = a_nodes;
|
|
_k838 = getFirstArrayKey( _a838 );
|
|
while ( isDefined( _k838 ) )
|
|
{
|
|
node = _a838[ _k838 ];
|
|
str_zone = maps/mp/zombies/_zm_zonemgr::get_zone_from_position( node.origin );
|
|
if ( !isDefined( str_zone ) )
|
|
{
|
|
}
|
|
else
|
|
{
|
|
if ( isDefined( node.b_player_downed_here ) && !node.b_player_downed_here )
|
|
{
|
|
start_wait = 0;
|
|
black_screen_wait = 4;
|
|
fade_in_time = 0,01;
|
|
fade_out_time = 0,2;
|
|
self thread maps/mp/gametypes_zm/_hud::fadetoblackforxsec( start_wait, black_screen_wait, fade_in_time, fade_out_time, "black" );
|
|
node.b_player_downed_here = 1;
|
|
e_linker = spawn( "script_origin", self.origin );
|
|
self playerlinkto( e_linker );
|
|
e_linker moveto( node.origin + vectorScale( ( 0, 0, 1 ), 8 ), 1 );
|
|
e_linker wait_to_unlink( self );
|
|
node.b_player_downed_here = undefined;
|
|
e_linker delete();
|
|
return;
|
|
}
|
|
}
|
|
_k838 = getNextArrayKey( _a838, _k838 );
|
|
}
|
|
}
|
|
|
|
wait_to_unlink( player )
|
|
{
|
|
player endon( "disconnect" );
|
|
wait 4;
|
|
self unlink();
|
|
}
|
|
|
|
tank_cooldown_timer()
|
|
{
|
|
self.n_cooldown_timer = 0;
|
|
str_location_original = self.str_location_current;
|
|
self playsound( "zmb_tank_start" );
|
|
self stoploopsound( 0,4 );
|
|
wait 0,4;
|
|
self playloopsound( "zmb_tank_loop", 1 );
|
|
while ( str_location_original == self.str_location_current )
|
|
{
|
|
self.n_cooldown_timer += self.n_players_on * 0,05;
|
|
wait 0,05;
|
|
}
|
|
}
|
|
|
|
wait_for_tank_cooldown()
|
|
{
|
|
self thread snd_fuel();
|
|
if ( self.n_cooldown_timer < 2 )
|
|
{
|
|
self.n_cooldown_timer = 2;
|
|
}
|
|
else
|
|
{
|
|
if ( self.n_cooldown_timer > 120 )
|
|
{
|
|
self.n_cooldown_timer = 120;
|
|
}
|
|
}
|
|
wait self.n_cooldown_timer;
|
|
level notify( "stp_cd" );
|
|
self playsound( "zmb_tank_ready" );
|
|
self playloopsound( "zmb_tank_idle" );
|
|
}
|
|
|
|
snd_fuel()
|
|
{
|
|
snd_cd_ent = spawn( "script_origin", self.origin );
|
|
snd_cd_ent linkto( self );
|
|
wait 4;
|
|
snd_cd_ent playsound( "zmb_tank_fuel_start" );
|
|
wait 0,5;
|
|
snd_cd_ent playloopsound( "zmb_tank_fuel_loop" );
|
|
level waittill( "stp_cd" );
|
|
snd_cd_ent stoploopsound( 0,5 );
|
|
snd_cd_ent playsound( "zmb_tank_fuel_end" );
|
|
wait 2;
|
|
snd_cd_ent delete();
|
|
}
|
|
|
|
follow_path( n_path_start )
|
|
{
|
|
self endon( "death" );
|
|
/#
|
|
assert( isDefined( n_path_start ), "vehicle_path() called without a path" );
|
|
#/
|
|
self notify( "newpath" );
|
|
self endon( "newpath" );
|
|
n_next_point = n_path_start;
|
|
while ( isDefined( n_next_point ) )
|
|
{
|
|
self.n_next_node = getvehiclenode( n_next_point.target, "targetname" );
|
|
self waittill( "reached_node", n_next_point );
|
|
self.n_current = n_next_point;
|
|
n_next_point notify( "trigger" );
|
|
if ( isDefined( n_next_point.script_noteworthy ) )
|
|
{
|
|
self notify( n_next_point.script_noteworthy );
|
|
self notify( "noteworthy" );
|
|
}
|
|
waittillframeend;
|
|
}
|
|
}
|
|
|
|
tank_tag_array_setup()
|
|
{
|
|
a_tank_tags = [];
|
|
a_tank_tags[ 0 ] = spawnstruct();
|
|
a_tank_tags[ 0 ].str_tag = "window_left_1_jmp_jnt";
|
|
a_tank_tags[ 0 ].disabled_at_bunker = 1;
|
|
a_tank_tags[ 0 ].disabled_at_church = 1;
|
|
a_tank_tags[ 0 ].side = "left";
|
|
a_tank_tags[ 1 ] = spawnstruct();
|
|
a_tank_tags[ 1 ].str_tag = "window_left_2_jmp_jnt";
|
|
a_tank_tags[ 1 ].disabled_at_bunker = 1;
|
|
a_tank_tags[ 1 ].disabled_at_church = 1;
|
|
a_tank_tags[ 1 ].side = "left";
|
|
a_tank_tags[ 2 ] = spawnstruct();
|
|
a_tank_tags[ 2 ].str_tag = "window_left_3_jmp_jnt";
|
|
a_tank_tags[ 2 ].disabled_at_bunker = 1;
|
|
a_tank_tags[ 2 ].disabled_at_church = 1;
|
|
a_tank_tags[ 2 ].side = "left";
|
|
a_tank_tags[ 3 ] = spawnstruct();
|
|
a_tank_tags[ 3 ].str_tag = "window_right_front_jmp_jnt";
|
|
a_tank_tags[ 3 ].side = "front";
|
|
a_tank_tags[ 4 ] = spawnstruct();
|
|
a_tank_tags[ 4 ].str_tag = "window_right_1_jmp_jnt";
|
|
a_tank_tags[ 4 ].side = "right";
|
|
a_tank_tags[ 5 ] = spawnstruct();
|
|
a_tank_tags[ 5 ].str_tag = "window_right_2_jmp_jnt";
|
|
a_tank_tags[ 5 ].disabled_at_church = 1;
|
|
a_tank_tags[ 5 ].side = "right";
|
|
a_tank_tags[ 6 ] = spawnstruct();
|
|
a_tank_tags[ 6 ].str_tag = "window_right_3_jmp_jnt";
|
|
a_tank_tags[ 6 ].disabled_at_church = 1;
|
|
a_tank_tags[ 6 ].side = "right";
|
|
a_tank_tags[ 7 ] = spawnstruct();
|
|
a_tank_tags[ 7 ].str_tag = "window_left_rear_jmp_jnt";
|
|
a_tank_tags[ 7 ].side = "rear";
|
|
return a_tank_tags;
|
|
}
|
|
|
|
get_players_on_tank( valid_targets_only )
|
|
{
|
|
if ( !isDefined( valid_targets_only ) )
|
|
{
|
|
valid_targets_only = 0;
|
|
}
|
|
a_players_on_tank = [];
|
|
a_players = getplayers();
|
|
_a1032 = a_players;
|
|
_k1032 = getFirstArrayKey( _a1032 );
|
|
while ( isDefined( _k1032 ) )
|
|
{
|
|
e_player = _a1032[ _k1032 ];
|
|
if ( is_player_valid( e_player ) && isDefined( e_player.b_already_on_tank ) && e_player.b_already_on_tank )
|
|
{
|
|
if ( !valid_targets_only || isDefined( e_player.ignoreme ) && !e_player.ignoreme && is_player_valid( e_player ) )
|
|
{
|
|
a_players_on_tank[ a_players_on_tank.size ] = e_player;
|
|
}
|
|
}
|
|
_k1032 = getNextArrayKey( _a1032, _k1032 );
|
|
}
|
|
return a_players_on_tank;
|
|
}
|
|
|
|
mechz_tag_array_setup()
|
|
{
|
|
a_mechz_tags = [];
|
|
a_mechz_tags[ 0 ] = spawnstruct();
|
|
a_mechz_tags[ 0 ].str_tag = "tag_mechz_1";
|
|
a_mechz_tags[ 0 ].in_use = 0;
|
|
a_mechz_tags[ 0 ].in_use_by = undefined;
|
|
a_mechz_tags[ 1 ] = spawnstruct();
|
|
a_mechz_tags[ 1 ].str_tag = "tag_mechz_2";
|
|
a_mechz_tags[ 1 ].in_use = 0;
|
|
a_mechz_tags[ 1 ].in_use_by = undefined;
|
|
a_mechz_tags[ 2 ] = spawnstruct();
|
|
a_mechz_tags[ 2 ].str_tag = "tag_mechz_3";
|
|
a_mechz_tags[ 2 ].in_use = 0;
|
|
a_mechz_tags[ 2 ].in_use_by = undefined;
|
|
a_mechz_tags[ 3 ] = spawnstruct();
|
|
a_mechz_tags[ 3 ].str_tag = "tag_mechz_4";
|
|
a_mechz_tags[ 3 ].in_use = 0;
|
|
a_mechz_tags[ 3 ].in_use_by = undefined;
|
|
return a_mechz_tags;
|
|
}
|
|
|
|
mechz_tag_in_use_cleanup( mechz, tag_struct_index )
|
|
{
|
|
mechz notify( "kill_mechz_tag_in_use_cleanup" );
|
|
mechz endon( "kill_mechz_tag_in_use_cleanup" );
|
|
mechz waittill_any_or_timeout( 30, "death", "kill_ft", "tank_flamethrower_attack_complete" );
|
|
self.a_mechz_tags[ tag_struct_index ].in_use = 0;
|
|
self.a_mechz_tags[ tag_struct_index ].in_use_by = undefined;
|
|
}
|
|
|
|
get_closest_mechz_tag_on_tank( mechz, target_org )
|
|
{
|
|
best_dist = -1;
|
|
best_tag_index = undefined;
|
|
i = 0;
|
|
while ( i < self.a_mechz_tags.size )
|
|
{
|
|
if ( self.a_mechz_tags[ i ].in_use && self.a_mechz_tags[ i ].in_use_by != mechz )
|
|
{
|
|
i++;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
s_tag = self.a_mechz_tags[ i ];
|
|
tag_org = self gettagorigin( s_tag.str_tag );
|
|
dist = distancesquared( tag_org, target_org );
|
|
if ( dist < best_dist || best_dist < 0 )
|
|
{
|
|
best_dist = dist;
|
|
best_tag_index = i;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
if ( isDefined( best_tag_index ) )
|
|
{
|
|
i = 0;
|
|
while ( i < self.a_mechz_tags.size )
|
|
{
|
|
if ( self.a_mechz_tags[ i ].in_use && self.a_mechz_tags[ i ].in_use_by == mechz )
|
|
{
|
|
self.a_mechz_tags[ i ].in_use = 0;
|
|
self.a_mechz_tags[ i ].in_use_by = undefined;
|
|
}
|
|
i++;
|
|
}
|
|
self.a_mechz_tags[ best_tag_index ].in_use = 1;
|
|
self.a_mechz_tags[ best_tag_index ].in_use_by = mechz;
|
|
self thread mechz_tag_in_use_cleanup( mechz, best_tag_index );
|
|
return self.a_mechz_tags[ best_tag_index ].str_tag;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
tank_tag_is_valid( s_tag, disable_sides )
|
|
{
|
|
if ( !isDefined( disable_sides ) )
|
|
{
|
|
disable_sides = 0;
|
|
}
|
|
if ( disable_sides )
|
|
{
|
|
if ( s_tag.side == "right" || s_tag.side == "left" )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
if ( self ent_flag( "tank_moving" ) )
|
|
{
|
|
if ( s_tag.side == "front" )
|
|
{
|
|
return 0;
|
|
}
|
|
if ( !isDefined( self.n_next_node ) )
|
|
{
|
|
return 1;
|
|
}
|
|
if ( !isDefined( self.n_next_node.script_string ) )
|
|
{
|
|
return 1;
|
|
}
|
|
if ( issubstr( self.n_next_node.script_string, "disable_" + s_tag.side ) )
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
at_church = self.str_location_current == "village";
|
|
at_bunker = self.str_location_current == "bunkers";
|
|
if ( at_church )
|
|
{
|
|
if ( isDefined( s_tag.disabled_at_church )return !s_tag.disabled_at_church;
|
|
}
|
|
else
|
|
{
|
|
&& at_bunker )
|
|
{
|
|
if ( isDefined( s_tag.disabled_at_bunker )return !s_tag.disabled_at_bunker;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
zombies_watch_tank()
|
|
{
|
|
a_tank_tags = tank_tag_array_setup();
|
|
self.a_tank_tags = a_tank_tags;
|
|
a_mechz_tags = mechz_tag_array_setup();
|
|
self.a_mechz_tags = a_mechz_tags;
|
|
while ( 1 )
|
|
{
|
|
a_zombies = get_round_enemy_array();
|
|
_a1198 = a_zombies;
|
|
_k1198 = getFirstArrayKey( _a1198 );
|
|
while ( isDefined( _k1198 ) )
|
|
{
|
|
e_zombie = _a1198[ _k1198 ];
|
|
if ( !isDefined( e_zombie.tank_state ) )
|
|
{
|
|
e_zombie thread tank_zombie_think();
|
|
}
|
|
_k1198 = getNextArrayKey( _a1198, _k1198 );
|
|
}
|
|
wait_network_frame();
|
|
}
|
|
}
|
|
|
|
start_chasing_tank()
|
|
{
|
|
self.tank_state = "tank_chase";
|
|
}
|
|
|
|
stop_chasing_tank()
|
|
{
|
|
self.tank_state = "none";
|
|
self.str_tank_tag = undefined;
|
|
self.tank_tag = undefined;
|
|
self.b_on_tank = 0;
|
|
self.tank_re_eval_time = undefined;
|
|
self notify( "change_goal" );
|
|
if ( isDefined( self.zombie_move_speed_original ) )
|
|
{
|
|
self set_zombie_run_cycle( self.zombie_move_speed_original );
|
|
}
|
|
}
|
|
|
|
choose_tag_and_chase()
|
|
{
|
|
s_tag = self get_closest_valid_tank_tag();
|
|
if ( isDefined( s_tag ) )
|
|
{
|
|
self.str_tank_tag = s_tag.str_tag;
|
|
self.tank_tag = s_tag;
|
|
self.tank_state = "tag_chase";
|
|
}
|
|
else
|
|
{
|
|
wait 1;
|
|
}
|
|
}
|
|
|
|
choose_tag_and_jump_down()
|
|
{
|
|
s_tag = self get_closest_valid_tank_tag( 1 );
|
|
if ( isDefined( s_tag ) )
|
|
{
|
|
self.str_tank_tag = s_tag.str_tag;
|
|
self.tank_tag = getstruct( s_tag.str_tag + "_down_start", "targetname" );
|
|
self.tank_state = "exit_tank";
|
|
self set_zombie_run_cycle( "walk" );
|
|
/#
|
|
assert( isDefined( self.tank_tag ) );
|
|
#/
|
|
}
|
|
else
|
|
{
|
|
wait 1;
|
|
}
|
|
}
|
|
|
|
climb_tag()
|
|
{
|
|
self endon( "death" );
|
|
self.tank_state = "climbing";
|
|
self.b_on_tank = 1;
|
|
str_tag = self.str_tank_tag;
|
|
self linkto( level.vh_tank, str_tag );
|
|
v_tag_origin = level.vh_tank gettagorigin( str_tag );
|
|
v_tag_angles = level.vh_tank gettagangles( str_tag );
|
|
str_anim_alias = str_tag;
|
|
if ( level.vh_tank ent_flag( "tank_moving" ) && str_tag == "window_left_rear_jmp_jnt" )
|
|
{
|
|
str_anim_alias = "window_rear_long_jmp_jnt";
|
|
}
|
|
if ( !self.has_legs )
|
|
{
|
|
str_anim_alias += "_crawler";
|
|
}
|
|
n_anim_index = self getanimsubstatefromasd( "zm_tank_jump_up", str_anim_alias );
|
|
self.b_climbing_tank = 1;
|
|
self animscripted( v_tag_origin, v_tag_angles, "zm_tank_jump_up", n_anim_index );
|
|
self zombieanimnotetrackthink( "tank_jump_up" );
|
|
self unlink();
|
|
self.b_climbing_tank = 0;
|
|
level.vh_tank tank_mark_tag_occupied( str_tag, self, 0 );
|
|
set_zombie_on_tank();
|
|
}
|
|
|
|
set_zombie_on_tank()
|
|
{
|
|
self setgoalpos( self.origin );
|
|
self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
|
|
self.tank_state = "on_tank";
|
|
}
|
|
|
|
jump_down_tag()
|
|
{
|
|
self endon( "death" );
|
|
self.tank_state = "jumping_down";
|
|
str_tag = self.str_tank_tag;
|
|
self linkto( level.vh_tank, str_tag );
|
|
v_tag_origin = level.vh_tank gettagorigin( str_tag );
|
|
v_tag_angles = level.vh_tank gettagangles( str_tag );
|
|
self setgoalpos( v_tag_origin );
|
|
str_anim_alias = str_tag;
|
|
if ( !self.has_legs )
|
|
{
|
|
str_anim_alias += "_crawler";
|
|
}
|
|
n_anim_index = self getanimsubstatefromasd( "zm_tank_jump_down", str_anim_alias );
|
|
self.b_climbing_tank = 1;
|
|
self animscripted( v_tag_origin, v_tag_angles, "zm_tank_jump_down", n_anim_index );
|
|
self zombieanimnotetrackthink( "tank_jump_down" );
|
|
self unlink();
|
|
self.b_climbing_tank = 0;
|
|
level.vh_tank tank_mark_tag_occupied( str_tag, self, 0 );
|
|
self.pursuing_tank_tag = 0;
|
|
stop_chasing_tank();
|
|
}
|
|
|
|
watch_zombie_fall_off_tank()
|
|
{
|
|
self endon( "death" );
|
|
while ( 1 )
|
|
{
|
|
if ( self.tank_state == "on_tank" || self.tank_state == "exit_tank" )
|
|
{
|
|
if ( !self entity_on_tank() )
|
|
{
|
|
stop_chasing_tank();
|
|
}
|
|
wait 0,5;
|
|
}
|
|
else
|
|
{
|
|
if ( self.tank_state == "none" )
|
|
{
|
|
if ( self entity_on_tank() )
|
|
{
|
|
set_zombie_on_tank();
|
|
}
|
|
wait 5;
|
|
}
|
|
}
|
|
wait_network_frame();
|
|
}
|
|
}
|
|
|
|
in_range_2d( v1, v2, range, vert_allowance )
|
|
{
|
|
if ( abs( v1[ 2 ] - v2[ 2 ] ) > vert_allowance )
|
|
{
|
|
return 0;
|
|
}
|
|
return distance2dsquared( v1, v2 ) < ( range * range );
|
|
}
|
|
|
|
tank_zombie_think()
|
|
{
|
|
self endon( "death" );
|
|
self.tank_state = "none";
|
|
self thread watch_zombie_fall_off_tank();
|
|
think_time = 0,5;
|
|
while ( 1 )
|
|
{
|
|
a_players_on_tank = get_players_on_tank( 1 );
|
|
tag_range = 32;
|
|
if ( level.vh_tank ent_flag( "tank_moving" ) )
|
|
{
|
|
tag_range = 64;
|
|
}
|
|
switch( self.tank_state )
|
|
{
|
|
case "none":
|
|
if ( !isDefined( self.ai_state ) || self.ai_state != "find_flesh" )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if ( a_players_on_tank.size == 0 )
|
|
{
|
|
break;
|
|
break;
|
|
}
|
|
else if ( is_player_valid( self.favoriteenemy ) )
|
|
{
|
|
if ( isDefined( self.favoriteenemy.b_already_on_tank ) && self.favoriteenemy.b_already_on_tank )
|
|
{
|
|
self start_chasing_tank();
|
|
}
|
|
}
|
|
else a_players = getplayers();
|
|
a_eligible_players = [];
|
|
_a1439 = a_players;
|
|
_k1439 = getFirstArrayKey( _a1439 );
|
|
while ( isDefined( _k1439 ) )
|
|
{
|
|
e_player = _a1439[ _k1439 ];
|
|
if ( isDefined( e_player.ignoreme ) && !e_player.ignoreme && is_player_valid( e_player ) )
|
|
{
|
|
a_eligible_players[ a_eligible_players.size ] = e_player;
|
|
}
|
|
_k1439 = getNextArrayKey( _a1439, _k1439 );
|
|
}
|
|
if ( a_eligible_players.size > 0 )
|
|
{
|
|
if ( a_players_on_tank.size == a_players.size )
|
|
{
|
|
self.favoriteenemy = random( a_eligible_players );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
self.favoriteenemy = tomb_get_closest_player_using_paths( self.origin, a_eligible_players );
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case "tank_chase":
|
|
if ( a_players_on_tank.size == 0 )
|
|
{
|
|
self stop_chasing_tank();
|
|
break;
|
|
break;
|
|
}
|
|
else dist_sq_to_tank = distancesquared( self.origin, level.vh_tank.origin );
|
|
if ( dist_sq_to_tank < 250000 )
|
|
{
|
|
self choose_tag_and_chase();
|
|
}
|
|
if ( self.has_legs && self.zombie_move_speed != "super_sprint" && isDefined( self.is_traversing ) && !self.is_traversing && self.ai_state == "find_flesh" )
|
|
{
|
|
if ( level.vh_tank ent_flag( "tank_moving" ) )
|
|
{
|
|
self set_zombie_run_cycle( "super_sprint" );
|
|
self thread zombie_chasing_tank_turn_crawler();
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case "tag_chase":
|
|
if ( !isDefined( self.tank_re_eval_time ) )
|
|
{
|
|
self.tank_re_eval_time = 6;
|
|
}
|
|
else
|
|
{
|
|
if ( self.tank_re_eval_time <= 0 )
|
|
{
|
|
if ( self entity_on_tank() )
|
|
{
|
|
self set_zombie_on_tank();
|
|
}
|
|
else
|
|
{
|
|
self stop_chasing_tank();
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
else self notify( "stop_path_to_tag" );
|
|
if ( a_players_on_tank.size == 0 )
|
|
{
|
|
self stop_chasing_tank();
|
|
break;
|
|
break;
|
|
}
|
|
else dist_sq_to_tank = distancesquared( self.origin, level.vh_tank.origin );
|
|
if ( dist_sq_to_tank > 1000000 || a_players_on_tank.size == 0 )
|
|
{
|
|
start_chasing_tank();
|
|
break;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
v_tag = level.vh_tank gettagorigin( self.str_tank_tag );
|
|
if ( in_range_2d( v_tag, self.origin, tag_range, tag_range ) )
|
|
{
|
|
tag_claimed = level.vh_tank tank_mark_tag_occupied( self.str_tank_tag, self, 1 );
|
|
if ( tag_claimed )
|
|
{
|
|
self thread climb_tag();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self thread update_zombie_goal_pos( self.str_tank_tag, "stop_path_to_tag" );
|
|
self.tank_re_eval_time -= think_time;
|
|
}
|
|
break;
|
|
break;
|
|
case "climbing":
|
|
case "on_tank":
|
|
if ( a_players_on_tank.size == 0 )
|
|
{
|
|
choose_tag_and_jump_down();
|
|
}
|
|
else if ( !isDefined( self.favoriteenemy ) || !is_player_valid( self.favoriteenemy, 1 ) )
|
|
{
|
|
self.favoriteenemy = random( a_players_on_tank );
|
|
}
|
|
break;
|
|
break;
|
|
case "exit_tank":
|
|
self notify( "stop_exit_tank" );
|
|
if ( a_players_on_tank.size > 0 )
|
|
{
|
|
set_zombie_on_tank();
|
|
break;
|
|
break;
|
|
}
|
|
else v_tag_pos = level.vh_tank tank_get_jump_down_offset( self.tank_tag );
|
|
if ( in_range_2d( v_tag_pos, self.origin, tag_range, tag_range ) )
|
|
{
|
|
tag_claimed = level.vh_tank tank_mark_tag_occupied( self.str_tank_tag, self, 1 );
|
|
if ( tag_claimed )
|
|
{
|
|
self thread jump_down_tag();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self thread update_zombie_goal_pos( self.tank_tag.targetname, "stop_exit_tank" );
|
|
wait 1;
|
|
}
|
|
break;
|
|
break;
|
|
case "jumping_down":
|
|
}
|
|
}
|
|
}
|
|
wait think_time;
|
|
}
|
|
}
|
|
|
|
update_zombie_goal_pos( str_position, stop_notify )
|
|
{
|
|
self notify( "change_goal" );
|
|
self endon( "death" );
|
|
self endon( "goal" );
|
|
self endon( "near_goal" );
|
|
self endon( "change_goal" );
|
|
if ( isDefined( stop_notify ) )
|
|
{
|
|
self endon( stop_notify );
|
|
}
|
|
s_script_origin = getstruct( str_position, "targetname" );
|
|
while ( self.tank_state != "none" )
|
|
{
|
|
if ( isDefined( s_script_origin ) )
|
|
{
|
|
v_origin = level.vh_tank tank_get_jump_down_offset( s_script_origin );
|
|
/#
|
|
if ( getDvar( "debug_tank" ) == "on" )
|
|
{
|
|
line( self.origin + vectorScale( ( 0, 0, 1 ), 30 ), v_origin );
|
|
#/
|
|
}
|
|
}
|
|
else
|
|
{
|
|
v_origin = level.vh_tank gettagorigin( str_position );
|
|
}
|
|
self setgoalpos( v_origin );
|
|
wait 0,05;
|
|
}
|
|
}
|
|
|
|
zombie_chasing_tank_turn_crawler()
|
|
{
|
|
self notify( "tank_watch_turn_crawler" );
|
|
self endon( "tank_watch_turn_crawler" );
|
|
self endon( "death" );
|
|
while ( self.has_legs )
|
|
{
|
|
wait 0,05;
|
|
}
|
|
self set_zombie_run_cycle( self.zombie_move_speed_original );
|
|
}
|
|
|
|
tank_mark_tag_occupied( str_tag, ai_occupier, set_occupied )
|
|
{
|
|
current_occupier = self.tag_occupied[ str_tag ];
|
|
min_dist_sq_to_tag = 1024;
|
|
if ( set_occupied )
|
|
{
|
|
if ( !isDefined( current_occupier ) )
|
|
{
|
|
self.tag_occupied[ str_tag ] = ai_occupier;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if ( ai_occupier == current_occupier || !isalive( current_occupier ) )
|
|
{
|
|
dist_sq_to_tag = distance2dsquared( ai_occupier.origin, self gettagorigin( str_tag ) );
|
|
if ( dist_sq_to_tag < min_dist_sq_to_tag )
|
|
{
|
|
self.tag_occupied[ str_tag ] = ai_occupier;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if ( !isDefined( current_occupier ) )
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if ( current_occupier != ai_occupier )
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
is_tag_crowded( str_tag )
|
|
{
|
|
v_tag = self gettagorigin( str_tag );
|
|
a_zombies = getaiarray( level.zombie_team );
|
|
n_nearby_zombies = 0;
|
|
_a1714 = a_zombies;
|
|
_k1714 = getFirstArrayKey( _a1714 );
|
|
while ( isDefined( _k1714 ) )
|
|
{
|
|
e_zombie = _a1714[ _k1714 ];
|
|
dist_sq = distancesquared( v_tag, e_zombie.origin );
|
|
if ( dist_sq < 4096 )
|
|
{
|
|
if ( isDefined( e_zombie.tank_state ) )
|
|
{
|
|
if ( e_zombie.tank_state != "tank_chase" && e_zombie.tank_state != "tag_chase" && e_zombie.tank_state != "none" )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
n_nearby_zombies++;
|
|
if ( n_nearby_zombies >= 4 )
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
_k1714 = getNextArrayKey( _a1714, _k1714 );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
get_closest_valid_tank_tag( jumping_down )
|
|
{
|
|
if ( !isDefined( jumping_down ) )
|
|
{
|
|
jumping_down = 0;
|
|
}
|
|
closest_dist_sq = 100000000;
|
|
closest_tag = undefined;
|
|
disable_sides = 0;
|
|
if ( jumping_down && level.vh_tank ent_flag( "tank_moving" ) )
|
|
{
|
|
disable_sides = 1;
|
|
}
|
|
_a1752 = level.vh_tank.a_tank_tags;
|
|
_k1752 = getFirstArrayKey( _a1752 );
|
|
while ( isDefined( _k1752 ) )
|
|
{
|
|
s_tag = _a1752[ _k1752 ];
|
|
if ( level.vh_tank tank_tag_is_valid( s_tag, disable_sides ) )
|
|
{
|
|
v_tag = level.vh_tank gettagorigin( s_tag.str_tag );
|
|
dist_sq = distancesquared( self.origin, v_tag );
|
|
if ( dist_sq < closest_dist_sq )
|
|
{
|
|
if ( !level.vh_tank is_tag_crowded( s_tag.str_tag ) )
|
|
{
|
|
closest_tag = s_tag;
|
|
closest_dist_sq = dist_sq;
|
|
}
|
|
}
|
|
}
|
|
_k1752 = getNextArrayKey( _a1752, _k1752 );
|
|
}
|
|
return closest_tag;
|
|
}
|
|
|
|
zombieanimnotetrackthink( str_anim_notetrack_notify, chunk, node )
|
|
{
|
|
self endon( "death" );
|
|
while ( 1 )
|
|
{
|
|
self waittill( str_anim_notetrack_notify, str_notetrack );
|
|
if ( str_notetrack == "end" )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
tank_run_flamethrowers()
|
|
{
|
|
self thread tank_flamethrower( "tag_flash", 1 );
|
|
wait 0,25;
|
|
self thread tank_flamethrower( "tag_flash_gunner1", 2 );
|
|
wait 0,25;
|
|
self thread tank_flamethrower( "tag_flash_gunner2", 3 );
|
|
}
|
|
|
|
tank_flamethrower_get_targets( str_tag, n_flamethrower_id )
|
|
{
|
|
a_zombies = getaiarray( level.zombie_team );
|
|
a_targets = [];
|
|
v_tag_pos = self gettagorigin( str_tag );
|
|
v_tag_angles = self gettagangles( str_tag );
|
|
v_tag_fwd = anglesToForward( v_tag_angles );
|
|
v_kill_pos = v_tag_pos + ( v_tag_fwd * 80 );
|
|
_a1813 = a_zombies;
|
|
_k1813 = getFirstArrayKey( _a1813 );
|
|
while ( isDefined( _k1813 ) )
|
|
{
|
|
ai_zombie = _a1813[ _k1813 ];
|
|
dist_sq = distance2dsquared( ai_zombie.origin, v_kill_pos );
|
|
if ( dist_sq > ( 80 * 80 ) )
|
|
{
|
|
}
|
|
else if ( isDefined( ai_zombie.tank_state ) )
|
|
{
|
|
if ( ai_zombie.tank_state == "climbing" || ai_zombie.tank_state == "jumping_down" )
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
v_to_zombie = vectornormalize( ai_zombie.origin - v_tag_pos );
|
|
n_dot = vectordot( v_tag_fwd, ai_zombie.origin );
|
|
if ( n_dot < 0,95 )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
a_targets[ a_targets.size ] = ai_zombie;
|
|
}
|
|
}
|
|
_k1813 = getNextArrayKey( _a1813, _k1813 );
|
|
}
|
|
return a_targets;
|
|
}
|
|
|
|
tank_flamethrower_cycle_targets( str_tag, n_flamethrower_id )
|
|
{
|
|
self endon( "flamethrower_stop_" + n_flamethrower_id );
|
|
while ( 1 )
|
|
{
|
|
a_targets = tank_flamethrower_get_targets( str_tag, n_flamethrower_id );
|
|
_a1854 = a_targets;
|
|
_k1854 = getFirstArrayKey( _a1854 );
|
|
while ( isDefined( _k1854 ) )
|
|
{
|
|
ai = _a1854[ _k1854 ];
|
|
if ( isalive( ai ) )
|
|
{
|
|
self setturrettargetent( ai );
|
|
wait 1;
|
|
}
|
|
_k1854 = getNextArrayKey( _a1854, _k1854 );
|
|
}
|
|
wait 1;
|
|
}
|
|
}
|
|
|
|
tank_flamethrower( str_tag, n_flamethrower_id )
|
|
{
|
|
zombieless_waits = 0;
|
|
time_between_flames = randomfloatrange( 3, 6 );
|
|
while ( 1 )
|
|
{
|
|
wait 1;
|
|
if ( n_flamethrower_id == 1 )
|
|
{
|
|
self setturrettargetvec( self.origin + ( anglesToForward( self.angles ) * 1000 ) );
|
|
}
|
|
self ent_flag_wait( "tank_moving" );
|
|
a_targets = tank_flamethrower_get_targets( str_tag, n_flamethrower_id );
|
|
if ( a_targets.size > 0 || zombieless_waits > time_between_flames )
|
|
{
|
|
self setclientfield( "tank_flamethrower_fx", n_flamethrower_id );
|
|
self thread flamethrower_damage_zombies( n_flamethrower_id, str_tag );
|
|
if ( n_flamethrower_id == 1 )
|
|
{
|
|
self thread tank_flamethrower_cycle_targets( str_tag, n_flamethrower_id );
|
|
}
|
|
if ( a_targets.size > 0 )
|
|
{
|
|
wait 6;
|
|
}
|
|
else
|
|
{
|
|
wait 3;
|
|
}
|
|
self setclientfield( "tank_flamethrower_fx", 0 );
|
|
self notify( "flamethrower_stop_" + n_flamethrower_id );
|
|
zombieless_waits = 0;
|
|
time_between_flames = randomfloatrange( 3, 6 );
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
zombieless_waits++;
|
|
}
|
|
}
|
|
}
|
|
|
|
flamethrower_damage_zombies( n_flamethrower_id, str_tag )
|
|
{
|
|
self endon( "flamethrower_stop_" + n_flamethrower_id );
|
|
while ( 1 )
|
|
{
|
|
a_targets = tank_flamethrower_get_targets( str_tag, n_flamethrower_id );
|
|
_a1926 = a_targets;
|
|
_k1926 = getFirstArrayKey( _a1926 );
|
|
while ( isDefined( _k1926 ) )
|
|
{
|
|
ai_zombie = _a1926[ _k1926 ];
|
|
if ( isalive( ai_zombie ) )
|
|
{
|
|
a_players = get_players_on_tank( 1 );
|
|
if ( a_players.size > 0 )
|
|
{
|
|
level notify( "vo_tank_flame_zombie" );
|
|
}
|
|
if ( str_tag == "tag_flash" )
|
|
{
|
|
ai_zombie do_damage_network_safe( self, ai_zombie.health, "zm_tank_flamethrower", "MOD_BURNED" );
|
|
ai_zombie thread zombie_gib_guts();
|
|
}
|
|
else
|
|
{
|
|
ai_zombie thread maps/mp/zombies/_zm_weap_staff_fire::flame_damage_fx( "zm_tank_flamethrower", self );
|
|
}
|
|
wait 0,05;
|
|
}
|
|
_k1926 = getNextArrayKey( _a1926, _k1926 );
|
|
}
|
|
wait_network_frame();
|
|
}
|
|
}
|
|
|
|
enemy_location_override()
|
|
{
|
|
self endon( "death" );
|
|
enemy = self.favoriteenemy;
|
|
location = enemy.origin;
|
|
tank = level.vh_tank;
|
|
if ( isDefined( self.is_mechz ) && self.is_mechz )
|
|
{
|
|
return location;
|
|
}
|
|
if ( isDefined( self.item ) )
|
|
{
|
|
return self.origin;
|
|
}
|
|
if ( is_true( self.reroute ) )
|
|
{
|
|
if ( isDefined( self.reroute_origin ) )
|
|
{
|
|
location = self.reroute_origin;
|
|
}
|
|
}
|
|
if ( isDefined( self.tank_state ) )
|
|
{
|
|
if ( self.tank_state == "tank_chase" )
|
|
{
|
|
self.goalradius = 128;
|
|
}
|
|
else if ( self.tank_state == "tag_chase" )
|
|
{
|
|
self.goalradius = 16;
|
|
}
|
|
else
|
|
{
|
|
self.goalradius = 32;
|
|
}
|
|
if ( self.tank_state == "tank_chase" || self.tank_state == "none" && isDefined( enemy.b_already_on_tank ) && enemy.b_already_on_tank )
|
|
{
|
|
tank_front = tank gettagorigin( "window_right_front_jmp_jnt" );
|
|
tank_back = tank gettagorigin( "window_left_rear_jmp_jnt" );
|
|
if ( tank ent_flag( "tank_moving" ) )
|
|
{
|
|
self.ignoreall = 1;
|
|
if ( isDefined( self.close_to_tank ) && !self.close_to_tank )
|
|
{
|
|
if ( getTime() != tank.chase_pos_time )
|
|
{
|
|
tank.chase_pos_time = getTime();
|
|
tank.chase_pos_index = 0;
|
|
tank_forward = vectornormalize( anglesToForward( level.vh_tank.angles ) );
|
|
tank_right = vectornormalize( anglesToRight( level.vh_tank.angles ) );
|
|
tank.chase_pos = [];
|
|
tank.chase_pos[ 0 ] = level.vh_tank.origin + vectorScale( tank_forward, -164 );
|
|
tank.chase_pos[ 1 ] = tank_front;
|
|
tank.chase_pos[ 2 ] = tank_back;
|
|
}
|
|
location = tank.chase_pos[ tank.chase_pos_index ];
|
|
tank.chase_pos_index++;
|
|
if ( tank.chase_pos_index >= 3 )
|
|
{
|
|
tank.chase_pos_index = 0;
|
|
}
|
|
dist_sq = distancesquared( self.origin, location );
|
|
if ( dist_sq < 4096 )
|
|
{
|
|
self.close_to_tank = 1;
|
|
}
|
|
}
|
|
return location;
|
|
}
|
|
self.close_to_tank = 0;
|
|
front_dist = distance2dsquared( enemy.origin, level.vh_tank.origin );
|
|
back_dist = distance2dsquared( enemy.origin, level.vh_tank.origin );
|
|
if ( front_dist < back_dist )
|
|
{
|
|
location = tank_front;
|
|
}
|
|
else
|
|
{
|
|
location = tank_back;
|
|
}
|
|
self.ignoreall = 0;
|
|
}
|
|
else
|
|
{
|
|
if ( self.tank_state == "tag_chase" )
|
|
{
|
|
location = level.vh_tank gettagorigin( self.str_tank_tag );
|
|
}
|
|
else
|
|
{
|
|
if ( self.tank_state == "exit_tank" )
|
|
{
|
|
location = level.vh_tank tank_get_jump_down_offset( self.tank_tag );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return location;
|
|
}
|
|
|
|
adjust_enemyoverride()
|
|
{
|
|
self endon( "death" );
|
|
location = self.enemyoverride[ 0 ];
|
|
tank = level.vh_tank;
|
|
ent = self.enemyoverride[ 1 ];
|
|
return location;
|
|
}
|
|
|
|
closest_player_tank( origin, players )
|
|
{
|
|
if ( isDefined( level.vh_tank ) || level.vh_tank.n_players_on > 0 && isDefined( level.calc_closest_player_using_paths ) && !level.calc_closest_player_using_paths )
|
|
{
|
|
player = getclosest( origin, players );
|
|
}
|
|
else
|
|
{
|
|
player = get_closest_player_using_paths( origin, players );
|
|
}
|
|
if ( isDefined( player ) )
|
|
{
|
|
return player;
|
|
}
|
|
}
|
|
|
|
zombie_on_tank_death_animscript_callback( inflictor, attacker, damage, flags, meansofdeath, weapon, vpoint, vdir, shitloc, psoffsettime, boneindex )
|
|
{
|
|
if ( isDefined( self.exploding ) && self.exploding )
|
|
{
|
|
self notify( "killanimscript" );
|
|
self maps/mp/zombies/_zm_spawner::reset_attack_spot();
|
|
return 1;
|
|
}
|
|
if ( isDefined( self ) )
|
|
{
|
|
level maps/mp/zombies/_zm_spawner::zombie_death_points( self.origin, meansofdeath, shitloc, attacker, self );
|
|
launchvector = undefined;
|
|
self thread maps/mp/zombies/_zm_spawner::zombie_ragdoll_then_explode( launchvector, attacker );
|
|
self notify( "killanimscript" );
|
|
self maps/mp/zombies/_zm_spawner::reset_attack_spot();
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
tomb_get_path_length_to_tank()
|
|
{
|
|
tank_front = level.vh_tank gettagorigin( "window_right_front_jmp_jnt" ) + vectorScale( ( 0, 0, 1 ), 30 );
|
|
tank_back = level.vh_tank gettagorigin( "window_left_rear_jmp_jnt" ) + vectorScale( ( 0, 0, 1 ), 30 );
|
|
path_length_1 = self calcpathlength( tank_front );
|
|
path_length_2 = self calcpathlength( tank_back );
|
|
if ( path_length_1 < path_length_2 )
|
|
{
|
|
return path_length_1;
|
|
}
|
|
else
|
|
{
|
|
return path_length_2;
|
|
}
|
|
}
|