mirror of
https://github.com/JezuzLizard/Recompilable-gscs-for-BO2-zombies-and-multiplayer.git
synced 2025-06-10 10:47:58 -05:00
2501 lines
60 KiB
Plaintext
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;
|
|
}
|