sr2lua/ss09.lua

  1. -- ss09.lua 
  2. -- SR2 mission script 
  3. -- 3/28/07 
  4.  
  5. -- Mission help table text tags 
  6.    HT_GO_TO_WAREHOUSE = "ss09_go_to_meatpacking_plant" 
  7.    HT_FIND_MR_SUNSHINE = "ss09_find_mr_sunshine" 
  8.    HT_KILL_MR_SUNSHINE = "ss09_kill_mr_sunshine" 
  9.    HT_MR_SUNSHINE_HEALTH = "ss09_sunshine_health_bar_label" 
  10.    HT_SHOOT_SUNSHINES_DOLL = "ss09_shoot_sunshines_doll" 
  11.  
  12. -- Mission states 
  13.    MS_GO_TO_WAREHOUSE = 1 
  14.    MS_ENTERED_WAREHOUSE_AREA = 2 
  15.    MS_ENTERED_WAREHOUSE = 3 
  16.    MS_REACHED_MR_SUNSHINE = 4 
  17.    MS_MR_SUNSHINE_FINAL_BATTLE = 6 
  18.  
  19. -- Groups, NPCs, vehicles, navpoints, and other names 
  20.    -- Mission constant names 
  21.    MISSION_NAME = "ss09" 
  22.    -- ( Mission Prefix ) 
  23.    MP = MISSION_NAME.."_$" 
  24.  
  25.    ENEMY_GANG = "Samedi" 
  26.  
  27.    -- Checkpoints 
  28.    CP_REACHED_WAREHOUSE_SIDE_1 = "Reached_Warehouse_Checkpoint_One" 
  29.    CP_REACHED_WAREHOUSE_SIDE_2 = "Reached_Warehouse_Checkpoint_Two" 
  30.    CP_REACHED_MR_SUNSHINE = "Reached_Mr_Sunshine" 
  31.  
  32.    -- Weapons 
  33.    SUNSHINE_RANGED_WEAPON = "ak47" 
  34.    SUNSHINE_MELEE_WEAPON = "machete" 
  35.  
  36.    -- Groups 
  37.    STARTER_CAR_GROUP = MP.."Starter_Car" 
  38.    STARTER_CAR_COOP_GROUP = MP.."Starter_Car_Coop" 
  39.    OUTSIDE_DEFENDERS_GROUP = MP.."Outside_Defenders" 
  40.    AMBIENT_CARS_GROUP = MP.."Ambient_Cars" 
  41.    MEATPACKING_PLANT_DEFENDERS = MP.."Plant_Defenders" 
  42.    MR_SUNSHINE_GROUP = MP.."Mr_Sunshine" 
  43.    MR_SUNSHINE_DEFENDERS_GROUP = MP.."Mr_Sunshine_Defenders" 
  44.    MR_SUNSHINE_REINFORCEMENTS_GROUP = MP.."Mr_Sunshine_Reinforcements" 
  45.    EXTRA_AMMO_GROUP = MP.."Extra_Ammo" 
  46.  
  47.    VOODOO_DOLL_GROUP = MP.."Voodoo_Doll" 
  48.  
  49.    -- NPC names 
  50.    OUTSIDE_DEFENDERS = { MP.."OD01", MP.."OD02", MP.."OD03", MP.."OD04", MP.."OD05", MP.."OD06", 
  51.                          MP.."OD07", MP.."OD08", MP.."OD09", MP.."OD10", MP.."OD11" } 
  52.  
  53.    OUTSIDE_DEFENDERS_TO_UNLEASH = { OUTSIDE_DEFENDERS[9], OUTSIDE_DEFENDERS[10], OUTSIDE_DEFENDERS[11] } 
  54.  
  55.    PLANT_DEFENDER_ASSAULTERS = { MP.."PD_Charge1", MP.."PD_Charge2" } 
  56.  
  57.    PLANT_DEFENDERS = { MP.."PD01", MP.."PD02", MP.."PD03", MP.."PD04", MP.."PD05", 
  58.                        MP.."PD06", MP.."PD07", MP.."PD08", MP.."PD09", MP.."PD10", 
  59.                        MP.."PD11", MP.."PD12" } 
  60.  
  61.    RUN_DOWNSTAIRS_GUY = PLANT_DEFENDERS[12] 
  62.  
  63.    SECOND_FLOOR_PLANT_DEFENDERS = { PLANT_DEFENDERS[6], PLANT_DEFENDERS[7], PLANT_DEFENDERS[8], 
  64.                                     PLANT_DEFENDERS[9], PLANT_DEFENDERS[10] } 
  65.  
  66.    MR_SUNSHINE_NAME = MP.."Mr_Sunshine" 
  67.  
  68.    WALKERS = { MP.."Walker01", MP.."Walker02" } 
  69.  
  70.    MR_SUNSHINE_DEFENDERS = { MP.."DF1", MP.."DF2", MP.."DF3", MP.."DF4" } 
  71.    MR_SUNSHINE_REINFORCEMENTS = { MP.."RF1", MP.."RF2", MP.."RFG", MP.."RF4", MP.."Downfall", MP.."SR3" } 
  72.  
  73.    MR_SUNSHINE_BODYGUARDS = { MP.."Sunshine_Bodyguard01", MP.."Sunshine_Bodyguard02" } 
  74.  
  75.    -- Vehicle names 
  76.  
  77.    -- Navpoints and paths 
  78.    WALKER_PATH = MP.."Walker_Path" 
  79.    LOCAL_PLAYER_START = MP.."Local_Player_Start" 
  80.    REMOTE_PLAYER_START = MP.."Remote_Player_Start" 
  81.    USE_VOODOO_ORIENT = MP.."Use_Voodoo_Orient" 
  82.    USE_VOODOO_LOCATION = MP.."Use_Voodoo" 
  83.  
  84.    USE_VOODOO_DIRECTION = MP.."Use_Voodoo_Direction" 
  85.    DOLL_FALL_START_LOCATION = MP.."Doll_Fall_Start" 
  86.  
  87.    INVINCIBLE_CANDLES_LOCATION = MP.."Invincible_Candles" 
  88.    SPARKING_LIGHTS_LOCATIONS = { MP.."Sparking_Light01", MP.."Sparking_Light02" } 
  89.  
  90.    PLANT_DEFENDER_ASSAULTERS_GOALS = { MP.."PD_Charge1_Goal", MP.."PD_Charge2_Goal" } 
  91.  
  92.    CHECKPOINT_WARP_LOCATIONS = { [CP_REACHED_WAREHOUSE_SIDE_1] = { [LOCAL_PLAYER] = MP.."Side1_Warp_Location_Local", [REMOTE_PLAYER] = MP.."Side1_Warp_Location_Remote" }, 
  93.                                  [CP_REACHED_WAREHOUSE_SIDE_2] = { [LOCAL_PLAYER] = MP.."Side2_Warp_Location_Local", [REMOTE_PLAYER] = MP.."Side2_Warp_Location_Remote" } } 
  94.  
  95.    SUNSHINE_BODYGUARD_PATHS = { MP.."Bodyguard1_Path", MP.."Bodyguard2_Path" } 
  96.  
  97.    SUNSHINE_TO_DOLL_PATHS = { MP.."To_Doll_01", MP.."To_Doll_02", MP.."To_Doll_03" } 
  98.    SUNSHINE_BACK_TO_TOP_PLATFORM_PATH = MP.."Back_to_Top_Platform" 
  99.  
  100.    MR_SUNSHINE_REINFORCEMENTS_GOALS = { MP.."RF1_Goal", MP.."RF2_Goal", MP.."RFG_Goal", MP.."RF4_Goal", MP.."Downfall_Goal", MP.."SR3_Goal" } 
  101.  
  102.    RUN_DOWNSTAIRS_GUY_GOAL = MP.."PD12_Goal" 
  103.  
  104.    POST_CT_WARP_POINTS = { [LOCAL_PLAYER] = MP.."Local_Post_CT_Warp", 
  105.                            [REMOTE_PLAYER] = MP.."Remote_Post_CT_Warp" } 
  106.  
  107.    -- Triggers 
  108.    NEAR_WAREHOUSE_TRIGGERS = { MP.."Near_Warehouse01", MP.."Near_Warehouse02" } 
  109.    WAREHOUSE_ENTRANCE_TRIGGER = MP.."Warehouse_Entrance" 
  110.    WALKER_TRIGGER = MP.."Walker_Trigger" 
  111.    MR_SUNSHINE_FIGHT_ENTRANCE_TRIGGER = MP.."Mr_Sunshine_Fight_Entrance" 
  112.    MR_SUNSHINES_PLATFORM_TRIGGER = MP.."Top_Platform" 
  113.  
  114.    -- Movers 
  115.    SUNSHINE_DOOR = MP.."Sunshine_Door" 
  116.  
  117.    -- Effects and animation states 
  118.    STAB_VOODOO_DOLL = "use voodoo" 
  119.    VOODOO_DOLL_KNOCKED_AWAY_FLINCH = "flinch bullet back" 
  120.    VOODOO_DOLL_FALL = "SS_doll_drop" 
  121.    INVINCIBLE_CANDLES_EFFECT = "SS_candles_invulnerable" 
  122.    USE_VOODOO_EFFECT = "SS_underglow" 
  123.    SPARKING_LIGHT_EFFECTS = { "Light_elec_spark", "Light_elec_spark02" } 
  124.  
  125.    -- Cutscene names 
  126.    USE_DOLL_CUTSCENE = "ig_ss09_scene1" 
  127.    WALK_UP_AND_USE_DOLL_CUTSCENE = "ig_ss09_scene2" 
  128.    CT_INTRO = "ss09-01" 
  129.    CT_OUTRO = "ss09-02" 
  130. -- Sound 
  131.    -- Persona overrides 
  132.    MR_SUNSHINE_PERSONA_OVERRIDES = 
  133.    { 
  134.    { "threat - alert (solo attack)", "SOS09_SUNSHINE_ATTACK" }, 
  135.    { "threat - alert (group attack)", "SOS09_SUNSHINE_ATTACK" }, 
  136.    { "threat - damage received (firearm)", "SOS09_SUNSHINE_TAKEDAM" }, 
  137.    { "threat - damage received (melee)", "SOS09_SUNSHINE_TAKEDAM" } 
  138.    } 
  139.  
  140.    -- Lines/Dialog Stream 
  141.    PLAYER_REACHES_TOP_PLATFORM_DIALOG_STREAM = 
  142.    { 
  143.    { "SUNSHINE_SOS9_ENTER_02", MR_SUNSHINE_NAME, 0 }, 
  144.    { "SOS9_STEPOFF_L2", MR_SUNSHINE_NAME, 0 } 
  145.  
  146.    } 
  147.  
  148.    SUNSHINE_USE_VOODOO_DOLL_LINES = "SOS09_SUNSHINE_USEDOLL" 
  149.    SUNSHINE_VOODOO_INTERRUPTED_LINES = "SUNSHINE_SOS9_VOODOO" 
  150.  
  151.    -- Sound effects 
  152.  
  153. -- Distances 
  154.    WANDER_RADIUS_METERS = 2.0 
  155.    SUNSHINE_MELEE_ATTACK_DIST = 5.0 
  156.  
  157. -- Percents and multipliers 
  158.    MR_SUNSHINE_HP_MULTIPLIER = 6 
  159.    VOODOO_DOLL_DAMAGE_PERCENT = .05 
  160.    SUNSHINE_RECOVER_PERCENT = .1 
  161.    RAGDOLL_DAMAGE_MODIFIER = 0.25 
  162.  
  163. -- Time values 
  164.    BEFORE_DISABLE_VOODOO_ATTACK_ALLOWED_SECONDS = 1 
  165.    VOODOO_ATTACK_BEFORE_EFFECT_SECONDS = 5.5 
  166.    MR_SUNSHINE_VOODOO_ATTACK_INTERVAL_SECONDS = 15 
  167.    MR_SUNSHINE_VOODOO_ATTACK_INTERVAL_WHEN_HIDING_SECONDS = 25 
  168.    THROUGH_WAREHOUSE_VOODOO_RAGDOLL_MS = 2000 
  169.    THROUGH_WAREHOUSE_VOODOO_RAGDOLL_MS_COOP = 4000 
  170.    VOODOO_RAGDOLL_MS = 2000 
  171.    REINFORCEMENTS_DELAY_SECONDS = 4.0 
  172.    MR_SUNSHINE_MIN_COVER_DELAY_SECONDS = 3.0 
  173.    MR_SUNSHINE_MAX_COVER_DELAY_SECONDS = 5.0 
  174.  
  175.    MR_SUNSHINE_PICK_UP_DOLL_SECONDS = 4 
  176.    POST_DOLL_RETRIEVAL_RESUME_VOODOO_ATTACK_DELAY_SECONDS = 30.0 - MR_SUNSHINE_VOODOO_ATTACK_INTERVAL_SECONDS 
  177.  
  178.    MR_SUNSHINE_FIRST_VOODOO_ATTACK_DELAY = MR_SUNSHINE_VOODOO_ATTACK_INTERVAL_SECONDS - 5 
  179.  
  180.    -- How long Mr. Sunshine attacks in melee when he does 
  181.    SUNSHINE_MELEE_ATTACK_DURATION_SECONDS = 5 
  182.    -- Once Mr. Sunshine does a melee attack, how long before he 
  183.    -- can do it again 
  184.    SUNSHINE_BETWEEN_MELEE_ATTACKS_DURATION_SECONDS = 10 
  185.    -- How often the game checks to see if Mr. Sunshine should do a 
  186.    -- melee attack 
  187.    SUNSHINE_MELEE_UPDATE_SECONDS = 1 
  188.  
  189.    THROUGH_THE_WAREHOUSE_VOODOO_ATTACK_INTERVAL_SECONDS = 15.0 
  190.    THROUGH_THE_WAREHOUSE_VOODOO_ATTACK_INTERVAL_COOP_SECONDS = 12.00 
  191.  
  192. -- Speeds 
  193.    VOODOO_RAGDOLL_PUSH_SPEED_MPS = 10 
  194.  
  195. -- Constant values and counts 
  196.    MIN_NOTORIETY_LEVEL = 5 
  197.    OUTSIDE_DEFENDERS_REMAINING_UNLEASH_THRESHOLD = sizeof_table( OUTSIDE_DEFENDERS ) - 2 
  198.    FAKE_NOTORIETY_LEVEL = 4 
  199.    SECOND_FLOOR_DEFENDER_THRESHOLD = 2 
  200.    MR_SUNSHINE_DEFENDERS_RESPAWN_THRESHOLD = 2 
  201.  
  202. -- Global variables 
  203.    Players_making_way_through_warehouse = false 
  204.  
  205.    Players_on_top_platform = { [LOCAL_PLAYER] = false, [REMOTE_PLAYER] = false } 
  206.    Mr_Sunshine_defender_count = 0 
  207.    Mr_Sunshine_voodoo_attack_thread_handle = INVALID_THREAD_HANDLE 
  208.    Mr_Sunshine_voodoo_attack_loop_thread_handle = INVALID_THREAD_HANDLE 
  209.    Mr_Sunshine_melee_attack_loop_thread_handle = INVALID_THREAD_HANDLE 
  210.    Mr_Sunshine_running_downstairs_thread_handle = INVALID_THREAD_HANDLE 
  211.  
  212.    Mr_Sunshine_approaching_voodoo_location = false 
  213.    Mr_Sunshine_doing_voodoo_attack = false 
  214.  
  215.    Mr_Sunshine_has_voodooed_once = false 
  216.    Mr_Sunshine_finished_running = false 
  217.    Mr_Sunshine_running_directly_downstairs = false 
  218.  
  219.    Player_shot_voodoo_doll = false 
  220.    Shoot_objective_given = false 
  221.  
  222.    Second_floor_defenders_remaining = sizeof_table( SECOND_FLOOR_PLANT_DEFENDERS ) 
  223.  
  224.    Outside_defenders_remaining = sizeof_table( OUTSIDE_DEFENDERS ) 
  225.  
  226.    Invincible_effect_handle = -1 
  227.    Use_voodoo_glow_handle = -1 
  228.    Sparking_lights_effect_handles = { -1 } 
  229.    Percent_damage_done_this_run = 0 
  230. 	Controls_disabled = false 
  231.  
  232. function ss09_either_player_on_top_platform() 
  233.    if ( Players_on_top_platform[LOCAL_PLAYER] or Players_on_top_platform[REMOTE_PLAYER] ) then 
  234.       return true 
  235.    end 
  236.    return false 
  237. end 
  238.  
  239. function ss09_sunshine_melee_attack_loop() 
  240.    while ( true ) do 
  241.       local dist, player = get_dist_closest_player_to_object( MR_SUNSHINE_NAME ) 
  242.       if ( dist < SUNSHINE_MELEE_ATTACK_DIST and 
  243.            ss09_mr_sunshine_not_doing_voodoo() ) then 
  244.          inv_item_remove_all( MR_SUNSHINE_NAME ) 
  245.          inv_item_add( SUNSHINE_MELEE_WEAPON, 1, MR_SUNSHINE_NAME ) 
  246.          inv_item_equip( SUNSHINE_MELEE_WEAPON, MR_SUNSHINE_NAME ) 
  247.  
  248.          attack_safe( MR_SUNSHINE_NAME, player ) 
  249.          delay( SUNSHINE_MELEE_ATTACK_DURATION_SECONDS ) 
  250.  
  251.          inv_item_remove_all( MR_SUNSHINE_NAME ) 
  252.          inv_item_add( SUNSHINE_RANGED_WEAPON, 1, MR_SUNSHINE_NAME ) 
  253.          inv_item_equip( SUNSHINE_RANGED_WEAPON, MR_SUNSHINE_NAME ) 
  254.          attack_safe( MR_SUNSHINE_NAME, player ) 
  255.  
  256.          delay( SUNSHINE_BETWEEN_MELEE_ATTACKS_DURATION_SECONDS ) 
  257.       else 
  258.          delay( SUNSHINE_MELEE_UPDATE_SECONDS ) 
  259.       end 
  260.    end 
  261. end 
  262.  
  263. function ss09_no_players_on_top_platform() 
  264.    if ( Players_on_top_platform[LOCAL_PLAYER] == false and 
  265.         Players_on_top_platform[REMOTE_PLAYER] == false ) then 
  266.       return true 
  267.    end 
  268.    return false 
  269. end 
  270.  
  271. function ss09_start( checkpoint_name, is_restart ) 
  272.    -- Start trigger is hit...the activate button was hit 
  273.    set_mission_author("Mark Gabby and Brad Johnson") 
  274.  
  275.    persona_override_group_start( SAMEDI_PERSONAS, POT_SITUATIONS[POT_ATTACK], "SS09_ATTACK" ) 
  276.  
  277.    mission_start_fade_out() 
  278.    
  279. 	if ( checkpoint_name == MISSION_START_CHECKPOINT ) then 
  280. 		-- The starter groups are this in single player 
  281. 		local start_groups = { STARTER_CAR_GROUP, OUTSIDE_DEFENDERS_GROUP, AMBIENT_CARS_GROUP } 
  282. 		-- If we're running in coop, append an extra group to the end 
  283. 		if ( coop_is_active() ) then 
  284. 			start_groups = { STARTER_CAR_GROUP, OUTSIDE_DEFENDERS_GROUP, AMBIENT_CARS_GROUP, STARTER_CAR_COOP_GROUP } 
  285. 		end 
  286. 		if (not is_restart) then 
  287. 			cutscene_play( CT_INTRO, start_groups, { LOCAL_PLAYER_START, REMOTE_PLAYER_START }, false ) 
  288. 			for index, group_name in pairs( start_groups ) do 
  289. 				group_show( group_name ) 
  290. 			end 
  291. 		else 
  292. 			for index, group_name in pairs( start_groups ) do 
  293. 				group_create( group_name, true ) 
  294. 			end 
  295.  
  296. 			-- Teleport after group creation to improve loading times 
  297. 			teleport_coop( LOCAL_PLAYER_START, REMOTE_PLAYER_START ) 
  298. 		end 
  299.    end 
  300.  
  301. 	local next_state = "Puerto Rico" 
  302.    local extra_data 
  303.    local actor_name 
  304.  
  305.    if ( checkpoint_name == MISSION_START_CHECKPOINT ) then 
  306.       next_state = MS_GO_TO_WAREHOUSE 
  307.    elseif ( checkpoint_name == CP_REACHED_WAREHOUSE_SIDE_1 or 
  308.             checkpoint_name == CP_REACHED_WAREHOUSE_SIDE_2 ) then 
  309.       group_create( OUTSIDE_DEFENDERS_GROUP, true ) 
  310.       group_create( AMBIENT_CARS_GROUP, true ) 
  311.  
  312.       group_create_hidden( MEATPACKING_PLANT_DEFENDERS, true ) 
  313.       group_create_hidden( MR_SUNSHINE_DEFENDERS_GROUP, true ) 
  314.  
  315.       teleport_coop( CHECKPOINT_WARP_LOCATIONS[checkpoint_name][LOCAL_PLAYER], 
  316.                      CHECKPOINT_WARP_LOCATIONS[checkpoint_name][REMOTE_PLAYER] ) 
  317.  
  318.       next_state = MS_ENTERED_WAREHOUSE_AREA 
  319.    elseif ( checkpoint_name == CP_REACHED_MR_SUNSHINE ) then 
  320.       group_create( MR_SUNSHINE_GROUP, true ) 
  321.       group_create( MR_SUNSHINE_DEFENDERS_GROUP, true ) 
  322.  
  323.       teleport( MR_SUNSHINE_NAME, USE_VOODOO_LOCATION ) 
  324.       mesh_mover_play_action( SUNSHINE_DOOR, "start1") 
  325. 		character_ragdoll( LOCAL_PLAYER, VOODOO_RAGDOLL_MS ) 
  326. 		if ( coop_is_active() ) then 
  327. 			character_ragdoll( REMOTE_PLAYER, VOODOO_RAGDOLL_MS ) 
  328. 		end 
  329.  
  330.       next_state = MS_REACHED_MR_SUNSHINE 
  331.       extra_data = true 
  332.    end 
  333.  
  334.    -- No need for guidance to the warehouse if we've already reached Mr. Sunshine. 
  335.    if ( checkpoint_name ~= CP_REACHED_MR_SUNSHINE ) then 
  336.       trigger_enable( WAREHOUSE_ENTRANCE_TRIGGER, true ) 
  337.       on_trigger( "ss09_reached_warehouse_entrance", WAREHOUSE_ENTRANCE_TRIGGER ) 
  338.       marker_add_trigger( WAREHOUSE_ENTRANCE_TRIGGER, MINIMAP_ICON_LOCATION, INGAME_EFFECT_LOCATION, SYNC_ALL ) 
  339.       waypoint_add( WAREHOUSE_ENTRANCE_TRIGGER, SYNC_ALL ) 
  340.    end 
  341.  
  342.    mission_start_fade_in() 
  343.  
  344.    group_create_hidden( VOODOO_DOLL_GROUP ) 
  345. 	if ( checkpoint_name == MISSION_START_CHECKPOINT ) then 
  346.       -- Create all the other groups, but create them hidden 
  347.       group_create_hidden( MEATPACKING_PLANT_DEFENDERS ) 
  348.       group_create_hidden( MR_SUNSHINE_DEFENDERS_GROUP ) 
  349. 	end 
  350.  
  351.    ss09_switch_state( next_state, actor_name, extra_data ) 
  352. end 
  353.  
  354. function ss09_player_damaged_in_ragdoll( attacked_object_name, attacker_name, percent_hp_remaining_after_attack ) 
  355.    -- Find the current health percent 
  356.    local cur_health_percent = get_current_hit_points( attacked_object_name ) / get_max_hit_points( attacked_object_name ) 
  357.    -- Find out the percent damage 
  358.    local damage_percent = cur_health_percent - percent_hp_remaining_after_attack 
  359.  
  360.    -- Reduce the percent damage 
  361.    local new_damage_percent = damage_percent * RAGDOLL_DAMAGE_MODIFIER 
  362.    -- Find a new percent remaining 
  363.    local new_percent_remaining = cur_health_percent - new_damage_percent 
  364.  
  365.    -- Using the new percent remaining to find the number of hit points this thingy should have 
  366.    local new_hit_points = get_max_hit_points( attacked_object_name ) * new_percent_remaining 
  367.  
  368.    if ( new_hit_points > 0 ) then 
  369.       set_current_hit_points( attacked_object_name, new_hit_points ) 
  370.    else 
  371.       character_kill( attacked_object_name ) 
  372.    end 
  373. end 
  374.  
  375. function ss09_do_in_warehouse_ragdoll() 
  376.    local player_to_ragdoll = LOCAL_PLAYER 
  377.  
  378.    local time_to_ragdoll_ms = THROUGH_WAREHOUSE_VOODOO_RAGDOLL_MS 
  379.    local delay_between_ragdoll_attacks_seconds = THROUGH_THE_WAREHOUSE_VOODOO_ATTACK_INTERVAL_SECONDS 
  380.    if ( coop_is_active() ) then 
  381.       time_to_ragdoll_ms = THROUGH_WAREHOUSE_VOODOO_RAGDOLL_MS_COOP 
  382.       delay_between_ragdoll_attacks_seconds = THROUGH_THE_WAREHOUSE_VOODOO_ATTACK_INTERVAL_COOP_SECONDS 
  383.    end 
  384.  
  385.    while( Players_making_way_through_warehouse ) do 
  386.       -- Dampen player damage while in ragdoll mode 
  387.       turn_invulnerable( player_to_ragdoll ) 
  388.       on_take_damage( "ss09_player_damaged_in_ragdoll", player_to_ragdoll ) 
  389.       character_ragdoll( player_to_ragdoll, time_to_ragdoll_ms, VOODOO_RAGDOLL_PUSH_SPEED_MPS ) 
  390.       mission_debug( "ragdolled "..player_to_ragdoll..", waiting "..time_to_ragdoll_ms.." milliseconds." ) 
  391.       delay( time_to_ragdoll_ms / 1000 ) 
  392.       -- Return player damage to normal after ragdolling 
  393.       turn_vulnerable( player_to_ragdoll ) 
  394.       on_take_damage( "", player_to_ragdoll ) 
  395.  
  396.       -- Switch between players in coop 
  397.       if ( coop_is_active() ) then 
  398.          if ( player_to_ragdoll == LOCAL_PLAYER ) then 
  399.             player_to_ragdoll = REMOTE_PLAYER 
  400.          else 
  401.             player_to_ragdoll = LOCAL_PLAYER 
  402.          end 
  403.       end 
  404.       mission_debug( "will ragdoll "..player_to_ragdoll..", waiting "..delay_between_ragdoll_attacks_seconds.." seconds." ) 
  405.       delay( delay_between_ragdoll_attacks_seconds ) 
  406.    end 
  407. end 
  408.  
  409. function ss09_outside_defender_killed() 
  410.    Outside_defenders_remaining = Outside_defenders_remaining - 1 
  411.  
  412.    if ( Outside_defenders_remaining == OUTSIDE_DEFENDERS_REMAINING_UNLEASH_THRESHOLD ) then 
  413.       for index, member_name in pairs( OUTSIDE_DEFENDERS_TO_UNLEASH ) do 
  414.          npc_leash_remove( member_name ) 
  415.       end 
  416.    end 
  417. end 
  418.  
  419. function ss09_plant_defender_charge( defender_name, goal_name ) 
  420.    move_to_safe( defender_name, goal_name, 2, false, true ) 
  421.  
  422.    local distance, closest_player = get_dist_closest_player_to_object( defender_name ) 
  423.  
  424.    npc_leash_to_nav( defender_name, goal_name, 2 ) 
  425.  
  426.    attack_safe( defender_name, closest_player ) 
  427.  
  428.    delay( 3.0 ) 
  429.    npc_leash_remove( defender_name ) 
  430. end 
  431.  
  432. -- Called to put the mission into a new state 
  433. -- 
  434. -- actor_name: May be nil. Relevant actor. 
  435. -- extra_data: For MS_REACHED_MR_SUNSHINE, true if this is a checkpoint 
  436. --             resume. 
  437. function ss09_switch_state( new_state, actor_name, extra_data ) 
  438.    -- Initial state- guide the player to the warehouse and set it up to be 
  439.    -- ready for his arrival 
  440.    if ( new_state == MS_GO_TO_WAREHOUSE ) then 
  441.       -- Have the outside defenders wander 
  442.       for index, member_name in pairs( OUTSIDE_DEFENDERS ) do 
  443.          on_death( "ss09_outside_defender_killed", member_name ) 
  444.          wander_start( member_name, member_name, WANDER_RADIUS_METERS ) 
  445.       end 
  446.  
  447.       -- Setup the near and entering warehouse triggers 
  448.       for trigger_index, trigger_name in pairs( NEAR_WAREHOUSE_TRIGGERS ) do 
  449.          trigger_enable( trigger_name, true ) 
  450.          on_trigger( "ss09_near_warehouse_side_"..trigger_index, trigger_name ) 
  451.       end 
  452.  
  453.       -- Guide the player to the warehouse 
  454.       mission_help_table( HT_GO_TO_WAREHOUSE, "", "", SYNC_ALL ) 
  455.       marker_add_trigger( WAREHOUSE_ENTRANCE_TRIGGER, MINIMAP_ICON_LOCATION, INGAME_EFFECT_LOCATION, SYNC_ALL ) 
  456.       waypoint_add( WAREHOUSE_ENTRANCE_TRIGGER, SYNC_ALL ) 
  457.  
  458.    -- The player has entered the warehouse's general area, have the outside 
  459.    -- defenders defend it 
  460.    elseif ( new_state == MS_ENTERED_WAREHOUSE_AREA ) then 
  461.       for index, name in pairs ( OUTSIDE_DEFENDERS ) do 
  462.          local distance, player = get_dist_closest_player_to_object( name ) 
  463.          attack_safe( name, player, false ) 
  464.       end 
  465.       notoriety_set_min( ENEMY_GANG, MIN_NOTORIETY_LEVEL ) 
  466.       notoriety_force_no_spawn( ENEMY_GANG, true ) 
  467.  
  468.    -- The player has entered the warehouse. 
  469.    -- Play the cutscene and then ready the interior defenders 
  470.    elseif ( new_state == MS_ENTERED_WAREHOUSE ) then 
  471.       --cutscene_play(  
  472.       Players_making_way_through_warehouse = true 
  473.       --thread_new( "ss09_do_in_warehouse_ragdoll" ) 
  474.  
  475.       -- Have the outside defenders all come and attack 
  476.       if ( group_is_loaded( OUTSIDE_DEFENDERS_GROUP ) ) then 
  477.          for index, name in pairs ( OUTSIDE_DEFENDERS ) do 
  478.             npc_leash_remove( name ) 
  479.             local distance, player = get_dist_closest_player_to_object( name ) 
  480.             attack_safe( name, player, false ) 
  481.          end 
  482.       end 
  483.  
  484.       -- Have two of the attackers charge the player and attack him from cover 
  485.       for index, member_name in pairs( PLANT_DEFENDER_ASSAULTERS ) do 
  486.          thread_new( "ss09_plant_defender_charge", member_name, 
  487.                      PLANT_DEFENDER_ASSAULTERS_GOALS[index] ) 
  488.       end 
  489.  
  490.       -- Let the player know that he's supposed to find Mr. Sunshine  
  491.       mission_help_table( HT_FIND_MR_SUNSHINE, "", "", SYNC_ALL ) 
  492.       waypoint_remove( SYNC_ALL ) 
  493.       group_show( MEATPACKING_PLANT_DEFENDERS ) 
  494.  
  495.       hud_set_fake_notoriety( ENEMY_GANG, true, FAKE_NOTORIETY_LEVEL ) 
  496.  
  497.       for index, member_name in pairs( PLANT_DEFENDERS ) do 
  498.          wander_start( member_name, member_name, WANDER_RADIUS_METERS ) 
  499.       end 
  500.  
  501.       for index, member_name in pairs( SECOND_FLOOR_PLANT_DEFENDERS ) do 
  502.          on_death( "ss09_second_floor_defender_died", member_name ) 
  503.       end 
  504.  
  505.       -- Setup some special-case triggers 
  506.       trigger_enable( WALKER_TRIGGER, true ) 
  507.       on_trigger( "ss09_walkers_walk", WALKER_TRIGGER ) 
  508.  
  509.       -- Set the transition trigger that triggers the next state 
  510.       trigger_enable( MR_SUNSHINE_FIGHT_ENTRANCE_TRIGGER, true ) 
  511.       on_trigger( "ss09_reached_mr_sunshine_fight_area", MR_SUNSHINE_FIGHT_ENTRANCE_TRIGGER ) 
  512.  
  513.       marker_add_navpoint( MR_SUNSHINE_NAME, MINIMAP_ICON_LOCATION, INGAME_EFFECT_LOCATION, SYNC_ALL ) 
  514.    elseif ( new_state == MS_REACHED_MR_SUNSHINE ) then 
  515.       Players_making_way_through_warehouse = false 
  516.  
  517.       local resuming_from_checkpoint = extra_data 
  518.       if ( not resuming_from_checkpoint ) then 
  519.          marker_remove_navpoint( MR_SUNSHINE_NAME, SYNC_ALL ) 
  520.  
  521.          -- Play the cutscene 
  522.          player_controls_disable( LOCAL_PLAYER ) 
  523.          if ( coop_is_active() ) then 
  524.             player_controls_disable( REMOTE_PLAYER ) 
  525.          end 
  526. 			Controls_disabled = true 
  527.          delay( 0.1 ) 
  528.          cutscene_play( WALK_UP_AND_USE_DOLL_CUTSCENE, "", { POST_CT_WARP_POINTS[LOCAL_PLAYER], POST_CT_WARP_POINTS[REMOTE_PLAYER] }, false ) 
  529. 			mesh_mover_play_action( SUNSHINE_DOOR, "start1") 
  530.          -- Show the groups 
  531. 			group_create( MR_SUNSHINE_GROUP, true ) 
  532.          group_show( MR_SUNSHINE_DEFENDERS_GROUP ) 
  533.  
  534. 			-- In case the cutscene was skipped 
  535.          teleport( MR_SUNSHINE_NAME, USE_VOODOO_LOCATION ) 
  536.          character_ragdoll( LOCAL_PLAYER, VOODOO_RAGDOLL_MS ) 
  537.          if ( coop_is_active() ) then 
  538.             character_ragdoll( REMOTE_PLAYER, VOODOO_RAGDOLL_MS ) 
  539.          end 
  540.          player_controls_enable( LOCAL_PLAYER ) 
  541.          if ( coop_is_active() ) then 
  542.             player_controls_enable( REMOTE_PLAYER ) 
  543.          end 
  544. 			Controls_disabled = false 
  545. 			fade_in( 1.0 ) 
  546. 			fade_in_block() 
  547.  
  548.          mission_set_checkpoint( CP_REACHED_MR_SUNSHINE ) 
  549.       else 
  550. 	      notoriety_set_min( ENEMY_GANG, MIN_NOTORIETY_LEVEL ) 
  551. 		   notoriety_force_no_spawn( ENEMY_GANG, true ) 
  552. 		end 
  553.  
  554.       mission_help_table( HT_KILL_MR_SUNSHINE, "", "", SYNC_ALL ) 
  555.  
  556.       -- Setup Mr. Sunshine 
  557.       ss09_start_invincible_effects() 
  558.       turn_invulnerable( MR_SUNSHINE_NAME ) 
  559.       -- Boss is too easy if you can ragdoll him 
  560.       character_prevent_flinching( MR_SUNSHINE_NAME, true ) 
  561.       character_prevent_explosion_fling( MR_SUNSHINE_NAME, true ) 
  562.       character_prevent_kneecapping( MR_SUNSHINE_NAME, true ) 
  563.       character_allow_ragdoll( MR_SUNSHINE_NAME, false ) 
  564.  
  565.       on_death( "ss09_mr_sunshine_killed", MR_SUNSHINE_NAME ) 
  566.  
  567.       local sunshine_hit_points = get_max_hit_points( LOCAL_PLAYER ) * MR_SUNSHINE_HP_MULTIPLIER 
  568.       set_max_hit_points( MR_SUNSHINE_NAME, sunshine_hit_points ) 
  569.       set_current_hit_points( MR_SUNSHINE_NAME, sunshine_hit_points ) 
  570.       marker_add_npc( MR_SUNSHINE_NAME, MINIMAP_ICON_KILL, "", SYNC_ALL ) 
  571.  
  572.       damage_indicator_on( 0, MR_SUNSHINE_NAME, 0, HT_MR_SUNSHINE_HEALTH, sunshine_hit_points ) 
  573.  
  574.       Mr_Sunshine_defender_count = 4 
  575.       for index, name in pairs( MR_SUNSHINE_DEFENDERS ) do 
  576.          on_death( "ss09_sunshine_defender_died", name ) 
  577.       end 
  578.  
  579.       local dist, player = get_dist_closest_player_to_object( MR_SUNSHINE_NAME ) 
  580.       attack_safe( MR_SUNSHINE_NAME, player ) 
  581.  
  582.       Mr_Sunshine_voodoo_attack_loop_thread_handle = thread_new( "ss09_mr_sunshine_voodoo_attack_loop" ) 
  583.       for index, name in pairs( MR_SUNSHINE_BODYGUARDS ) do 
  584.          thread_new( "ss09_bodyguard_do_defense", name, SUNSHINE_BODYGUARD_PATHS[index] ) 
  585.       end 
  586.  
  587.       for index, override in pairs( MR_SUNSHINE_PERSONA_OVERRIDES ) do 
  588.          persona_override_character_start( MR_SUNSHINE_NAME, override[1], override[2] ) 
  589.       end 
  590.  
  591.       group_create( EXTRA_AMMO_GROUP ) 
  592.    elseif ( new_state == MS_MR_SUNSHINE_FINAL_BATTLE ) then 
  593.    end 
  594. end 
  595.  
  596. function ss09_start_invincible_effects() 
  597.    if ( Invincible_effect_handle == -1 ) then 
  598.       -- looping = true 
  599.       Invincible_effect_handle = effect_play( INVINCIBLE_CANDLES_EFFECT, INVINCIBLE_CANDLES_LOCATION, true ) 
  600.    end 
  601. end 
  602.  
  603. function ss09_stop_invincible_effects() 
  604.    if ( Invincible_effect_handle ~= -1 ) then 
  605.       effect_stop( Invincible_effect_handle ) 
  606.       Invincible_effect_handle = -1 
  607.    end 
  608. end 
  609.  
  610. -- Causes the bodyguard to path to the location specified and then attack the closest player. 
  611. -- 
  612. -- bodyguard_name: Name of the bodyguard to do the path. 
  613. -- path_name: Name of the path to path along. 
  614. -- 
  615. function ss09_bodyguard_do_defense( bodyguard_name, path_name ) 
  616.    move_to_safe( bodyguard_name, path_name, 2, true, true ) 
  617.  
  618.    local dist, player = get_dist_closest_player_to_object( MR_SUNSHINE_NAME ) 
  619.    attack_safe( bodyguard_name, player ) 
  620. end 
  621.  
  622. -- Callback when a player leaves the top platform. 
  623. -- If he's damaged enough, he needs to go into hiding. 
  624. -- 
  625. function ss09_left_top_platform( triggerer_name ) 
  626.    Players_on_top_platform[triggerer_name] = false 
  627.  
  628.    if ( ss09_no_players_on_top_platform() ) then 
  629.       if ( Mr_Sunshine_melee_attack_loop_thread_handle ~= INVALID_THREAD_HANDLE ) then 
  630.          thread_kill( Mr_Sunshine_melee_attack_loop_thread_handle ) 
  631.          Mr_Sunshine_melee_attack_loop_thread_handle = INVALID_THREAD_HANDLE 
  632.       end 
  633.    end 
  634. end 
  635.  
  636. function ss09_near_warehouse( triggerer_name ) 
  637.    for trigger_index, trigger_name in pairs( NEAR_WAREHOUSE_TRIGGERS ) do 
  638.       trigger_enable( trigger_name, false ) 
  639.    end 
  640.    ss09_switch_state( MS_ENTERED_WAREHOUSE_AREA, triggerer_name ) 
  641. end 
  642.  
  643. function ss09_near_warehouse_side_1( triggerer_name, trigger_name ) 
  644.    mission_set_checkpoint( CP_REACHED_WAREHOUSE_SIDE_1 ) 
  645.    ss09_near_warehouse( triggerer_name ) 
  646. end 
  647.  
  648. function ss09_near_warehouse_side_2( triggerer_name, trigger_name ) 
  649.    mission_set_checkpoint( CP_REACHED_WAREHOUSE_SIDE_2 ) 
  650.    ss09_near_warehouse( triggerer_name ) 
  651. end 
  652.  
  653. function ss09_reached_warehouse_entrance( triggerer_name, trigger_name ) 
  654.    trigger_enable( trigger_name, false ) 
  655.    ss09_switch_state( MS_ENTERED_WAREHOUSE ) 
  656. end 
  657.  
  658. function ss09_second_floor_defender_died() 
  659.    Second_floor_defenders_remaining = Second_floor_defenders_remaining - 1 
  660.    if ( Second_floor_defenders_remaining == ( SECOND_FLOOR_DEFENDER_THRESHOLD ) ) then 
  661.       -- retry on failure = true, move and fire = true 
  662.       npc_leash_remove( RUN_DOWNSTAIRS_GUY ) 
  663.       move_to( RUN_DOWNSTAIRS_GUY, RUN_DOWNSTAIRS_GUY_GOAL, 2, true, true ) 
  664.    end 
  665. end 
  666.  
  667. function ss09_walkers_walk() 
  668.    set_ignore_ai_flag( WALKERS[1], false ) 
  669.    set_ignore_ai_flag( WALKERS[2], false ) 
  670.  
  671.    thread_new( "ss09_walker01_walk" ) 
  672.    thread_new( "ss09_walker02_walk" ) 
  673. end 
  674.  
  675. function ss09_walker01_walk() 
  676.    move_to( WALKERS[1], WALKER_PATH, 1, true, false ) 
  677. end 
  678.  
  679. function ss09_walker02_walk() 
  680.    move_to( WALKERS[2], WALKER_PATH, 1, true, false ) 
  681. end 
  682.  
  683. function ss09_reached_mr_sunshine_fight_area( triggerer_name, trigger_name ) 
  684.    trigger_enable( trigger_name, false ) 
  685.    ss09_switch_state( MS_REACHED_MR_SUNSHINE ) 
  686. end 
  687.  
  688. function ss09_mr_sunshine_killed() 
  689.    character_allow_ragdoll( MR_SUNSHINE_NAME, true ) 
  690.    character_prevent_flinching( MR_SUNSHINE_NAME, false ) 
  691.    character_prevent_explosion_fling( MR_SUNSHINE_NAME, false ) 
  692.    character_prevent_kneecapping( MR_SUNSHINE_NAME, false ) 
  693.  
  694.    thread_kill( Mr_Sunshine_voodoo_attack_loop_thread_handle ) 
  695.  
  696.    mission_end_success( MISSION_NAME, CT_OUTRO, { POST_CT_WARP_POINTS[LOCAL_PLAYER], POST_CT_WARP_POINTS[REMOTE_PLAYER] } ) 
  697. end 
  698.  
  699. function ss09_mr_sunshine_voodoo_attack_loop() 
  700.    -- Mr. Sunshine does a voodoo attack every set number of seconds 
  701.    while( character_is_dead( MR_SUNSHINE_NAME ) == false ) do 
  702.       if ( Mr_Sunshine_has_voodooed_once == false ) then 
  703.          Mr_Sunshine_has_voodooed_once = true 
  704.          mission_debug( "mr sunshine first delay before next attack" ) 
  705.          delay( MR_SUNSHINE_FIRST_VOODOO_ATTACK_DELAY ) 
  706.       else 
  707.         mission_debug( "mr sunshine delay before next attack" ) 
  708.          delay( MR_SUNSHINE_VOODOO_ATTACK_INTERVAL_SECONDS ) 
  709.       end 
  710.  
  711.       mission_debug( "mr sunshine doing attack!" ) 
  712.       Mr_Sunshine_voodoo_attack_thread_handle = thread_new( "ss09_mr_sunshine_do_voodoo_attack" ) 
  713.       while ( thread_check_done( Mr_Sunshine_voodoo_attack_thread_handle ) == false ) do 
  714.          delay( 0 ) 
  715.       end 
  716.  
  717.       mission_debug( "mr sunshine did attack!" ) 
  718.    end 
  719. end 
  720.  
  721. function ss09_voodoo_doll_fall() 
  722.    -- Switch Mr. Sunshine into a different animation 
  723.    action_stop_custom( MR_SUNSHINE_NAME ) 
  724.    -- Play the voodoo doll falling effect 
  725.    -- looping = false 
  726.    effect_play( VOODOO_DOLL_FALL, DOLL_FALL_START_LOCATION, false ) 
  727.    -- Show the voodoo doll on the ground after the effect finishes 
  728.    group_show( VOODOO_DOLL_GROUP ) 
  729. end 
  730.  
  731. -- Function to track if Mr. Sunshine took damage when doing his 
  732. -- voodoo attack. If the damage was from an explosion, it knocks 
  733. -- his voodoo doll out of his hand. 
  734. -- 
  735. function ss09_sunshine_took_damage_during_voodoo( character_name, attacker_name, damage_percent_remaining, was_explosion ) 
  736.    if ( was_explosion ) then 
  737.       mission_debug( damage_percent_remaining.." percent life remaining." ) 
  738.       ss09_sunshine_hand_hit( character_name ) 
  739.    end 
  740. end 
  741.  
  742. function ss09_sunshine_hand_hit( character_name ) 
  743.    mission_debug( "You hit Mr. Sunshine's hand!", 10 ) 
  744.  
  745.    if ( Mr_Sunshine_voodoo_attack_thread_handle ~= INVALID_THREAD_HANDLE ) then 
  746.       ss09_abort_voodoo_attack() 
  747.       Player_shot_voodoo_doll = true 
  748.  
  749.       voodoo_glow_stop( MR_SUNSHINE_NAME ) 
  750.       effect_stop( Use_voodoo_glow_handle ) 
  751.       Use_voodoo_glow_handle = -1 
  752.       for index, handle in pairs( Sparking_lights_effect_handles ) do 
  753.          effect_stop( handle ) 
  754.          Sparking_lights_effect_handles[index] = -1 
  755.       end 
  756.  
  757.       action_play_non_blocking( MR_SUNSHINE_NAME, VOODOO_DOLL_KNOCKED_AWAY_FLINCH, nil, nil, true ) 
  758.  
  759.       thread_kill( Mr_Sunshine_voodoo_attack_loop_thread_handle ) 
  760.       Mr_Sunshine_voodoo_attack_loop_thread_handle = INVALID_THREAD_HANDLE 
  761.  
  762.       -- Unbind the callback 
  763.       on_character_right_hand_hit( "", character_name ) 
  764.       on_take_damage( "ss09_mr_sunshine_took_damage_while_running", MR_SUNSHINE_NAME ) 
  765.        
  766.       -- Have the Voodoo doll fall 
  767.       thread_new( "ss09_voodoo_doll_fall" ) 
  768.  
  769.       -- Make Mr. Sunshine vulnerable again 
  770.       ss09_stop_invincible_effects() 
  771.       if ( coop_is_active() == false ) then 
  772. 		turn_vulnerable( MR_SUNSHINE_NAME ) 
  773.       end 
  774.       character_prevent_flinching( MR_SUNSHINE_NAME, false ) 
  775.  
  776.       marker_remove_npc( MR_SUNSHINE_NAME, SYNC_ALL ) 
  777.       marker_add_npc( MR_SUNSHINE_NAME, MINIMAP_ICON_KILL, INGAME_EFFECT_KILL, SYNC_ALL ) 
  778.  
  779.       set_ignore_ai_flag( MR_SUNSHINE_NAME, false ) 
  780.       attack_closest_player( MR_SUNSHINE_NAME ) 
  781.  
  782.       Percent_damage_done_this_run = 0 
  783.       Mr_Sunshine_running_downstairs_thread_handle = thread_new( "ss09_mr_sunshine_run_downstairs" ) 
  784.  
  785.       repeat 
  786.          thread_yield() 
  787.       until ( Mr_Sunshine_finished_running  )  
  788.  
  789.       on_take_damage( "", MR_SUNSHINE_NAME ) 
  790.  
  791.       crouch_stop( MR_SUNSHINE_NAME ) 
  792.       -- Hide the voodoo doll 
  793.       group_hide( VOODOO_DOLL_GROUP ) 
  794.       ss09_start_invincible_effects() 
  795.       marker_remove_npc( MR_SUNSHINE_NAME, SYNC_ALL ) 
  796.       marker_add_npc( MR_SUNSHINE_NAME, MINIMAP_ICON_KILL, "", SYNC_ALL ) 
  797.       turn_invulnerable( MR_SUNSHINE_NAME ) 
  798.  
  799.       -- Move back to the top platform 
  800.       -- retry on failure, move and fire 
  801.       npc_go_idle( MR_SUNSHINE_NAME ) 
  802.       set_ignore_ai_flag( MR_SUNSHINE_NAME, true ) 
  803.       mission_debug( "Mr. Sunshine told to run back up." ) 
  804.       move_to_safe( MR_SUNSHINE_NAME, SUNSHINE_BACK_TO_TOP_PLATFORM_PATH, 2, true, false ) 
  805.       mission_debug( "Mr. Sunshine run back up fell through." ) 
  806.       set_ignore_ai_flag( MR_SUNSHINE_NAME, false ) 
  807.  
  808.       delay( POST_DOLL_RETRIEVAL_RESUME_VOODOO_ATTACK_DELAY_SECONDS ) 
  809.       Mr_Sunshine_voodoo_attack_loop_thread_handle = thread_new( "ss09_mr_sunshine_voodoo_attack_loop" ) 
  810.    end 
  811. end 
  812.  
  813. function ss09_mr_sunshine_took_damage_while_running( attacked_object_name, attacker_name, percent_hp_remaining_after_attack ) 
  814.    if ( coop_is_active() ) then 
  815.       local sunshine_max_hp = get_max_hit_points( MR_SUNSHINE_NAME ) 
  816.       local percent_damage_before_hit = get_current_hit_points( MR_SUNSHINE_NAME ) / sunshine_max_hp 
  817.  
  818.       -- The percent damage is updated to itself plus any percentage just done 
  819.       Percent_damage_done_this_run = Percent_damage_done_this_run + ( percent_damage_before_hit - percent_hp_remaining_after_attack ) 
  820.  
  821.       if ( Percent_damage_done_this_run >= .35 ) then 
  822.          -- Set the percent remaining up a bit so that it's capped at .33 
  823.          if ( Percent_damage_done_this_run > .35 ) then 
  824.             percent_hp_remaining_after_attack = percent_hp_remaining_after_attack + ( Percent_damage_done_this_run - .33 ) 
  825.          end 
  826.  
  827.          ss09_mr_sunshine_set_run_directly_downstairs() 
  828. --[[ 
  829.          thread_kill( Mr_Sunshine_running_downstairs_thread_handle ) 
  830.          Mr_Sunshine_running_downstairs_thread_handle = thread_new( "ss09_mr_sunshine_run_directly_downstairs" )]] 
  831.       end 
  832.  
  833.       if ( attacker_name ~= nil ) then 
  834.          mission_debug( attacker_name.." attacked Sunshine." ) 
  835.       end 
  836.       mission_debug( "Setting Sunshine HP to "..percent_hp_remaining_after_attack.." percent." ) 
  837.  
  838.       set_current_hit_points( MR_SUNSHINE_NAME, percent_hp_remaining_after_attack * sunshine_max_hp ) 
  839.    end 
  840. end 
  841.  
  842. function ss09_mr_sunshine_set_run_directly_downstairs() 
  843.    turn_invulnerable( MR_SUNSHINE_NAME ) 
  844.    set_ignore_ai_flag( MR_SUNSHINE_NAME, true ) 
  845.    on_take_damage( "", MR_SUNSHINE_NAME ) 
  846.    marker_remove_npc( MR_SUNSHINE_NAME, SYNC_ALL ) 
  847.    character_prevent_flinching( MR_SUNSHINE_NAME, true ) 
  848.    Mr_Sunshine_running_directly_downstairs = true 
  849. end 
  850.  
  851. function ss09_mr_sunshine_run_downstairs() 
  852.    Mr_Sunshine_finished_running = false 
  853.    Mr_Sunshine_running_directly_downstairs = false 
  854.  
  855.    -- Do the run to the bottom thingy - stopping along the way 
  856.    for index, path in pairs( SUNSHINE_TO_DOLL_PATHS ) do 
  857.       -- retry on failure, move and fire 
  858.       mission_debug( MR_SUNSHINE_NAME.." pathing along "..path..".", 10 ) 
  859.       npc_go_idle( MR_SUNSHINE_NAME ) 
  860.       move_to_safe( MR_SUNSHINE_NAME, path, 2, true, true ) 
  861.       if ( Mr_Sunshine_running_directly_downstairs == false ) then 
  862.          local cover_delay = rand_float( MR_SUNSHINE_MIN_COVER_DELAY_SECONDS, 
  863.                                          MR_SUNSHINE_MAX_COVER_DELAY_SECONDS ) 
  864.          attack_closest_player( MR_SUNSHINE_NAME ) 
  865.          mission_debug( "cover delay = "..cover_delay ) 
  866.          delay( cover_delay ) 
  867.       end 
  868.    end 
  869.  
  870.    crouch_start( MR_SUNSHINE_NAME ) 
  871.    character_prevent_flinching( MR_SUNSHINE_NAME, true ) 
  872.    delay( MR_SUNSHINE_PICK_UP_DOLL_SECONDS ) 
  873.  
  874.    Mr_Sunshine_finished_running = true 
  875. end 
  876.  
  877. function ss09_start_sparking_lights() 
  878.    local sparking_effect_handles = {} 
  879.  
  880.    for index, light_location in pairs( SPARKING_LIGHTS_LOCATIONS ) do 
  881.       local random_effect_index = rand_int( 1, sizeof_table( SPARKING_LIGHT_EFFECTS ) ) 
  882.       local sparking_effect = SPARKING_LIGHT_EFFECTS[random_effect_index] 
  883.  
  884.       -- looping = true 
  885.       sparking_effect_handles[index] = effect_play( sparking_effect, light_location, true ) 
  886.    end 
  887.  
  888.    return sparking_effect_handles 
  889. end 
  890.  
  891. function ss09_stop_sparking_lights( sparking_effect_handles ) 
  892.    for index, handle in pairs( sparking_effect_handles ) do 
  893.       effect_stop( handle ) 
  894.    end 
  895. end 
  896.  
  897. function ss09_mr_sunshine_do_voodoo_attack() 
  898.    if ( ss09_mr_sunshine_not_doing_voodoo() ) then 
  899.       set_ignore_ai_flag( MR_SUNSHINE_NAME, true ) 
  900.       --marker_add_navpoint( USE_VOODOO_LOCATION, "", INGAME_EFFECT_LOCATION, SYNC_ALL ) 
  901.  
  902.       inv_item_equip( SUNSHINE_RANGED_WEAPON, MR_SUNSHINE_NAME ) 
  903.  
  904.       -- Have him run over to the navpoint 
  905.       Mr_Sunshine_approaching_voodoo_location = true 
  906.       move_to( MR_SUNSHINE_NAME, USE_VOODOO_ORIENT, 2, true, false ) 
  907.       move_to( MR_SUNSHINE_NAME, USE_VOODOO_LOCATION, 2, true, false ) 
  908.  
  909.       -- turn to target's orientation = true 
  910.       turn_to( MR_SUNSHINE_NAME, USE_VOODOO_DIRECTION, true ) 
  911.       delay( 0.5 ) 
  912.  
  913.       --action_play( MR_SUNSHINE_NAME, STAB_VOODOO_DOLL, nil, nil, .75, true ) 
  914.       if ( Player_shot_voodoo_doll == false ) then 
  915.          -- Only have an objective to shoot the doll given once 
  916.          if ( Shoot_objective_given == false ) then 
  917.             mission_help_table( HT_SHOOT_SUNSHINES_DOLL ) 
  918.             Shoot_objective_given = true 
  919.          -- Nag the player afterward so there's not a bunch of objectives 
  920.          else 
  921.             mission_help_table_nag( HT_SHOOT_SUNSHINES_DOLL ) 
  922.          end 
  923.       end 
  924.  
  925.       -- looping = true 
  926.       Use_voodoo_glow_handle = effect_play( USE_VOODOO_EFFECT, USE_VOODOO_LOCATION, true ) 
  927.       Sparking_lights_effect_handles = ss09_start_sparking_lights() 
  928.  
  929.       -- Play the animation ( do the attack ) 
  930.       action_play_non_blocking(MR_SUNSHINE_NAME, STAB_VOODOO_DOLL, nil, nil, true ) 
  931.       audio_play( SUNSHINE_USE_VOODOO_DOLL_LINES, "voice", false ) 
  932.  
  933.       -- Don't let the player disable the voodoo attack until the animation has played for a bit 
  934.       delay( BEFORE_DISABLE_VOODOO_ATTACK_ALLOWED_SECONDS ) 
  935.       Mr_Sunshine_approaching_voodoo_location = false 
  936.       Mr_Sunshine_doing_voodoo_attack = true 
  937.       -- Allow the animation to get to the "stab" part before hitting the player 
  938.       voodoo_glow_start( MR_SUNSHINE_NAME ) 
  939.       on_character_right_hand_hit( "ss09_sunshine_hand_hit", MR_SUNSHINE_NAME ) 
  940.       on_take_damage( "ss09_sunshine_took_damage_during_voodoo", MR_SUNSHINE_NAME ) 
  941.       delay( VOODOO_ATTACK_BEFORE_EFFECT_SECONDS - BEFORE_DISABLE_VOODOO_ATTACK_ALLOWED_SECONDS ) 
  942.       voodoo_glow_stop( MR_SUNSHINE_NAME ) 
  943.       on_character_right_hand_hit( "", MR_SUNSHINE_NAME ) 
  944.       on_take_damage( "", MR_SUNSHINE_NAME ) 
  945.       Mr_Sunshine_doing_voodoo_attack = false 
  946.  
  947.       -- At this point, the thread should not be killed under any circumstances 
  948.       Mr_Sunshine_voodoo_attack_thread_handle = INVALID_THREAD_HANDLE 
  949.  
  950.       set_ignore_ai_flag( MR_SUNSHINE_NAME, false ) 
  951.       -- Ragdoll the player 
  952.       character_ragdoll( LOCAL_PLAYER, VOODOO_RAGDOLL_MS, VOODOO_RAGDOLL_PUSH_SPEED_MPS ) 
  953.       if ( coop_is_active() ) then 
  954.          character_ragdoll( REMOTE_PLAYER, VOODOO_RAGDOLL_MS, VOODOO_RAGDOLL_PUSH_SPEED_MPS ) 
  955.       end 
  956.       audio_play( "SFX_SOS_VOODOO_DOLL_STAB" ) 
  957.  
  958.       -- Stop the effect - it's done playing 
  959.       effect_stop( Use_voodoo_glow_handle ) 
  960.       for index, handle in pairs( Sparking_lights_effect_handles ) do 
  961.          effect_stop( handle ) 
  962.          Sparking_lights_effect_handles[index] = -1 
  963.       end 
  964.  
  965.       --ss09_stop_sparking_lights( sparking_lights_effect_handles ) 
  966.  
  967.       -- Give Mr. Sunshine HP 
  968.       local sunshine_max_hit_points = get_max_hit_points( MR_SUNSHINE_NAME ) 
  969.       local sunshine_hit_points_boost = sunshine_max_hit_points * SUNSHINE_RECOVER_PERCENT 
  970.       local sunshine_current_hit_points = get_current_hit_points( MR_SUNSHINE_NAME ) 
  971.  
  972.       local sunshine_new_hit_points = sunshine_current_hit_points + sunshine_hit_points_boost 
  973.       if ( coop_is_active() ) then 
  974.          sunshine_new_hit_points = sunshine_new_hit_points + sunshine_hit_points_boost 
  975.       end 
  976.  
  977.       if ( sunshine_new_hit_points > sunshine_max_hit_points ) then 
  978.          sunshine_new_hit_points = sunshine_max_hit_points 
  979.       end 
  980.       set_current_hit_points( MR_SUNSHINE_NAME, sunshine_new_hit_points ) 
  981.  
  982.       -- Take away some of the player's HP 
  983.       ss09_do_voodoo_damage( LOCAL_PLAYER ) 
  984.       if ( coop_is_active() ) then 
  985.          ss09_do_voodoo_damage( REMOTE_PLAYER ) 
  986.       end 
  987.  
  988.       --marker_remove_navpoint( USE_VOODOO_LOCATION, SYNC_ALL ) 
  989.  
  990.       -- Return Mr. Sunshine's weapon 
  991.       inv_item_equip( SUNSHINE_RANGED_WEAPON, MR_SUNSHINE_NAME ) 
  992.    end 
  993. end 
  994.  
  995. function ss09_do_voodoo_damage( player_name ) 
  996.    local player_voodoo_damage = get_max_hit_points( player_name ) * VOODOO_DOLL_DAMAGE_PERCENT 
  997.    local player_cur_hit_points = get_current_hit_points( player_name ) 
  998.  
  999.    local player_new_hit_points = player_cur_hit_points - player_voodoo_damage 
  1000.    if ( player_new_hit_points > 0 ) then 
  1001.       set_current_hit_points( player_name, player_new_hit_points ) 
  1002.    else 
  1003.       character_kill( player_name ) 
  1004.    end 
  1005. end 
  1006.  
  1007. function ss09_abort_voodoo_attack() 
  1008.    Mr_Sunshine_doing_voodoo_attack = false 
  1009.    thread_kill( Mr_Sunshine_voodoo_attack_thread_handle ) 
  1010.    audio_play_for_character( SUNSHINE_VOODOO_INTERRUPTED_LINES, MR_SUNSHINE_NAME, "voice", false, false ) 
  1011.    Mr_Sunshine_voodoo_attack_thread_handle = INVALID_THREAD_HANDLE 
  1012.    set_ignore_ai_flag( MR_SUNSHINE_NAME, false ) 
  1013.    marker_remove_navpoint( USE_VOODOO_LOCATION, SYNC_ALL ) 
  1014. end 
  1015.  
  1016.  
  1017. -- Returns true if Mr. Sunshine is in his voodoo attack state, false otherwise. 
  1018. -- This includes both running up to do it and actually doing the attack animation. 
  1019. -- 
  1020. function ss09_mr_sunshine_not_doing_voodoo() 
  1021.    if ( Mr_Sunshine_approaching_voodoo_location == false and 
  1022.         Mr_Sunshine_doing_voodoo_attack == false ) then 
  1023.       return true 
  1024.    end 
  1025.  
  1026.    return false 
  1027. end 
  1028.  
  1029. function ss09_sunshine_defender_died() 
  1030.    Mr_Sunshine_defender_count = Mr_Sunshine_defender_count - 1 
  1031.  
  1032.    mission_debug( "defender died, "..Mr_Sunshine_defender_count.." remain" ) 
  1033.    if ( Mr_Sunshine_defender_count == MR_SUNSHINE_DEFENDERS_RESPAWN_THRESHOLD ) then 
  1034.       release_to_world( MR_SUNSHINE_REINFORCEMENTS_GROUP ) 
  1035.       delay( REINFORCEMENTS_DELAY_SECONDS ) 
  1036.       group_create( MR_SUNSHINE_REINFORCEMENTS_GROUP ) 
  1037.       Mr_Sunshine_defender_count = sizeof_table( MR_SUNSHINE_REINFORCEMENTS ) 
  1038.       delay( 0 ) 
  1039.       for index, name in pairs( MR_SUNSHINE_REINFORCEMENTS ) do 
  1040.          on_death( "ss09_sunshine_defender_died", name ) 
  1041.          thread_new( "ss09_sunshine_defender_deploy", name, MR_SUNSHINE_REINFORCEMENTS_GOALS[index] ) 
  1042.       end 
  1043.    end 
  1044. end 
  1045.  
  1046. function ss09_sunshine_defender_deploy( name, goal ) 
  1047.    -- retry on failure = true, move and fire = true 
  1048.    move_to_safe( name, goal, 2, true, true ) 
  1049.    npc_leash_to_nav( name, goal, 8.0 ) 
  1050.  
  1051.    attack_closest_player( name ) 
  1052. end 
  1053.  
  1054. function ss09_cleanup() 
  1055.    -- Cleanup mission here 
  1056.    hud_set_fake_notoriety( ENEMY_GANG, false, 0 ) 
  1057.    notoriety_force_no_spawn( ENEMY_GANG, false ) 
  1058.    notoriety_set_min( ENEMY_GANG, 0 ) 
  1059.  
  1060.    trigger_enable( MR_SUNSHINES_PLATFORM_TRIGGER, false ) 
  1061.  
  1062. 	mesh_mover_reset( SUNSHINE_DOOR ) 
  1063.     
  1064.    persona_override_group_stop( SAMEDI_PERSONAS, POT_SITUATIONS[POT_ATTACK] ) 
  1065.    ss09_stop_invincible_effects() 
  1066.  
  1067. 	if ( Controls_disabled ) then 
  1068. 		player_controls_enable( LOCAL_PLAYER ) 
  1069. 		if ( coop_is_active() ) then 
  1070. 			player_controls_enable( REMOTE_PLAYER ) 
  1071. 		end 
  1072. 	end 
  1073. end 
  1074.  
  1075. function ss09_success() 
  1076.    -- Called when the mission has ended with success 
  1077. end