burc_2004

_zm_ai_sloth.gsc

Oct 22nd, 2015
235
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 106.67 KB | None | 0 0
  1. #include maps/mp/zombies/_zm_weap_time_bomb;
  2. #include maps/mp/zombies/_zm_weap_slowgun;
  3. #include maps/mp/zombies/_zm_powerups;
  4. #include maps/mp/animscripts/zm_run;
  5. #include maps/mp/animscripts/zm_death;
  6. #include maps/mp/zombies/_zm_unitrigger;
  7. #include maps/mp/animscripts/zm_shared;
  8. #include maps/mp/zombies/_zm_spawner;
  9. #include maps/mp/zombies/_zm_equip_headchopper;
  10. #include maps/mp/zombies/_zm_score;
  11. #include maps/mp/zombies/_zm_stats;
  12. #include maps/mp/zombies/_zm_audio;
  13. #include maps/mp/zombies/_zm_equipment;
  14. #include maps/mp/zombies/_zm_zonemgr;
  15. #include maps/mp/zombies/_zm_ai_sloth;
  16. #include maps/mp/zombies/_zm_ai_sloth_ffotd;
  17. #include maps/mp/zombies/_zm_ai_sloth_utility;
  18. #include maps/mp/zombies/_zm_ai_sloth_magicbox;
  19. #include maps/mp/zombies/_zm_ai_sloth_crawler;
  20. #include maps/mp/zombies/_zm_ai_sloth_buildables;
  21. #include maps/mp/animscripts/zm_utility;
  22. #include maps/mp/zombies/_zm_utility;
  23. #include maps/mp/_utility;
  24. #include common_scripts/utility;
  25.  
  26. precache()
  27. {
  28. /#
  29.     precachemodel( "fx_axis_createfx" );
  30. #/
  31.     level.small_magic_box = "p6_anim_zm_bu_magic_box_sml";
  32.     level.small_turbine = "p6_anim_zm_bu_turbine_sml";
  33.     precachemodel( level.small_magic_box );
  34.     precachemodel( level.small_turbine );
  35.     precache_fx();
  36.     level._effect[ "barrier_break" ] = loadfx( "maps/zombie_buried/fx_buried_barrier_break" );
  37.     level._effect[ "fx_buried_sloth_building" ] = loadfx( "maps/zombie_buried/fx_buried_sloth_building" );
  38.     level._effect[ "fx_buried_sloth_box_slam" ] = loadfx( "maps/zombie_buried/fx_buried_sloth_box_slam" );
  39.     level._effect[ "fx_buried_sloth_drinking" ] = loadfx( "maps/zombie_buried/fx_buried_sloth_drinking" );
  40.     level._effect[ "fx_buried_sloth_eating" ] = loadfx( "maps/zombie_buried/fx_buried_sloth_eating" );
  41.     level._effect[ "fx_buried_sloth_glass_brk" ] = loadfx( "maps/zombie_buried/fx_buried_sloth_glass_brk" );
  42.     level._effect[ "fx_buried_sloth_powerup_cycle" ] = loadfx( "maps/zombie_buried/fx_buried_sloth_powerup_cycle" );
  43. }
  44.  
  45. precache_fx()
  46. {
  47. }
  48.  
  49. init()
  50. {
  51.     register_sloth_client_fields();
  52.     flag_init( "sloth_blocker_towneast" );
  53.     level.sloth_spawners = getentarray( "sloth_zombie_spawner", "script_noteworthy" );
  54.     array_thread( level.sloth_spawners, ::add_spawn_function, ::sloth_prespawn );
  55.     level thread sloth_spawning_logic();
  56.     level thread init_roam_points();
  57.     level thread init_barricades();
  58.     level thread init_interiors();
  59.     level thread init_teleport_points();
  60.     level thread init_candy_context();
  61.     level thread init_build_buildables();
  62.     level thread init_wallbuys();
  63.     level thread init_generator();
  64.     level thread init_fetch_buildables();
  65.     level thread jail_cell_watcher();
  66.     level thread init_hunched_volume();
  67.     level thread init_crash_triggers();
  68.     level thread watch_bar_couch();
  69.     sloth_time_bomb_setup();
  70.     level.wait_for_sloth = ::wait_for_sloth;
  71.     level.ignore_stop_func = ::ignore_stop_func;
  72.     level thread sloth_ffotd_init();
  73. /#
  74.     level.sloth_devgui_teleport = ::sloth_devgui_teleport;
  75.     level.sloth_devgui_booze = ::sloth_devgui_booze;
  76.     level.sloth_devgui_candy = ::sloth_devgui_candy;
  77.     level.sloth_devgui_warp_to_jail = ::sloth_devgui_warp_to_jail;
  78.     level.sloth_devgui_move_lamp = ::sloth_devgui_move_lamp;
  79.     level.sloth_devgui_make_crawler = ::sloth_devgui_make_crawler;
  80.     level.sloth_devgui_barricade = ::sloth_devgui_barricade;
  81.     level.sloth_devgui_context = ::sloth_devgui_context;
  82.     level.sloth_devgui_double_wide = ::sloth_devgui_double_wide;
  83.     level thread sloth_debug_doors();
  84.     level thread sloth_debug_barricade();
  85. #/
  86. }
  87.  
  88. register_sloth_client_fields()
  89. {
  90.     registerclientfield( "actor", "actor_is_sloth", 12000, 1, "int" );
  91.     registerclientfield( "actor", "sloth_berserk", 12000, 1, "int" );
  92.     registerclientfield( "actor", "sloth_ragdoll_zombie", 12000, 1, "int" );
  93.     registerclientfield( "actor", "sloth_vomit", 12000, 1, "int" );
  94.     registerclientfield( "actor", "sloth_buildable", 12000, 1, "int" );
  95.     registerclientfield( "actor", "sloth_drinking", 12000, 1, "int" );
  96.     registerclientfield( "actor", "sloth_eating", 12000, 1, "int" );
  97.     registerclientfield( "actor", "sloth_glass_brk", 12000, 1, "int" );
  98. }
  99.  
  100. init_interiors()
  101. {
  102.     level.interiors = [];
  103.     level.interiors[ level.interiors.size ] = "zone_underground_jail";
  104.     level.interiors[ level.interiors.size ] = "zone_underground_jail2";
  105.     level.interiors[ level.interiors.size ] = "zone_underground_courthouse";
  106.     level.interiors[ level.interiors.size ] = "zone_underground_bar";
  107.     level.interiors[ level.interiors.size ] = "zone_morgue";
  108.     level.interiors[ level.interiors.size ] = "zone_morgue_upstairs";
  109.     level.interiors[ level.interiors.size ] = "zone_church_main";
  110.     level.interiors[ level.interiors.size ] = "zone_church_upstairs";
  111.     level.interiors[ level.interiors.size ] = "zone_stables";
  112.     level.interiors[ level.interiors.size ] = "zone_bank";
  113.     level.interiors[ level.interiors.size ] = "zone_candy_store";
  114.     level.interiors[ level.interiors.size ] = "zone_candy_store_floor2";
  115.     level.interiors[ level.interiors.size ] = "zone_toy_store";
  116.     level.interiors[ level.interiors.size ] = "zone_toy_store_floor2";
  117.     level.interiors[ level.interiors.size ] = "zone_general_store";
  118.     level.interiors[ level.interiors.size ] = "zone_gun_store";
  119.     level.interiors[ level.interiors.size ] = "zone_tunnels_north";
  120.     level.interiors[ level.interiors.size ] = "zone_tunnels_north2";
  121.     level.interiors[ level.interiors.size ] = "zone_tunnels_center";
  122.     level.interiors[ level.interiors.size ] = "zone_tunnel_gun2stables";
  123.     level.interiors[ level.interiors.size ] = "zone_tunnel_gun2saloon";
  124.     level thread setup_door_markers();
  125. }
  126.  
  127. init_teleport_points()
  128. {
  129.     level.maze_depart = getstructarray( "sloth_to_maze_begin", "targetname" );
  130.     level.maze_arrive = getstructarray( "sloth_to_maze_end", "targetname" );
  131.     level.courtyard_depart = getstructarray( "sloth_from_maze_begin", "targetname" );
  132.     level.courtyard_arrive = getstructarray( "sloth_from_maze_end", "targetname" );
  133.     level.maze_to_mansion = getstructarray( "sloth_maze_to_mansion", "targetname" );
  134. }
  135.  
  136. sloth_init_roam_point()
  137. {
  138.     _a171 = level.roam_points;
  139.     _k171 = getFirstArrayKey( _a171 );
  140.     while ( isDefined( _k171 ) )
  141.     {
  142.         point = _a171[ _k171 ];
  143.         if ( point.script_noteworthy == "zone_street_lightwest" )
  144.         {
  145.             self.current_roam = point;
  146.             return;
  147.         }
  148.         _k171 = getNextArrayKey( _a171, _k171 );
  149.     }
  150. }
  151.  
  152. watch_double_wide()
  153. {
  154.     self endon( "death" );
  155.     level.double_wide_volume = getentarray( "ignore_double_wide", "targetname" );
  156.     while ( 1 )
  157.     {
  158.         self.ignore_double_wide = 0;
  159.         _a194 = level.double_wide_volume;
  160.         _k194 = getFirstArrayKey( _a194 );
  161.         while ( isDefined( _k194 ) )
  162.         {
  163.             volume = _a194[ _k194 ];
  164.             if ( self istouching( volume ) )
  165.             {
  166.                 self.ignore_double_wide = 1;
  167.             }
  168.             _k194 = getNextArrayKey( _a194, _k194 );
  169.         }
  170.         if ( isDefined( level.double_wide_override ) )
  171.         {
  172.             self [[ level.double_wide_override ]]();
  173.         }
  174.         wait 0,2;
  175.     }
  176. }
  177.  
  178. watch_interiors()
  179. {
  180.     self endon( "death" );
  181.     while ( 1 )
  182.     {
  183.         self.is_inside = 0;
  184.         i = 0;
  185.         while ( i < level.sloth_doors.size )
  186.         {
  187.             door_flag = level.sloth_doors[ i ].script_flag;
  188.             if ( isDefined( door_flag ) )
  189.             {
  190.                 if ( flag( door_flag ) )
  191.                 {
  192.                     dist = distancesquared( self.origin, level.sloth_doors[ i ].origin );
  193.                     if ( dist < 14400 )
  194.                     {
  195.                         self.is_inside = 1;
  196.                         break;
  197.                     }
  198.                 }
  199.             }
  200.             else
  201.             {
  202.                 i++;
  203.             }
  204.         }
  205.         i = 0;
  206.         while ( i < level.sloth_hunched_structs.size )
  207.         {
  208.             dist = distancesquared( self.origin, level.sloth_hunched_structs[ i ].origin );
  209.             if ( dist < 14400 )
  210.             {
  211.                 self.is_inside = 1;
  212.                 break;
  213.             }
  214.             else
  215.             {
  216.                 i++;
  217.             }
  218.         }
  219.         while ( !self.is_inside )
  220.         {
  221.             i = 0;
  222.             while ( i < level.interiors.size )
  223.             {
  224.                 name = level.interiors[ i ];
  225.                 if ( self maps/mp/zombies/_zm_zonemgr::entity_in_zone( name ) )
  226.                 {
  227.                     self.is_inside = 1;
  228.                     break;
  229.                 }
  230.                 else
  231.                 {
  232.                     i++;
  233.                 }
  234.             }
  235.         }
  236.         if ( !self.is_inside )
  237.         {
  238.             if ( self istouching( level.hunched_volume ) )
  239.             {
  240.                 self.is_inside = 1;
  241.             }
  242.         }
  243.         if ( isDefined( level.interior_override ) )
  244.         {
  245.             self [[ level.interior_override ]]();
  246.         }
  247.         self sloth_update_double_wide();
  248.         wait 0,1;
  249.     }
  250. }
  251.  
  252. sloth_update_double_wide()
  253. {
  254. /#
  255.     if ( is_true( level.devgui_double_wide ) )
  256.     {
  257.         return;
  258. #/
  259.     }
  260.     if ( is_true( self.ignore_double_wide ) || self.is_inside )
  261.     {
  262.         if ( self.using_double_wide )
  263.         {
  264.             self.using_double_wide = 0;
  265.             setdvar( "zombie_double_wide_checks", 0 );
  266.             self setphysparams( 15, 0, 73 );
  267. /#
  268.             setdvarint( "scr_sloth_debug_width", 15 );
  269.             setdvarint( "scr_sloth_debug_height", 73 );
  270.             self.debug_width = getDvarInt( #"2443DFBB" );
  271.             self.debug_height = getDvarInt( #"897C9AB4" );
  272. #/
  273.         }
  274.     }
  275.     else
  276.     {
  277.         if ( !self.using_double_wide )
  278.         {
  279.             self.using_double_wide = 1;
  280.             setdvar( "zombie_double_wide_checks", 1 );
  281.             self setphysparams( 25, 0, 73 );
  282. /#
  283.             setdvarint( "scr_sloth_debug_width", 25 );
  284.             setdvarint( "scr_sloth_debug_height", 73 );
  285.             self.debug_width = getDvarInt( #"2443DFBB" );
  286.             self.debug_height = getDvarInt( #"897C9AB4" );
  287. #/
  288.         }
  289.     }
  290. }
  291.  
  292. watch_zombies()
  293. {
  294.     self endon( "death" );
  295.     level endon( "maxis_minigame_start" );
  296.     while ( 1 )
  297.     {
  298.         all_far = 1;
  299.         zombies = get_round_enemy_array();
  300.         i = 0;
  301.         while ( i < zombies.size )
  302.         {
  303.             zombie = zombies[ i ];
  304.             dist = distancesquared( self.origin, zombie.origin );
  305.             if ( dist <= 3600 )
  306.             {
  307.                 self.near_zombies = 1;
  308.                 all_far = 0;
  309.                 i++;
  310.                 continue;
  311.             }
  312.             else
  313.             {
  314.                 if ( dist <= 14400 )
  315.                 {
  316.                     all_far = 0;
  317.                 }
  318.             }
  319.             i++;
  320.         }
  321.         if ( all_far )
  322.         {
  323.             self.near_zombies = 0;
  324.         }
  325.         wait 0,2;
  326.     }
  327. }
  328.  
  329. watch_player_zombies()
  330. {
  331.     self endon( "death" );
  332.     self notify( "stop_player_watch" );
  333.     self endon( "stop_player_watch" );
  334.     level endon( "maxis_minigame_start" );
  335.     while ( 1 )
  336.     {
  337.         while ( isDefined( self.candy_player ) )
  338.         {
  339.             self.target_zombies = [];
  340.             zombies = get_round_enemy_array();
  341.             i = 0;
  342.             while ( i < zombies.size )
  343.             {
  344.                 zombie = zombies[ i ];
  345.                 if ( !is_true( zombie.completed_emerging_into_playable_area ) )
  346.                 {
  347.                     i++;
  348.                     continue;
  349.                 }
  350.                 else if ( is_true( zombie.is_traversing ) )
  351.                 {
  352.                     i++;
  353.                     continue;
  354.                 }
  355.                 else z_delta = abs( self.candy_player.origin[ 2 ] - zombie.origin[ 2 ] );
  356.                 if ( z_delta > 120 )
  357.                 {
  358.                     i++;
  359.                     continue;
  360.                 }
  361.                 else
  362.                 {
  363.                     dist = distancesquared( self.candy_player.origin, zombie.origin );
  364.                     if ( dist <= 57600 )
  365.                     {
  366.                         self.target_zombies[ self.target_zombies.size ] = zombie;
  367.                     }
  368.                 }
  369.                 i++;
  370.             }
  371.         }
  372.         wait 0,2;
  373.     }
  374. }
  375.  
  376. watch_subwoofers()
  377. {
  378.     self endon( "death" );
  379.     level endon( "maxis_minigame_start" );
  380.     while ( 1 )
  381.     {
  382.         self.subwoofer = undefined;
  383.         equipment = maps/mp/zombies/_zm_equipment::get_destructible_equipment_list();
  384.         _a425 = equipment;
  385.         _k425 = getFirstArrayKey( _a425 );
  386.         while ( isDefined( _k425 ) )
  387.         {
  388.             item = _a425[ _k425 ];
  389.             if ( isDefined( item.equipname ) && item.equipname == "equip_subwoofer_zm" )
  390.             {
  391.                 if ( is_true( item.power_on ) )
  392.                 {
  393. /#
  394.                     self sloth_debug_context( item, sqrt( 32400 ) );
  395. #/
  396.                     dist = distancesquared( self.origin, item.origin );
  397.                     if ( dist < 32400 )
  398.                     {
  399.                         self.subwoofer = item;
  400.                     }
  401.                 }
  402.             }
  403.             _k425 = getNextArrayKey( _a425, _k425 );
  404.         }
  405.         wait 0,2;
  406.     }
  407. }
  408.  
  409. watch_stink()
  410. {
  411.     self endon( "death" );
  412.     level endon( "maxis_minigame_start" );
  413.     while ( 1 )
  414.     {
  415.         self.stink = undefined;
  416.         has_perk = 0;
  417.         players = getplayers();
  418.         _a462 = players;
  419.         _k462 = getFirstArrayKey( _a462 );
  420.         while ( isDefined( _k462 ) )
  421.         {
  422.             player = _a462[ _k462 ];
  423.             if ( player hasperk( "specialty_nomotionsensor" ) )
  424.             {
  425.                 has_perk = 1;
  426.                 break;
  427.             }
  428.             else
  429.             {
  430.                 _k462 = getNextArrayKey( _a462, _k462 );
  431.             }
  432.         }
  433.         while ( has_perk && isDefined( level.perk_vulture ) )
  434.         {
  435.             while ( isDefined( level.perk_vulture.zombie_stink_array ) && level.perk_vulture.zombie_stink_array.size > 0 )
  436.             {
  437.                 _a475 = level.perk_vulture.zombie_stink_array;
  438.                 _k475 = getFirstArrayKey( _a475 );
  439.                 while ( isDefined( _k475 ) )
  440.                 {
  441.                     stink = _a475[ _k475 ];
  442. /#
  443.                     self sloth_debug_context( stink, 70 );
  444. #/
  445.                     dist = distancesquared( self.origin, stink.origin );
  446.                     if ( dist < 4900 )
  447.                     {
  448.                         self.stink = stink;
  449.                     }
  450.                     _k475 = getNextArrayKey( _a475, _k475 );
  451.                 }
  452.             }
  453.         }
  454.         wait 0,2;
  455.     }
  456. }
  457.  
  458. watch_pack_volume()
  459. {
  460.     volume = getent( "sloth_pack_volume", "targetname" );
  461.     while ( isDefined( volume ) )
  462.     {
  463.         while ( 1 )
  464.         {
  465.             if ( self istouching( volume ) )
  466.             {
  467.                 self sloth_teleport_to_maze();
  468.             }
  469.             wait 0,1;
  470.         }
  471.     }
  472. }
  473.  
  474. watch_jail_door()
  475. {
  476.     self endon( "death" );
  477.     while ( 1 )
  478.     {
  479.         level waittill( "cell_open" );
  480.         if ( isDefined( level.jail_open_door ) )
  481.         {
  482.             level thread [[ level.jail_open_door ]]( self.got_booze );
  483.         }
  484.     }
  485. }
  486.  
  487. sloth_teleport_to_maze()
  488. {
  489.     points = array_randomize( level.maze_arrive );
  490. /#
  491.     sloth_print( "teleporting to maze" );
  492. #/
  493.     self forceteleport( points[ 0 ].origin );
  494.     if ( self.state == "berserk" )
  495.     {
  496.         self sloth_set_state( "crash", 0 );
  497.     }
  498.     wait 0,1;
  499. }
  500.  
  501. is_towneast_open()
  502. {
  503.     if ( flag( "sloth_blocker_towneast" ) )
  504.     {
  505.         return 1;
  506.     }
  507.     if ( is_general_store_open() )
  508.     {
  509.         return 1;
  510.     }
  511.     if ( is_candy_store_open() )
  512.     {
  513.         return 1;
  514.     }
  515.     return 0;
  516. }
  517.  
  518. is_maze_open()
  519. {
  520.     if ( flag( "mansion_lawn_door1" ) )
  521.     {
  522.         return 1;
  523.     }
  524.     return 0;
  525. }
  526.  
  527. is_general_store_open()
  528. {
  529.     if ( !flag( "general_store_door1" ) || flag( "general_store_door2" ) && flag( "general_store_door3" ) )
  530.     {
  531.         return 1;
  532.     }
  533.     return 0;
  534. }
  535.  
  536. is_candy_store_open()
  537. {
  538.     if ( flag( "candy_store_door1" ) || flag( "candy2lighteast" ) )
  539.     {
  540.         return 1;
  541.     }
  542.     return 0;
  543. }
  544.  
  545. is_bar_open()
  546. {
  547.     if ( flag( "bar_door1" ) )
  548.     {
  549.         return 1;
  550.     }
  551.     if ( is_true( level.bar_couch ) )
  552.     {
  553.         return 1;
  554.     }
  555.     return 0;
  556. }
  557.  
  558. watch_bar_couch()
  559. {
  560.     self endon( "stop_watch_bar_couch" );
  561.     bar_couch_pos = ( 1021, -1754, 172 );
  562.     bar_couch_trigger = undefined;
  563.     debris_triggers = getentarray( "zombie_debris", "targetname" );
  564.     _a631 = debris_triggers;
  565.     _k631 = getFirstArrayKey( _a631 );
  566.     while ( isDefined( _k631 ) )
  567.     {
  568.         trigger = _a631[ _k631 ];
  569.         dist = distancesquared( trigger.origin, bar_couch_pos );
  570.         if ( dist < 4096 )
  571.         {
  572.             bar_couch_trigger = trigger;
  573.             break;
  574.         }
  575.         else
  576.         {
  577.             _k631 = getNextArrayKey( _a631, _k631 );
  578.         }
  579.     }
  580.     if ( isDefined( bar_couch_trigger ) )
  581.     {
  582.         bar_couch_trigger waittill( "trigger" );
  583. /#
  584.         sloth_print( "bar couch bought" );
  585. #/
  586.         level.bar_couch = 1;
  587.     }
  588. }
  589.  
  590. sloth_behind_mansion()
  591. {
  592.     _a656 = level.maze_arrive;
  593.     _k656 = getFirstArrayKey( _a656 );
  594.     while ( isDefined( _k656 ) )
  595.     {
  596.         point = _a656[ _k656 ];
  597.         dist = distancesquared( self.origin, point.origin );
  598.         if ( dist < 360000 )
  599.         {
  600.             return 1;
  601.         }
  602.         _k656 = getNextArrayKey( _a656, _k656 );
  603.     }
  604.     if ( self behind_mansion_zone() )
  605.     {
  606.         return 1;
  607.     }
  608.     return 0;
  609. }
  610.  
  611. behind_mansion_zone()
  612. {
  613.     behind_zones = [];
  614.     behind_zones[ behind_zones.size ] = "zone_mansion_backyard";
  615.     behind_zones[ behind_zones.size ] = "zone_maze";
  616.     behind_zones[ behind_zones.size ] = "zone_maze_staircase";
  617.     _a680 = behind_zones;
  618.     _k680 = getFirstArrayKey( _a680 );
  619.     while ( isDefined( _k680 ) )
  620.     {
  621.         zone = _a680[ _k680 ];
  622.         if ( self maps/mp/zombies/_zm_zonemgr::entity_in_zone( zone ) )
  623.         {
  624.             return 1;
  625.         }
  626.         _k680 = getNextArrayKey( _a680, _k680 );
  627.     }
  628.     return 0;
  629. }
  630.  
  631. setup_door_markers()
  632. {
  633.     level.sloth_doors = [];
  634.     level.sloth_hunched_structs = getstructarray( "hunched_struct", "targetname" );
  635.     idx = 0;
  636.     doors = getentarray( "zombie_door", "targetname" );
  637.     _a702 = doors;
  638.     _k702 = getFirstArrayKey( _a702 );
  639.     while ( isDefined( _k702 ) )
  640.     {
  641.         door = _a702[ _k702 ];
  642.         level.sloth_doors[ idx ] = spawnstruct();
  643.         level.sloth_doors[ idx ].origin = door.origin;
  644.         level.sloth_doors[ idx ].script_flag = door.script_flag;
  645.         idx++;
  646.         _k702 = getNextArrayKey( _a702, _k702 );
  647.     }
  648.     barricades = getentarray( "sloth_barricade", "targetname" );
  649.     _a714 = barricades;
  650.     _k714 = getFirstArrayKey( _a714 );
  651.     while ( isDefined( _k714 ) )
  652.     {
  653.         barricade = _a714[ _k714 ];
  654.         if ( isDefined( barricade.script_noteworthy ) && barricade.script_noteworthy == "door" )
  655.         {
  656.             level.sloth_doors[ idx ] = spawnstruct();
  657.             level.sloth_doors[ idx ].origin = barricade.origin;
  658.             level.sloth_doors[ idx ].script_flag = barricade.script_flag;
  659.             if ( barricade.script_flag == "jail_door1" )
  660.             {
  661.                 level.jail_door = level.sloth_doors[ idx ];
  662. /#
  663.                 level.jail_barricade = barricade;
  664. #/
  665.             }
  666.             idx++;
  667.         }
  668.         _k714 = getNextArrayKey( _a714, _k714 );
  669.     }
  670. }
  671.  
  672. init_roam_points()
  673. {
  674.     level.roam_points = getnodearray( "sloth_roam", "targetname" );
  675. }
  676.  
  677. init_barricades()
  678. {
  679.     triggers = getentarray( "sloth_barricade", "targetname" );
  680.     level.barricade_ents = [];
  681.     _a749 = triggers;
  682.     _k749 = getFirstArrayKey( _a749 );
  683.     while ( isDefined( _k749 ) )
  684.     {
  685.         trigger = _a749[ _k749 ];
  686.         trigger thread watch_barricade();
  687.         level.barricade_ents[ level.barricade_ents.size ] = trigger.target;
  688.         _k749 = getNextArrayKey( _a749, _k749 );
  689.     }
  690. }
  691.  
  692. watch_barricade()
  693. {
  694.     self endon( "death" );
  695.     self endon( "maxis_minigame_opens_barricade" );
  696.     if ( isDefined( self.script_string ) )
  697.     {
  698.         should_delete = self.script_string != "no_delete";
  699.     }
  700.     if ( !should_delete )
  701.     {
  702.         self.func_no_delete = ::hide_sloth_barrier;
  703.     }
  704.     while ( 1 )
  705.     {
  706.         self waittill( "trigger", who );
  707.         if ( isDefined( level.sloth ) && who == level.sloth && who.state == "berserk" )
  708.         {
  709.             should_break = is_true( who.run_berserk );
  710.         }
  711. /#
  712.         if ( isplayer( who ) && is_true( level.devgui_break ) )
  713.         {
  714.             level.devgui_break = 0;
  715.             should_break = 1;
  716. #/
  717.         }
  718.         if ( should_break )
  719.         {
  720.             if ( !isplayer( who ) )
  721.             {
  722.                 who sloth_set_state( "crash", 1 );
  723.                 level thread maps/mp/zombies/_zm_audio::sndmusicstingerevent( "sloth_escape" );
  724.             }
  725.             if ( isDefined( who.booze_player ) )
  726.             {
  727.                 who.booze_player maps/mp/zombies/_zm_stats::increment_client_stat( "buried_sloth_booze_break_barricade", 0 );
  728.                 who.booze_player maps/mp/zombies/_zm_stats::increment_player_stat( "buried_sloth_booze_break_barricade" );
  729.                 reward_dist = distance( who.berserk_start_org, who.origin );
  730.                 points = int( reward_dist / 10 ) * 10;
  731.                 who.booze_player maps/mp/zombies/_zm_score::add_to_player_score( points );
  732.                 who.booze_player thread sloth_clears_path_vo();
  733.                 who.booze_player = undefined;
  734.             }
  735.             if ( isDefined( self.script_flag ) && level flag_exists( self.script_flag ) )
  736.             {
  737. /#
  738.                 sloth_print( "flag_set " + self.script_flag );
  739. #/
  740.                 flag_set( self.script_flag );
  741.                 if ( self.script_flag == "jail_door1" )
  742.                 {
  743.                     level notify( "jail_barricade_down" );
  744.                 }
  745.             }
  746.             if ( isDefined( self.script_noteworthy ) )
  747.             {
  748.                 if ( self.script_noteworthy == "courtyard_fountain" )
  749.                 {
  750.                     level notify( "courtyard_fountain_open" );
  751.                 }
  752.             }
  753.             if ( isDefined( self.script_int ) )
  754.             {
  755.                 exploder( self.script_int );
  756.             }
  757.             pieces = getentarray( self.target, "targetname" );
  758.             _a831 = pieces;
  759.             _k831 = getFirstArrayKey( _a831 );
  760.             while ( isDefined( _k831 ) )
  761.             {
  762.                 piece = _a831[ _k831 ];
  763.                 if ( should_delete )
  764.                 {
  765.                     piece delete();
  766.                 }
  767.                 else
  768.                 {
  769.                     piece hide_sloth_barrier();
  770.                 }
  771.                 _k831 = getNextArrayKey( _a831, _k831 );
  772.             }
  773.             self thread maps/mp/zombies/_zm_equip_headchopper::destroyheadchopperstouching( 0 );
  774.             self playsound( "zmb_sloth_barrier_break" );
  775.             level notify( "sloth_breaks_barrier" );
  776.             if ( should_delete )
  777.             {
  778.                 self delete();
  779.             }
  780.             else
  781.             {
  782.                 self hide_sloth_barrier();
  783.             }
  784.             return;
  785.         }
  786.     }
  787. }
  788.  
  789. sloth_clears_path_vo()
  790. {
  791.     self endon( "death" );
  792.     self endon( "disconnect" );
  793.     wait 2;
  794.     self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "sloth_clears_path" );
  795. }
  796.  
  797. hide_sloth_barrier()
  798. {
  799.     self.is_hidden = 1;
  800.     self notsolid();
  801.     self ghost();
  802.     if ( isDefined( self.script_noteworthy ) && self.script_noteworthy == "clip" )
  803.     {
  804.         self connectpaths();
  805.     }
  806. }
  807.  
  808. unhide_sloth_barrier()
  809. {
  810.     self.is_hidden = 0;
  811.     self solid();
  812.     self show();
  813.     if ( isDefined( self.script_noteworthy ) && self.script_noteworthy == "clip" )
  814.     {
  815.         self disconnectpaths();
  816.     }
  817. }
  818.  
  819. is_barricade_ent( ent )
  820. {
  821.     i = 0;
  822.     while ( i < level.barricade_ents.size )
  823.     {
  824.         if ( isDefined( ent.targetname ) )
  825.         {
  826.             if ( ent.targetname == level.barricade_ents[ i ] )
  827.             {
  828.                 return 1;
  829.             }
  830.         }
  831.         i++;
  832.     }
  833.     return 0;
  834. }
  835.  
  836. jail_cell_watcher()
  837. {
  838.     level.jail_cell_volume = getent( "jail_cell_volume", "targetname" );
  839. }
  840.  
  841. init_hunched_volume()
  842. {
  843.     level.hunched_volume = getent( "hunched_volume", "targetname" );
  844. }
  845.  
  846. init_crash_triggers()
  847. {
  848.     level.crash_triggers = getentarray( "crash_trigger", "targetname" );
  849.     _a935 = level.crash_triggers;
  850.     _k935 = getFirstArrayKey( _a935 );
  851.     while ( isDefined( _k935 ) )
  852.     {
  853.         trigger = _a935[ _k935 ];
  854.         trigger thread watch_crash_trigger();
  855.         _k935 = getNextArrayKey( _a935, _k935 );
  856.     }
  857. }
  858.  
  859. watch_crash_trigger()
  860. {
  861.     while ( 1 )
  862.     {
  863.         self waittill( "trigger", who );
  864.         if ( who == level.sloth && who.state == "berserk" )
  865.         {
  866. /#
  867.             sloth_print( "crash trigger" );
  868. #/
  869.             who setclientfield( "sloth_berserk", 0 );
  870.             who sloth_set_state( "crash", 0 );
  871.         }
  872.     }
  873. }
  874.  
  875. bell_ring()
  876. {
  877.     level endon( "maxis_minigame_start" );
  878.     while ( 1 )
  879.     {
  880.         level waittill( "bell_rung" );
  881.         if ( isDefined( level.sloth ) )
  882.         {
  883.         }
  884.     }
  885. }
  886.  
  887. wait_for_sloth( wait_state )
  888. {
  889.     level endon( "ignore_wait" );
  890.     sloth = level.sloth;
  891.     if ( isDefined( sloth ) )
  892.     {
  893.         sloth.bench = self;
  894.         if ( wait_state == "gunshop_arrival" )
  895.         {
  896.             while ( 1 )
  897.             {
  898.                 if ( sloth.state == "gunshop_candy" )
  899.                 {
  900.                     break;
  901.                 }
  902.                 else
  903.                 {
  904.                     wait 0,1;
  905.                 }
  906.             }
  907.         }
  908.         else if ( wait_state == "gunshop_table" )
  909.         {
  910.             sloth waittill( "table_eat_done" );
  911.         }
  912.     }
  913. }
  914.  
  915. wait_for_timeout()
  916. {
  917.     level endon( "candy_bench" );
  918.     if ( isDefined( self.bench ) )
  919.     {
  920.         self.bench waittill( "weap_bench_off" );
  921.         self.bench = undefined;
  922.         self stop_action();
  923.         self sloth_set_state( "roam" );
  924.     }
  925. }
  926.  
  927. wait_for_candy()
  928. {
  929.     if ( isDefined( self.bench ) )
  930.     {
  931.         self.bench endon( "weap_bench_off" );
  932.     }
  933.     level waittill( "candy_bench" );
  934.     self sloth_set_state( "table_eat" );
  935. }
  936.  
  937. init_build_buildables()
  938. {
  939.     level.sloth_buildables = [];
  940.     level.sloth_buildables[ level.sloth_buildables.size ] = "riotshield_zm";
  941.     level.sloth_buildables[ level.sloth_buildables.size ] = "turret";
  942.     level.sloth_buildables[ level.sloth_buildables.size ] = "raygun";
  943.     level.sloth_buildables[ level.sloth_buildables.size ] = "electric_trap";
  944.     level.sloth_buildables[ level.sloth_buildables.size ] = "turbine";
  945.     level.sloth_buildables[ level.sloth_buildables.size ] = "springpad_zm";
  946.     level.sloth_buildables[ level.sloth_buildables.size ] = "subwoofer_zm";
  947.     level.sloth_buildables[ level.sloth_buildables.size ] = "headchopper_zm";
  948.     level.sloth_buildable_zones = [];
  949.     level waittill( "buildables_setup" );
  950.     wait 0,1;
  951.     _a1058 = level.sloth_buildables;
  952.     _k1058 = getFirstArrayKey( _a1058 );
  953.     while ( isDefined( _k1058 ) )
  954.     {
  955.         sloth_buildable = _a1058[ _k1058 ];
  956.         _a1060 = level.buildable_stubs;
  957.         _k1060 = getFirstArrayKey( _a1060 );
  958.         while ( isDefined( _k1060 ) )
  959.         {
  960.             stub = _a1060[ _k1060 ];
  961.             if ( stub.buildablezone.buildable_name == sloth_buildable )
  962.             {
  963.                 level.sloth_buildable_zones[ level.sloth_buildable_zones.size ] = stub.buildablezone;
  964.             }
  965.             _k1060 = getNextArrayKey( _a1060, _k1060 );
  966.         }
  967.         _k1058 = getNextArrayKey( _a1058, _k1058 );
  968.     }
  969. }
  970.  
  971. init_wallbuys()
  972. {
  973.     level waittill( "buildables_setup" );
  974.     level.sloth_wallbuy_stubs = [];
  975.     _a1079 = level.buildable_stubs;
  976.     _k1079 = getFirstArrayKey( _a1079 );
  977.     while ( isDefined( _k1079 ) )
  978.     {
  979.         stub = _a1079[ _k1079 ];
  980.         if ( isDefined( stub.in_zone ) && stub.in_zone == "zone_mansion" )
  981.         {
  982.         }
  983.         else
  984.         {
  985.             if ( stub.buildablezone.buildable_name == "chalk" )
  986.             {
  987.                 level.sloth_wallbuy_stubs[ level.sloth_wallbuy_stubs.size ] = stub;
  988.             }
  989.         }
  990.         _k1079 = getNextArrayKey( _a1079, _k1079 );
  991.     }
  992.     level.gunshop_zone = getent( "sloth_candyzone_gunshop", "targetname" );
  993. }
  994.  
  995. init_generator()
  996. {
  997.     level waittill( "buildables_setup" );
  998.     level.generator_zones = [];
  999.     _a1104 = level.buildable_stubs;
  1000.     _k1104 = getFirstArrayKey( _a1104 );
  1001.     while ( isDefined( _k1104 ) )
  1002.     {
  1003.         stub = _a1104[ _k1104 ];
  1004.         if ( stub.buildablezone.buildable_name == "oillamp_zm" )
  1005.         {
  1006.             level.generator_zones[ level.generator_zones.size ] = stub.buildablezone;
  1007.         }
  1008.         _k1104 = getNextArrayKey( _a1104, _k1104 );
  1009.     }
  1010. }
  1011.  
  1012. init_fetch_buildables()
  1013. {
  1014.     power_items = [];
  1015.     power_items[ power_items.size ] = "turret";
  1016.     power_items[ power_items.size ] = "electric_trap";
  1017.     power_items[ power_items.size ] = "subwoofer_zm";
  1018.     level.power_zones = [];
  1019.     level waittill( "buildables_setup" );
  1020.     wait 0,1;
  1021.     _a1129 = level.buildable_stubs;
  1022.     _k1129 = getFirstArrayKey( _a1129 );
  1023.     while ( isDefined( _k1129 ) )
  1024.     {
  1025.         stub = _a1129[ _k1129 ];
  1026.         _a1131 = power_items;
  1027.         _k1131 = getFirstArrayKey( _a1131 );
  1028.         while ( isDefined( _k1131 ) )
  1029.         {
  1030.             item = _a1131[ _k1131 ];
  1031.             if ( stub.buildablezone.buildable_name == item )
  1032.             {
  1033.                 level.power_zones[ level.power_zones.size ] = stub.buildablezone;
  1034.             }
  1035.             else
  1036.             {
  1037.                 if ( stub.buildablezone.buildable_name == "turbine" )
  1038.                 {
  1039.                     level.turbine_zone = stub.buildablezone;
  1040.                 }
  1041.             }
  1042.             _k1131 = getNextArrayKey( _a1131, _k1131 );
  1043.         }
  1044.         _k1129 = getNextArrayKey( _a1129, _k1129 );
  1045.     }
  1046. }
  1047.  
  1048. init_candy_context()
  1049. {
  1050.     register_candy_context( "protect", 95, ::protect_condition, ::protect_start, ::protect_update, ::protect_action );
  1051.     register_candy_context( "build_buildable", 40, ::build_buildable_condition, ::common_context_start, ::common_context_update, ::build_buildable_action, ::build_buildable_interrupt );
  1052.     register_candy_context( "wallbuy", 80, ::wallbuy_condition, ::common_context_start, ::common_context_update, ::wallbuy_action, ::wallbuy_interrupt );
  1053.     register_candy_context( "fetch_buildable", 50, ::fetch_buildable_condition, ::fetch_buildable_start, ::common_context_update, ::fetch_buildable_action, ::fetch_buildable_interrupt );
  1054.     register_candy_context( "box_lock", 65, ::box_lock_condition, ::common_context_start, ::common_context_update, ::box_lock_action );
  1055.     register_candy_context( "box_move", 70, ::box_move_condition, ::common_context_start, ::common_context_update, ::box_move_action, ::box_move_interrupt );
  1056.     register_candy_context( "box_spin", 75, ::box_spin_condition, ::common_context_start, ::common_context_update, ::box_spin_action );
  1057.     register_candy_context( "powerup_cycle", 30, ::powerup_cycle_condition, ::common_context_start, ::common_context_update, ::powerup_cycle_action );
  1058.     register_candy_context( "crawler", 85, ::crawler_condition, ::common_context_start, ::common_context_update, ::crawler_action );
  1059. }
  1060.  
  1061. register_candy_context( name, priority, func_condition, func_start, func_update, func_action, func_interrupt )
  1062. {
  1063.     if ( !isDefined( level.candy_context ) )
  1064.     {
  1065.         level.candy_context = [];
  1066.     }
  1067.     level.candy_context[ name ] = spawnstruct();
  1068.     level.candy_context[ name ].name = name;
  1069.     level.candy_context[ name ].priority = priority;
  1070.     level.candy_context[ name ].condition = func_condition;
  1071.     level.candy_context[ name ].start = func_start;
  1072.     level.candy_context[ name ].update = func_update;
  1073.     level.candy_context[ name ].action = func_action;
  1074.     level.candy_context[ name ].interrupt = func_interrupt;
  1075. }
  1076.  
  1077. unregister_candy_context( name )
  1078. {
  1079.     remove_context = undefined;
  1080.     if ( !isDefined( level.candy_context ) || level.candy_context.size == 0 )
  1081.     {
  1082.         return;
  1083.     }
  1084.     _a1188 = level.candy_context;
  1085.     _k1188 = getFirstArrayKey( _a1188 );
  1086.     while ( isDefined( _k1188 ) )
  1087.     {
  1088.         context = _a1188[ _k1188 ];
  1089.         if ( context.name == name )
  1090.         {
  1091.             remove_context = context;
  1092.             break;
  1093.         }
  1094.         else
  1095.         {
  1096.             _k1188 = getNextArrayKey( _a1188, _k1188 );
  1097.         }
  1098.     }
  1099.     if ( isDefined( remove_context ) )
  1100.     {
  1101.         arrayremovevalue( level.candy_context, remove_context, 1 );
  1102. /#
  1103.         sloth_print( remove_context.name + " removed from candy context" );
  1104. #/
  1105.     }
  1106. }
  1107.  
  1108. sloth_grab_powerup()
  1109. {
  1110.     i = 0;
  1111.     while ( i < level.active_powerups.size )
  1112.     {
  1113.         powerup = level.active_powerups[ i ];
  1114.         dist = distancesquared( powerup.origin, self.origin );
  1115.         if ( dist < 9216 )
  1116.         {
  1117.             if ( isDefined( self.follow_player ) )
  1118.             {
  1119.                 self.follow_player.ignore_range_powerup = powerup;
  1120.             }
  1121.         }
  1122.         i++;
  1123.     }
  1124. }
  1125.  
  1126. sloth_prespawn()
  1127. {
  1128.     self endon( "death" );
  1129.     level endon( "intermission" );
  1130.     level.sloth = self;
  1131.     if ( !isDefined( level.possible_slowgun_targets ) )
  1132.     {
  1133.         level.possible_slowgun_targets = [];
  1134.     }
  1135.     level.possible_slowgun_targets[ level.possible_slowgun_targets.size ] = self;
  1136.     self sloth_init_update_funcs();
  1137.     self sloth_init_start_funcs();
  1138.     self.has_legs = 1;
  1139.     self.no_gib = 1;
  1140.     self.nododgemove = 1;
  1141.     self.is_sloth = 1;
  1142.     self.ignore_enemy_count = 1;
  1143.     recalc_zombie_array();
  1144.     self setphysparams( 15, 0, 73 );
  1145. /#
  1146.     setdvarint( "scr_sloth_debug_width", 15 );
  1147.     setdvarint( "scr_sloth_debug_height", 73 );
  1148.     self.debug_width = getDvarInt( #"2443DFBB" );
  1149.     self.debug_height = getDvarInt( #"897C9AB4" );
  1150.     self thread sloth_devgui_update_phys_params();
  1151. #/
  1152.     self.ignore_nuke = 1;
  1153.     self.ignore_lava_damage = 1;
  1154.     self.ignore_devgui_death = 1;
  1155.     self.ignore_electric_trap = 1;
  1156.     self.ignore_game_over_death = 1;
  1157.     self.ignore_enemyoverride = 1;
  1158.     self.ignore_solo_last_stand = 1;
  1159.     self.ignore_riotshield = 1;
  1160.     self.paralyzer_hit_callback = ::sloth_paralyzed;
  1161.     self.paralyzer_slowtime = 0;
  1162.     self.allowpain = 0;
  1163.     self.jail_start = getstruct( "sloth_idle_pos", "targetname" );
  1164.     self forceteleport( self.jail_start.origin, self.jail_start.angles );
  1165.     self.gunshop = getstruct( "sloth_gunshop", "targetname" );
  1166.     self set_zombie_run_cycle( "walk" );
  1167.     self.locomotion = "walk";
  1168.     self animmode( "normal" );
  1169.     self orientmode( "face enemy" );
  1170.     self maps/mp/zombies/_zm_spawner::zombie_setup_attack_properties();
  1171.     self maps/mp/zombies/_zm_spawner::zombie_complete_emerging_into_playable_area();
  1172.     self setfreecameralockonallowed( 0 );
  1173.     self.zmb_vocals_attack = "zmb_vocals_zombie_attack";
  1174.     if ( !isDefined( self.sndent ) )
  1175.     {
  1176.         origin = self gettagorigin( "J_neck" );
  1177.         self.sndent = spawn( "script_origin", origin );
  1178.         self.sndent linkto( self, "J_neck" );
  1179.     }
  1180.     self.meleedamage = 5;
  1181.     self.ignoreall = 1;
  1182.     self.ignoreme = 1;
  1183.     self.ignore_spring_pad = 1;
  1184.     self.ignore_headchopper = 1;
  1185.     self thread create_candy_booze_trigger();
  1186.     self.zombie_init_done = 1;
  1187.     self notify( "zombie_init_done" );
  1188.     self.needs_action = 1;
  1189.     self.actor_damage_func = ::sloth_damage_func;
  1190.     self.non_attacker_func = ::sloth_non_attacker;
  1191.     self.set_anim_rate = ::sloth_set_anim_rate;
  1192.     self.reset_anim = ::sloth_reset_anim;
  1193.     self sloth_set_traverse_funcs();
  1194.     self disableaimassist();
  1195.     self.goalradius = 16;
  1196.     self pushplayer( 1 );
  1197.     self.anchor = spawn( "script_origin", self.origin );
  1198.     self.anchor.angles = self.angles;
  1199.     self.is_inside = 1;
  1200.     self.near_zombies = 0;
  1201.     self.aiteam = "allies";
  1202.     self.using_double_wide = 0;
  1203.     self thread sloth_init_roam_point();
  1204.     self thread watch_double_wide();
  1205.     self thread watch_interiors();
  1206.     self thread watch_zombies();
  1207.     self thread watch_stink();
  1208.     self thread watch_pack_volume();
  1209.     self thread watch_jail_door();
  1210.     self thread watch_crash_pos();
  1211.     self.headbang_time = getTime();
  1212.     self.smell_time = getTime();
  1213.     self.leg_pain_time = getTime();
  1214.     self.to_maze = 1;
  1215.     self.from_maze = 0;
  1216.     self.damage_taken = 0;
  1217.     self setclientfield( "actor_is_sloth", 1 );
  1218. /#
  1219.     self thread sloth_debug_buildables();
  1220. #/
  1221.     self thread sloth_ffotd_prespawn();
  1222. }
  1223.  
  1224. sloth_set_traverse_funcs()
  1225. {
  1226.     self.pre_traverse = ::sloth_pre_traverse;
  1227.     self.post_traverse = ::sloth_post_traverse;
  1228. }
  1229.  
  1230. sloth_pre_traverse()
  1231. {
  1232.     if ( !self is_jail_state() )
  1233.     {
  1234.         if ( self.state == "context" )
  1235.         {
  1236.             if ( isDefined( self.buildable_model ) )
  1237.             {
  1238.                 self setanimstatefromasd( "zm_sling_equipment" );
  1239.                 self maps/mp/animscripts/zm_shared::donotetracks( "sling_equipment_anim" );
  1240.             }
  1241.             else
  1242.             {
  1243.                 if ( is_true( self.box_model_visible ) )
  1244.                 {
  1245.                     self setanimstatefromasd( "zm_sling_magicbox" );
  1246.                     self maps/mp/animscripts/zm_shared::donotetracks( "sling_magicbox_anim" );
  1247.                 }
  1248.             }
  1249.             return;
  1250.         }
  1251.         else
  1252.         {
  1253.             thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.gift_trigger );
  1254.         }
  1255.     }
  1256. }
  1257.  
  1258. sloth_post_traverse()
  1259. {
  1260.     if ( !self is_jail_state() )
  1261.     {
  1262.         if ( self.state == "context" )
  1263.         {
  1264.             if ( isDefined( self.buildable_model ) )
  1265.             {
  1266.                 self setanimstatefromasd( "zm_unsling_equipment" );
  1267.                 self maps/mp/animscripts/zm_shared::donotetracks( "unsling_equipment_anim" );
  1268.             }
  1269.             else
  1270.             {
  1271.                 if ( is_true( self.box_model_visible ) )
  1272.                 {
  1273.                     self setanimstatefromasd( "zm_unsling_magicbox" );
  1274.                     self maps/mp/animscripts/zm_shared::donotetracks( "unsling_magicbox_anim" );
  1275.                 }
  1276.             }
  1277.             return;
  1278.         }
  1279.         else
  1280.         {
  1281.             maps/mp/zombies/_zm_unitrigger::register_unitrigger( self.gift_trigger, ::maps/mp/zombies/_zm_buildables::buildable_place_think );
  1282.         }
  1283.     }
  1284. }
  1285.  
  1286. sloth_spawning_logic()
  1287. {
  1288.     level endon( "intermission" );
  1289.     if ( level.intermission )
  1290.     {
  1291.         return;
  1292.     }
  1293. /#
  1294.     if ( getDvarInt( "zombie_cheat" ) == 2 || getDvarInt( "zombie_cheat" ) >= 4 )
  1295.     {
  1296.         return;
  1297. #/
  1298.     }
  1299. /#
  1300.     for ( ;; )
  1301.     {
  1302.         while ( !is_true( level.sloth_enable ) )
  1303.         {
  1304.             wait 0,2;
  1305.         }
  1306. #/
  1307.     }
  1308.     spawner = getent( "sloth_zombie_spawner", "script_noteworthy" );
  1309.     if ( !isDefined( spawner ) )
  1310.     {
  1311. /#
  1312.         assertmsg( "No sloth spawner in the map." );
  1313. #/
  1314.         return;
  1315.     }
  1316.     ai = spawn_zombie( spawner, "sloth" );
  1317.     if ( !isDefined( ai ) )
  1318.     {
  1319. /#
  1320.         assertmsg( "Sloth: failed spawn" );
  1321. #/
  1322.         return;
  1323.     }
  1324.     ai waittill( "zombie_init_done" );
  1325.     ai sloth_set_state( "jail_idle" );
  1326.     ai thread sloth_think();
  1327. /#
  1328. #/
  1329.     level._sloth_ai = ai;
  1330. }
  1331.  
  1332. sloth_init_update_funcs()
  1333. {
  1334.     self.update_funcs = [];
  1335.     self.update_funcs[ "jail_idle" ] = ::update_jail_idle;
  1336.     self.update_funcs[ "jail_cower" ] = ::update_jail_cower;
  1337.     self.update_funcs[ "jail_open" ] = ::update_jail_open;
  1338.     self.update_funcs[ "jail_run" ] = ::update_jail_run;
  1339.     self.update_funcs[ "jail_wait" ] = ::update_jail_wait;
  1340.     self.update_funcs[ "jail_close" ] = ::update_jail_close;
  1341.     self.update_funcs[ "player_idle" ] = ::update_player_idle;
  1342.     self.update_funcs[ "roam" ] = ::update_roam;
  1343.     self.update_funcs[ "follow" ] = ::update_follow;
  1344.     self.update_funcs[ "mansion" ] = ::update_mansion;
  1345.     self.update_funcs[ "berserk" ] = ::update_berserk;
  1346.     self.update_funcs[ "eat" ] = ::update_eat;
  1347.     self.update_funcs[ "crash" ] = ::update_crash;
  1348.     self.update_funcs[ "gunshop_run" ] = ::update_gunshop_run;
  1349.     self.update_funcs[ "gunshop_candy" ] = ::update_gunshop_candy;
  1350.     self.update_funcs[ "table_eat" ] = ::update_table_eat;
  1351.     self.update_funcs[ "headbang" ] = ::update_headbang;
  1352.     self.update_funcs[ "smell" ] = ::update_smell;
  1353.     self.update_funcs[ "context" ] = ::update_context;
  1354.     self.locomotion_func = ::update_locomotion;
  1355. }
  1356.  
  1357. sloth_think()
  1358. {
  1359.     self endon( "death" );
  1360.     while ( 1 )
  1361.     {
  1362.         self [[ self.update_funcs[ self.state ] ]]();
  1363.         wait 0,1;
  1364.     }
  1365. }
  1366.  
  1367. update_jail_idle()
  1368. {
  1369.     if ( is_true( self.open_jail ) )
  1370.     {
  1371.         level notify( "cell_open" );
  1372.         self.open_jail = 0;
  1373.     }
  1374.     if ( is_true( level.cell_open ) )
  1375.     {
  1376.         self stop_action();
  1377.         self sloth_set_state( "jail_cower" );
  1378.         maps/mp/zombies/_zm_unitrigger::register_unitrigger( self.gift_trigger, ::maps/mp/zombies/_zm_buildables::buildable_place_think );
  1379.     }
  1380. }
  1381.  
  1382. update_jail_cower()
  1383. {
  1384.     if ( is_true( self.got_booze ) && is_true( level.cell_open ) )
  1385.     {
  1386.         player = self get_player_to_follow();
  1387.         if ( isDefined( player ) )
  1388.         {
  1389.             self sloth_set_state( "follow", player );
  1390.             return;
  1391.         }
  1392.     }
  1393. }
  1394.  
  1395. update_jail_open()
  1396. {
  1397.     if ( self.needs_action )
  1398.     {
  1399.         self sloth_set_state( "jail_cower" );
  1400.     }
  1401. }
  1402.  
  1403. update_jail_run()
  1404. {
  1405.     if ( self.needs_action )
  1406.     {
  1407.         self sloth_set_state( "jail_wait" );
  1408.     }
  1409. }
  1410.  
  1411. update_jail_wait()
  1412. {
  1413.     players = get_players();
  1414.     _a1584 = players;
  1415.     _k1584 = getFirstArrayKey( _a1584 );
  1416.     while ( isDefined( _k1584 ) )
  1417.     {
  1418.         player = _a1584[ _k1584 ];
  1419.         if ( player maps/mp/zombies/_zm_zonemgr::entity_in_zone( "zone_underground_jail" ) )
  1420.         {
  1421.             if ( is_holding_candybooze( player ) )
  1422.             {
  1423.                 maps/mp/zombies/_zm_unitrigger::register_unitrigger( self.gift_trigger, ::maps/mp/zombies/_zm_buildables::buildable_place_think );
  1424.                 self sloth_set_state( "follow", player );
  1425.             }
  1426.             return;
  1427.         }
  1428.         _k1584 = getNextArrayKey( _a1584, _k1584 );
  1429.     }
  1430.     _a1597 = players;
  1431.     _k1597 = getFirstArrayKey( _a1597 );
  1432.     while ( isDefined( _k1597 ) )
  1433.     {
  1434.         player = _a1597[ _k1597 ];
  1435.         if ( is_player_valid( player ) )
  1436.         {
  1437.             dist = distancesquared( player.origin, level.jail_door.origin );
  1438.             if ( dist < 32400 )
  1439.             {
  1440.                 return;
  1441.             }
  1442.         }
  1443.         _k1597 = getNextArrayKey( _a1597, _k1597 );
  1444.     }
  1445.     if ( self.needs_action )
  1446.     {
  1447.         self sloth_set_state( "jail_close" );
  1448.     }
  1449. }
  1450.  
  1451. update_jail_close()
  1452. {
  1453.     if ( self.needs_action )
  1454.     {
  1455.         self sloth_set_state( "jail_idle" );
  1456.     }
  1457. }
  1458.  
  1459. update_player_idle()
  1460. {
  1461.     if ( self sloth_is_pain() )
  1462.     {
  1463.         return;
  1464.     }
  1465.     if ( self sloth_is_traversing() )
  1466.     {
  1467.         return;
  1468.     }
  1469.     if ( isDefined( self.follow_player ) )
  1470.     {
  1471.         player = self.follow_player;
  1472.         if ( is_true( player.is_in_ghost_zone ) || !sloth_on_same_side( player ) )
  1473.         {
  1474.             self sloth_set_state( "mansion" );
  1475.             return;
  1476.         }
  1477.         if ( is_holding_candybooze( self.follow_player ) )
  1478.         {
  1479.             player_dist = distancesquared( self.origin, self.follow_player.origin );
  1480.             if ( player_dist > 20736 )
  1481.             {
  1482.                 self sloth_set_state( "follow", self.follow_player );
  1483.                 return;
  1484.             }
  1485.         }
  1486.         else
  1487.         {
  1488.             self sloth_set_state( "roam" );
  1489.             return;
  1490.         }
  1491.         self orientmode( "face point", self.follow_player.origin );
  1492.         gimme_anim = undefined;
  1493.         if ( is_holding( self.follow_player, "booze" ) )
  1494.         {
  1495.             gimme_anim = "zm_gimme_booze";
  1496.         }
  1497.         else
  1498.         {
  1499.             if ( is_holding( self.follow_player, "candy" ) )
  1500.             {
  1501.                 gimme_anim = "zm_gimme_candy";
  1502.             }
  1503.         }
  1504.         if ( !is_true( self.damage_accumulating ) )
  1505.         {
  1506.             self action_player_idle( gimme_anim );
  1507.         }
  1508.     }
  1509.     else
  1510.     {
  1511.         self sloth_set_state( "roam" );
  1512.     }
  1513. }
  1514.  
  1515. update_locomotion()
  1516. {
  1517.     should_run = getTime() < self.leg_pain_time;
  1518.     if ( should_run )
  1519.     {
  1520.         self sloth_check_ragdolls();
  1521.         if ( self.zombie_move_speed == "run" )
  1522.         {
  1523.             if ( self.is_inside )
  1524.             {
  1525.                 self set_zombie_run_cycle( "run_hunched" );
  1526.                 self.locomotion = "run_hunched";
  1527.             }
  1528.         }
  1529.         else if ( self.zombie_move_speed == "run_hunched" )
  1530.         {
  1531.             if ( !self.is_inside )
  1532.             {
  1533.                 self set_zombie_run_cycle( "run" );
  1534.                 self.locomotion = "run";
  1535.             }
  1536.         }
  1537.         else if ( self.is_inside )
  1538.         {
  1539.             self set_zombie_run_cycle( "run_hunched" );
  1540.             self.locomotion = "run_hunched";
  1541.         }
  1542.         else
  1543.         {
  1544.             self set_zombie_run_cycle( "run" );
  1545.             self.locomotion = "run";
  1546.         }
  1547.     }
  1548.     else if ( self.zombie_move_speed == "run" || self.zombie_move_speed == "run_hunched" )
  1549.     {
  1550.         if ( self.is_inside )
  1551.         {
  1552.             self set_zombie_run_cycle( "walk_hunched" );
  1553.             self.locomotion = "walk_hunched";
  1554.         }
  1555.         else if ( self.near_zombies )
  1556.         {
  1557.             self set_zombie_run_cycle( "walk_scared" );
  1558.             self.locomotion = "walk_scared";
  1559.         }
  1560.         else
  1561.         {
  1562.             self set_zombie_run_cycle( "walk" );
  1563.             self.locomotion = "walk";
  1564.         }
  1565.     }
  1566.     else
  1567.     {
  1568.         if ( self.zombie_move_speed == "walk" )
  1569.         {
  1570.             if ( self.is_inside )
  1571.             {
  1572.                 self set_zombie_run_cycle( "walk_hunched" );
  1573.                 self.locomotion = "walk_hunched";
  1574.             }
  1575.             else
  1576.             {
  1577.                 if ( self.near_zombies )
  1578.                 {
  1579.                     self set_zombie_run_cycle( "walk_scared" );
  1580.                     self.locomotion = "walk_scared";
  1581.                 }
  1582.             }
  1583.             return;
  1584.         }
  1585.         else if ( self.zombie_move_speed == "walk_scared" )
  1586.         {
  1587.             if ( self.is_inside )
  1588.             {
  1589.                 self set_zombie_run_cycle( "walk_hunched" );
  1590.                 self.locomotion = "walk_hunched";
  1591.             }
  1592.             else
  1593.             {
  1594.                 if ( !self.near_zombies )
  1595.                 {
  1596.                     self set_zombie_run_cycle( "walk" );
  1597.                     self.locomotion = "walk";
  1598.                 }
  1599.             }
  1600.             return;
  1601.         }
  1602.         else
  1603.         {
  1604.             if ( self.zombie_move_speed == "walk_hunched" )
  1605.             {
  1606.                 if ( !self.is_inside )
  1607.                 {
  1608.                     self set_zombie_run_cycle( "walk" );
  1609.                     self.locomotion = "walk";
  1610.                 }
  1611.             }
  1612.         }
  1613.     }
  1614. }
  1615.  
  1616. update_roam()
  1617. {
  1618.     if ( self sloth_is_pain() )
  1619.     {
  1620.         return;
  1621.     }
  1622.     self.ignore_timebomb_slowdown = 0;
  1623.     if ( isDefined( self.locomotion_func ) )
  1624.     {
  1625.         self [[ self.locomotion_func ]]();
  1626.     }
  1627.     player = self get_player_to_follow();
  1628.     if ( isDefined( player ) )
  1629.     {
  1630.         self sloth_set_state( "follow", player );
  1631.         return;
  1632.     }
  1633.     if ( isDefined( self.mansion_goal ) )
  1634.     {
  1635.         self setgoalpos( self.mansion_goal.origin );
  1636.         dist = distancesquared( self.origin, self.mansion_goal.origin );
  1637.         if ( dist < 1024 )
  1638.         {
  1639.             self action_teleport_to_courtyard();
  1640.             self stop_action();
  1641.             return;
  1642.         }
  1643.     }
  1644.     if ( self should_smell() )
  1645.     {
  1646.         self sloth_set_state( "smell" );
  1647.         return;
  1648.     }
  1649.     if ( is_true( self.needs_action ) )
  1650.     {
  1651.         points = array_randomize( level.roam_points );
  1652.         self thread action_roam_point( points[ 0 ] );
  1653.     }
  1654. }
  1655.  
  1656. get_player_to_follow()
  1657. {
  1658.     players = get_players();
  1659.     i = 0;
  1660.     while ( i < players.size )
  1661.     {
  1662.         player = players[ i ];
  1663.         if ( is_holding_candybooze( player ) )
  1664.         {
  1665.             return player;
  1666.         }
  1667.         i++;
  1668.     }
  1669. }
  1670.  
  1671. should_headbang()
  1672. {
  1673.     if ( self sloth_is_traversing() )
  1674.     {
  1675.         return 0;
  1676.     }
  1677.     if ( isDefined( self.subwoofer ) )
  1678.     {
  1679.         if ( getTime() > self.headbang_time )
  1680.         {
  1681.             return 1;
  1682.         }
  1683.     }
  1684.     return 0;
  1685. }
  1686.  
  1687. should_smell()
  1688. {
  1689.     if ( self sloth_is_traversing() )
  1690.     {
  1691.         return 0;
  1692.     }
  1693.     if ( isDefined( self.stink ) )
  1694.     {
  1695.         if ( getTime() > self.smell_time )
  1696.         {
  1697.             return 1;
  1698.         }
  1699.     }
  1700.     return 0;
  1701. }
  1702.  
  1703. update_follow()
  1704. {
  1705.     if ( self sloth_is_pain() )
  1706.     {
  1707.         return;
  1708.     }
  1709.     if ( isDefined( self.locomotion_func ) )
  1710.     {
  1711.         self [[ self.locomotion_func ]]();
  1712.     }
  1713.     if ( self should_smell() )
  1714.     {
  1715.         self sloth_set_state( "smell" );
  1716.         return;
  1717.     }
  1718.     player = self.follow_player;
  1719.     if ( isDefined( player ) )
  1720.     {
  1721.         if ( is_holding_candybooze( player ) )
  1722.         {
  1723.             player_dist = distancesquared( self.origin, player.origin );
  1724.             if ( is_true( player.is_in_ghost_zone ) || !sloth_on_same_side( player ) )
  1725.             {
  1726.                 self sloth_set_state( "mansion" );
  1727.             }
  1728.             else
  1729.             {
  1730.                 if ( player_dist < 8100 )
  1731.                 {
  1732.                     self sloth_set_state( "player_idle" );
  1733.                 }
  1734.                 else
  1735.                 {
  1736.                     self action_player_follow( player );
  1737.                 }
  1738.             }
  1739.             return;
  1740.         }
  1741.         else
  1742.         {
  1743.             self sloth_set_state( "roam" );
  1744.         }
  1745.     }
  1746. }
  1747.  
  1748. sloth_on_same_side( player )
  1749. {
  1750.     if ( self sloth_behind_mansion() )
  1751.     {
  1752.         if ( player behind_mansion_zone() )
  1753.         {
  1754.             return 1;
  1755.         }
  1756.     }
  1757.     else
  1758.     {
  1759.         if ( !player behind_mansion_zone() )
  1760.         {
  1761.             return 1;
  1762.         }
  1763.     }
  1764.     return 0;
  1765. }
  1766.  
  1767. update_mansion()
  1768. {
  1769.     player = self.follow_player;
  1770.     if ( isDefined( player ) )
  1771.     {
  1772.         if ( is_holding_candybooze( player ) )
  1773.         {
  1774.             if ( is_true( player.is_in_ghost_zone ) )
  1775.             {
  1776.                 name = player.current_ghost_room_name;
  1777.                 if ( isDefined( name ) )
  1778.                 {
  1779.                     room = level.ghost_rooms[ name ];
  1780.                     if ( is_true( room.to_maze ) )
  1781.                     {
  1782.                         self.to_maze = 1;
  1783.                         self.from_maze = 0;
  1784.                     }
  1785.                     else
  1786.                     {
  1787.                         if ( is_true( room.from_maze ) )
  1788.                         {
  1789.                             self.to_maze = 0;
  1790.                             self.from_maze = 1;
  1791.                         }
  1792.                     }
  1793.                 }
  1794.             }
  1795.             else if ( self sloth_on_same_side( player ) )
  1796.             {
  1797.                 self sloth_set_state( "follow", player );
  1798.                 return;
  1799.             }
  1800.             if ( self sloth_behind_mansion() )
  1801.             {
  1802.                 self.to_maze = 0;
  1803.                 self.from_maze = 1;
  1804.             }
  1805.             else
  1806.             {
  1807.                 self.to_maze = 1;
  1808.                 self.from_maze = 0;
  1809.             }
  1810.             if ( isDefined( self.teleporting ) )
  1811.             {
  1812.                 if ( self.teleporting == "to_maze" )
  1813.                 {
  1814.                     if ( self sloth_behind_mansion() )
  1815.                     {
  1816.                         self.teleporting = undefined;
  1817.                     }
  1818.                 }
  1819.                 else
  1820.                 {
  1821.                     if ( self.teleporting == "to_courtyard" )
  1822.                     {
  1823.                         if ( !self sloth_behind_mansion() )
  1824.                         {
  1825.                             self.teleporting = undefined;
  1826.                         }
  1827.                     }
  1828.                 }
  1829.                 return;
  1830.             }
  1831.             if ( is_true( self.to_maze ) && !self sloth_behind_mansion() )
  1832.             {
  1833.                 self action_navigate_mansion( level.maze_depart, level.maze_arrive );
  1834.             }
  1835.             else
  1836.             {
  1837.                 if ( is_true( self.from_maze ) && self sloth_behind_mansion() )
  1838.                 {
  1839.                     self action_navigate_mansion( level.courtyard_depart, level.courtyard_arrive );
  1840.                 }
  1841.             }
  1842.             return;
  1843.         }
  1844.         else
  1845.         {
  1846.             self sloth_set_state( "roam" );
  1847.         }
  1848.     }
  1849. }
  1850.  
  1851. update_drink()
  1852. {
  1853.     if ( is_true( self.needs_action ) )
  1854.     {
  1855.         self sloth_set_state( "berserk" );
  1856.     }
  1857. }
  1858.  
  1859. sloth_check_ragdolls( ignore_zombie )
  1860. {
  1861.     non_ragdoll = 0;
  1862.     zombies = getaispeciesarray( level.zombie_team, "all" );
  1863.     i = 0;
  1864.     while ( i < zombies.size )
  1865.     {
  1866.         zombie = zombies[ i ];
  1867.         if ( is_true( zombie.is_sloth ) )
  1868.         {
  1869.             i++;
  1870.             continue;
  1871.         }
  1872.         else if ( isDefined( ignore_zombie ) && zombie == ignore_zombie )
  1873.         {
  1874.             i++;
  1875.             continue;
  1876.         }
  1877.         else
  1878.         {
  1879.             if ( isDefined( self.crawler ) && zombie == self.crawler )
  1880.             {
  1881.                 i++;
  1882.                 continue;
  1883.             }
  1884.             else
  1885.             {
  1886.                 if ( self is_facing( zombie ) )
  1887.                 {
  1888.                     dist = distancesquared( self.origin, zombie.origin );
  1889.                     if ( dist < 4096 )
  1890.                     {
  1891.                         if ( !self sloth_ragdoll_zombie( zombie ) )
  1892.                         {
  1893.                             if ( !is_true( self.no_gib ) && ( non_ragdoll % 3 ) == 0 )
  1894.                             {
  1895.                                 zombie.force_gib = 1;
  1896.                                 zombie.a.gib_ref = random( array( "guts", "right_arm", "left_arm", "head" ) );
  1897.                                 zombie thread maps/mp/animscripts/zm_death::do_gib();
  1898.                             }
  1899.                             non_ragdoll++;
  1900.                             zombie dodamage( zombie.health * 10, zombie.origin );
  1901.                             zombie playsound( "zmb_ai_sloth_attack_impact" );
  1902.                             zombie.noragdoll = 1;
  1903.                             zombie.nodeathragdoll = 1;
  1904.                             level.zombie_total++;
  1905.                         }
  1906.                         if ( isDefined( self.target_zombie ) && self.target_zombie == zombie )
  1907.                         {
  1908.                             self.target_zombie = undefined;
  1909.                         }
  1910.                     }
  1911.                 }
  1912.             }
  1913.         }
  1914.         i++;
  1915.     }
  1916. }
  1917.  
  1918. sloth_ragdoll_zombie( zombie )
  1919. {
  1920.     if ( !isDefined( self.ragdolls ) )
  1921.     {
  1922.         self.ragdolls = 0;
  1923.     }
  1924.     if ( self.ragdolls < 4 )
  1925.     {
  1926.         self.ragdolls++;
  1927.         zombie dodamage( zombie.health * 10, zombie.origin );
  1928.         zombie playsound( "zmb_ai_sloth_attack_impact" );
  1929.         zombie startragdoll();
  1930.         zombie setclientfield( "sloth_ragdoll_zombie", 1 );
  1931.         level.zombie_total++;
  1932.         self thread sloth_ragdoll_wait();
  1933.         return 1;
  1934.     }
  1935.     return 0;
  1936. }
  1937.  
  1938. sloth_ragdoll_wait()
  1939. {
  1940.     self endon( "death" );
  1941.     wait 1;
  1942.     if ( self.ragdolls > 0 )
  1943.     {
  1944.         self.ragdolls--;
  1945.  
  1946.     }
  1947. }
  1948.  
  1949. sloth_kill_zombie( zombie )
  1950. {
  1951.     if ( !self sloth_ragdoll_zombie( zombie ) )
  1952.     {
  1953.         if ( !is_true( self.no_gib ) )
  1954.         {
  1955.             zombie.force_gib = 1;
  1956.             zombie.a.gib_ref = random( array( "guts", "right_arm", "left_arm", "head" ) );
  1957.             zombie thread maps/mp/animscripts/zm_death::do_gib();
  1958.         }
  1959.         zombie dodamage( zombie.health * 10, zombie.origin );
  1960.         zombie playsound( "zmb_ai_sloth_attack_impact" );
  1961.     }
  1962. }
  1963.  
  1964. update_berserk()
  1965. {
  1966.     if ( !is_true( self.run_berserk ) )
  1967.     {
  1968.         return;
  1969.     }
  1970.     self sloth_grab_powerup();
  1971.     self sloth_check_ragdolls();
  1972.     self.ignore_timebomb_slowdown = 1;
  1973.     start = self.origin + vectorScale( ( 0, 1, 0 ), 39 );
  1974.     facing = anglesToForward( self.angles );
  1975.     end = start + ( facing * 48 );
  1976.     crash = 0;
  1977.     trace = physicstrace( start, end, vectorScale( ( 0, 1, 0 ), 15 ), vectorScale( ( 0, 1, 0 ), 15 ), self );
  1978. /#
  1979.     if ( getDvarInt( #"B6252E7C" ) == 2 )
  1980.     {
  1981.         line( start, end, ( 0, 1, 0 ), 1, 0, 100 );
  1982. #/
  1983.     }
  1984.     if ( isDefined( trace[ "entity" ] ) )
  1985.     {
  1986.         hit_ent = trace[ "entity" ];
  1987.         if ( is_true( hit_ent.is_zombie ) )
  1988.         {
  1989.             return;
  1990.         }
  1991.         else if ( isplayer( hit_ent ) )
  1992.         {
  1993.             if ( !is_true( self.slowing ) )
  1994.             {
  1995.                 hit_ent dodamage( hit_ent.health, hit_ent.origin );
  1996. /#
  1997.                 sloth_print( "hit player" );
  1998. #/
  1999.             }
  2000.             return;
  2001.         }
  2002.         else if ( is_barricade_ent( hit_ent ) )
  2003.         {
  2004. /#
  2005.             if ( isDefined( hit_ent.targetname ) )
  2006.             {
  2007.                 sloth_print( "hit barricade ent " + hit_ent.targetname );
  2008. #/
  2009.             }
  2010.             return;
  2011.         }
  2012.         else
  2013.         {
  2014. /#
  2015.             if ( isDefined( hit_ent.targetname ) )
  2016.             {
  2017.                 sloth_print( "hit " + hit_ent.targetname );
  2018. #/
  2019.             }
  2020.             if ( isDefined( hit_ent.targetname ) && hit_ent.targetname == "sloth_fountain_clip" )
  2021.             {
  2022.                 fountain = getent( "courtyard_fountain", "script_noteworthy" );
  2023.                 if ( isDefined( fountain ) )
  2024.                 {
  2025.                     fountain notify( "trigger" );
  2026.                     return;
  2027.                 }
  2028.             }
  2029.             crash = 1;
  2030.         }
  2031.     }
  2032.     if ( isDefined( trace[ "fraction" ] ) && trace[ "fraction" ] < 1 )
  2033.     {
  2034.         crash = 1;
  2035.     }
  2036.     if ( getTime() > ( self.berserk_time + 500 ) )
  2037.     {
  2038.         dist = distancesquared( self.origin, self.berserk_org );
  2039.         if ( dist < 900 )
  2040.         {
  2041. /#
  2042.             sloth_print( "BERSERK FAILSAFE!!!" );
  2043. #/
  2044.             crash = 1;
  2045.         }
  2046.         self.berserk_org = self.origin;
  2047.         self.berserk_time = getTime();
  2048.     }
  2049.     if ( crash && self.state != "crash" )
  2050.     {
  2051.         self setclientfield( "sloth_berserk", 0 );
  2052.         self sloth_set_state( "crash", 0 );
  2053.     }
  2054. }
  2055.  
  2056. update_eat()
  2057. {
  2058.     if ( is_true( self.needs_action ) )
  2059.     {
  2060.         self setclientfield( "sloth_eating", 0 );
  2061.         if ( isDefined( self.candy_model ) )
  2062.         {
  2063.             self.candy_model ghost();
  2064.         }
  2065.         context = self check_contextual_actions();
  2066.         if ( isDefined( context ) )
  2067.         {
  2068.             if ( isDefined( self.candy_player ) )
  2069.             {
  2070.                 self.candy_player maps/mp/zombies/_zm_stats::increment_client_stat( "buried_sloth_candy_" + context.name, 0 );
  2071.                 self.candy_player maps/mp/zombies/_zm_stats::increment_player_stat( "buried_sloth_candy_" + context.name );
  2072.                 self.candy_player thread sloth_feed_vo();
  2073.             }
  2074.             self sloth_set_state( "context", context );
  2075.             return;
  2076.         }
  2077.         self sloth_set_state( "roam" );
  2078.     }
  2079. }
  2080.  
  2081. update_crash()
  2082. {
  2083.     if ( is_true( self.needs_action ) )
  2084.     {
  2085.         self.reset_asd = undefined;
  2086.         maps/mp/zombies/_zm_unitrigger::register_unitrigger( self.gift_trigger, ::maps/mp/zombies/_zm_buildables::buildable_place_think );
  2087.         self notify( "stop_berserk" );
  2088.         self sloth_set_state( "roam" );
  2089.     }
  2090. }
  2091.  
  2092. update_gunshop_run()
  2093. {
  2094.     if ( is_true( self.needs_action ) )
  2095.     {
  2096.         self sloth_set_state( "gunshop_candy" );
  2097.     }
  2098. }
  2099.  
  2100. update_gunshop_candy()
  2101. {
  2102. }
  2103.  
  2104. update_table_eat()
  2105. {
  2106.     if ( is_true( self.needs_action ) )
  2107.     {
  2108.         self sloth_set_state( "roam" );
  2109.     }
  2110. }
  2111.  
  2112. update_headbang()
  2113. {
  2114.     if ( getTime() > self.headbang_time )
  2115.     {
  2116.         self.headbang_time = getTime() + 30000;
  2117.         self stop_action();
  2118.         self sloth_set_state( "roam" );
  2119.     }
  2120. }
  2121.  
  2122. update_smell()
  2123. {
  2124.     if ( is_true( self.needs_action ) )
  2125.     {
  2126.         self.smell_time = getTime() + 30000;
  2127.         self sloth_set_state( "roam" );
  2128.     }
  2129. }
  2130.  
  2131. update_context()
  2132. {
  2133.     self [[ self.context.update ]]();
  2134. }
  2135.  
  2136. sloth_init_start_funcs()
  2137. {
  2138.     self.start_funcs = [];
  2139.     self.start_funcs[ "jail_idle" ] = ::start_jail_idle;
  2140.     self.start_funcs[ "jail_cower" ] = ::start_jail_cower;
  2141.     self.start_funcs[ "jail_open" ] = ::start_jail_open;
  2142.     self.start_funcs[ "jail_run" ] = ::start_jail_run;
  2143.     self.start_funcs[ "jail_wait" ] = ::start_jail_wait;
  2144.     self.start_funcs[ "jail_close" ] = ::start_jail_close;
  2145.     self.start_funcs[ "player_idle" ] = ::start_player_idle;
  2146.     self.start_funcs[ "roam" ] = ::start_roam;
  2147.     self.start_funcs[ "follow" ] = ::start_follow;
  2148.     self.start_funcs[ "mansion" ] = ::start_mansion;
  2149.     self.start_funcs[ "berserk" ] = ::start_berserk;
  2150.     self.start_funcs[ "eat" ] = ::start_eat;
  2151.     self.start_funcs[ "crash" ] = ::start_crash;
  2152.     self.start_funcs[ "gunshop_run" ] = ::start_gunshop_run;
  2153.     self.start_funcs[ "gunshop_candy" ] = ::start_gunshop_candy;
  2154.     self.start_funcs[ "table_eat" ] = ::start_table_eat;
  2155.     self.start_funcs[ "headbang" ] = ::start_headbang;
  2156.     self.start_funcs[ "smell" ] = ::start_smell;
  2157.     self.start_funcs[ "context" ] = ::start_context;
  2158. }
  2159.  
  2160. sloth_set_state( state, param2 )
  2161. {
  2162.     if ( isDefined( self.start_funcs[ state ] ) )
  2163.     {
  2164.         result = 0;
  2165.         if ( isDefined( param2 ) )
  2166.         {
  2167.             result = self [[ self.start_funcs[ state ] ]]( param2 );
  2168.         }
  2169.         else
  2170.         {
  2171.             result = self [[ self.start_funcs[ state ] ]]();
  2172.         }
  2173.         if ( result == 1 )
  2174.         {
  2175.             self.state = state;
  2176. /#
  2177.             sloth_print( "change state to " + self.state );
  2178. #/
  2179.         }
  2180.     }
  2181. }
  2182.  
  2183. start_jail_idle()
  2184. {
  2185.     self thread action_jail_idle();
  2186.     self thread sndchangebreathingstate( "breathe" );
  2187.     return 1;
  2188. }
  2189.  
  2190. start_jail_cower()
  2191. {
  2192.     self thread action_jail_cower( self.got_booze );
  2193.     self thread sndchangebreathingstate( "scared" );
  2194.     return 1;
  2195. }
  2196.  
  2197. start_jail_close()
  2198. {
  2199.     self thread action_jail_close();
  2200.     self thread sndchangebreathingstate( "breathe" );
  2201.     return 1;
  2202. }
  2203.  
  2204. start_jail_open()
  2205. {
  2206.     self thread action_jail_open();
  2207.     return 1;
  2208. }
  2209.  
  2210. is_jail_state()
  2211. {
  2212.     states = [];
  2213.     states[ states.size ] = "jail_idle";
  2214.     states[ states.size ] = "jail_cower";
  2215.     states[ states.size ] = "jail_open";
  2216.     states[ states.size ] = "jail_run";
  2217.     states[ states.size ] = "jail_wait";
  2218.     states[ states.size ] = "jail_close";
  2219.     _a2505 = states;
  2220.     _k2505 = getFirstArrayKey( _a2505 );
  2221.     while ( isDefined( _k2505 ) )
  2222.     {
  2223.         state = _a2505[ _k2505 ];
  2224.         if ( self.state == state )
  2225.         {
  2226.             return 1;
  2227.         }
  2228.         _k2505 = getNextArrayKey( _a2505, _k2505 );
  2229.     }
  2230.     return 0;
  2231. }
  2232.  
  2233. start_jail_run( do_pain )
  2234. {
  2235.     if ( self is_jail_state() )
  2236.     {
  2237.         return 0;
  2238.     }
  2239.     if ( self.state == "berserk" || self.state == "crash" )
  2240.     {
  2241.         return 0;
  2242.     }
  2243.     if ( self sloth_is_traversing() )
  2244.     {
  2245.         return 0;
  2246.     }
  2247.     if ( self.state == "gunshop_candy" || self.state == "table_eat" )
  2248.     {
  2249.         if ( isDefined( self.bench ) )
  2250.         {
  2251.             if ( isDefined( level.weapon_bench_reset ) )
  2252.             {
  2253.                 self.bench [[ level.weapon_bench_reset ]]();
  2254.             }
  2255.         }
  2256.     }
  2257.     self stop_action();
  2258.     self thread sndchangebreathingstate( "scared" );
  2259.     self thread action_jail_run( self.jail_start.origin, do_pain );
  2260.     if ( self.state == "context" )
  2261.     {
  2262.         if ( isDefined( self.context.interrupt ) )
  2263.         {
  2264.             self [[ self.context.interrupt ]]();
  2265.         }
  2266.     }
  2267.     self sloth_init_roam_point();
  2268.     thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.gift_trigger );
  2269.     return 1;
  2270. }
  2271.  
  2272. start_jail_wait()
  2273. {
  2274.     self stopanimscripted();
  2275.     self action_jail_wait();
  2276.     self thread sndchangebreathingstate( "scared" );
  2277.     return 1;
  2278. }
  2279.  
  2280. start_player_idle( lock )
  2281. {
  2282.     if ( self sloth_is_traversing() )
  2283.     {
  2284.         return 0;
  2285.     }
  2286.     if ( self.state == "jail_cower" )
  2287.     {
  2288.         return 0;
  2289.     }
  2290.     if ( is_true( lock ) )
  2291.     {
  2292.         self orientmode( "face default" );
  2293.         self.anchor.origin = self.origin;
  2294.         self.anchor.angles = self.angles;
  2295.         self linkto( self.anchor );
  2296.     }
  2297.     gimme_anim = undefined;
  2298.     if ( is_holding( self.follow_player, "booze" ) )
  2299.     {
  2300.         gimme_anim = "zm_gimme_booze";
  2301.     }
  2302.     else
  2303.     {
  2304.         if ( is_holding( self.follow_player, "candy" ) )
  2305.         {
  2306.             gimme_anim = "zm_gimme_candy";
  2307.         }
  2308.     }
  2309.     if ( !is_true( self.damage_accumulating ) )
  2310.     {
  2311.         self action_player_idle( gimme_anim );
  2312.     }
  2313.     self thread sndchangebreathingstate( "happy" );
  2314.     return 1;
  2315. }
  2316.  
  2317. check_behind_mansion()
  2318. {
  2319.     if ( self sloth_behind_mansion() )
  2320.     {
  2321. /#
  2322.         sloth_print( "get back to mansion first" );
  2323. #/
  2324.         near = ( 3652, -500, 20 );
  2325.         _a2627 = level.maze_to_mansion;
  2326.         _k2627 = getFirstArrayKey( _a2627 );
  2327.         while ( isDefined( _k2627 ) )
  2328.         {
  2329.             point = _a2627[ _k2627 ];
  2330.             dist = distance( point.origin, near );
  2331.             if ( dist < 10 )
  2332.             {
  2333.                 self.mansion_goal = point;
  2334.             }
  2335.             _k2627 = getNextArrayKey( _a2627, _k2627 );
  2336.         }
  2337.     }
  2338.     else self.mansion_goal = undefined;
  2339. }
  2340.  
  2341. start_roam()
  2342. {
  2343.     self stop_action();
  2344.     self thread sndchangebreathingstate( "breathe", "happy" );
  2345.     self maps/mp/animscripts/zm_run::needsupdate();
  2346.     self.follow_player = undefined;
  2347.     self.candy_player = undefined;
  2348.     self check_behind_mansion();
  2349.     return 1;
  2350. }
  2351.  
  2352. start_follow( player )
  2353. {
  2354.     self stop_action();
  2355.     self thread sndchangebreathingstate( "happy" );
  2356.     self set_zombie_run_cycle( "walk" );
  2357.     self.locomotion = "walk";
  2358.     self.follow_player = player;
  2359.     self.current_roam = undefined;
  2360.     return 1;
  2361. }
  2362.  
  2363. start_mansion()
  2364. {
  2365.     self stop_action();
  2366.     self thread sndchangebreathingstate( "scared" );
  2367.     self maps/mp/animscripts/zm_run::needsupdate();
  2368.     self.can_follow = 0;
  2369.     return 1;
  2370. }
  2371.  
  2372. start_berserk( player )
  2373. {
  2374.     self thread remove_gift_trigger( 0,1 );
  2375.     if ( !is_true( self.got_booze ) )
  2376.     {
  2377.         self.got_booze = 1;
  2378.     }
  2379.     self.booze_player = player;
  2380.     self.berserk_start_org = self.origin;
  2381.     self.berserk_org = self.origin;
  2382.     self.booze_player maps/mp/zombies/_zm_stats::increment_client_stat( "buried_sloth_booze_given", 0 );
  2383.     self.booze_player maps/mp/zombies/_zm_stats::increment_player_stat( "buried_sloth_booze_given" );
  2384.     self setclientfield( "sloth_berserk", 1 );
  2385.     player thread sloth_feed_vo();
  2386.     closest = self get_facing_barricade();
  2387.     if ( !isDefined( closest ) )
  2388.     {
  2389. /#
  2390.         sloth_print( "failed to get barricade assist, try player" );
  2391. #/
  2392.         closest = player get_facing_barricade( 1 );
  2393.         if ( isDefined( closest ) )
  2394.         {
  2395.             self.aim_barricade = closest;
  2396.         }
  2397.     }
  2398.     self.run_berserk = 0;
  2399.     self action_berserk( self.follow_player );
  2400.     self thread sndchangebreathingstate( "angry" );
  2401.     return 1;
  2402. }
  2403.  
  2404. sloth_feed_vo()
  2405. {
  2406.     self endon( "death" );
  2407.     self endon( "disconnect" );
  2408.     if ( isDefined( level.sloth_has_been_given_booze ) && !level.sloth_has_been_given_booze )
  2409.     {
  2410.         level.sloth_has_been_given_booze = 1;
  2411.         self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "first_bersek" );
  2412.     }
  2413.     else
  2414.     {
  2415.         self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "sloth_generic_feed" );
  2416.     }
  2417. }
  2418.  
  2419. sloth_debug_barricade()
  2420. {
  2421. /#
  2422.     while ( 1 )
  2423.     {
  2424.         player = gethostplayer();
  2425.         while ( !isDefined( player ) )
  2426.         {
  2427.             wait 1;
  2428.         }
  2429.         while ( getDvarInt( #"B6252E7C" ) != 3 )
  2430.         {
  2431.             wait 1;
  2432.         }
  2433.         closest = player get_facing_barricade( 1 );
  2434.         wait 1;
  2435. #/
  2436.     }
  2437. }
  2438.  
  2439. get_facing_barricade( ignore_segment_dist )
  2440. {
  2441.     max_dist = 144000000;
  2442.     closest = undefined;
  2443.     closest_dot = 0;
  2444.     closest_dot_position = 0;
  2445.     closest_dot_facing = 0;
  2446.     closest_segment_point = undefined;
  2447.     if ( isplayer( self ) )
  2448.     {
  2449.         angles = self getplayerangles();
  2450.         vec_forward = vectornormalize( anglesToForward( flat_angle( angles ) ) );
  2451.     }
  2452.     else
  2453.     {
  2454.         angles = self.angles;
  2455.         vec_forward = vectornormalize( anglesToForward( flat_angle( angles ) ) ) * -1;
  2456.     }
  2457.     triggers = getentarray( "sloth_barricade", "targetname" );
  2458.     i = 0;
  2459.     while ( i < triggers.size )
  2460.     {
  2461.         barricade = triggers[ i ];
  2462.         if ( isDefined( barricade ) )
  2463.         {
  2464.             if ( isDefined( barricade.script_noteworthy ) && barricade.script_noteworthy == "courtyard_fountain" )
  2465.             {
  2466.                 i++;
  2467.                 continue;
  2468.             }
  2469.             else
  2470.             {
  2471.                 ground_pos = groundpos( barricade.origin );
  2472.                 start = ( self.origin[ 0 ], self.origin[ 1 ], ground_pos[ 2 ] );
  2473.                 barricade_dist = distance( ground_pos, start );
  2474.                 if ( barricade_dist > 900 )
  2475.                 {
  2476.                     i++;
  2477.                     continue;
  2478.                 }
  2479.                 else segment_length = barricade_dist * 2;
  2480.                 end = start + ( vec_forward * segment_length );
  2481.                 segment_point = pointonsegmentnearesttopoint( start, end, ground_pos );
  2482.                 vec_barricade = vectornormalize( anglesToForward( barricade.angles ) ) * -1;
  2483.                 dot_barricade = vectordot( vec_forward, vec_barricade );
  2484.                 if ( dot_barricade < 0,707 )
  2485.                 {
  2486.                     i++;
  2487.                     continue;
  2488.                 }
  2489.                 else vec_position = vectornormalize( ground_pos - start );
  2490.                 dot_position = vectordot( vec_position, vec_barricade );
  2491.                 if ( dot_position < 0,707 )
  2492.                 {
  2493.                     i++;
  2494.                     continue;
  2495.                 }
  2496.                 else dot_facing_pos = vectordot( vec_position, vec_forward );
  2497.                 dist = distancesquared( ground_pos, segment_point );
  2498.                 if ( !is_true( ignore_segment_dist ) )
  2499.                 {
  2500.                     if ( dist > 10000 )
  2501.                     {
  2502.                         i++;
  2503.                         continue;
  2504.                     }
  2505.                 }
  2506.                 else
  2507.                 {
  2508.                     if ( dist < max_dist )
  2509.                     {
  2510.                         max_dist = dist;
  2511.                         closest = barricade;
  2512.                         closest_segment_point = segment_point;
  2513.                         closest_dot = dot_barricade;
  2514.                         closest_dot_position = dot_position;
  2515.                         closest_dot_facing = dot_facing_pos;
  2516.                     }
  2517.                 }
  2518.             }
  2519.         }
  2520.         i++;
  2521.     }
  2522.     if ( isDefined( closest ) )
  2523.     {
  2524.         ground_pos = groundpos( closest.origin );
  2525. /#
  2526.         if ( getDvarInt( #"B6252E7C" ) == 3 )
  2527.         {
  2528.             line( closest_segment_point, ground_pos, ( 0, 1, 0 ), 1, 0, 60 );
  2529. #/
  2530.         }
  2531.         dist = distancesquared( closest_segment_point, ground_pos );
  2532.         self.aim_barricade = closest;
  2533.         barricade_dist = distance( self.origin, ground_pos );
  2534. /#
  2535.         if ( getDvarInt( #"B6252E7C" ) == 3 )
  2536.         {
  2537.             line( self.origin, ground_pos, ( 0, 1, 0 ), 1, 0, 60 );
  2538. #/
  2539.         }
  2540.     }
  2541.     return closest;
  2542. }
  2543.  
  2544. barricade_assist()
  2545. {
  2546.     max_dist = 144000000;
  2547.     closest = undefined;
  2548.     closest_dot = 0;
  2549.     closest_segment_point = undefined;
  2550.     vec_forward = vectornormalize( anglesToForward( self.angles ) );
  2551.     vec_backward = vec_forward * -1;
  2552.     triggers = getentarray( "sloth_barricade", "targetname" );
  2553.     i = 0;
  2554.     while ( i < triggers.size )
  2555.     {
  2556.         barricade = triggers[ i ];
  2557.         if ( isDefined( barricade ) )
  2558.         {
  2559.             ground_pos = groundpos( barricade.origin );
  2560.             barricade_dist = distance( ground_pos, self.origin );
  2561.             segment_length = barricade_dist * 2;
  2562.             sloth_start = self.origin;
  2563.             sloth_end = self.origin + ( vec_backward * segment_length );
  2564.             segment_point = pointonsegmentnearesttopoint( sloth_start, sloth_end, ground_pos );
  2565.             dist = distancesquared( ground_pos, segment_point );
  2566.             if ( dist < max_dist )
  2567.             {
  2568.                 max_dist = dist;
  2569.                 closest = barricade;
  2570.                 closest_segment_point = segment_point;
  2571.             }
  2572.         }
  2573.         i++;
  2574.     }
  2575.     if ( isDefined( closest ) )
  2576.     {
  2577.         ground_pos = groundpos( closest.origin );
  2578. /#
  2579.         if ( getDvarInt( #"B6252E7C" ) == 2 )
  2580.         {
  2581.             line( closest_segment_point, ground_pos, ( 0, 1, 0 ), 1, 0, 500 );
  2582. #/
  2583.         }
  2584.         dist = distancesquared( closest_segment_point, ground_pos );
  2585.         if ( dist < 10000 )
  2586.         {
  2587.             self.aim_barricade = closest;
  2588.         }
  2589. /#
  2590.         sloth_print( "dist: " + sqrt( dist ) + " max_dist: " + sqrt( max_dist ) );
  2591. #/
  2592. /#
  2593.         if ( getDvarInt( #"B6252E7C" ) == 2 )
  2594.         {
  2595.             line( self.origin, ground_pos, ( 0, 1, 0 ), 1, 0, 500 );
  2596. #/
  2597.         }
  2598.     }
  2599. }
  2600.  
  2601. start_eat( player )
  2602. {
  2603.     self thread remove_gift_trigger( 0,1 );
  2604.     self.candy_player = player;
  2605.     self.candy_player maps/mp/zombies/_zm_stats::increment_client_stat( "buried_sloth_candy_given", 0 );
  2606.     self.candy_player maps/mp/zombies/_zm_stats::increment_player_stat( "buried_sloth_candy_given" );
  2607.     self thread watch_player_zombies();
  2608.     twr_origin = self gettagorigin( "tag_weapon_right" );
  2609.     twr_angles = self gettagangles( "tag_weapon_right" );
  2610.     if ( !isDefined( self.candy_model ) )
  2611.     {
  2612.         self.candy_model = spawn( "script_model", twr_origin );
  2613.         self.candy_model.angles = twr_angles;
  2614.         self.candy_model setmodel( level.candy_model );
  2615.         self.candy_model linkto( self, "tag_weapon_right" );
  2616.     }
  2617.     else
  2618.     {
  2619.         self.candy_model show();
  2620.     }
  2621.     self setclientfield( "sloth_eating", 1 );
  2622.     self thread action_animscripted( "zm_eat_candy", "eat_candy_anim" );
  2623.     return 1;
  2624. }
  2625.  
  2626. start_crash( barricade )
  2627. {
  2628.     if ( self.state == "crash" )
  2629.     {
  2630.         return 0;
  2631.     }
  2632.     if ( barricade )
  2633.     {
  2634.         self.reset_asd = "zm_barricade";
  2635.         self thread action_anim( "zm_barricade", "crash_anim" );
  2636.     }
  2637.     else
  2638.     {
  2639.         self.reset_asd = "zm_crash";
  2640.         self thread action_anim( "zm_crash", "crash_anim" );
  2641.     }
  2642.     self thread sndchangebreathingstate( "happy" );
  2643. /#
  2644.     if ( isDefined( self.debug_berserk ) )
  2645.     {
  2646.         elapsed = ( getTime() - self.debug_berserk ) / 1000;
  2647.         dist = distance( self.origin, self.debug_berserk_org );
  2648.         sloth_print( ( "berserk dist = " + dist + " elapsed = " + elapsed + " rate = " ) + ( dist / elapsed ) );
  2649. #/
  2650.     }
  2651.     return 1;
  2652. }
  2653.  
  2654. start_gunshop_run()
  2655. {
  2656.     if ( self.state == "follow" || self.state == "roam" )
  2657.     {
  2658.         self thread action_gunshop_run();
  2659.         self thread sndchangebreathingstate( "breathe", "happy" );
  2660.         return 1;
  2661.     }
  2662.     return 0;
  2663. }
  2664.  
  2665. start_gunshop_candy()
  2666. {
  2667.     self thread wait_for_timeout();
  2668.     self thread wait_for_candy();
  2669.     self thread action_gunshop_candy();
  2670.     self thread sndchangebreathingstate( "happy" );
  2671.     return 1;
  2672. }
  2673.  
  2674. start_table_eat()
  2675. {
  2676.     self stop_action();
  2677.     self thread action_table_eat();
  2678.     return 1;
  2679. }
  2680.  
  2681. start_headbang()
  2682. {
  2683.     self stop_action();
  2684.     self.headbang_time = getTime() + 10000;
  2685.     self thread action_headbang();
  2686.     self thread sndchangebreathingstate( "happy" );
  2687.     return 1;
  2688. }
  2689.  
  2690. start_smell()
  2691. {
  2692.     self stop_action();
  2693.     self thread action_smell();
  2694.     self thread sndchangebreathingstate( "breathe", "happy" );
  2695.     return 1;
  2696. }
  2697.  
  2698. start_context( context )
  2699. {
  2700.     self stop_action();
  2701.     self thread sndchangebreathingstate( "happy", "angry" );
  2702.     self.ignore_common_run = 0;
  2703.     self.context = context;
  2704.     self [[ context.start ]]();
  2705.     return 1;
  2706. }
  2707.  
  2708. remove_gift_trigger( delay )
  2709. {
  2710.     if ( isDefined( delay ) )
  2711.     {
  2712.         wait delay;
  2713.     }
  2714.     while ( 1 )
  2715.     {
  2716.         if ( isDefined( self.gift_trigger ) )
  2717.         {
  2718.             thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( self.gift_trigger );
  2719.             return;
  2720.         }
  2721.         wait 0,1;
  2722.     }
  2723. }
  2724.  
  2725. action_jail_idle()
  2726. {
  2727.     self endon( "stop_action" );
  2728.     self.needs_action = 0;
  2729.     self setgoalpos( self.origin );
  2730.     while ( 1 )
  2731.     {
  2732.         self animscripted( self.jail_start.origin, self.jail_start.angles, "zm_jail_idle" );
  2733.         maps/mp/animscripts/zm_shared::donotetracks( "jail_idle_anim" );
  2734.     }
  2735. }
  2736.  
  2737. action_jail_cower( jumpback )
  2738. {
  2739.     cower_trans = "zm_jail_2_cower";
  2740.     cower_idle = "zm_cower_idle";
  2741.     if ( is_true( jumpback ) )
  2742.     {
  2743.         cower_trans = "zm_jail_2_cower_jumpback";
  2744.         cower_idle = "zm_cower_jumpback_idle";
  2745.     }
  2746.     self.needs_action = 0;
  2747.     self animscripted( self.jail_start.origin, self.jail_start.angles, cower_trans );
  2748.     maps/mp/animscripts/zm_shared::donotetracks( "jail_2_cower_anim" );
  2749.     self.anchor.origin = self.origin;
  2750.     self.anchor.angles = self.angles;
  2751.     self linkto( self.anchor );
  2752.     self setgoalpos( self.origin );
  2753.     self setanimstatefromasd( cower_idle );
  2754. }
  2755.  
  2756. action_jail_open()
  2757. {
  2758.     self.needs_action = 0;
  2759.     self animscripted( self.jail_start.origin, self.jail_start.angles, "zm_jail_open" );
  2760.     maps/mp/animscripts/zm_shared::donotetracks( "jail_open_anim" );
  2761.     self.needs_action = 1;
  2762. }
  2763.  
  2764. action_jail_close()
  2765. {
  2766.     self.needs_action = 0;
  2767.     if ( isDefined( level.jail_close_door ) )
  2768.     {
  2769.         level thread [[ level.jail_close_door ]]();
  2770.     }
  2771.     self animscripted( self.jail_start.origin, self.jail_start.angles, "zm_cower_2_close" );
  2772.     self blend_notetracks( "cower_2_close_anim" );
  2773.     level notify( "cell_close" );
  2774.     self.needs_action = 1;
  2775. }
  2776.  
  2777. action_jail_wait()
  2778. {
  2779.     self.needs_action = 0;
  2780.     self setgoalpos( self.origin );
  2781.     self.anchor.origin = self.origin;
  2782.     self.anchor.angles = self.angles;
  2783.     self linkto( self.anchor );
  2784.     self setanimstatefromasd( "zm_cower_jumpback_idle" );
  2785.     self.needs_action = 1;
  2786. }
  2787.  
  2788. action_teleport_to_courtyard()
  2789. {
  2790. /#
  2791.     sloth_print( "teleport to courtyard" );
  2792. #/
  2793.     points = array_randomize( level.courtyard_arrive );
  2794.     self forceteleport( points[ 0 ].origin );
  2795.     self.mansion_goal = undefined;
  2796. }
  2797.  
  2798. finish_pain()
  2799. {
  2800.     self endon( "death" );
  2801.     self endon( "pain_done" );
  2802.     while ( 1 )
  2803.     {
  2804.         anim_state = self getanimstatefromasd();
  2805.         if ( anim_state != "zm_pain" && anim_state != "zm_pain_no_restart" )
  2806.         {
  2807. /#
  2808.             sloth_print( "pain was interrupted" );
  2809. #/
  2810.             self setanimstatefromasd( "zm_pain_no_restart" );
  2811.         }
  2812.         wait 0,1;
  2813.     }
  2814. }
  2815.  
  2816. action_jail_run( pos, do_pain )
  2817. {
  2818.     self.needs_action = 0;
  2819.     if ( isDefined( self.candy_model ) )
  2820.     {
  2821.         self.candy_model ghost();
  2822.     }
  2823.     if ( isDefined( self.booze_model ) )
  2824.     {
  2825.         self.booze_model ghost();
  2826.     }
  2827.     if ( is_true( do_pain ) )
  2828.     {
  2829.         if ( !self sloth_is_traversing() && !is_true( self.is_pain ) )
  2830.         {
  2831.             self.is_pain = 1;
  2832.             self setanimstatefromasd( "zm_pain" );
  2833.             self.reset_asd = "zm_pain";
  2834.             self thread finish_pain();
  2835.             maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" );
  2836.             self notify( "pain_done" );
  2837.             self.is_pain = 0;
  2838.         }
  2839.     }
  2840.     while ( 1 )
  2841.     {
  2842.         if ( !self sloth_is_pain() )
  2843.         {
  2844.             break;
  2845.         }
  2846.         else
  2847.         {
  2848.             wait 0,1;
  2849.         }
  2850.     }
  2851.     self.reset_asd = undefined;
  2852.     self animmode( "normal" );
  2853.     self set_zombie_run_cycle( "run_wounded" );
  2854.     self.locomotion = "run_wounded";
  2855.     self thread sloth_retreat_vo();
  2856.     self check_behind_mansion();
  2857.     if ( isDefined( self.mansion_goal ) )
  2858.     {
  2859.         self setgoalpos( self.mansion_goal.origin );
  2860.         self waittill( "goal" );
  2861.         self action_teleport_to_courtyard();
  2862.     }
  2863.     self setgoalpos( pos );
  2864.     self waittill( "goal" );
  2865.     self animscripted( self.jail_start.origin, self.jail_start.angles, "zm_run_into_jail_cower" );
  2866.     self blend_notetracks( "run_into_jail_cower_anim" );
  2867.     self.needs_action = 1;
  2868. }
  2869.  
  2870. sloth_retreat_vo()
  2871. {
  2872.     wait 1;
  2873.     a_players = getplayers();
  2874.     a_closest = get_array_of_closest( self.origin, a_players );
  2875.     i = 0;
  2876.     while ( i < a_closest.size )
  2877.     {
  2878.         if ( isDefined( a_closest[ i ].dontspeak ) && !a_closest[ i ].dontspeak )
  2879.         {
  2880.             if ( isalive( a_closest[ i ] ) )
  2881.             {
  2882.                 a_closest[ i ] thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "sloth_retreat_cell" );
  2883.             }
  2884.         }
  2885.         i++;
  2886.     }
  2887. }
  2888.  
  2889. action_roam_point( point )
  2890. {
  2891.     self endon( "death" );
  2892.     self notify( "stop_action" );
  2893.     self endon( "stop_action" );
  2894.     self.needs_action = 0;
  2895.     if ( isDefined( self.current_roam ) )
  2896.     {
  2897.         if ( point.script_noteworthy != self.current_roam.script_noteworthy )
  2898.         {
  2899. /#
  2900.             sloth_print( "using sloth_mover " + self.current_roam.script_noteworthy );
  2901. #/
  2902.             sub_goal_array = getstructarray( self.current_roam.script_noteworthy, "script_noteworthy" );
  2903.             _a3338 = sub_goal_array;
  2904.             _k3338 = getFirstArrayKey( _a3338 );
  2905.             while ( isDefined( _k3338 ) )
  2906.             {
  2907.                 sg = _a3338[ _k3338 ];
  2908.                 if ( isDefined( sg.targetname ) && sg.targetname == "player_respawn_point" )
  2909.                 {
  2910.                 }
  2911.                 else
  2912.                 {
  2913.                     sub_goal = sg;
  2914.                 }
  2915.                 _k3338 = getNextArrayKey( _a3338, _k3338 );
  2916.             }
  2917.             ground_pos = groundpos( sub_goal.origin );
  2918.             self sloth_check_turn( ground_pos, 0 );
  2919.             self setgoalpos( ground_pos );
  2920.             self waittill( "goal" );
  2921.             sub_goal_next = getstruct( sub_goal.target, "targetname" );
  2922.             ground_pos = groundpos( sub_goal_next.origin );
  2923.             self sloth_check_turn( ground_pos, 0 );
  2924.             self setgoalpos( ground_pos );
  2925.             self waittill( "goal" );
  2926.         }
  2927.     }
  2928.     self sloth_check_turn( point.origin, 0 );
  2929.     self setgoalnode( point );
  2930.     self waittill( "goal" );
  2931.     self.current_roam = point;
  2932.     self.needs_action = 1;
  2933. }
  2934.  
  2935. action_player_idle( gimme_anim )
  2936. {
  2937.     self.needs_action = 0;
  2938.     self setgoalpos( self.origin );
  2939.     if ( isDefined( gimme_anim ) )
  2940.     {
  2941.         self setanimstatefromasd( gimme_anim );
  2942.     }
  2943.     else
  2944.     {
  2945.         self setanimstatefromasd( "zm_player_idle" );
  2946.     }
  2947. }
  2948.  
  2949. action_navigate_mansion( depart_points, arrive_points )
  2950. {
  2951.     if ( !isDefined( self.teleport ) )
  2952.     {
  2953.         points = array_randomize( depart_points );
  2954.         i = 0;
  2955.         while ( i < points.size )
  2956.         {
  2957.             end = i + 1;
  2958.             if ( end == points.size )
  2959.             {
  2960.                 end = 0;
  2961.             }
  2962.             points[ i ].next = points[ end ];
  2963.             i++;
  2964.         }
  2965.         self.teleport = points[ 0 ];
  2966.         self setgoalpos( self.teleport.origin );
  2967.     }
  2968.     else
  2969.     {
  2970.         dist = distancesquared( self.origin, self.teleport.origin );
  2971.         if ( dist < 1024 )
  2972.         {
  2973.             if ( self player_can_see_sloth() )
  2974.             {
  2975. /#
  2976.                 sloth_print( "player can see sloth, try another spot" );
  2977. #/
  2978.                 self.teleport = self.teleport.next;
  2979.                 self setgoalpos( self.teleport.origin );
  2980.                 return;
  2981.             }
  2982.             if ( depart_points[ 0 ].targetname == level.maze_depart[ 0 ].targetname )
  2983.             {
  2984. /#
  2985.                 sloth_print( "teleport to maze" );
  2986. #/
  2987.                 self.teleporting = "to_maze";
  2988.             }
  2989.             else
  2990.             {
  2991. /#
  2992.                 sloth_print( "teleport to courtyard" );
  2993. #/
  2994.                 self.teleporting = "to_courtyard";
  2995.             }
  2996.             arrive = array_randomize( arrive_points );
  2997.             self forceteleport( arrive[ 0 ].origin );
  2998.             self setgoalpos( arrive[ 0 ].origin );
  2999.             self.teleport = undefined;
  3000.             self.teleport_time = getTime();
  3001.         }
  3002.     }
  3003. }
  3004.  
  3005. player_can_see_sloth()
  3006. {
  3007.     players = get_players();
  3008.     _a3447 = players;
  3009.     _k3447 = getFirstArrayKey( _a3447 );
  3010.     while ( isDefined( _k3447 ) )
  3011.     {
  3012.         player = _a3447[ _k3447 ];
  3013.         if ( player.sessionstate == "spectator" )
  3014.         {
  3015.         }
  3016.         else
  3017.         {
  3018.             if ( player is_player_looking_at( self.origin, 0,7, 0, undefined ) )
  3019.             {
  3020.                 return 1;
  3021.             }
  3022.         }
  3023.         _k3447 = getNextArrayKey( _a3447, _k3447 );
  3024.     }
  3025.     return 0;
  3026. }
  3027.  
  3028. sloth_check_turn( pos, dot_limit )
  3029. {
  3030.     if ( !isDefined( dot_limit ) )
  3031.     {
  3032.         dot_limit = -0,707;
  3033.     }
  3034.     self endon( "death" );
  3035.     if ( !isDefined( self.locomotion ) )
  3036.     {
  3037. /#
  3038.         sloth_print( "tried turn but no locomotion defined" );
  3039. #/
  3040.         return;
  3041.     }
  3042.     if ( is_true( self.is_turning ) )
  3043.     {
  3044.         return;
  3045.     }
  3046.     vec_forward = vectornormalize( anglesToForward( self.angles ) );
  3047.     vec_goal = vectornormalize( pos - self.origin );
  3048.     dot = vectordot( vec_forward, vec_goal );
  3049.     if ( dot < dot_limit )
  3050.     {
  3051.         turn_asd = "zm_sloth_" + self.locomotion + "_turn_180";
  3052.         if ( !self hasanimstatefromasd( turn_asd ) )
  3053.         {
  3054. /#
  3055.             sloth_print( "no turn for " + turn_asd );
  3056. #/
  3057.             return;
  3058.             return;
  3059.         }
  3060.         else
  3061.         {
  3062.             self.is_turning = 1;
  3063.             self animcustom( ::sloth_do_turn_anim );
  3064.             anim_length = self getanimlengthfromasd( turn_asd, 0 );
  3065.             self waittill_notify_or_timeout( "turn_anim_done", anim_length );
  3066.             self.is_turning = 0;
  3067.         }
  3068.     }
  3069. }
  3070.  
  3071. sloth_do_turn_anim()
  3072. {
  3073.     self endon( "death" );
  3074.     self endon( "stop_action" );
  3075.     turn_asd = "zm_sloth_" + self.locomotion + "_turn_180";
  3076. /#
  3077.     sloth_print( turn_asd );
  3078. #/
  3079.     self setanimstatefromasd( turn_asd );
  3080.     if ( isDefined( self.crawler ) )
  3081.     {
  3082.         turn_crawler_asd = "zm_crawler_crawlerhold_walk";
  3083.         if ( self.is_inside )
  3084.         {
  3085.             turn_crawler_asd += "_hunched";
  3086.         }
  3087.         turn_crawler_asd += "_turn_180";
  3088.         self.crawler setanimstatefromasd( turn_crawler_asd );
  3089.     }
  3090.     maps/mp/animscripts/zm_shared::donotetracks( "sloth_turn_180_anim" );
  3091.     self notify( "turn_anim_done" );
  3092.     self.is_turning = 0;
  3093. }
  3094.  
  3095. action_player_follow( player )
  3096. {
  3097.     origin = player.origin;
  3098.     if ( is_true( player.slowgun_flying ) )
  3099.     {
  3100.         ground_ent = player getgroundent();
  3101.         if ( !isDefined( ground_ent ) )
  3102.         {
  3103.             ground_pos = groundpos( player.origin );
  3104.             node = getnearestnode( ground_pos );
  3105.             if ( !isDefined( node ) )
  3106.             {
  3107.                 node = getnearestnode( self.origin );
  3108.             }
  3109.             if ( isDefined( node ) )
  3110.             {
  3111.                 origin = node.origin;
  3112.             }
  3113.         }
  3114.     }
  3115.     self setgoalpos( origin );
  3116. }
  3117.  
  3118. action_player_ask( gimme_anim )
  3119. {
  3120.     self endon( "stop_action" );
  3121.     if ( !isDefined( gimme_anim ) )
  3122.     {
  3123.         self.needs_action = 1;
  3124.         return;
  3125.     }
  3126.     self.needs_action = 0;
  3127.     self setanimstatefromasd( gimme_anim );
  3128.     maps/mp/animscripts/zm_shared::donotetracks( "gimme_anim" );
  3129.     self.needs_action = 1;
  3130. }
  3131.  
  3132. action_berserk( player )
  3133. {
  3134.     self.needs_action = 0;
  3135.     self animcustom( ::custom_berserk );
  3136. }
  3137.  
  3138. action_anim( asd_name, notify_name )
  3139. {
  3140.     self endon( "death" );
  3141.     self.needs_action = 0;
  3142.     self setanimstatefromasd( asd_name );
  3143.     maps/mp/animscripts/zm_shared::donotetracks( notify_name );
  3144.     self.needs_action = 1;
  3145. }
  3146.  
  3147. action_animscripted( asd_name, notify_name, origin, angles )
  3148. {
  3149.     self endon( "death" );
  3150.     org = self.origin;
  3151.     ang = self.angles;
  3152.     if ( isDefined( origin ) )
  3153.     {
  3154.         org = origin;
  3155.     }
  3156.     if ( isDefined( angles ) )
  3157.     {
  3158.         ang = angles;
  3159.     }
  3160.     self.needs_action = 0;
  3161.     self animscripted( org, ang, asd_name );
  3162.     maps/mp/animscripts/zm_shared::donotetracks( notify_name );
  3163.     self.needs_action = 1;
  3164. }
  3165.  
  3166. custom_berserk()
  3167. {
  3168.     self endon( "death" );
  3169.     self setanimstatefromasd( "zm_drink_booze" );
  3170.     twr_origin = self gettagorigin( "tag_weapon_right" );
  3171.     twr_angles = self gettagangles( "tag_weapon_right" );
  3172.     if ( !isDefined( self.booze_model ) )
  3173.     {
  3174.         self.booze_model = spawn( "script_model", twr_origin );
  3175.         self.booze_model.angles = twr_angles;
  3176.         self.booze_model setmodel( level.booze_model );
  3177.         self.booze_model linkto( self, "tag_weapon_right" );
  3178.     }
  3179.     else
  3180.     {
  3181.         self.booze_model show();
  3182.     }
  3183.     self thread booze_wait();
  3184.     self setclientfield( "sloth_drinking", 1 );
  3185.     self blend_notetracks( "drink_booze_anim" );
  3186.     if ( isDefined( self.aim_barricade ) )
  3187.     {
  3188. /#
  3189.         if ( isDefined( self.aim_barricade.script_noteworthy ) )
  3190.         {
  3191.             sloth_print( "aiming at: " + self.aim_barricade.script_noteworthy );
  3192. #/
  3193.         }
  3194.         self orientmode( "face point", self.aim_barricade.origin );
  3195.     }
  3196.     self setanimstatefromasd( "zm_drink_booze_aim" );
  3197.     self setclientfield( "sloth_glass_brk", 0 );
  3198.     self setclientfield( "sloth_drinking", 0 );
  3199.     self thread kill_near_zombies();
  3200.     self blend_notetracks( "drink_booze_aim_anim" );
  3201.     self notify( "stop_kill_near_zombies" );
  3202.     if ( isDefined( self.aim_barricade ) )
  3203.     {
  3204.         self orientmode( "face default" );
  3205.         self.aim_barricade = undefined;
  3206.     }
  3207.     self.berserk_time = getTime();
  3208.     self.run_berserk = 1;
  3209.     self animmode( "gravity" );
  3210.     self setanimstatefromasd( "zm_move_run_berserk" );
  3211.     self.reset_asd = "zm_move_run_berserk";
  3212.     if ( isDefined( self.booze_player ) )
  3213.     {
  3214.         self thread maps/mp/zombies/_zm_audio::create_and_play_dialog( "general", "sloth_run" );
  3215.     }
  3216. /#
  3217.     self.debug_berserk = getTime();
  3218.     self.debug_berserk_org = self.origin;
  3219. #/
  3220.     self waittill( "stop_berserk" );
  3221.     self animmode( "normal" );
  3222.     self.run_berserk = 0;
  3223.     self.needs_action = 1;
  3224. }
  3225.  
  3226. blend_notetracks( animname )
  3227. {
  3228.     self endon( "death" );
  3229.     self waittillmatch( animname );
  3230.     return "blend";
  3231. }
  3232.  
  3233. kill_near_zombies()
  3234. {
  3235.     self endon( "death" );
  3236.     self endon( "stop_kill_near_zombies" );
  3237.     gibbed = 0;
  3238.     zombies = getaispeciesarray( level.zombie_team, "all" );
  3239.     i = 0;
  3240.     while ( i < zombies.size )
  3241.     {
  3242.         zombie = zombies[ i ];
  3243.         if ( is_true( zombie.is_sloth ) )
  3244.         {
  3245.             i++;
  3246.             continue;
  3247.         }
  3248.         else
  3249.         {
  3250.             dist = distancesquared( self.origin, zombie.origin );
  3251.             if ( dist < 4096 )
  3252.             {
  3253.                 if ( !is_true( self.no_gib ) && ( gibbed % 3 ) == 0 )
  3254.                 {
  3255.                     zombie.force_gib = 1;
  3256.                     zombie.a.gib_ref = random( array( "guts", "right_arm", "left_arm", "head" ) );
  3257.                     zombie thread maps/mp/animscripts/zm_death::do_gib();
  3258.                 }
  3259.                 gibbed++;
  3260.                 zombie dodamage( zombie.health * 10, zombie.origin );
  3261.                 zombie.noragdoll = 1;
  3262.                 zombie.nodeathragdoll = 1;
  3263.                 level.zombie_total++;
  3264.             }
  3265.         }
  3266.         i++;
  3267.     }
  3268. }
  3269.  
  3270. booze_wait()
  3271. {
  3272.     self endon( "death" );
  3273.     while ( 1 )
  3274.     {
  3275.         self waittill( "drink_booze_anim", note );
  3276.         if ( note == "hitground" || note == "end" )
  3277.         {
  3278.             self setclientfield( "sloth_glass_brk", 1 );
  3279.             if ( isDefined( self.booze_model ) )
  3280.             {
  3281.                 self.booze_model ghost();
  3282.             }
  3283.             return;
  3284.         }
  3285.         else
  3286.         {
  3287.         }
  3288.     }
  3289. }
  3290.  
  3291. action_gunshop_run()
  3292. {
  3293.     self endon( "death" );
  3294.     self.needs_action = 0;
  3295.     self set_zombie_run_cycle( "run" );
  3296.     self.locomotion = "run";
  3297.     self setgoalpos( self.gunshop.origin );
  3298.     self waittill( "goal" );
  3299.     self set_zombie_run_cycle( "walk" );
  3300.     self.locomotion = "walk";
  3301.     self.needs_action = 1;
  3302. }
  3303.  
  3304. action_gunshop_candy()
  3305. {
  3306.     self endon( "death" );
  3307.     self endon( "stop_action" );
  3308.     self.needs_action = 0;
  3309.     self setgoalpos( self.origin );
  3310.     while ( 1 )
  3311.     {
  3312.         self animscripted( self.origin, self.angles, "zm_player_idle" );
  3313.         maps/mp/animscripts/zm_shared::donotetracks( "player_idle_anim" );
  3314.     }
  3315. }
  3316.  
  3317. action_table_eat()
  3318. {
  3319.     self endon( "death" );
  3320.     self endon( "stop_action" );
  3321.     asd = "zm_eat_candy_storage_table";
  3322.     table_org = self.origin;
  3323.     align_org = self.origin;
  3324.     align_angles = self.angles;
  3325.     if ( isDefined( self.bench ) )
  3326.     {
  3327.         table = getent( self.bench.target, "targetname" );
  3328.         anim_id = self getanimfromasd( asd, 0 );
  3329.         table_org = getstartorigin( table.origin, table.angles, anim_id );
  3330.         align_org = table.origin;
  3331.         align_angles = table.angles;
  3332.     }
  3333.     self.needs_action = 0;
  3334.     self setgoalpos( table_org );
  3335.     self waittill( "goal" );
  3336.     self animscripted( align_org, align_angles, asd );
  3337.     maps/mp/animscripts/zm_shared::donotetracks( "eat_candy_storage_table_anim" );
  3338.     self notify( "table_eat_done" );
  3339.     self.needs_action = 1;
  3340. }
  3341.  
  3342. action_headbang()
  3343. {
  3344.     self endon( "death" );
  3345.     self endon( "stop_action" );
  3346.     self.needs_action = 0;
  3347.     self setgoalpos( self.origin );
  3348.     while ( 1 )
  3349.     {
  3350.         self animscripted( self.origin, self.angles, "zm_headbang" );
  3351.         maps/mp/animscripts/zm_shared::donotetracks( "headbang_anim" );
  3352.     }
  3353. }
  3354.  
  3355. action_smell()
  3356. {
  3357.     self endon( "death" );
  3358.     self endon( "stop_action" );
  3359.     self.needs_action = 0;
  3360.     self setgoalpos( self.origin );
  3361.     self animscripted( self.origin, self.angles, "zm_smell_react" );
  3362.     maps/mp/animscripts/zm_shared::donotetracks( "smell_react_anim" );
  3363.     self.needs_action = 1;
  3364. }
  3365.  
  3366. stop_action()
  3367. {
  3368.     self notify( "stop_action" );
  3369.     self.is_turning = 0;
  3370.     self.teleport = undefined;
  3371.     self.needs_action = 1;
  3372.     self stopanimscripted();
  3373.     self unlink();
  3374.     self orientmode( "face default" );
  3375. }
  3376.  
  3377. check_contextual_actions()
  3378. {
  3379.     context = undefined;
  3380.     keys = getarraykeys( level.candy_context );
  3381.     i = 0;
  3382.     while ( i < keys.size )
  3383.     {
  3384.         if ( self [[ level.candy_context[ keys[ i ] ].condition ]]() )
  3385.         {
  3386.             if ( isDefined( context ) )
  3387.             {
  3388.                 if ( level.candy_context[ keys[ i ] ].priority < context.priority )
  3389.                 {
  3390.                     context = level.candy_context[ keys[ i ] ];
  3391.                 }
  3392.                 i++;
  3393.                 continue;
  3394.             }
  3395.             else
  3396.             {
  3397.                 context = level.candy_context[ keys[ i ] ];
  3398.             }
  3399.         }
  3400.         i++;
  3401.     }
  3402.     return context;
  3403. }
  3404.  
  3405. common_context_start()
  3406. {
  3407. /#
  3408.     sloth_print( self.context.name );
  3409. #/
  3410.     self.context_done = 0;
  3411.     self thread [[ self.context.action ]]();
  3412. }
  3413.  
  3414. common_context_update()
  3415. {
  3416.     if ( is_true( self.context_done ) )
  3417.     {
  3418.         maps/mp/zombies/_zm_unitrigger::register_unitrigger( self.gift_trigger, ::maps/mp/zombies/_zm_buildables::buildable_place_think );
  3419.         self orientmode( "face default" );
  3420.         self set_zombie_run_cycle( "walk" );
  3421.         self.locomotion = "walk";
  3422.         self sloth_set_state( "roam" );
  3423.     }
  3424.     else
  3425.     {
  3426.         if ( !is_true( self.ignore_common_run ) )
  3427.         {
  3428.             self common_context_run( "run" );
  3429.         }
  3430.         anim_state = self getanimstatefromasd();
  3431.         if ( anim_state == "zm_move_run" || anim_state == "zm_move_run_hunched" )
  3432.         {
  3433.             self sloth_check_ragdolls();
  3434.         }
  3435.     }
  3436. }
  3437.  
  3438. common_context_run( move_run )
  3439. {
  3440.     if ( self.is_inside )
  3441.     {
  3442.         move_run += "_hunched";
  3443.     }
  3444.     if ( self.zombie_move_speed != move_run )
  3445.     {
  3446.         self set_zombie_run_cycle( move_run );
  3447.         self.locomotion = move_run;
  3448.     }
  3449.     else
  3450.     {
  3451.         if ( is_true( self.was_idle ) )
  3452.         {
  3453.             self.was_idle = 0;
  3454.             self maps/mp/animscripts/zm_run::needsupdate();
  3455.         }
  3456.     }
  3457. }
  3458.  
  3459. common_context_action()
  3460. {
  3461.     self common_context_run( "run" );
  3462. }
  3463.  
  3464. protect_condition()
  3465. {
  3466.     return 1;
  3467. }
  3468.  
  3469. protect_start()
  3470. {
  3471. /#
  3472.     sloth_print( "protect " + self.candy_player.name );
  3473. #/
  3474.     self.protect_time = getTime();
  3475.     self thread protect_action();
  3476.     self thread sndchangebreathingstate( "angry" );
  3477. }
  3478.  
  3479. protect_update()
  3480. {
  3481.     if ( !is_true( self.candy_player.is_in_ghost_zone ) || ( getTime() - self.protect_time ) > 45000 && should_ignore_candybooze( self.candy_player ) )
  3482.     {
  3483.         if ( isDefined( self.target_zombie ) )
  3484.         {
  3485.             self.target_zombie = undefined;
  3486.         }
  3487.         maps/mp/zombies/_zm_unitrigger::register_unitrigger( self.gift_trigger, ::maps/mp/zombies/_zm_buildables::buildable_place_think );
  3488.         self notify( "stop_player_watch" );
  3489.         self set_zombie_run_cycle( "walk" );
  3490.         self.locomotion = "walk";
  3491.         self sloth_set_state( "roam" );
  3492.         self orientmode( "face default" );
  3493.     }
  3494. }
  3495.  
  3496. protect_action()
  3497. {
  3498.     self endon( "death" );
  3499.     self endon( "stop_action" );
  3500.     self setclientfield( "sloth_berserk", 0 );
  3501.     if ( !isDefined( level.sloth_protect ) )
  3502.     {
  3503.         level.sloth_protect = 1;
  3504.     }
  3505.     else
  3506.     {
  3507.         level.sloth_protect++;
  3508.     }
  3509.     while ( 1 )
  3510.     {
  3511.         if ( !isDefined( self.target_zombie ) || self.target_zombie.health <= 0 )
  3512.         {
  3513.             if ( self.target_zombies.size > 0 )
  3514.             {
  3515.                 closest = undefined;
  3516.                 closest_dist = undefined;
  3517.                 i = 0;
  3518.                 while ( i < self.target_zombies.size )
  3519.                 {
  3520.                     zombie = self.target_zombies[ i ];
  3521.                     if ( zombie.health > 0 )
  3522.                     {
  3523.                         dist = distancesquared( self.candy_player.origin, zombie.origin );
  3524.                         if ( !isDefined( closest ) || dist < closest_dist )
  3525.                         {
  3526.                             closest = zombie;
  3527.                             closest_dist = dist;
  3528.                         }
  3529.                     }
  3530.                     i++;
  3531.                 }
  3532.                 if ( isDefined( closest ) )
  3533.                 {
  3534.                     self.target_zombie = closest;
  3535.                 }
  3536.             }
  3537.         }
  3538.         if ( isDefined( self.target_zombie ) )
  3539.         {
  3540.             dist = distancesquared( self.origin, self.target_zombie.origin );
  3541.             if ( dist < 4096 )
  3542.             {
  3543.                 self sloth_check_turn( self.target_zombie.origin, -0,923 );
  3544.                 self.anchor.origin = self.origin;
  3545.                 self.anchor.angles = flat_angle( vectorToAngle( self.target_zombie.origin - self.origin ) );
  3546.                 self animscripted( self.anchor.origin, self.anchor.angles, "zm_melee_attack" );
  3547.                 maps/mp/animscripts/zm_shared::donotetracks( "melee_attack", ::sloth_melee_notetracks );
  3548.                 self.target_zombie = undefined;
  3549.             }
  3550.             else
  3551.             {
  3552.                 self sloth_check_turn( self.target_zombie.origin, -0,923 );
  3553.                 self setgoalpos( self.target_zombie.origin );
  3554.                 self common_context_run( "run_frantic" );
  3555.                 self sloth_check_ragdolls( self.target_zombie );
  3556. /#
  3557.                 if ( getDvarInt( #"B6252E7C" ) == 2 )
  3558.                 {
  3559.                     line( self.origin, self.target_zombie.origin, ( 0, 1, 0 ), 1, 0, 6 );
  3560. #/
  3561.                 }
  3562.             }
  3563.         }
  3564.         else dist = distancesquared( self.origin, self.candy_player.origin );
  3565.         if ( dist < 32400 && !self sloth_is_traversing() )
  3566.         {
  3567.             self setgoalpos( self.origin );
  3568.             self setanimstatefromasd( "zm_idle_protect" );
  3569.             self.was_idle = 1;
  3570.         }
  3571.         else
  3572.         {
  3573.             self sloth_check_turn( self.candy_player.origin, -0,923 );
  3574.             self setgoalpos( self.candy_player.origin );
  3575.             self common_context_run( "run_frantic" );
  3576.             self sloth_check_ragdolls( self.target_zombie );
  3577.         }
  3578.         wait 0,1;
  3579.     }
  3580. }
  3581.  
  3582. sloth_melee_notetracks( note )
  3583. {
  3584.     if ( note != "j_wrist_ri" || note == "j_wrist_le" && note == "j_ball_ri" )
  3585.     {
  3586.         if ( isDefined( self.target_zombie ) )
  3587.         {
  3588.             playfxontag( level._effect[ "headshot_nochunks" ], self.target_zombie, "j_head" );
  3589.             self sloth_kill_zombie( self.target_zombie );
  3590.         }
  3591.         self sloth_check_ragdolls( self.target_zombie );
  3592.     }
  3593. }
  3594.  
  3595. lamp_condition()
  3596. {
  3597.     if ( !isDefined( level.oillamp ) )
  3598.     {
  3599.         return 0;
  3600.     }
  3601.     if ( !isDefined( level.oillamp.unitrigger ) || is_true( level.oillamp.built ) )
  3602.     {
  3603.         return 0;
  3604.     }
  3605.     i = 0;
  3606.     while ( i < level.generator_zones.size )
  3607.     {
  3608.         zone = level.generator_zones[ i ];
  3609.         dist = distancesquared( zone.stub.origin, self.origin );
  3610.         if ( dist < 14400 )
  3611.         {
  3612.             self.buildable_zone = zone;
  3613.             return 1;
  3614.         }
  3615.         i++;
  3616.     }
  3617.     return 0;
  3618. }
  3619.  
  3620. lamp_action()
  3621. {
  3622.     self endon( "death" );
  3623.     self endon( "stop_action" );
  3624.     self set_zombie_run_cycle( "run" );
  3625.     self.locomotion = "run";
  3626.     self maps/mp/animscripts/zm_run::needsupdate();
  3627.     self.oillamp = level.oillamp;
  3628.     lamp_gone = 0;
  3629.     while ( 1 )
  3630.     {
  3631.         if ( self.oillamp != level.oillamp )
  3632.         {
  3633. /#
  3634.             sloth_print( "lamp moved" );
  3635. #/
  3636.             self.oillamp = level.oillamp;
  3637.         }
  3638.         if ( isDefined( self.oillamp.unitrigger ) && !is_true( self.oillamp.built ) )
  3639.         {
  3640.             self setgoalpos( self.oillamp.unitrigger.origin );
  3641.             dist = distancesquared( self.oillamp.unitrigger.origin, self.origin );
  3642.             if ( dist < 4096 )
  3643.             {
  3644.                 break;
  3645.             }
  3646.             else }
  3647.         else lamp_gone = 1;
  3648.         break;
  3649.         wait 0,1;
  3650.     }
  3651.     if ( lamp_gone )
  3652.     {
  3653. /#
  3654.         sloth_print( "lamp is gone" );
  3655. #/
  3656.         self.context_done = 1;
  3657.         return;
  3658.     }
  3659. /#
  3660.     sloth_print( "got lamp" );
  3661. #/
  3662.     self.oillamp maps/mp/zombies/_zm_buildables::piece_unspawn();
  3663.     self action_animscripted( "zm_wallbuy_remove", "wallbuy_remove_anim" );
  3664.     stub = self.buildable_zone.stub;
  3665.     vec_right = vectornormalize( anglesToRight( stub.angles ) );
  3666.     ground_pos = stub.origin - ( vec_right * 60 );
  3667.     ground_pos = groundpos( ground_pos );
  3668.     self setgoalpos( ground_pos );
  3669.     self waittill( "goal" );
  3670.     generator_angle = vectorToAngle( vec_right );
  3671.     self orientmode( "face angle", generator_angle[ 1 ] );
  3672.     wait 0,75;
  3673.     self action_animscripted( "zm_wallbuy_add", "wallbuy_add_anim" );
  3674.     self player_set_buildable_piece( self.oillamp, 1 );
  3675.     self maps/mp/zombies/_zm_buildables::player_build( self.buildable_zone );
  3676. /#
  3677.     sloth_print( "placed lamp" );
  3678. #/
  3679.     self.context_done = 1;
  3680. }
  3681.  
  3682. powerup_cycle_condition()
  3683. {
  3684.     while ( level.active_powerups.size > 0 )
  3685.     {
  3686.         _a4262 = level.active_powerups;
  3687.         _k4262 = getFirstArrayKey( _a4262 );
  3688.         while ( isDefined( _k4262 ) )
  3689.         {
  3690.             powerup = _a4262[ _k4262 ];
  3691.             ground_pos = groundpos( powerup.origin );
  3692. /#
  3693.             self sloth_debug_context( powerup, sqrt( 32400 ) );
  3694. #/
  3695.             dist = distancesquared( self.origin, ground_pos );
  3696.             if ( dist < 32400 )
  3697.             {
  3698.                 self.active_powerup = powerup;
  3699.                 self.active_powerup notify( "powerup_reset" );
  3700.                 self.active_powerup show();
  3701.                 return 1;
  3702.             }
  3703.             _k4262 = getNextArrayKey( _a4262, _k4262 );
  3704.         }
  3705.     }
  3706.     return 0;
  3707. }
  3708.  
  3709. powerup_cycle_action()
  3710. {
  3711.     self endon( "death" );
  3712.     self endon( "stop_action" );
  3713.     self common_context_action();
  3714. /#
  3715.     level.zombie_devgui_power = 0;
  3716. #/
  3717.     if ( isDefined( self.active_powerup ) )
  3718.     {
  3719.         powerup_pos = groundpos( self.active_powerup.origin );
  3720.         dest_pos = powerup_pos;
  3721.         too_close = 0;
  3722.         dist = distancesquared( self.origin, powerup_pos );
  3723.         if ( dist < 2116 )
  3724.         {
  3725.             too_close = 1;
  3726. /#
  3727.             sloth_print( "too close to powerup: " + sqrt( dist ) );
  3728. #/
  3729.             vec_forward = vectornormalize( anglesToForward( self.angles ) );
  3730.             dest_pos = groundpos( self.active_powerup.origin + ( vec_forward * 100 ) );
  3731.         }
  3732.         self setgoalpos( dest_pos );
  3733.         time_started = getTime();
  3734.         while ( 1 )
  3735.         {
  3736.             dist = distancesquared( self.origin, powerup_pos );
  3737.             if ( too_close )
  3738.             {
  3739.                 self orientmode( "face point", powerup_pos );
  3740.                 if ( dist > 2500 )
  3741.                 {
  3742.                     self setgoalpos( self.origin );
  3743.                     if ( is_facing( self.active_powerup ) )
  3744.                     {
  3745.                         break;
  3746.                     }
  3747.                 }
  3748.                 else if ( ( getTime() - time_started ) > 3000 )
  3749.                 {
  3750. /#
  3751.                     sloth_print( "couldn't get away" );
  3752. #/
  3753.                     break;
  3754.                 }
  3755.                 else }
  3756.             else if ( dist < 3136 )
  3757.             {
  3758.                 self setgoalpos( self.origin );
  3759.                 break;
  3760.             }
  3761.             else
  3762.             {
  3763.                 wait 0,1;
  3764.             }
  3765.         }
  3766.         if ( isDefined( self.active_powerup ) )
  3767.         {
  3768.             if ( !too_close )
  3769.             {
  3770.                 self sloth_face_object( self.active_powerup, "point", powerup_pos );
  3771.             }
  3772.         }
  3773.         if ( isDefined( self.active_powerup ) )
  3774.         {
  3775.             self.anchor.origin = self.origin;
  3776.             self.anchor.angles = flat_angle( vectorToAngle( powerup_pos - self.origin ) );
  3777.             self animscripted( self.anchor.origin, self.anchor.angles, "zm_cycle_powerup" );
  3778.             maps/mp/animscripts/zm_shared::donotetracks( "cycle_powerup_anim", ::powerup_change );
  3779.         }
  3780.     }
  3781.     self.context_done = 1;
  3782. }
  3783.  
  3784. powerup_change( note )
  3785. {
  3786.     if ( note == "change" )
  3787.     {
  3788.         if ( isDefined( self.active_powerup ) )
  3789.         {
  3790.             playfx( level._effect[ "fx_buried_sloth_powerup_cycle" ], self.active_powerup.origin );
  3791.             powerup = maps/mp/zombies/_zm_powerups::get_valid_powerup();
  3792.             struct = level.zombie_powerups[ powerup ];
  3793.             if ( self.active_powerup.powerup_name == struct.powerup_name )
  3794.             {
  3795.                 powerup = maps/mp/zombies/_zm_powerups::get_valid_powerup();
  3796.                 struct = level.zombie_powerups[ powerup ];
  3797.             }
  3798.             self.active_powerup setmodel( struct.model_name );
  3799.             self.active_powerup.powerup_name = struct.powerup_name;
  3800.             self.active_powerup.hint = struct.hint;
  3801.             self.active_powerup.solo = struct.solo;
  3802.             self.active_powerup.caution = struct.caution;
  3803.             self.active_powerup.zombie_grabbable = struct.zombie_grabbable;
  3804.             self.active_powerup.func_should_drop_with_regular_powerups = struct.func_should_drop_with_regular_powerups;
  3805.             self.active_powerup thread maps/mp/zombies/_zm_powerups::powerup_timeout();
  3806.             if ( isDefined( struct.fx ) )
  3807.             {
  3808.                 self.active_powerup.fx = struct.fx;
  3809.             }
  3810.         }
  3811.     }
  3812. }
  3813.  
  3814. dance_condition()
  3815. {
  3816.     if ( isDefined( level.sloth_protect ) )
  3817.     {
  3818.         next_protect = level.sloth_protect + 1;
  3819.         if ( ( next_protect % 3 ) == 0 )
  3820.         {
  3821.             return 1;
  3822.         }
  3823.     }
  3824.     return 0;
  3825. }
  3826.  
  3827. dance_action()
  3828. {
  3829.     self endon( "death" );
  3830.     self endon( "stop_action" );
  3831.     self common_context_action();
  3832.     self setclientfield( "sloth_vomit", 0 );
  3833.     self.dance_end = getTime() + 30000;
  3834.     level.sloth_protect = 0;
  3835.     while ( 1 )
  3836.     {
  3837.         if ( getTime() >= self.dance_end )
  3838.         {
  3839.             break;
  3840.         }
  3841.         else
  3842.         {
  3843.             self animscripted( self.origin, self.angles, "zm_dance" );
  3844.             maps/mp/animscripts/zm_shared::donotetracks( "dance_anim", ::dance_attack );
  3845.             wait 0,1;
  3846.         }
  3847.     }
  3848.     self notify( "stop_dance" );
  3849.     self animscripted( self.origin, self.angles, "zm_vomit" );
  3850.     maps/mp/animscripts/zm_shared::donotetracks( "vomit_anim", ::vomit_notetrack );
  3851.     self.context_done = 1;
  3852. }
  3853.  
  3854. dance_attack( note )
  3855. {
  3856.     while ( note == "fire" )
  3857.     {
  3858.         zombies = get_round_enemy_array();
  3859.         i = 0;
  3860.         while ( i < zombies.size )
  3861.         {
  3862.             zombie = zombies[ i ];
  3863.             dist = distancesquared( self.origin, zombie.origin );
  3864.             if ( dist < 4096 )
  3865.             {
  3866.                 zombie dodamage( zombie.health * 10, zombie.origin );
  3867.                 zombie playsound( "zmb_ai_sloth_attack_impact" );
  3868.             }
  3869.             i++;
  3870.         }
  3871.     }
  3872. }
  3873.  
  3874. vomit_notetrack( note )
  3875. {
  3876.     if ( note == "vomit" )
  3877.     {
  3878.         self setclientfield( "sloth_vomit", 1 );
  3879.     }
  3880. }
  3881.  
  3882. sloth_paralyzed( player, upgraded )
  3883. {
  3884.     sizzle = "zombie_slowgun_sizzle";
  3885.     if ( upgraded )
  3886.     {
  3887.         sizzle = "zombie_slowgun_sizzle_ug";
  3888.     }
  3889.     if ( isDefined( level._effect[ sizzle ] ) )
  3890.     {
  3891.         playfxontag( level._effect[ sizzle ], self, "J_SpineLower" );
  3892.     }
  3893.     self maps/mp/zombies/_zm_weap_slowgun::zombie_slow_for_time( 0,3 );
  3894. }
  3895.  
  3896. is_holding_candybooze( player )
  3897. {
  3898.     if ( is_holding( player, "candy" ) || is_holding( player, "booze" ) )
  3899.     {
  3900.         return 1;
  3901.     }
  3902.     return 0;
  3903. }
  3904.  
  3905. is_holding( player, name )
  3906. {
  3907.     if ( should_ignore_candybooze( player ) )
  3908.     {
  3909.         return 0;
  3910.     }
  3911.     piece = player player_get_buildable_piece( 1 );
  3912.     if ( isDefined( piece ) )
  3913.     {
  3914.         if ( isDefined( piece.buildablename ) && piece.buildablename == name )
  3915.         {
  3916.             return 1;
  3917.         }
  3918.     }
  3919.     return 0;
  3920. }
  3921.  
  3922. create_candy_booze_trigger()
  3923. {
  3924.     if ( !is_buildable_included( "sloth" ) )
  3925.     {
  3926.         return;
  3927.     }
  3928.     gift_trigger = maps/mp/zombies/_zm_buildables::ai_buildable_trigger_think( self, "sloth", "sloth", "", 3 );
  3929.     gift_trigger bpstub_set_custom_think_callback( ::bptrigger_think_unbuild_no_return );
  3930.     gift_trigger.onbeginuse = ::onbeginusecandybooze;
  3931.     gift_trigger.onenduse = ::onendusecandybooze;
  3932.     gift_trigger.onuse = ::onuseplantobjectcandybooze;
  3933.     gift_trigger.oncantuse = ::oncantusecandybooze;
  3934.     gift_trigger.prompt_and_visibility_func = ::sloth_gift_prompt;
  3935.     gift_trigger.originfunc = ::sloth_get_unitrigger_origin;
  3936.     gift_trigger.buildablestruct.building = "";
  3937.     gift_trigger.building_prompt = &"ZM_BURIED_GIVING";
  3938.     gift_trigger.build_weapon = "no_hands_zm";
  3939.     gift_trigger.ignore_open_sesame = 1;
  3940.     gift_trigger.usetime = int( 750 );
  3941.     gift_trigger.radius = 96;
  3942.     self.gift_trigger = gift_trigger;
  3943.     gift_trigger thread watch_prompt_reassessment();
  3944.     level thread wait_start_candy_booze( gift_trigger.buildablezone.pieces[ 1 ] );
  3945.     self waittill( "death" );
  3946.     gift_trigger maps/mp/zombies/_zm_buildables::buildablestub_remove();
  3947.     thread maps/mp/zombies/_zm_unitrigger::unregister_unitrigger( gift_trigger );
  3948. }
  3949.  
  3950. wait_start_candy_booze( piece )
  3951. {
  3952.     piece piece_unspawn();
  3953.     level.jail_barricade_down = 0;
  3954.     level waittill( "jail_barricade_down" );
  3955.     level.jail_barricade_down = 1;
  3956.     piece piece_spawn_at();
  3957. }
  3958.  
  3959. watch_prompt_reassessment()
  3960. {
  3961.     self.inactive_reasses_time = 0,2;
  3962.     self.active_reasses_time = 0,2;
  3963.     level waittill( "jail_barricade_down" );
  3964.     self.inactive_reasses_time = 0,3;
  3965.     self.active_reasses_time = 0,3;
  3966. }
  3967.  
  3968. is_facing( facee, dot_limit )
  3969. {
  3970.     if ( !isDefined( dot_limit ) )
  3971.     {
  3972.         dot_limit = 0,7;
  3973.     }
  3974.     if ( isplayer( self ) )
  3975.     {
  3976.         orientation = self getplayerangles();
  3977.     }
  3978.     else
  3979.     {
  3980.         orientation = self.angles;
  3981.     }
  3982.     forwardvec = anglesToForward( orientation );
  3983.     forwardvec2d = ( forwardvec[ 0 ], forwardvec[ 1 ], 0 );
  3984.     unitforwardvec2d = vectornormalize( forwardvec2d );
  3985.     tofaceevec = facee.origin - self.origin;
  3986.     tofaceevec2d = ( tofaceevec[ 0 ], tofaceevec[ 1 ], 0 );
  3987.     unittofaceevec2d = vectornormalize( tofaceevec2d );
  3988.     dotproduct = vectordot( unitforwardvec2d, unittofaceevec2d );
  3989.     return dotproduct > dot_limit;
  3990. }
  3991.  
  3992. sloth_get_unitrigger_origin()
  3993. {
  3994.     if ( isDefined( self.origin_parent ) )
  3995.     {
  3996.         forward = anglesToForward( self.origin_parent.angles );
  3997.         return ( self.origin_parent.origin + vectorScale( ( 0, 1, 0 ), 35 ) ) + ( 32 * forward );
  3998.     }
  3999.     return self.origin;
  4000. }
  4001.  
  4002. sloth_gift_prompt( player )
  4003. {
  4004.     can_use = 1;
  4005.     if ( isDefined( self.thread_running ) )
  4006.     {
  4007.         active = self.thread_running;
  4008.     }
  4009.     sloth = self.stub.link_parent;
  4010.     if ( active )
  4011.     {
  4012.         dotlimit = 0,7;
  4013.     }
  4014.     else
  4015.     {
  4016.         dotlimit = 0,75;
  4017.     }
  4018.     if ( !player is_facing( sloth, dotlimit ) || !sloth is_facing( player, dotlimit ) )
  4019.     {
  4020.         self.stub.hint_string = "";
  4021.         self sethintstring( self.stub.hint_string );
  4022.         can_use = 0;
  4023.     }
  4024.     else
  4025.     {
  4026.         if ( active )
  4027.         {
  4028.             can_use = 1;
  4029.         }
  4030.         else
  4031.         {
  4032.             piece = player player_get_buildable_piece( 1 );
  4033.             if ( isDefined( piece ) )
  4034.             {
  4035.                 if ( piece.buildablename == "candy" )
  4036.                 {
  4037.                     level.zombie_buildables[ "sloth" ].hint = &"ZM_BURIED_CANDY_GV";
  4038.                 }
  4039.                 else
  4040.                 {
  4041.                     level.zombie_buildables[ "sloth" ].hint = &"ZM_BURIED_BOOZE_GV";
  4042.                 }
  4043.             }
  4044.             can_use = self buildabletrigger_update_prompt( player );
  4045.         }
  4046.     }
  4047.     if ( can_use )
  4048.     {
  4049.         self.reassess_time = self.stub.active_reasses_time;
  4050.     }
  4051.     return can_use;
  4052. }
  4053.  
  4054. onbeginusecandybooze( player )
  4055. {
  4056.     sloth = self.origin_parent;
  4057.     sloth sloth_set_state( "player_idle", 1 );
  4058. }
  4059.  
  4060. onendusecandybooze( team, player, result )
  4061. {
  4062.     sloth = self.origin_parent;
  4063.     if ( sloth.state != "jail_cower" || result )
  4064.     {
  4065.         sloth unlink();
  4066.     }
  4067. }
  4068.  
  4069. oncantusecandybooze( player )
  4070. {
  4071. }
  4072.  
  4073. onuseplantobjectcandybooze( player )
  4074. {
  4075.     if ( !isDefined( player player_get_buildable_piece( 1 ) ) )
  4076.     {
  4077.         return;
  4078.     }
  4079.     self.hint_string = "";
  4080.     switch( player player_get_buildable_piece( 1 ).buildablename )
  4081.     {
  4082.         case "booze":
  4083.             if ( level.sloth.state == "eat" )
  4084.             {
  4085.                 return;
  4086.             }
  4087.             level.sloth sloth_set_state( "berserk", player );
  4088.             break;
  4089.         case "candy":
  4090.             if ( level.sloth.state == "berserk" )
  4091.             {
  4092.                 return;
  4093.             }
  4094.             level.sloth sloth_set_state( "eat", player );
  4095.             player notify( "player_gives_sloth_candy" );
  4096.             break;
  4097.     }
  4098.     self.built = 1;
  4099. }
  4100.  
  4101. sloth_damage_func( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime, boneindex )
  4102. {
  4103.     if ( sweapon == "equip_headchopper_zm" )
  4104.     {
  4105.         self.damageweapon_name = sweapon;
  4106.         self check_zombie_damage_callbacks( smeansofdeath, shitloc, vpoint, eattacker, idamage );
  4107.         self.damageweapon_name = undefined;
  4108.     }
  4109.     if ( isDefined( self.sloth_damage_func ) )
  4110.     {
  4111.         damage = self [[ self.sloth_damage_func ]]( einflictor, eattacker, idamage, idflags, smeansofdeath, sweapon, vpoint, vdir, shitloc, psoffsettime );
  4112.         return damage;
  4113.     }
  4114.     if ( smeansofdeath == level.slowgun_damage_mod && sweapon == "slowgun_zm" )
  4115.     {
  4116.         return 0;
  4117.     }
  4118.     if ( smeansofdeath == "MOD_MELEE" )
  4119.     {
  4120.         self sloth_leg_pain();
  4121.         return 0;
  4122.     }
  4123.     if ( self.state == "jail_idle" )
  4124.     {
  4125.         self stop_action();
  4126.         self sloth_set_state( "jail_cower" );
  4127.         maps/mp/zombies/_zm_unitrigger::register_unitrigger( self.gift_trigger, ::maps/mp/zombies/_zm_buildables::buildable_place_think );
  4128.         return 0;
  4129.     }
  4130.     if ( smeansofdeath != "MOD_EXPLOSIVE" && smeansofdeath != "MOD_EXPLOSIVE_SPLASH" && smeansofdeath != "MOD_GRENADE" && smeansofdeath != "MOD_GRENADE_SPLASH" || smeansofdeath == "MOD_PROJECTILE" && smeansofdeath == "MOD_PROJECTILE_SPLASH" )
  4131.     {
  4132.         do_pain = self sloth_pain_react();
  4133.         self sloth_set_state( "jail_run", do_pain );
  4134.         return 0;
  4135.     }
  4136.     if ( !is_true( self.damage_accumulating ) )
  4137.     {
  4138.         self thread sloth_accumulate_damage( idamage );
  4139.     }
  4140.     else
  4141.     {
  4142.         self.damage_taken += idamage;
  4143.         self.num_hits++;
  4144.     }
  4145.     return 0;
  4146. }
  4147.  
  4148. sloth_pain_react()
  4149. {
  4150.     if ( self.state != "roam" || self.state == "follow" && self.state == "player_idle" )
  4151.     {
  4152.         if ( !self sloth_is_traversing() )
  4153.         {
  4154.             return 1;
  4155.         }
  4156.     }
  4157.     return 0;
  4158. }
  4159.  
  4160. sloth_accumulate_damage( amount )
  4161. {
  4162.     self endon( "death" );
  4163.     self notify( "stop_accumulation" );
  4164.     self endon( "stop_accumulation" );
  4165.     self.damage_accumulating = 1;
  4166.     self.damage_taken = amount;
  4167.     self.num_hits = 1;
  4168.     if ( self sloth_pain_react() )
  4169.     {
  4170.         self.is_pain = 1;
  4171.         prev_anim_state = self getanimstatefromasd();
  4172.         if ( self.state == "roam" || self.state == "follow" )
  4173.         {
  4174.             self animmode( "gravity" );
  4175.         }
  4176.         self setanimstatefromasd( "zm_pain" );
  4177.         self.reset_asd = "zm_pain";
  4178.         maps/mp/animscripts/zm_shared::donotetracks( "pain_anim" );
  4179.         if ( self.state == "roam" || self.state == "follow" )
  4180.         {
  4181.             self animmode( "normal" );
  4182.         }
  4183.         self.is_pain = 0;
  4184.         self.reset_asd = undefined;
  4185.         self setanimstatefromasd( prev_anim_state );
  4186.     }
  4187.     else
  4188.     {
  4189.         wait 1;
  4190.     }
  4191. /#
  4192.     sloth_print( "num hits: " + self.num_hits );
  4193. #/
  4194.     self.damage_accumulating = 0;
  4195.     if ( self.num_hits >= 3 )
  4196.     {
  4197.         self sloth_set_state( "jail_run", 0 );
  4198.     }
  4199. }
  4200.  
  4201. sloth_leg_pain()
  4202. {
  4203.     self.leg_pain_time = getTime() + 4000;
  4204. }
  4205.  
  4206. sloth_non_attacker( damage, weapon )
  4207. {
  4208.     return 0;
  4209. }
  4210.  
  4211. sloth_set_anim_rate( rate )
  4212. {
  4213.     if ( isDefined( self.crawler ) )
  4214.     {
  4215.         self.crawler maps/mp/zombies/_zm_weap_slowgun::set_anim_rate( rate );
  4216.     }
  4217. }
  4218.  
  4219. sloth_reset_anim()
  4220. {
  4221.     self endon( "death" );
  4222.     if ( self.state == "jail_idle" )
  4223.     {
  4224.         self animscripted( self.jail_start.origin, self.jail_start.angles, "zm_jail_idle" );
  4225.         maps/mp/animscripts/zm_shared::donotetracks( "jail_idle_anim" );
  4226.     }
  4227.     else if ( isDefined( self.reset_asd ) )
  4228.     {
  4229.         self setanimstatefromasd( self.reset_asd );
  4230.     }
  4231.     else
  4232.     {
  4233.         self maps/mp/zombies/_zm_weap_slowgun::reset_anim();
  4234.     }
  4235. }
  4236.  
  4237. sloth_time_bomb_setup()
  4238. {
  4239.     maps/mp/zombies/_zm_weap_time_bomb::time_bomb_add_custom_func_global_save( ::time_bomb_global_data_save_sloth );
  4240.     maps/mp/zombies/_zm_weap_time_bomb::time_bomb_add_custom_func_global_restore( ::time_bomb_global_data_restore_sloth );
  4241. }
  4242.  
  4243. time_bomb_global_data_save_sloth()
  4244. {
  4245. }
  4246.  
  4247. time_bomb_global_data_restore_sloth()
  4248. {
  4249.     players = getplayers();
  4250.     _a4918 = players;
  4251.     _k4918 = getFirstArrayKey( _a4918 );
  4252.     while ( isDefined( _k4918 ) )
  4253.     {
  4254.         player = _a4918[ _k4918 ];
  4255.         if ( player istouching( level.jail_cell_volume ) )
  4256.         {
  4257.             if ( !is_true( level.cell_open ) )
  4258.             {
  4259.                 level.sloth.open_jail = 1;
  4260.             }
  4261.         }
  4262.         _k4918 = getNextArrayKey( _a4918, _k4918 );
  4263.     }
  4264. }
  4265.  
  4266. sndchangebreathingstate( type1, type2 )
  4267. {
  4268.     self notify( "sndStateChange" );
  4269.     self endon( "sndStateChange" );
  4270.     alias = "zmb_ai_sloth_lp_" + type1;
  4271.     if ( isDefined( type2 ) )
  4272.     {
  4273.         if ( cointoss() )
  4274.         {
  4275.             alias = "zmb_ai_sloth_lp_" + type2;
  4276.         }
  4277.     }
  4278.     self.sndent stoploopsound( 0,75 );
  4279.     wait 0,75;
  4280.     self.sndent playloopsound( alias, 0,75 );
  4281. }
  4282.  
  4283. ignore_stop_func()
  4284. {
  4285.     if ( is_true( self.is_inert ) )
  4286.     {
  4287.         return 1;
  4288.     }
  4289.     return 0;
  4290. }
  4291.  
  4292. sloth_debug_axis()
  4293. {
  4294. /#
  4295.     self endon( "death" );
  4296.     if ( !isDefined( self.debug_axis ) )
  4297.     {
  4298.         org = self gettagorigin( "tag_weapon_right" );
  4299.         ang = self gettagangles( "tag_weapon_right" );
  4300.         self.debug_axis = spawn( "script_model", org );
  4301.         self.debug_axis.angles = ang;
  4302.         self.debug_axis setmodel( "fx_axis_createfx" );
  4303.         self.debug_axis linkto( self, "tag_weapon_right" );
  4304. #/
  4305.     }
  4306. }
  4307.  
  4308. sloth_debug_doors()
  4309. {
  4310. /#
  4311.     while ( 1 )
  4312.     {
  4313.         while ( is_true( level.sloth_debug_doors ) )
  4314.         {
  4315.             _a5004 = level.sloth_doors;
  4316.             _k5004 = getFirstArrayKey( _a5004 );
  4317.             while ( isDefined( _k5004 ) )
  4318.             {
  4319.                 door = _a5004[ _k5004 ];
  4320.                 debugstar( door.origin, 100, ( 0, 1, 0 ) );
  4321.                 circle( door.origin, 120, ( 0, 1, 0 ), 0, 1, 100 );
  4322.                 _k5004 = getNextArrayKey( _a5004, _k5004 );
  4323.             }
  4324.         }
  4325.         wait 1;
  4326. #/
  4327.     }
  4328. }
  4329.  
  4330. sloth_debug_buildables()
  4331. {
  4332. /#
  4333.     while ( 1 )
  4334.     {
  4335.         if ( is_true( level.sloth_debug_buildables ) )
  4336.         {
  4337.             if ( !isDefined( self.buildable_model ) )
  4338.             {
  4339.                 tag_name = "tag_stowed_back";
  4340.                 twr_origin = self gettagorigin( tag_name );
  4341.                 twr_angles = self gettagangles( tag_name );
  4342.                 self.devgui_buildable = 1;
  4343.                 self.buildable_model = spawn( "script_model", twr_origin );
  4344.                 self.buildable_model.angles = twr_angles;
  4345.                 self.buildable_model setmodel( level.small_turbine );
  4346.                 self.buildable_model linkto( self, tag_name );
  4347.             }
  4348.             _a5039 = level.sloth_buildable_zones;
  4349.             _k5039 = getFirstArrayKey( _a5039 );
  4350.             while ( isDefined( _k5039 ) )
  4351.             {
  4352.                 zone = _a5039[ _k5039 ];
  4353.                 debugstar( zone.stub.origin, 100, ( 0, 1, 0 ) );
  4354.                 _k5039 = getNextArrayKey( _a5039, _k5039 );
  4355.             }
  4356.         }
  4357.         else if ( is_true( self.devgui_buildable ) )
  4358.         {
  4359.             self.devgui_buildable = 0;
  4360.             if ( isDefined( self.buildable_model ) )
  4361.             {
  4362.                 self.buildable_model unlink();
  4363.                 self.buildable_model delete();
  4364.             }
  4365.         }
  4366.         wait 1;
  4367. #/
  4368.     }
  4369. }
  4370.  
  4371. sloth_debug_input()
  4372. {
  4373. /#
  4374.     level.player_candy = 0;
  4375.     wait 2;
  4376.     while ( 1 )
  4377.     {
  4378.         while ( !getDvarInt( #"B6252E7C" ) )
  4379.         {
  4380.             wait 0,2;
  4381.         }
  4382.         twr_origin = self gettagorigin( "tag_weapon_right" );
  4383.         debugstar( twr_origin, 6, ( 0, 1, 0 ) );
  4384.         player = get_players()[ 0 ];
  4385.         if ( player actionslotonebuttonpressed() )
  4386.         {
  4387.         }
  4388.         else if ( player actionslottwobuttonpressed() )
  4389.         {
  4390.         }
  4391.         else if ( player actionslotthreebuttonpressed() )
  4392.         {
  4393.         }
  4394.         else
  4395.         {
  4396.             if ( player actionslotfourbuttonpressed() )
  4397.             {
  4398.             }
  4399.         }
  4400.         wait 0,1;
  4401. #/
  4402.     }
  4403. }
  4404.  
  4405. sloth_devgui_teleport()
  4406. {
  4407. /#
  4408.     sloth = level.sloth;
  4409.     if ( isDefined( sloth ) )
  4410.     {
  4411.         player = gethostplayer();
  4412.         direction = player getplayerangles();
  4413.         direction_vec = anglesToForward( direction );
  4414.         eye = player geteye();
  4415.         scale = 8000;
  4416.         direction_vec = ( direction_vec[ 0 ] * scale, direction_vec[ 1 ] * scale, direction_vec[ 2 ] * scale );
  4417.         trace = bullettrace( eye, eye + direction_vec, 0, undefined );
  4418.         if ( sloth.state == "jail_idle" )
  4419.         {
  4420.             maps/mp/zombies/_zm_unitrigger::register_unitrigger( sloth.gift_trigger, ::maps/mp/zombies/_zm_buildables::buildable_place_think );
  4421.             level.devgui_break = 1;
  4422.             level.jail_barricade notify( "trigger" );
  4423.         }
  4424.         sloth forceteleport( trace[ "position" ] );
  4425.         sloth.got_booze = 1;
  4426.         level notify( "cell_open" );
  4427.         if ( sloth.state != "context" )
  4428.         {
  4429.             sloth stop_action();
  4430.             sloth sloth_set_state( "roam" );
  4431. #/
  4432.         }
  4433.     }
  4434. }
  4435.  
  4436. sloth_devgui_barricade()
  4437. {
  4438. /#
  4439.     player = gethostplayer();
  4440.     direction = player getplayerangles();
  4441.     direction_vec = anglesToForward( direction );
  4442.     eye = player geteye();
  4443.     scale = 8000;
  4444.     direction_vec = ( direction_vec[ 0 ] * scale, direction_vec[ 1 ] * scale, direction_vec[ 2 ] * scale );
  4445.     trace = bullettrace( eye, eye + direction_vec, 0, undefined );
  4446.     pos = trace[ "position" ];
  4447.     closest = 0;
  4448.     triggers = getentarray( "sloth_barricade", "targetname" );
  4449.     i = 0;
  4450.     while ( i < triggers.size )
  4451.     {
  4452.         trigger = triggers[ i ];
  4453.         dist = distancesquared( trigger.origin, pos );
  4454.         if ( i == 0 )
  4455.         {
  4456.             dist_max = dist;
  4457.             i++;
  4458.             continue;
  4459.         }
  4460.         else
  4461.         {
  4462.             if ( dist < dist_max )
  4463.             {
  4464.                 closest = i;
  4465.                 dist_max = dist;
  4466.             }
  4467.         }
  4468.         i++;
  4469.     }
  4470.     level.devgui_break = 1;
  4471.     triggers[ closest ] notify( "trigger" );
  4472. #/
  4473. }
  4474.  
  4475. sloth_devgui_context()
  4476. {
  4477. /#
  4478.     sloth = level.sloth;
  4479.     if ( isDefined( sloth ) )
  4480.     {
  4481.         sloth.context_debug = 1;
  4482.         sloth check_contextual_actions();
  4483. #/
  4484.     }
  4485. }
  4486.  
  4487. sloth_devgui_booze()
  4488. {
  4489. /#
  4490.     sloth = level.sloth;
  4491.     if ( isDefined( sloth ) )
  4492.     {
  4493.         player = gethostplayer();
  4494.         sloth stop_action();
  4495.         sloth sloth_set_state( "berserk", player );
  4496. #/
  4497.     }
  4498. }
  4499.  
  4500. sloth_devgui_candy()
  4501. {
  4502. /#
  4503.     sloth = level.sloth;
  4504.     if ( isDefined( sloth ) )
  4505.     {
  4506.         player = gethostplayer();
  4507.         sloth stop_action();
  4508.         sloth sloth_set_state( "eat", player );
  4509. #/
  4510.     }
  4511. }
  4512.  
  4513. sloth_devgui_warp_to_jail()
  4514. {
  4515. /#
  4516.     player = gethostplayer();
  4517.     player setorigin( ( -1142, 557, 28 ) );
  4518.     player setplayerangles( vectorScale( ( 0, 1, 0 ), 90 ) );
  4519. #/
  4520. }
  4521.  
  4522. sloth_devgui_move_lamp()
  4523. {
  4524. /#
  4525.     level.oillamp maps/mp/zombies/_zm_buildables::piece_unspawn();
  4526.     level.oillamp maps/mp/zombies/_zm_buildables::piece_spawn_at();
  4527. #/
  4528. }
  4529.  
  4530. sloth_devgui_make_crawler()
  4531. {
  4532. /#
  4533.     zombies = get_round_enemy_array();
  4534.     _a5231 = zombies;
  4535.     _k5231 = getFirstArrayKey( _a5231 );
  4536.     while ( isDefined( _k5231 ) )
  4537.     {
  4538.         zombie = _a5231[ _k5231 ];
  4539.         gib_style = [];
  4540.         gib_style[ gib_style.size ] = "no_legs";
  4541.         gib_style[ gib_style.size ] = "right_leg";
  4542.         gib_style[ gib_style.size ] = "left_leg";
  4543.         gib_style = array_randomize( gib_style );
  4544.         zombie.a.gib_ref = gib_style[ 0 ];
  4545.         zombie.has_legs = 0;
  4546.         zombie allowedstances( "crouch" );
  4547.         zombie setphysparams( 15, 0, 24 );
  4548.         zombie allowpitchangle( 1 );
  4549.         zombie setpitchorient();
  4550.         health = zombie.health;
  4551.         health *= 0,1;
  4552.         zombie thread maps/mp/animscripts/zm_run::needsdelayedupdate();
  4553.         zombie thread maps/mp/animscripts/zm_death::do_gib();
  4554.         _k5231 = getNextArrayKey( _a5231, _k5231 );
  4555. #/
  4556.     }
  4557. }
  4558.  
  4559. sloth_devgui_double_wide()
  4560. {
  4561. /#
  4562.     if ( getDvar( "zombie_double_wide_checks" ) == "1" )
  4563.     {
  4564.         setdvar( "zombie_double_wide_checks", 0 );
  4565.         iprintln( "double wide disabled" );
  4566.         level.devgui_double_wide = 0;
  4567.     }
  4568.     else
  4569.     {
  4570.         setdvar( "zombie_double_wide_checks", 1 );
  4571.         iprintln( "double wide enabled" );
  4572.         level.devgui_double_wide = 1;
  4573. #/
  4574.     }
  4575. }
  4576.  
  4577. sloth_devgui_update_phys_params()
  4578. {
  4579. /#
  4580.     while ( 1 )
  4581.     {
  4582.         devgui_width = getDvarInt( #"2443DFBB" );
  4583.         devgui_height = getDvarInt( #"897C9AB4" );
  4584.         if ( self.debug_width != devgui_width || self.debug_height != devgui_height )
  4585.         {
  4586.             self.debug_width = devgui_width;
  4587.             self.debug_height = devgui_height;
  4588.             self setphysparams( self.debug_width, 0, self.debug_height );
  4589.         }
  4590.         wait 0,2;
  4591. #/
  4592.     }
  4593. }
Advertisement
Add Comment
Please, Sign In to add comment