Files
Recompilable-gscs-for-BO2-z…/zm_transit_patch/maps/mp/zm_transit_openings.gsc
2020-08-30 17:40:45 -07:00

2501 lines
60 KiB
Plaintext

#include maps/mp/zm_transit_cling;
#include maps/mp/zombies/_zm_buildables;
#include maps/mp/zombies/_zm_audio;
#include maps/mp/animscripts/zm_run;
#include maps/mp/zombies/_zm_spawner;
#include maps/mp/zombies/_zm_ai_basic;
#include maps/mp/animscripts/zm_shared;
#include maps/mp/animscripts/zm_utility;
#include maps/mp/zm_transit_bus;
#include maps/mp/zombies/_zm_powerups;
#include maps/mp/zm_transit_utility;
#include maps/mp/zombies/_zm_utility;
#include maps/mp/zombies/_zm_blockers;
#include maps/mp/_utility;
#include common_scripts/utility;
main()
{
self _businittags();
self _setupnumattachtable();
self.openings = [];
x = 1;
while ( x <= 10 )
{
script_noteworthy = undefined;
switch( x )
{
case 10:
script_noteworthy = "front";
break;
case 11:
case 12:
script_noteworthy = "door";
break;
}
self busaddopening( "tag_entry_point" + x, script_noteworthy );
x++;
}
self bussetupladder();
self bussetuproofopening();
self businitmantle();
self businitrightandleft();
}
busaddopening( tag_name, script_noteworthy )
{
index = self.openings.size;
self.openings[ index ] = spawnstruct();
opening = self.openings[ index ];
opening.name = script_noteworthy;
opening.enabled = 1;
opening.zombie = undefined;
opening.boards = [];
opening.boardsnum = 0;
opening.blockertrigger = undefined;
opening.zombietrigger = undefined;
opening.rebuildtrigger = undefined;
opening.tagname = tag_name;
opening.bindtag = _busfindclosesttag( self gettagorigin( tag_name ) );
/#
assert( isDefined( opening.bindtag ) );
#/
opening.jumptag = _busgetjumptagfrombindtag( opening.bindtag );
opening.jumpent = level.the_bus;
opening.roofjoint = _busgetroofjointfrombindtag( opening.bindtag );
opening.origin = level.the_bus gettagorigin( opening.bindtag );
opening.angles = self gettagangles( opening.bindtag );
targets = getentarray( tag_name, "targetname" );
if ( !isDefined( targets ) )
{
/#
assert( 0 );
#/
return;
}
if ( !is_classic() )
{
i = 0;
while ( i < targets.size )
{
if ( targets[ i ] iszbarrier() )
{
targets[ i ] delete();
}
i++;
}
return;
}
i = 0;
while ( i < targets.size )
{
target = targets[ i ];
if ( target iszbarrier() )
{
hasbarriers = 1;
if ( isDefined( script_noteworthy ) && script_noteworthy == "front" )
{
hasbarriers = 0;
}
opening.zbarrier = target;
opening.zbarrier setmovingplatformenabled( 1 );
while ( hasbarriers )
{
opening.zbarrier.chunk_health = [];
opening.zbarrier setzbarriercolmodel( "p6_anim_zm_barricade_board_bus_collision" );
maps/mp/zombies/_zm_powerups::register_carpenter_node( opening, ::post_carpenter_callback );
j = 0;
while ( j < opening.zbarrier getnumzbarrierpieces() )
{
opening.zbarrier.chunk_health[ j ] = 0;
j++;
}
}
target.origin = level.the_bus gettagorigin( opening.bindtag );
}
else if ( target.script_noteworthy == "blocker" )
{
target delete();
i++;
continue;
}
else if ( target.script_noteworthy == "rebuild" )
{
opening.rebuildtrigger = target;
opening.rebuildtrigger enablelinkto();
opening.rebuildtrigger linkto( self );
opening.rebuildtrigger setcursorhint( "HINT_NOICON" );
opening.rebuildtrigger set_hint_string( self, "default_reward_barrier_piece" );
opening.rebuildtrigger triggerignoreteam();
opening.rebuildtrigger setinvisibletoall();
opening.rebuildtrigger setmovingplatformenabled( 1 );
self thread busopeningrebuildthink( opening );
i++;
continue;
}
else if ( target.script_noteworthy == "zombie" )
{
opening.zombietrigger = target;
opening.zombietrigger enablelinkto();
opening.zombietrigger linkto( self );
opening.zombietrigger setmovingplatformenabled( 1 );
opening.zombietrigger setteamfortrigger( level.zombie_team );
self thread busopeningzombiethink( opening );
}
target linkto( self, "", self worldtolocalcoords( target.origin ), target.angles - self.angles );
i++;
}
if ( isDefined( opening.zbarrier ) )
{
opening blocker_attack_spots();
}
opening notify( "opening_init_complete" );
/#
if ( opening.boardsnum != 0 )
{
assert( opening.boardsnum == opening.boards.size );
}
#/
}
post_carpenter_callback()
{
if ( isDefined( self.rebuildtrigger ) )
{
self.rebuildtrigger setinvisibletoall();
}
}
businitmantle()
{
mantlebrush = getentarray( "window_mantle", "targetname" );
while ( isDefined( mantlebrush ) && mantlebrush.size > 0 )
{
i = 0;
while ( i < mantlebrush.size )
{
mantlebrush[ i ] delete();
i++;
}
}
}
busattachjumpent( ent, opening )
{
jump_origin = self gettagorigin( opening.jumptag );
jump_angles = self gettagangles( opening.jumptag );
ent.origin = jump_origin;
ent.angles = jump_angles;
ent linkto( self, "", self worldtolocalcoords( ent.origin ), ent.angles - self.angles );
}
busopeningbyname( name )
{
i = 0;
while ( i < self.openings.size )
{
opening = self.openings[ i ];
if ( isDefined( opening.name ) && opening.name == name )
{
return opening;
}
i++;
}
return undefined;
}
busopeningsetenabled( name, enabled )
{
i = 0;
while ( i < self.openings.size )
{
opening = self.openings[ i ];
if ( isDefined( opening.name ) && opening.name == name )
{
opening.enabled = enabled;
}
i++;
}
}
_businittags()
{
self.openingtags = [];
self.openingtags[ self.openingtags.size ] = "window_right_front_jnt";
self.openingtags[ self.openingtags.size ] = "window_left_front_jnt";
self.openingtags[ self.openingtags.size ] = "door_front_jnt";
self.openingtags[ self.openingtags.size ] = "door_rear_jnt";
self.openingtags[ self.openingtags.size ] = "window_right_1_jnt";
self.openingtags[ self.openingtags.size ] = "window_right_2_jnt";
self.openingtags[ self.openingtags.size ] = "window_right_3_jnt";
self.openingtags[ self.openingtags.size ] = "window_right_4_jnt";
self.openingtags[ self.openingtags.size ] = "window_right_rear_jnt";
self.openingtags[ self.openingtags.size ] = "window_left_rear_jnt";
self.openingtags[ self.openingtags.size ] = "window_left_1_jnt";
self.openingtags[ self.openingtags.size ] = "window_left_2_jnt";
self.openingtags[ self.openingtags.size ] = "window_left_3_jnt";
self.openingtags[ self.openingtags.size ] = "window_left_4_jnt";
self.openingtags[ self.openingtags.size ] = "window_left_5_jnt";
/#
i = 0;
while ( i < self.openingtags.size )
{
adddebugcommand( "devgui_cmd "Zombies:1/Bus:14/Window Openings:3/Select Tag:1/" + self.openingtags[ i ] + ":" + self.openingtags.size + "" "zombie_devgui attach_tag " + self.openingtags[ i ] + ""\n" );
i++;
#/
}
}
_busfindclosesttag( checkpos )
{
closest = undefined;
closestdist = -1;
/#
assert( isDefined( self.openingtags ) );
#/
i = 0;
while ( i < self.openingtags.size )
{
tag = self.openingtags[ i ];
pos = self gettagorigin( tag );
dist2 = distancesquared( checkpos, pos );
if ( !isDefined( closest ) || dist2 < closestdist )
{
closest = tag;
closestdist = dist2;
}
i++;
}
return closest;
}
_busgetjumptagfrombindtag( tag )
{
jump_tag = undefined;
switch( tag )
{
case "window_right_1_jnt":
jump_tag = "window_right_1_jmp_jnt";
break;
case "window_right_2_jnt":
jump_tag = "window_right_2_jmp_jnt";
break;
case "window_right_3_jnt":
jump_tag = "window_right_3_jmp_jnt";
break;
case "window_right_4_jnt":
jump_tag = "window_right_4_jmp_jnt";
break;
case "window_left_1_jnt":
jump_tag = "window_left_1_jmp_jnt";
break;
case "window_left_2_jnt":
jump_tag = "window_left_2_jmp_jnt";
break;
case "window_left_3_jnt":
jump_tag = "window_left_3_jmp_jnt";
break;
case "window_left_4_jnt":
jump_tag = "window_left_4_jmp_jnt";
break;
case "window_left_5_jnt":
jump_tag = "window_left_5_jmp_jnt";
break;
case "window_right_rear_jnt":
jump_tag = "window_right_rear_jmp_jnt";
break;
case "window_left_rear_jnt":
jump_tag = "window_left_rear_jmp_jnt";
break;
case "window_right_front_jnt":
jump_tag = "window_right_front_jmp_jnt";
break;
case "window_left_front_jnt":
jump_tag = "window_left_front_jmp_jnt";
break;
case "door_rear_jnt":
jump_tag = "door_rear_jmp_jnt";
break;
case "door_front_jnt":
jump_tag = "door_front_jmp_jnt";
break;
default:
}
return jump_tag;
}
}
_busgetroofjointfrombindtag( tag )
{
roofjoint = undefined;
switch( tag )
{
case "window_left_1_jnt":
case "window_left_front_jnt":
case "window_right_1_jnt":
case "window_right_front_jnt":
roofjoint = "window_roof_1_jnt";
break;
case "window_left_2_jnt":
case "window_left_3_jnt":
case "window_left_4_jnt":
case "window_left_5_jnt":
case "window_left_rear_jnt":
case "window_right_2_jnt":
case "window_right_3_jnt":
case "window_right_4_jnt":
case "window_right_rear_jnt":
roofjoint = "window_roof_2_jnt";
default:
break;
}
return roofjoint;
}
}
_setupnumattachtable()
{
level.numattachtable = [];
level.numattachtable[ 0 ] = -1;
level.numattachtable[ 1 ] = 6;
level.numattachtable[ 2 ] = 8;
level.numattachtable[ 3 ] = 10;
level.numattachtable[ 4 ] = -1;
}
busgetopeningfortag( tagname )
{
i = 0;
while ( i < self.openings.size )
{
if ( self.openings[ i ].bindtag == tagname )
{
return self.openings[ i ];
}
i++;
}
return undefined;
}
zombieanimnotetrackthink( notifystring, chunk, node )
{
self endon( "death" );
while ( 1 )
{
self waittill( notifystring, notetrack );
if ( notetrack == "end" )
{
return;
continue;
}
else if ( notetrack == "board" || notetrack == "destroy_piece" )
{
node.zbarrier setzbarrierpiecestate( chunk, "opening" );
if ( isDefined( node.rebuildtrigger ) )
{
node.rebuildtrigger setvisibletoall();
}
continue;
}
else
{
while ( notetrack == "fire" )
{
attackplayers = self zombiegetplayerstoattack();
while ( attackplayers.size )
{
i = 0;
while ( i < attackplayers.size )
{
attackplayers[ i ] dodamage( self.meleedamage, self.origin, self, self, "none", "MOD_MELEE" );
i++;
}
}
}
}
}
}
busopeningblockerthink( opening )
{
self endon( "intermission" );
while ( 1 )
{
opening.blockertrigger waittill( "trigger", player );
while ( isDefined( opening.zombie ) )
{
continue;
}
}
self notify( "OnBlockerPlaced" );
}
buswatchtriggervisibility( opening )
{
self endon( "intermission" );
opening waittill( "opening_init_complete" );
if ( !isDefined( opening.zbarrier ) || opening.zbarrier getnumzbarrierpieces() < 1 )
{
return;
}
if ( !isDefined( level.buswatchtriggervisibility_spread ) )
{
level.buswatchtriggervisibility_spread = 0;
}
else
{
level.buswatchtriggervisibility_spread++;
wait ( 0,05 * level.buswatchtriggervisibility_spread );
}
while ( 1 )
{
if ( no_valid_repairable_boards( opening ) )
{
opening.rebuildtrigger setinvisibletoall();
}
else
{
opening.rebuildtrigger setvisibletoall();
}
wait 1;
}
}
busopeningrebuildthink( opening )
{
self endon( "intermission" );
self thread buswatchtriggervisibility( opening );
cost = 10;
if ( isDefined( opening.rebuildtrigger.zombie_cost ) )
{
cost = opening.rebuildtrigger.zombie_cost;
}
while ( 1 )
{
opening.rebuildtrigger waittill( "trigger", player );
players = get_players();
has_perk = player has_blocker_affecting_perk();
while ( player_fails_blocker_repair_trigger_preamble( player, players, opening.rebuildtrigger, 0 ) )
{
continue;
}
while ( all_chunks_intact( opening ) )
{
continue;
}
while ( no_valid_repairable_boards( opening ) )
{
continue;
}
chunk = get_random_destroyed_chunk( opening );
if ( isDefined( player.pers_upgrades_awarded[ "board" ] ) )
{
self thread replace_chunk( opening, chunk, has_perk, player.pers_upgrades_awarded[ "board" ] );
}
opening do_post_chunk_repair_delay( has_perk );
while ( !is_player_valid( player ) )
{
if ( no_valid_repairable_boards( opening ) )
{
opening.rebuildtrigger setinvisibletoall();
}
}
player handle_post_board_repair_rewards( cost );
if ( no_valid_repairable_boards( opening ) )
{
opening.rebuildtrigger setinvisibletoall();
}
}
}
_determinejumpfromorigin( opening )
{
return level.the_bus gettagorigin( opening.jumptag );
}
_getsideofbusopeningison( opening_tag )
{
side = undefined;
switch( opening_tag )
{
case "door_front_jnt":
case "door_rear_jnt":
case "window_right_1_jnt":
case "window_right_2_jnt":
case "window_right_3_jnt":
case "window_right_4_jnt":
side = "right";
break;
case "window_left_1_jnt":
case "window_left_2_jnt":
case "window_left_3_jnt":
case "window_left_4_jnt":
case "window_left_5_jnt":
side = "left";
break;
case "window_left_front_jnt":
case "window_right_front_jnt":
side = "front";
break;
case "window_left_rear_jnt":
case "window_right_rear_jnt":
side = "back";
break;
}
return side;
}
busopeningzombiethink( opening )
{
self endon( "intermission" );
if ( _isopeningdoor( opening.bindtag ) )
{
opening.enabled = 0;
return;
}
while ( 1 )
{
opening.zombietrigger waittill( "trigger", zombie );
while ( zombie.isdog )
{
continue;
}
if ( isDefined( zombie.isscreecher ) && zombie.isscreecher )
{
continue;
}
if ( isDefined( zombie.is_avogadro ) && zombie.is_avogadro )
{
continue;
}
while ( !isalive( zombie ) )
{
continue;
}
while ( !opening.enabled )
{
continue;
}
if ( _isopeningdoor( opening.bindtag ) && self.doorsclosed )
{
continue;
}
if ( isDefined( zombie.favoriteenemy ) )
{
enemy_on_roof = zombie.favoriteenemy.isonbusroof;
}
while ( self.ismoving && isDefined( self.disabled_by_emp ) && self.disabled_by_emp && !self.doorsclosed && !enemy_on_roof )
{
continue;
}
monkey = undefined;
if ( isDefined( zombie.enemyoverride ) )
{
monkey = zombie.enemyoverride[ 1 ];
}
if ( isDefined( monkey ) && !monkey maps/mp/zm_transit_bus::entity_is_on_bus( 1 ) )
{
continue;
}
if ( !isDefined( zombie.favoriteenemy ) || !zombie.favoriteenemy.isonbus )
{
continue;
}
if ( isDefined( zombie.isonbus ) && zombie.isonbus )
{
continue;
}
while ( isDefined( zombie.opening ) )
{
continue;
}
while ( isDefined( opening.zombie ) )
{
continue;
}
if ( isDefined( zombie.is_inert ) && zombie.is_inert )
{
continue;
}
if ( isDefined( zombie.cannotattachtobus ) && zombie.cannotattachtobus )
{
continue;
}
while ( !level.the_bus.ismoving )
{
jump_origin = _determinejumpfromorigin( opening );
distance_from_jump_origin2 = distance2dsquared( jump_origin, zombie.origin );
while ( distance_from_jump_origin2 > 256 )
{
continue;
}
}
if ( isDefined( zombie.dismount_start ) && zombie.dismount_start )
{
continue;
}
zombie thread zombieattachtobus( self, opening );
}
}
_buscanzombieattach( zombie )
{
currentlyattached = 0;
i = 0;
while ( i < self.openings.size )
{
if ( isDefined( self.openings[ i ].zombie ) )
{
currentlyattached++;
}
i++;
}
players = get_players();
maxattach = level.numattachtable[ players.size ];
if ( maxattach < 0 )
{
return currentlyattached < maxattach;
}
}
zombieplayattachedanim( animname )
{
self endon( "death" );
anim_index = self getanimsubstatefromasd( "zm_bus_attached", animname );
animationid = self getanimfromasd( "zm_bus_attached", anim_index );
tag_origin = self.attachent gettagorigin( self.attachtag );
tag_angles = self.attachent gettagangles( self.attachtag );
start_origin = getstartorigin( tag_origin, tag_angles, animationid );
start_angles = getstartangles( tag_origin, tag_angles, animationid );
self animscripted( start_origin, start_angles, "zm_bus_attached", anim_index );
self zombieanimnotetrackthink( "bus_attached_anim" );
}
debugline( frompoint, color, durationframes )
{
/#
i = 0;
while ( i < durationframes )
{
line( frompoint, ( frompoint[ 0 ], frompoint[ 1 ], frompoint[ 2 ] + 50 ), color );
wait 0,05;
i++;
#/
}
}
debugbox( frompoint, color, durationframes )
{
/#
i = 0;
while ( i < durationframes )
{
box( frompoint, ( 0, -1, 0 ), ( 0, -1, 0 ), 0, color );
wait 0,05;
i++;
#/
}
}
_isopeningdoor( opening_tag )
{
is_door = 0;
switch( opening_tag )
{
case "door_front_jnt":
case "door_rear_jnt":
is_door = 1;
break;
default:
}
return is_door;
}
}
busexitthink( trigger )
{
while ( 1 )
{
trigger waittill( "trigger", zombie );
if ( isDefined( zombie.is_inert ) && zombie.is_inert )
{
continue;
}
if ( isDefined( zombie.walk_to_exit ) && !zombie.walk_to_exit )
{
continue;
}
if ( isDefined( zombie.exiting_window ) && zombie.exiting_window )
{
continue;
}
going_to_roof = 0;
while ( isDefined( zombie.favoriteenemy ) && zombie.favoriteenemy.isonbusroof == 1 )
{
going_to_roof = 1;
while ( trigger.substate == 2 )
{
continue;
}
}
while ( !going_to_roof && isDefined( level.the_bus.doorsclosed ) && !level.the_bus.doorsclosed && zombie.ai_state != "zombieWindowToRoof" )
{
continue;
}
zombie thread zombieexitwindow( self, trigger, going_to_roof );
}
}
zombieexitwindow( bus, trigger, going_to_roof )
{
self endon( "death" );
self.ai_state = "zombieExitWindow";
self.inert_delay = ::zombieexitwindowdelay;
self.exiting_window = 1;
self linkto( bus, trigger.tag );
tag_origin = bus gettagorigin( trigger.tag );
tag_angles = bus gettagangles( trigger.tag );
exit_anim = "zm_window_exit";
if ( going_to_roof )
{
exit_anim = "zm_bus_window2roof";
}
animstate = maps/mp/animscripts/zm_utility::append_missing_legs_suffix( exit_anim );
self animscripted( tag_origin, tag_angles, animstate, trigger.substate );
maps/mp/animscripts/zm_shared::donotetracks( "window_exit_anim" );
self.exiting_window = undefined;
self.walk_to_exit = undefined;
self unlink();
self setgoalpos( self.origin );
self.inert_delay = undefined;
if ( going_to_roof )
{
return;
}
self animmode( "normal" );
self orientmode( "face enemy" );
self.forcemovementscriptstate = 0;
self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
}
zombieexitwindowdelay()
{
self endon( "death" );
while ( isDefined( self.exiting_window ) && self.exiting_window )
{
wait 0,1;
}
while ( 1 )
{
if ( self.ai_state == "find_flesh" )
{
break;
}
else
{
wait 0,1;
}
}
self notify( "stop_find_flesh" );
self notify( "zombie_acquire_enemy" );
self.inert_delay = undefined;
}
teleportthreadex( verticaloffset, delay, frames )
{
amount = verticaloffset / frames;
if ( amount > 10 )
{
amount = 10;
}
else
{
if ( amount < -10 )
{
amount = -10;
}
}
offset = ( 0, 0, amount );
i = 0;
while ( i < frames )
{
self teleport( self.origin + offset );
wait 0,05;
i++;
}
}
zombieopeningdelay()
{
self endon( "death" );
self maps/mp/zombies/_zm_spawner::zombie_history( "opening delay detach " + getTime() );
while ( isDefined( self.jumpingtowindow ) && self.jumpingtowindow )
{
while ( 1 )
{
if ( isDefined( self.jumpingtowindow ) && !self.jumpingtowindow )
{
break;
}
else
{
wait 0,1;
}
}
}
self zombiedetachfrombus( self.left_or_right );
while ( 1 )
{
if ( self.ai_state == "find_flesh" )
{
break;
}
else
{
wait 0,1;
}
}
self notify( "stop_find_flesh" );
self notify( "zombie_acquire_enemy" );
self.inert_delay = undefined;
}
zombieattachtobus( thebus, opening, removeafterdone )
{
self endon( "death" );
self endon( "removed" );
self endon( "sonicBoom" );
level endon( "intermission" );
self notify( "stop_find_flesh" );
self notify( "zombie_acquire_enemy" );
self endon( "detach_on_window" );
self endon( "exploding" );
self.ai_state = "zombieAttachToBus";
self maps/mp/zombies/_zm_spawner::zombie_history( "zombieAttachToBus " + getTime() );
opening.zombie = self;
self.dont_throw_gib = 1;
self.forcemovementscriptstate = 1;
self.opening = opening;
self.left_or_right = self zombieattachleftorright( thebus );
self.attachent = level.the_bus;
self.attachtag = self.opening.bindtag;
self linkto( self.attachent, self.attachtag );
from_front = 0;
from_rear = 0;
self.inert_delay = ::zombieopeningdelay;
if ( _isopeningdoor( opening.bindtag ) )
{
self animscripted( self.origin, self.angles, "zm_jump_on_bus", 0 );
if ( opening.bindtag == "door_front_jnt" )
{
from_front = 1;
}
else
{
from_rear = 1;
}
}
else
{
self.jumpingtowindow = 1;
asd_name = "zm_zbarrier_jump_on_bus";
side = _getsideofbusopeningison( opening.bindtag );
if ( isDefined( side ) && side == "front" )
{
asd_name = "zm_zbarrier_jump_on_bus_front";
}
animstate = maps/mp/animscripts/zm_utility::append_missing_legs_suffix( asd_name );
tag_origin = self.attachent gettagorigin( self.attachtag );
tag_angles = self.attachent gettagangles( self.attachtag );
self animmode( "noclip" );
self animscripted( tag_origin, tag_angles, animstate, "jump_window" + self.left_or_right );
}
self zombieanimnotetrackthink( "jump_on_bus_anim" );
self animmode( "gravity" );
self.jumpingtowindow = 0;
if ( isDefined( self.a.gib_ref ) || self.a.gib_ref == "left_arm" && self.a.gib_ref == "right_arm" )
{
self dodamage( self.health + 666, self.origin );
self startragdoll();
self launchragdoll( ( 0, -1, 0 ) );
opening.zombie = undefined;
}
if ( 1 )
{
hitpos = self.attachent gettagorigin( self.attachtag );
hitposinbus = pointonsegmentnearesttopoint( thebus.frontworld, thebus.backworld, hitpos );
hitdir = vectornormalize( hitposinbus - hitpos );
hitforce = vectorScale( hitdir, 100 );
hitpos += vectorScale( ( 0, -1, 0 ), 50 );
earthquake( randomfloatrange( 0,3, 0,4 ), randomfloatrange( 0,2, 0,4 ), hitpos, 150 );
play_sound_at_pos( "grab_metal_bar", hitpos );
}
if ( self zombiecanjumponroof( opening ) )
{
self zombiejumponroof( thebus, opening, removeafterdone, self.left_or_right );
self zombiesetnexttimetojumponroof();
self maps/mp/animscripts/zm_run::needsupdate();
if ( !self.isdog )
{
self maps/mp/animscripts/zm_run::moverun();
}
}
else
{
for ( ;; )
{
while ( 1 )
{
if ( !isDefined( opening.zbarrier ) || maps/mp/zombies/_zm_spawner::get_attack_spot( opening ) )
{
break;
}
else
{
/#
println( "Zombie failed to get bus attack spot" );
#/
wait 0,5;
}
}
}
while ( !all_chunks_destroyed( opening ) )
{
if ( zombieshoulddetachfromwindow() )
{
zombiedetachfrombus( self.left_or_right );
return;
}
self.onbuswindow = 1;
chunk = get_closest_non_destroyed_chunk( self.origin, opening );
waited = 0;
if ( isDefined( chunk ) )
{
waited = 1;
opening.zbarrier setzbarrierpiecestate( chunk, "targetted_by_zombie" );
opening thread check_zbarrier_piece_for_zombie_death( chunk, opening.zbarrier, self );
self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "teardown", self.animname );
animstatebase = opening.zbarrier getzbarrierpieceanimstate( chunk );
animsubstate = "spot_" + self.attacking_spot_index + self.left_or_right + "_piece_" + opening.zbarrier getzbarrierpieceanimsubstate( chunk );
anim_sub_index = self getanimsubstatefromasd( animstatebase + "_in", animsubstate );
tag_origin = self.attachent gettagorigin( self.attachtag );
tag_angles = self.attachent gettagangles( self.attachtag );
self animscripted( tag_origin, tag_angles, maps/mp/animscripts/zm_utility::append_missing_legs_suffix( animstatebase + "_in" ), anim_sub_index );
self zombieanimnotetrackthink( "board_tear_bus_anim", chunk, opening );
while ( opening.zbarrier.chunk_health[ chunk ] >= 0 )
{
tag_origin = self.attachent gettagorigin( self.attachtag );
tag_angles = self.attachent gettagangles( self.attachtag );
self animscripted( tag_origin, tag_angles, maps/mp/animscripts/zm_utility::append_missing_legs_suffix( animstatebase + "_loop" ), anim_sub_index );
self zombieanimnotetrackthink( "board_tear_bus_anim", chunk, opening );
opening.zbarrier.chunk_health[ chunk ]--;
}
tag_origin = self.attachent gettagorigin( self.attachtag );
tag_angles = self.attachent gettagangles( self.attachtag );
self animscripted( tag_origin, tag_angles, maps/mp/animscripts/zm_utility::append_missing_legs_suffix( animstatebase + "_out" ), anim_sub_index );
self zombieanimnotetrackthink( "board_tear_bus_anim", chunk, opening );
}
tried_attack = self zombietryattackthroughwindow( 1, self.left_or_right );
if ( !tried_attack && !waited )
{
wait 0,1;
}
}
self.onbuswindow = undefined;
if ( !_isopeningdoor( opening.bindtag ) )
{
self zombiekeepattackingthroughwindow( self.left_or_right );
side = _getsideofbusopeningison( opening.bindtag );
if ( side == "front" )
{
from_front = 1;
}
anim_state = "window_climbin";
if ( from_front )
{
anim_state += "_front";
anim_state += self.left_or_right;
}
else if ( from_rear )
{
anim_state += "_back";
}
else
{
anim_state += self.left_or_right;
}
min_chance_at_round = 5;
max_chance_at_round = 12;
if ( level.round_number >= min_chance_at_round )
{
round = min( level.round_number, max_chance_at_round );
range = max_chance_at_round - min_chance_at_round;
chance = ( 100 / range ) * ( round - min_chance_at_round );
if ( randomintrange( 0, 100 ) <= chance )
{
anim_state += "_fast";
}
}
anim_index = self getanimsubstatefromasd( "zm_zbarrier_climbin_bus", anim_state );
enter_anim = self getanimfromasd( "zm_zbarrier_climbin_bus", anim_index );
tag_origin = self.attachent gettagorigin( self.attachtag );
tag_angles = self.attachent gettagangles( self.attachtag );
self.climbing_into_bus = 1;
self.entering_bus = 1;
self animmode( "noclip" );
self animscripted( tag_origin, tag_angles, "zm_zbarrier_climbin_bus", anim_index );
self zombieanimnotetrackthink( "climbin_bus_anim" );
self animmode( "gravity" );
self maps/mp/animscripts/zm_run::needsupdate();
if ( !self.isdog )
{
self maps/mp/animscripts/zm_run::moverun();
}
}
opening.zombie = undefined;
self.opening = undefined;
self unlink();
self setgoalpos( self.origin );
}
self reset_attack_spot();
self.climbing_into_bus = 0;
if ( isDefined( removeafterdone ) && removeafterdone )
{
self delete();
return;
}
self.inert_delay = undefined;
}
zombieattachleftorright( bus )
{
tag = self.opening.bindtag;
if ( isDefined( bus.doorsclosed ) && !bus.doorsclosed )
{
if ( tag != "window_right_1_jnt" || tag == "window_right_2_jnt" && tag == "window_right_3_jnt" )
{
return "_r";
}
else
{
if ( tag == "window_right_4_jnt" )
{
return "_l";
}
}
}
side = getopeningside( tag );
while ( isDefined( side ) )
{
if ( side == "right" )
{
openings = bus.openingright;
}
else
{
if ( side == "left" )
{
openings = bus.openingleft;
}
}
_a1332 = openings;
_k1332 = getFirstArrayKey( _a1332 );
while ( isDefined( _k1332 ) )
{
opening = _a1332[ _k1332 ];
if ( opening == self.opening )
{
}
else
{
if ( isDefined( opening.zombie ) )
{
return opening.zombie.left_or_right;
}
}
_k1332 = getNextArrayKey( _a1332, _k1332 );
}
}
left_or_right = "_l";
if ( randomint( 10 ) > 5 )
{
left_or_right = "_r";
}
return left_or_right;
}
businitrightandleft()
{
self.openingright = [];
self.openingleft = [];
_a1367 = self.openings;
_k1367 = getFirstArrayKey( _a1367 );
while ( isDefined( _k1367 ) )
{
opening = _a1367[ _k1367 ];
side = getopeningside( opening.bindtag );
if ( isDefined( side ) )
{
if ( side == "right" )
{
self.openingright[ self.openingright.size ] = opening;
break;
}
else
{
if ( side == "left" )
{
self.openingleft[ self.openingleft.size ] = opening;
}
}
}
_k1367 = getNextArrayKey( _a1367, _k1367 );
}
}
getopeningside( tag )
{
i = 1;
while ( i <= 4 )
{
window_tag = "window_right_" + i + "_jnt";
if ( tag == window_tag )
{
return "right";
}
i++;
}
i = 1;
while ( i <= 5 )
{
window_tag = "window_left_" + i + "_jnt";
if ( tag == window_tag )
{
return "left";
}
i++;
}
return undefined;
}
zombiegetwindowanimrate()
{
animrate = 1;
animrateroundscalar = 0;
players = get_players();
if ( players.size > 1 )
{
target_rate = 1,5;
target_round = 25;
target_num_players = 4;
rate = ( target_rate - 1 ) / target_round / target_num_players;
animrateroundscalar = rate * players.size;
animrate = 1 + ( animrateroundscalar * level.round_number );
if ( animrate > target_rate )
{
animrate = target_rate;
}
}
return animrate;
}
zombiedetachfrombus( postfix )
{
if ( !isDefined( self.opening ) )
{
return;
}
if ( isDefined( self.opening.zombie ) && self.opening.zombie == self )
{
self.opening.zombie = undefined;
}
is_right = 0;
if ( postfix == "_r" )
{
is_right = 1;
}
bindtag = self.opening.bindtag;
side = _getsideofbusopeningison( bindtag );
tag_origin = level.the_bus gettagorigin( bindtag );
tag_angles = level.the_bus gettagangles( bindtag );
self.opening = undefined;
self.isonbusroof = 0;
self.onbuswindow = undefined;
self.ai_state = "zombieDetachFromBus";
self.entering_bus = 0;
self.isonbus = 0;
asd_name = "zm_window_dismount";
if ( isDefined( side ) && side == "front" )
{
asd_name = "zm_front_window_dismount";
}
animstate = maps/mp/animscripts/zm_utility::append_missing_legs_suffix( asd_name );
self animscripted( tag_origin, tag_angles, animstate, is_right );
self.dismount_start = 1;
self thread dismount_timer();
maps/mp/animscripts/zm_shared::donotetracks( "window_dismount_anim" );
self unlink();
self reset_attack_spot();
self.dismount_start = 0;
self.forcemovementscriptstate = 0;
self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
self.dont_throw_gib = undefined;
self notify( "detach_on_window" );
}
dismount_timer()
{
self endon( "death" );
wait 1,5;
self.dismount_start = 0;
}
zombiegetcymbalmonkey()
{
if ( isDefined( self.monkey_time ) && getTime() < self.monkey_time )
{
return self.monkey;
}
poi = undefined;
if ( level.cymbal_monkeys.size > 0 )
{
poi = self get_zombie_point_of_interest( self.origin, level.cymbal_monkeys );
}
if ( isDefined( poi ) )
{
self.monkey = poi[ 1 ];
self.monkey_time = getTime() + 250;
return poi[ 1 ];
}
return undefined;
}
zombieshoulddetachfromwindow()
{
monkey = self zombiegetcymbalmonkey();
if ( isDefined( monkey ) )
{
if ( monkey maps/mp/zm_transit_bus::entity_is_on_bus( 1 ) )
{
return 0;
}
else
{
return 1;
}
}
enemy = self.favoriteenemy;
if ( isDefined( enemy ) && !self.favoriteenemy.isonbus )
{
return 1;
}
return 0;
}
zombiecanjumponroof( opening )
{
if ( level.the_bus.numplayersonroof == 0 )
{
if ( all_chunks_destroyed( opening ) )
{
return 0;
}
if ( isDefined( level.bus_zombie_on_roof ) )
{
return 0;
}
if ( level.bus_roof_next_time > getTime() )
{
return 0;
}
}
percentchance = 0;
if ( level.round_number <= 5 )
{
percentchance = 5;
}
else if ( level.round_number <= 10 )
{
percentchance = 20;
}
else if ( level.round_number <= 20 )
{
percentchance = 30;
}
else if ( level.round_number <= 25 )
{
percentchance = 40;
}
else
{
percentchance = 50;
}
percentofplayersonroof = 1;
if ( level.the_bus.numplayersnear > 0 )
{
percentofplayersonroof = level.the_bus.numplayersonroof / level.the_bus.numplayersnear;
}
percentofplayersonroof *= 100;
if ( percentchance < percentofplayersonroof )
{
percentchance = percentofplayersonroof;
}
if ( randomint( 100 ) < percentchance )
{
return 1;
}
return 0;
}
zombiesetnexttimetojumponroof()
{
level.bus_roof_next_time = getTime() + level.bus_roof_min_interval_time + randomint( level.bus_roof_max_interval_time - level.bus_roof_min_interval_time );
}
zombiejumponroof( thebus, opening, removeafterdone, postfix )
{
level.bus_zombie_on_roof = self;
self.climbing_onto_bus = 1;
self.entering_bus = 1;
self animscripted( self.opening.zbarrier.origin, self.opening.zbarrier.angles, "zm_zbarrier_window_climbup", "window_climbup" + postfix );
self zombieanimnotetrackthink( "bus_window_climbup" );
play_sound_at_pos( "grab_metal_bar", self.origin );
opening.zombie = undefined;
self.opening = undefined;
self unlink();
self setgoalpos( self.origin );
self.climbing_onto_bus = 0;
if ( level.the_bus.numplayersonroof > 0 )
{
level.bus_zombie_on_roof = undefined;
}
}
bussetupladder()
{
trigger = getent( "bus_ladder_trigger", "targetname" );
if ( !isDefined( trigger ) )
{
return;
}
trigger enablelinkto();
trigger linkto( level.the_bus );
trigger setmovingplatformenabled( 1 );
trigger setinvisibletoall();
mantlebrush = getentarray( "ladder_mantle", "targetname" );
while ( isDefined( mantlebrush ) && mantlebrush.size > 0 )
{
i = 0;
while ( i < mantlebrush.size )
{
self thread busdeferredinitladdermantle( mantlebrush[ i ] );
i++;
}
}
thread busladderthink();
}
busdeferredinitladdermantle( mantle )
{
origin = self worldtolocalcoords( mantle.origin );
mantle linkto( self, "", origin, ( 0, -1, 0 ) );
mantle setmovingplatformenabled( 1 );
wait_for_buildable( "busladder" );
mantle delete();
}
busladderthink()
{
origin = level.the_bus gettagorigin( "tag_ladder_attach" );
origin += ( 10, 3, -30 );
angles = level.the_bus gettagangles( "tag_ladder_attach" );
angles += vectorScale( ( 0, -1, 0 ), 90 );
level.the_bus.ladder = spawn( "script_model", origin );
level.the_bus.ladder.angles = angles;
level.the_bus.ladder setmodel( "com_stepladder_large_closed" );
level.the_bus.ladder notsolid();
level.the_bus.ladder linkto( level.the_bus, "tag_ladder_attach" );
level.the_bus.ladder setmovingplatformenabled( 1 );
level.the_bus.ladder hide();
player = wait_for_buildable( "busladder" );
flag_set( "ladder_attached" );
level.the_bus.ladder show();
player maps/mp/zombies/_zm_buildables::track_placed_buildables( "busladder" );
}
bussetuproofopening()
{
level.bus_roof_open = 0;
level.bus_zombie_on_roof = undefined;
level.bus_roof_next_time = 0;
level.bus_roof_min_interval_time = 10000;
level.bus_roof_max_interval_time = 20000;
trigger = getent( "bus_hatch_bottom_trigger", "targetname" );
if ( !isDefined( trigger ) )
{
return;
}
trigger enablelinkto();
trigger linkto( level.the_bus );
trigger setmovingplatformenabled( 1 );
self thread bus_hatch_wait();
self thread bus_hatch_tearin_wait();
clipbrush = getentarray( "hatch_clip", "targetname" );
while ( isDefined( clipbrush ) && clipbrush.size > 0 )
{
i = 0;
while ( i < clipbrush.size )
{
self thread businithatchclip( clipbrush[ i ] );
i++;
}
}
mantlebrush = getentarray( "hatch_mantle", "targetname" );
while ( isDefined( mantlebrush ) && mantlebrush.size > 0 )
{
i = 0;
while ( i < mantlebrush.size )
{
self thread busdeferredinithatchmantle( mantlebrush[ i ] );
i++;
}
}
hatch_location = spawn( "script_origin", level.the_bus localtoworldcoords( ( 227, -1,7, 48 ) ) );
hatch_location enablelinkto();
hatch_location linkto( level.the_bus );
hatch_location setmovingplatformenabled( 1 );
level.the_bus.hatch_location = hatch_location;
/#
adddebugcommand( "devgui_cmd "Zombies:1/Bus:14/Hatch:4/Allow Traverse:1" "zombie_devgui hatch_available"\n" );
self thread wait_open_sesame();
#/
}
wait_open_sesame()
{
level waittill( "open_sesame" );
self notify( "hatch_mantle_allowed" );
if ( isDefined( level.bus_tearin_roof ) )
{
level.bus_tearin_roof hide();
}
level.the_bus showpart( "tag_hatch_attach_ladder" );
level.the_bus hidepart( "tag_hatch_pristine" );
level.the_bus hidepart( "tag_hatch_damaged" );
level.bus_roof_open = 1;
level.bus_roof_tearing = 0;
}
bus_hatch_wait()
{
level.the_bus hidepart( "tag_hatch_attach_ladder" );
player = wait_for_buildable( "bushatch" );
flag_set( "hatch_attached" );
level.the_bus showpart( "tag_hatch_attach_ladder" );
level.the_bus hidepart( "tag_hatch_pristine" );
level.the_bus hidepart( "tag_hatch_damaged" );
level.bus_roof_open = 1;
level.bus_roof_tearing = 0;
self notify( "hatch_mantle_allowed" );
player maps/mp/zombies/_zm_buildables::track_placed_buildables( "bushatch" );
}
bus_hatch_tearin_wait()
{
self endon( "hatch_mantle_allowed" );
level.the_bus hidepart( "tag_hatch_damaged" );
self waittill( "hatch_ripped_open" );
level.the_bus hidepart( "tag_hatch_pristine" );
level.the_bus showpart( "tag_hatch_damaged" );
self notify( "hatch_drop_allowed" );
playfxontag( level._effect[ "bus_hatch_bust" ], self, "tag_headlights" );
}
businithatchclip( clip )
{
origin = self worldtolocalcoords( clip.origin );
clip linkto( self, "", origin, ( 0, -1, 0 ) );
clip setmovingplatformenabled( 1 );
self waittill_any( "hatch_mantle_allowed", "hatch_drop_allowed" );
clip delete();
}
busdeferredinithatchmantle( mantle )
{
origin = self worldtolocalcoords( mantle.origin );
mantle.origin = vectorScale( ( 0, -1, 0 ), 100 );
self waittill( "hatch_mantle_allowed" );
mantle linkto( self, "", origin, ( 0, -1, 0 ) );
mantle setmovingplatformenabled( 1 );
}
zombieonbusenemy()
{
new_enemy = undefined;
if ( isDefined( level.the_bus.bus_riders_alive ) && level.the_bus.bus_riders_alive.size > 0 )
{
new_enemy = getclosest( self.origin, level.the_bus.bus_riders_alive );
}
if ( isDefined( new_enemy ) && isDefined( self.favoriteenemy ) && isDefined( new_enemy ) && self.favoriteenemy != new_enemy )
{
if ( isDefined( self.favoriteenemy.isonbus ) && !self.favoriteenemy.isonbus )
{
self.favoriteenemy = new_enemy;
return;
}
else
{
if ( self.isonbusroof == new_enemy.isonbusroof )
{
self.favoriteenemy = new_enemy;
}
}
}
}
zombiemoveonbus()
{
self endon( "death" );
self endon( "removed" );
level endon( "intermission" );
self notify( "endOnBus" );
self endon( "endOnBus" );
self notify( "stop_find_flesh" );
self notify( "zombie_acquire_enemy" );
wait 0,05;
self orientmode( "face enemy" );
self.goalradius = 32;
self.forcemovementscriptstate = 1;
self.ai_state = "zombieMoveOnBus";
self maps/mp/zombies/_zm_spawner::zombie_history( "zombieMoveOnBus " + getTime() );
bus_nodes = getnodearray( "the_bus", "target" );
while ( 1 )
{
self zombieonbusenemy();
if ( !isDefined( self.favoriteenemy ) )
{
break;
}
else if ( isDefined( self.isonbus ) )
{
self_on_bus = self.isonbus;
}
if ( isDefined( self.isonbusroof ) )
{
self_is_on_bus_roof = self.isonbusroof;
}
if ( !self_on_bus )
{
break;
}
else
{
if ( isDefined( self.is_inert ) && self.is_inert )
{
self.ignoreall = 1;
while ( isDefined( self.is_inert ) && self.is_inert )
{
wait 0,1;
}
self.ignoreall = 0;
}
poi_override = 0;
if ( self.forcemovementscriptstate )
{
monkey = self zombiegetcymbalmonkey();
if ( isDefined( monkey ) )
{
poi_override = 1;
self.ignoreall = 1;
self animmode( "normal" );
self orientmode( "face motion" );
if ( !level.the_bus maps/mp/zm_transit_bus::busispointinside( monkey.origin ) )
{
self zombiewalktoexit();
}
else
{
self setgoalpos( monkey.origin );
}
break;
}
else
{
self.ignoreall = 0;
self animmode( "gravity" );
self orientmode( "face enemy" );
while ( isDefined( level.the_bus.doorsclosed ) && !level.the_bus.doorsclosed )
{
doorstrigger = getentarray( "bus_door_trigger", "targetname" );
_a1984 = doorstrigger;
_k1984 = getFirstArrayKey( _a1984 );
while ( isDefined( _k1984 ) )
{
trigger = _a1984[ _k1984 ];
if ( self istouching( trigger ) )
{
self orientmode( "face motion" );
break;
}
else
{
_k1984 = getNextArrayKey( _a1984, _k1984 );
}
}
}
dist_sq = distancesquared( self.favoriteenemy.origin, bus_nodes[ 0 ].origin );
goal_node = bus_nodes[ 0 ];
i = 1;
while ( i < bus_nodes.size )
{
bus_sq = distancesquared( self.favoriteenemy.origin, bus_nodes[ i ].origin );
if ( bus_sq < dist_sq )
{
dist_sq = bus_sq;
goal_node = bus_nodes[ i ];
}
i++;
}
if ( self_is_on_bus_roof )
{
self.goalradius = 16;
}
else
{
self.goalradius = 32;
}
self setgoalnode( goal_node );
}
}
enemy = self.favoriteenemy;
if ( isDefined( enemy ) )
{
enemy_on_bus = enemy.isonbus;
}
if ( enemy_on_bus && isDefined( enemy.isonbusroof ) )
{
enemy_on_roof = enemy.isonbusroof;
}
if ( !enemy_on_bus && !self_is_on_bus_roof )
{
monkey = self zombiegetcymbalmonkey();
if ( !isDefined( monkey ) || !monkey maps/mp/zm_transit_bus::entity_is_on_bus( 1 ) )
{
self thread zombieexitbus();
return;
}
}
else
{
if ( enemy_on_bus && self_is_on_bus_roof != enemy_on_roof )
{
self thread zombieheighttraverse();
return;
break;
}
else
{
if ( self_is_on_bus_roof && !enemy_on_bus )
{
self thread zombiejumpoffroof();
return;
break;
}
else
{
if ( isDefined( poi_override ) && !poi_override )
{
disttoenemy = distance2d( self.origin, self.favoriteenemy.origin );
shouldbeinforcemovement = disttoenemy > 32;
if ( !shouldbeinforcemovement && self.forcemovementscriptstate )
{
self.forcemovementscriptstate = 0;
self animmode( "normal" );
self orientmode( "face enemy" );
}
if ( shouldbeinforcemovement && !self.forcemovementscriptstate )
{
self.forcemovementscriptstate = 1;
self animmode( "gravity" );
self orientmode( "face enemy" );
}
}
}
}
}
wait 0,1;
}
}
self animmode( "normal" );
self orientmode( "face enemy" );
self.forcemovementscriptstate = 0;
self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
}
zombiewalktoexit()
{
self endon( "death" );
bus = level.the_bus;
self.walk_to_exit = 1;
check_pos = self.origin;
enemy = self.favoriteenemy;
if ( isDefined( enemy ) )
{
check_pos = enemy.origin;
}
if ( !level.the_bus.doorsclosed )
{
front_dist = distance2dsquared( check_pos, level.the_bus.front_door.origin );
back_dist = distance2dsquared( check_pos, level.the_bus.back_door.origin );
link_one = undefined;
link_two = undefined;
door_node = undefined;
door_dist = undefined;
if ( front_dist < back_dist )
{
door_dist = distance2dsquared( self.origin, level.the_bus.front_door.origin );
if ( door_dist < 256 )
{
door_node = level.the_bus.front_door;
}
}
else
{
door_dist = distance2dsquared( self.origin, level.the_bus.back_door.origin );
if ( door_dist < 256 )
{
door_node = level.the_bus.back_door;
}
}
if ( isDefined( door_node ) )
{
if ( isDefined( door_node.links ) )
{
if ( isDefined( door_node.links[ 0 ] ) )
{
link_one = door_node.links[ 0 ];
}
if ( isDefined( door_node.links[ 1 ] ) )
{
link_two = door_node.links[ 1 ];
}
}
link_goal = undefined;
if ( isDefined( link_one ) )
{
link_goal = link_one;
}
if ( isDefined( link_one ) && isDefined( link_two ) )
{
link_one_dist = distance2dsquared( check_pos, link_one.origin );
link_two_dist = distance2dsquared( check_pos, link_two.origin );
link_goal = link_one;
if ( link_two_dist < link_one_dist )
{
link_goal = link_two;
}
}
if ( isDefined( link_goal ) )
{
self setgoalnode( link_goal );
return;
}
}
door_goal = level.the_bus.front_door;
if ( back_dist < front_dist )
{
door_goal = level.the_bus.back_door;
}
self setgoalnode( door_goal );
}
else
{
dist_f = distancesquared( check_pos, bus.front_door_inside.origin );
dist_bl = distancesquared( check_pos, bus.exit_back_l.origin );
dist_br = distancesquared( check_pos, bus.exit_back_r.origin );
goal_node = bus.front_door_inside;
if ( dist_bl < dist_br )
{
if ( dist_bl < dist_f )
{
goal_node = bus.exit_back_l;
}
}
else
{
if ( dist_br < dist_f )
{
goal_node = bus.exit_back_r;
}
}
self setgoalnode( goal_node );
}
}
zombiewindowtoroof()
{
self endon( "death" );
self animmode( "normal" );
self orientmode( "face motion" );
self.ai_state = "zombieWindowToRoof";
self maps/mp/zombies/_zm_spawner::zombie_history( "zombieWindowToRoof " + getTime() );
while ( 1 )
{
self zombiewalktowindow();
if ( isDefined( self.exiting_window ) && self.exiting_window )
{
break;
}
else
{
if ( isDefined( self.isonbus ) || !self.isonbus && isDefined( self.ai_state == "find_flesh" ) && self.ai_state == "find_flesh" )
{
return;
}
wait 0,1;
}
}
while ( isDefined( self.exiting_window ) && self.exiting_window )
{
wait 0,1;
}
}
zombiewalktowindow()
{
self endon( "death" );
bus = level.the_bus;
self.walk_to_exit = 1;
check_pos = self.origin;
dist_f = distancesquared( check_pos, bus.front_door_inside.origin );
dist_bl = distancesquared( check_pos, bus.exit_back_l.origin );
goal_node = bus.front_door_inside;
if ( dist_bl < dist_f )
{
goal_node = bus.exit_back_l;
}
self setgoalnode( goal_node );
}
zombieattackplayerclinging( player )
{
self endon( "death" );
level endon( "intermission" );
self.goalradius = 15;
enemy_clinging = 1;
while ( enemy_clinging )
{
best_attack_pos = maps/mp/zm_transit_cling::_getbusattackposition( player );
dist_from_pos2 = distance2dsquared( best_attack_pos, self.origin );
enemy_origin = player _playergetorigin();
direction = enemy_origin - self.origin;
direction_angles = vectorToAngle( direction );
direction_angles = ( direction_angles[ 0 ], direction_angles[ 1 ], 0 );
if ( dist_from_pos2 > 400 )
{
self orientmode( "face point", best_attack_pos );
self setgoalpos( best_attack_pos );
}
else
{
self zombiescriptedattack( player, direction_angles, ::zombiedamageplayercling );
}
enemy_clinging = player maps/mp/zm_transit_cling::playerisclingingtobus();
wait 0,1;
}
self.goalradius = 32;
}
zombieattackplayeronturret( player )
{
self endon( "death" );
level endon( "intermission" );
enemy_on_turret = 1;
while ( enemy_on_turret )
{
enemy_origin = self.favoriteenemy _playergetorigin();
dist_from_turret2 = distance2dsquared( enemy_origin, self.origin );
direction = enemy_origin - self.origin;
direction_angles = vectorToAngle( direction );
direction_angles = ( direction_angles[ 0 ], direction_angles[ 1 ], 0 );
if ( dist_from_turret2 > 1024 )
{
self setgoalpos( enemy_origin, direction_angles );
}
else
{
self zombiescriptedattack( player, direction_angles, ::zombiedamageplayerturret );
}
wait 0,1;
if ( isDefined( self.favoriteenemy.onbusturret ) && isDefined( self.favoriteenemy.busturret ) )
{
enemy_on_turret = self.favoriteenemy.onbusturret;
}
}
}
zombiescriptedattack( player, direction_angles, damage_func )
{
self orientmode( "face angle", direction_angles[ 1 ] );
zombie_attack_anim = self zombiepickunmovingattackanim();
self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "attack", self.animname );
while ( 1 )
{
self waittill( "meleeanim", note );
if ( note == "end" || note == "stop" )
{
return;
}
else if ( note == "fire" )
{
if ( isDefined( damage_func ) )
{
[[ damage_func ]]( player );
}
}
}
}
zombiedamageplayerturret( player )
{
if ( player.onbusturret )
{
player dodamage( self.meleedamage, self.origin, self );
}
}
zombiedamageplayercling( player )
{
if ( player maps/mp/zm_transit_cling::playerisclingingtobus() )
{
player dodamage( self.meleedamage, self.origin, self );
}
}
_playergetorigin()
{
if ( isDefined( self.onbusturret ) && isDefined( self.busturret ) && self.onbusturret )
{
turret = self.busturret;
turret_exit = getent( turret.target, "targetname" );
return turret_exit.origin;
}
return self.origin;
}
zombiepickunmovingattackanim()
{
melee_anim = undefined;
if ( self.has_legs )
{
rand_num = randomint( 4 );
melee_anim = level._zombie_melee[ self.animname ][ rand_num ];
}
else if ( self.a.gib_ref == "no_legs" )
{
melee_anim = random( level._zombie_stumpy_melee[ self.animname ] );
}
else
{
melee_anim = level._zombie_melee_crawl[ self.animname ][ 0 ];
}
return melee_anim;
}
zombieexitbus()
{
self endon( "death" );
self endon( "stop_zombieExitBus" );
level endon( "intermission" );
self animmode( "normal" );
self orientmode( "face motion" );
self maps/mp/zombies/_zm_spawner::zombie_history( "zombieExitBus " + getTime() );
while ( 1 )
{
if ( isDefined( self.exiting_window ) && self.exiting_window )
{
break;
}
else
{
if ( isDefined( self.isonbus ) && !self.isonbus )
{
self.walk_to_exit = 0;
return;
}
if ( isDefined( self.solo_revive_exit ) && !self.solo_revive_exit )
{
monkey = undefined;
if ( isDefined( self.enemyoverride ) )
{
monkey = self.enemyoverride[ 1 ];
}
ignore_enemy = 0;
if ( isDefined( monkey ) && !monkey maps/mp/zm_transit_bus::entity_is_on_bus( 1 ) )
{
ignore_enemy = 1;
}
if ( !ignore_enemy )
{
enemy = self.favoriteenemy;
if ( isDefined( enemy ) )
{
if ( enemy.isonbus )
{
self.walk_to_exit = 0;
self thread zombiemoveonbus();
return;
}
}
}
}
self zombiewalktoexit();
wait 0,1;
}
}
while ( isDefined( self.exiting_window ) && self.exiting_window )
{
wait 0,1;
}
self.dont_throw_gib = undefined;
self orientmode( "face enemy" );
self.forcemovementscriptstate = 0;
self thread maps/mp/zombies/_zm_ai_basic::find_flesh();
}
zombiejumpoffroof()
{
self endon( "death" );
self endon( "removed" );
level endon( "intermission" );
self animmode( "gravity" );
self orientmode( "face goal" );
self maps/mp/zombies/_zm_spawner::zombie_history( "zombieJumpOffRoof " + getTime() );
while ( 1 )
{
enemy = self.favoriteenemy;
if ( isDefined( enemy ) )
{
enemy_on_bus = enemy.isonbus;
}
enemiesonbus = level.the_bus.numaliveplayersridingbus > 0;
if ( isDefined( self.isonbus ) )
{
selfisonbus = self.isonbus;
}
if ( enemy_on_bus )
{
self thread zombiemoveonbus();
return;
}
if ( !selfisonbus )
{
return;
}
else closest_jump_tag = self zombiegetclosestroofjumptag();
goal_pos = level.the_bus gettagorigin( closest_jump_tag );
if ( distance2dsquared( self.origin, goal_pos ) <= 1024 )
{
self.attachent = level.the_bus;
self.attachtag = closest_jump_tag;
self linkto( self.attachent, self.attachtag, ( 0, -1, 0 ), ( 0, -1, 0 ) );
wait 0,1;
self zombieplayattachedanim( "jump_down_127" );
self setgoalpos( self.origin );
self unlink();
return;
}
else
{
self setgoalpos( goal_pos );
self orientmode( "face point", goal_pos );
wait 0,1;
}
}
}
zombieheighttraverse()
{
level endon( "intermission" );
self endon( "death" );
self endon( "removed" );
self endon( "zombieHeightTraverseStop" );
self animmode( "gravity" );
self orientmode( "face goal" );
self.zombie_ladder_stage = 1;
self.goal_local_offset = level.the_bus.ladder_local_offset;
self.goal_local_offset = ( self.goal_local_offset[ 0 ], self.goal_local_offset[ 1 ], level.the_bus.floor );
self.goal_local_angles = vectorScale( ( 0, -1, 0 ), 90 );
self maps/mp/zombies/_zm_spawner::zombie_history( "zombieHeightTraverse " + getTime() );
if ( !isDefined( self.isonbusroof ) || !self.isonbusroof )
{
bus = level.the_bus;
hatch_dist = distancesquared( self.origin, bus.hatch_location.origin );
front_dist = distancesquared( self.origin, bus.front_door_inside.origin );
back_dist = distancesquared( self.origin, bus.exit_back_l.origin );
closer_to_hatch = 1;
if ( front_dist < hatch_dist || back_dist < hatch_dist )
{
closer_to_hatch = 0;
}
if ( isDefined( level.bus_roof_open ) && level.bus_roof_open && isDefined( level.bus_roof_tearing ) || level.bus_roof_tearing && !closer_to_hatch )
{
self zombiewindowtoroof();
}
else
{
if ( self zombiepathtoladder() )
{
self zombieclimbtoroof();
}
}
}
else
{
if ( self zombiepathtoroofopening() )
{
self zombiejumpdownhatch();
}
else
{
enemy = self.favoriteenemy;
if ( isDefined( enemy ) && isDefined( enemy.isonbus ) && !enemy.isonbus )
{
self thread zombiejumpoffroof();
return;
}
}
}
if ( isDefined( self.isonbus ) && self.isonbus )
{
self thread zombiemoveonbus();
}
}
zombiepathtoladder()
{
self.goalradius = 2;
while ( isDefined( self.enemy ) && self.enemy.isonbusroof )
{
if ( !self.isonbus )
{
self.goalradius = 32;
return 0;
}
goal_dir = anglesToForward( level.the_bus.angles + self.goal_local_angles );
goal_pos = level.the_bus.hatch_location.origin;
if ( distancesquared( self.origin, goal_pos ) <= 1600 )
{
self.goalradius = 32;
self.ladder_pos = goal_pos;
return 1;
}
self setgoalpos( goal_pos );
self orientmode( "face point", goal_pos );
wait 0,1;
}
self.goalradius = 32;
return 0;
}
zombiepathtoroofopening()
{
self.goalradius = 2;
goal_tag = self zombiegetclosestroofopeningjumptag();
while ( 1 )
{
self zombieonbusenemy();
enemy = self.favoriteenemy;
if ( isDefined( enemy ) && isDefined( enemy.isonbusroof ) && enemy.isonbusroof )
{
break;
}
else
{
if ( isDefined( enemy ) && isDefined( enemy.isonbus ) && !enemy.isonbus )
{
break;
}
else
{
if ( !self.isonbus )
{
break;
}
else
{
goal_dir = level.the_bus gettagangles( goal_tag );
goal_pos = level.the_bus gettagorigin( goal_tag );
if ( distance2d( self.origin, goal_pos ) <= 32 )
{
self.goalradius = 32;
return 1;
}
self setgoalpos( goal_pos );
self orientmode( "face point", goal_pos );
wait 0,1;
}
}
}
}
self.goalradius = 32;
return 0;
}
zombiejumpdownhatch()
{
self endon( "death" );
self thread zombiejumpdownhatchkilled();
enemy = self.favoriteenemy;
if ( isDefined( enemy ) && isDefined( enemy.isonbusroof ) && enemy.isonbusroof )
{
self unlink();
return;
}
while ( isDefined( level.bus_roof_tearing ) && level.bus_roof_tearing )
{
wait 0,1;
}
roof_tag = self zombiegetclosestroofopeningjumptag();
if ( !level.bus_roof_open )
{
self.inert_delay = ::zombieroofteardelay;
level.bus_roof_open = 1;
level.bus_roof_tearing = 1;
self linkto( level.the_bus, roof_tag );
tag_origin = level.the_bus gettagorigin( roof_tag );
tag_angles = level.the_bus gettagangles( roof_tag );
substate = 1;
if ( roof_tag == "window_roof_2_jnt" )
{
substate = 2;
}
animstate = "zm_bus_attached";
self animscripted( tag_origin, tag_angles, animstate, substate );
maps/mp/animscripts/zm_shared::donotetracks( "bus_attached_anim" );
self.inert_delay = undefined;
level.bus_roof_tearing = 0;
level.the_bus notify( "hatch_ripped_open" );
}
self.hatch_jump = 1;
self.inert_delay = ::zombiehatchjumpdelay;
hatch_tag = "tag_hatch_attach_ladder";
self linkto( level.the_bus, hatch_tag );
tag_origin = level.the_bus gettagorigin( hatch_tag );
tag_angles = level.the_bus gettagangles( hatch_tag );
substate = 0;
if ( roof_tag == "window_roof_1_jnt" )
{
substate = 1;
}
animstate = maps/mp/animscripts/zm_utility::append_missing_legs_suffix( "zm_bus_hatch_jump_down" );
self animscripted( tag_origin, tag_angles, animstate, substate );
maps/mp/animscripts/zm_shared::donotetracks( "bus_hatch_jump_anim" );
self unlink();
self.hatch_jump = 0;
self.inert_delay = undefined;
self setgoalpos( self.origin );
level.bus_zombie_on_roof = undefined;
}
zombiehatchjumpdelay()
{
/#
iprintln( "hatch delay" );
#/
while ( isDefined( self.hatch_jump ) && self.hatch_jump )
{
wait 0,1;
}
}
zombieroofteardelay()
{
self endon( "death" );
self notify( "zombieHeightTraverseStop" );
self unlink();
level.bus_roof_open = 0;
level.bus_roof_tearing = 0;
self.inert_wakeup_override = ::zombierooftearwakeup;
}
zombierooftearwakeup()
{
self endon( "death" );
self.inert_wakeup_override = undefined;
self thread zombieheighttraverse();
}
zombiejumpdownhatchkilled()
{
while ( isDefined( level.bus_roof_tearing ) && level.bus_roof_tearing )
{
if ( !isDefined( self ) )
{
level.bus_roof_tearing = 0;
return;
}
else
{
wait 0,1;
}
}
}
zombieclimbtoroof()
{
self endon( "death" );
hatch_tag = "tag_hatch_attach_ladder";
self linkto( level.the_bus, hatch_tag );
tag_origin = level.the_bus gettagorigin( hatch_tag );
tag_angles = level.the_bus gettagangles( hatch_tag );
hatch_vec = vectornormalize( anglesToForward( tag_angles ) );
player = self.favoriteenemy;
player_vec = vectornormalize( player.origin - tag_origin );
substate = 0;
dot = vectordot( hatch_vec, player_vec );
if ( dot > 0 )
{
substate = 1;
}
animstate = maps/mp/animscripts/zm_utility::append_missing_legs_suffix( "zm_bus_hatch_jump_up" );
self animscripted( tag_origin, tag_angles, animstate, substate );
maps/mp/animscripts/zm_shared::donotetracks( "bus_hatch_jump_anim" );
self unlink();
self setgoalpos( self.origin );
}
zombiegetclosestroofjumptag()
{
root = "tag_roof_jump_off";
best = root + "1";
best_pos = level.the_bus gettagorigin( best );
best_pos_dist2 = distance2dsquared( self.origin, best_pos );
i = 1;
while ( i <= 4 )
{
next_pos = level.the_bus gettagorigin( root + i );
next_pos_dist2 = distance2dsquared( self.origin, next_pos );
if ( next_pos_dist2 < best_pos_dist2 )
{
best = root + i;
best_pos = next_pos;
best_pos_dist2 = next_pos_dist2;
}
i++;
}
return best;
}
zombiegetclosestroofopeningjumptag()
{
pos1 = level.the_bus gettagorigin( "window_roof_1_jnt" );
pos2 = level.the_bus gettagorigin( "window_roof_2_jnt" );
closest = "window_roof_1_jnt";
pos1_dist2 = distance2dsquared( self.origin, pos1 );
pos2_dist2 = distance2dsquared( self.origin, pos2 );
if ( pos2_dist2 < pos1_dist2 )
{
closest = "window_roof_2_jnt";
}
return closest;
}
zombiegetclosestdoortag()
{
pos1 = level.the_bus gettagorigin( "door_rear_jnt" );
pos2 = level.the_bus gettagorigin( "door_front_jnt" );
closest = "door_rear_jnt";
pos1_dist2 = distance2dsquared( self.origin, pos1 );
pos2_dist2 = distance2dsquared( self.origin, pos2 );
if ( pos2_dist2 < pos1_dist2 )
{
closest = "door_front_jnt";
}
return closest;
}
zombiekeepattackingthroughwindow( left_or_right )
{
while ( self zombietryattackthroughwindow( 0, left_or_right ) )
{
tag_origin = self.attachent gettagorigin( self.attachtag );
tag_angles = self.attachent gettagangles( self.attachtag );
asd_name = "zm_zbarrier_window_idle";
side = _getsideofbusopeningison( self.attachtag );
if ( side == "front" )
{
asd_name = "zm_zbarrier_front_window_idle";
}
self animscripted( tag_origin, tag_angles, asd_name, "window_idle" + left_or_right );
self zombieanimnotetrackthink( "bus_window_idle" );
}
}
zombietryattackthroughwindow( is_random, postfix )
{
attackplayers = self zombiegetplayerstoattack();
if ( attackplayers.size == 0 )
{
return 0;
}
should_attack = 1;
if ( is_random )
{
rand = randomint( 100 );
should_attack = rand < 80;
}
if ( should_attack )
{
self thread maps/mp/zombies/_zm_audio::do_zombies_playvocals( "attack", self.animname );
tag_origin = self.attachent gettagorigin( self.attachtag );
tag_angles = self.attachent gettagangles( self.attachtag );
asd_name = "zm_zbarrier_window_attack";
side = _getsideofbusopeningison( self.attachtag );
if ( isDefined( side ) && side == "front" )
{
asd_name = "zm_zbarrier_front_window_attack";
}
self animscripted( tag_origin, tag_angles, asd_name, "window_attack" + postfix );
self zombieanimnotetrackthink( "bus_window_attack" );
return 1;
}
return 0;
}
zombiegetplayerstoattack()
{
playerstoattack = [];
players = get_players();
attackrange = 72;
attackrange *= attackrange;
attackheight = 37;
attackheight *= attackheight;
i = 0;
while ( i < players.size )
{
if ( isDefined( self.opening ) && isDefined( self.opening.rebuildtrigger ) )
{
if ( players[ i ] istouching( self.opening.rebuildtrigger ) )
{
playerstoattack[ playerstoattack.size ] = players[ i ];
}
i++;
continue;
}
else
{
xydist = distance2dsquared( self.origin, players[ i ].origin );
zdist = self.origin[ 2 ] - players[ i ].origin[ 2 ];
zdist2 = zdist * zdist;
if ( xydist <= attackrange && zdist2 <= attackheight )
{
playerstoattack[ playerstoattack.size ] = players[ i ];
}
}
i++;
}
return playerstoattack;
}