-- ss08.lua
-- SR2 mission script
-- 3/28/07
-- Mission help table text tags
   HT_TRUCK_DESTROYED = "ss08_truck_destroyed"
   HT_GET_BACK_TO_WAREHOUSE = "ss08_get_back_to_warehouse"
   HT_WAREHOUSE_ABANDONED = "ss08_warehouse_abandoned"
   HT_DEFEND_THE_DUST = "ss08_defend_the_dust"
   HT_PIERCE_DIED = "ss08_pierce_died"
   HT_SHAUNDI_DIED = "ss08_shaundi_died"
   HT_PIERCE_ABANDONED = "ss08_pierce_abandoned"
   HT_SHAUNDI_ABANDONED = "ss08_shaundi_abandoned"
   HT_PROTECT_WHILE_LOADING = "ss08_protect_while_loading"
   HT_GET_DRUGS_TO_HQ = "ss08_get_drugs_to_hq"
   HT_PIERCE_WAITING_ON_YOU = "ss08_pierce_waiting_on_you"
   HT_GET_A_CAR = "ss08_get_a_car"
   HT_ESCORT_TRUCK_TO_HIDEOUT = "ss08_escort_truck_to_hideout"
   HT_TRUCK_HEALTH = "ss08_truck_health"
   HT_X_OF_Y_BOXES_LOADED = "ss08_x_of_y_crates_loaded"

-- Mission states
   MS_INIT = 1
   MS_INITIAL_JUNKIES_ATTACK = 2
   MS_REAL_ATTACK_STARTS = 3
   MS_WAITING_FOR_PIERCE = 4
   MS_LOADING_TRUCK = 5
   MS_TRUCK_LOADED = 6
   MS_TRAVELING_TO_BASE = 7
   MS_VICTORY = 8

-- Groups, NPCs, vehicles, navpoints, and other names
   -- Mission constant names
   MISSION_NAME = "ss08"
   -- ( Mission Prefix )
   MP = MISSION_NAME.."_$"

   CHASE_GROUP_GROUP_PREFIX = MP.."Chase_Group"
   CHASE_GROUP_OBJECT_PREFIX = MP.."CG_"
   CHASE_GROUP_NPC_SUFFIX = "_M"
   CHASE_GROUP_VEHICLE_SUFFIX = "_V"
   CHASE_GROUP_TRIGGER_SUFFIX = "_T"

   WEST = 1
   EAST = 2
   SOUTH = 3

   POLICE_GANG = "police"

   -- Checkpoints
   CP_TRUCK_LOADED = "Truck_Loaded"

   -- Loading states - for loading packages
   LS_NONE = 0
   LS_CARRYING_TO_DROPOFF = 1
   LS_MOVING_TO_PICK_UP = 2
   LS_WAITING_AT_DROPOFF = 3
   LS_WAITING_AT_PICKUP = 4
   LS_DISABLED = 5
   LS_JUST_REVIVED = 6

   -- Groups
   HOMIES_GROUP = MP.."Saint_Homies"
   DRUG_TRUCK_LOADING_GROUP = MP.."Drug_Truck_Loading"
   DRUG_TRUCK_GROUP = MP.."Drug_Truck"
   JUNKIES_GROUP = MP.."Initial_Attack_Junkies"
   ESCAPE_CAR_GROUP = MP.."Escape_Car"
   CUTSCENE_GROUP = MP.."Cutscene"
   OUTSIDE_OF_WAREHOUSE_AMBUSHER_GROUP = MP.."Outside_of_Warehouse_Ambush"
   PATH_AMBUSHER_GROUPS = { MP.."Path_Ambush_01", MP.."Path_Ambush_02" }

   ALL_ATTACK_SQUADS = { [WEST] = MP.."West_01", [EAST] = MP.."East_01", [SOUTH] = MP.."South_01" }

   CHASE_SQUAD_GROUP_NAMES = {}

   DRUG_BOXES_GROUP = MP.."Drug_Boxes"

   RANDOM_CHASE_SQUAD_GROUPS = { MP.."Random_Chase_Squad1", MP.."Random_Chase_Squad2", MP.."Random_Chase_Squad3" }

   -- NPC names
   INITIAL_ATTACK_JUNKIE_NAMES = { MP.."Initial_Junkie01", MP.."Initial_Junkie02", MP.."Initial_Junkie03",
                                   MP.."Initial_Junkie04", MP.."Initial_Junkie05", MP.."Initial_Junkie06" }
   PIERCE_NAME = MP.."Pierce"
   SHAUNDI_NAME = MP.."Shaundi"
   WEST_ATTACK_SQUAD_MEMBERS = { MP.."West_01_M01", MP.."West_01_M02", MP.."West_01_M03" }
   EAST_ATTACK_SQUAD_MEMBERS = { MP.."East_01_M01", MP.."East_01_M02", MP.."East_01_M03" }
   SOUTH_ATTACK_SQUAD_MEMBERS = { MP.."South_01_M01", MP.."South_01_M02", MP.."South_01_M03" }

   ATTACK_SQUADS_MEMBERS = { [WEST] = WEST_ATTACK_SQUAD_MEMBERS, [EAST] = EAST_ATTACK_SQUAD_MEMBERS,
                             [SOUTH] = SOUTH_ATTACK_SQUAD_MEMBERS }

   OUTSIDE_OF_WAREHOUSE_AMBUSHER_MEMBERS = { MP.."Ambusher_01", MP.."Ambusher_02", MP.."Ambusher_03" }

   PATH_AMBUSHER_GROUPS_MEMBERS = { { MP.."PA1_M01", MP.."PA1_M02", MP.."PA1_M03" },
                                    { MP.."PA2_M01", MP.."PA2_M02", MP.."PA2_M03" } }

   RANDOM_CHASE_SQUAD_MEMBERS = { { MP.."RC1_M1", MP.."RC1_M2" },
                                  { MP.."RC2_M1", MP.."RC2_M2" },
                                  { MP.."RC3_M1", MP.."RC3_M2", MP.."RC3_M3", MP.."RC3_M4" } }

   CHASE_SQUAD_GROUP_MEMBERS = {}

   -- Vehicle names
   DRUG_TRUCK_LOADING = MP.."Drug_Truck_02"
   DRUG_TRUCK = MP.."Drug_Truck"

   ATTACK_SQUAD_VEHICLES = { [EAST] =  MP.."East_V1", [WEST] = MP.."West_V1",
                             [SOUTH] = MP.."South_V1" }

   ESCAPE_CAR_NAME = MP.."Escape_Car"

   RANDOM_CHASE_SQUAD_VEHICLES = { MP.."RC1_V", MP.."RC2_V", MP.."RC3_V" }

   CHASE_SQUAD_GROUP_VEHICLES = {}

   -- Navpoints
   PLAYER1_START = MP.."Player1_Start"
   PLAYER2_START = MP.."Player2_Start"
   BOX_PICKUP_NAV = MP.."Box_Pickup_Position"
   BOX_DROPOFFS = { [PIERCE_NAME] = MP.."Pierce_Dropoff", [SHAUNDI_NAME] = MP.."Shaundi_Dropoff" }

   BOX_LOADING_TARGET = MP.."Box_Loading_Target"

   PIERCE_GET_TRUCK_PATH = { MP.."PE_00", MP.."PE_01", MP.."PE_02", MP.."PE_03",
                             MP.."PE_04", MP.."PE_05", MP.."PE_06", MP.."PE_07",
                             MP.."PE_08", MP.."PE_09", MP.."PE_10", MP.."PE_11" }
   PIERCE_RETURN_TO_LOAD_TRUCK_PATH = { MP.."PR_01", MP.."PR_02", MP.."PR_03",
                                        MP.."PR_04", MP.."PR_05" }

   ATTACK_VEHICLE_PATHS = { [EAST] = MP.."Attack_Path_East", [WEST] = MP.."Attack_Path_West",
                            [SOUTH] = MP.."Attack_Path_South" }

   BACK_TO_HQ_PATH_INITIAL = MP.."THQ_Initial_Path"
   BACK_TO_HQ_PATHS_MAIN = { MP.."THQ_01", MP.."THQ_02" }

   BACK_TO_HQ_PATH_FINAL = MP.."THQ_Final_Path"

   DROPOFF_POINTS = { [EAST] = { MP.."Dropoff_E01", MP.."Dropoff_E02", MP.."Dropoff_E03", MP.."Dropoff_E04", MP.."Dropoff_E05" },
                      [WEST] = { MP.."Dropoff_W01", MP.."Dropoff_W02", MP.."Dropoff_W03", MP.."Dropoff_W04", MP.."Dropoff_W05" },
                      [SOUTH] = { MP.."Dropoff_S01", MP.."Dropoff_S02", MP.."Dropoff_S03", MP.."Dropoff_S04" } }

   AMBUSHER_GOALS = { MP.."Ambusher01_Goal", MP.."Ambusher02_Goal", MP.."Ambusher03_Goal" }

   RANDOM_CHASE_SQUAD_SPAWN_LOCATIONS = { MP.."Path_Spawn01", MP.."Path_Spawn02", MP.."Path_Spawn03", MP.."Path_Spawn04",
                                          MP.."Path_Spawn05", MP.."Path_Spawn06", MP.."Path_Spawn07", MP.."Path_Spawn08",
                                          MP.."Path_Spawn09", MP.."Path_Spawn10", MP.."Path_Spawn11", MP.."Path_Spawn12",
                                          MP.."Path_Spawn13", MP.."Path_Spawn14", MP.."Path_Spawn15", MP.."Path_Spawn16",
                                          MP.."Path_Spawn17" }

   ARRIVAL_NAVPOINTS = { [LOCAL_PLAYER] = MP.."P1_Arrival", [REMOTE_PLAYER] = MP.."P2_Arrival" }

   -- Triggers
   WAREHOUSE_AREA = MP.."Warehouse_Area"

   SAINTS_HQ = MP.."Saints_HQ"

   CHASE_SQUAD_TRIGGER_NAMES = {}
   OUTSIDE_OF_WAREHOUSE_AMBUSH_TRIGGER = MP.."Outside_of_Warehouse_Ambush"
   PATH_AMBUSHER_TRIGGERS = { MP.."Path_Ambush_01_Trigger", MP.."Path_Ambush_02_Trigger" }

   -- Movers
   DRUG_BOXES = { MP.."Drug_Box_01", MP.."Drug_Box_02", MP.."Drug_Box_03", MP.."Drug_Box_04", MP.."Drug_Box_05",
                  MP.."Drug_Box_06", MP.."Drug_Box_07", MP.."Drug_Box_08", MP.."Drug_Box_09", MP.."Drug_Box_10",
                  MP.."Drug_Box_11", MP.."Drug_Box_12" }
   GARAGE_DOOR = MP.."Garage_Door"
   DOORS = { MP.."Door01", MP.."Door02", MP.."Door03" }

   -- Effects and animation states

   -- Weapons
   CHASE_SQUAD_HEAVY_WEAPONS = { "twelve_gauge", "gal43" }
   CHASE_SQUAD_THROWN_WEAPONS = { "molotov" }
   CHASE_SQUAD_LIGHT_WEAPONS = { "beretta" }
   
   -- Cutscenes
   ARRIVAL_CUTSCENE_NAME = "ig_ss08_scene0"
   SEATING_CUTSCENE_NAME = "ig_ss08_scene1"
   CT_INTRO = "ss08-01"
   CT_OUTRO = "ss08-02"
-- Sound
   -- Persona overrides
   SHAUNDI_JUNKIE_COMBAT_PERSONA_OVERRIDES = { { "combat - congratulate self", "SHAUNDI_SOS8_CONGRAT" },
                                               { "threat - damage received (firearm)", "SHAUNDI_SOS8_TAKEDAM" },
                                               { "threat - damage received (melee)", "SHAUNDI_SOS8_TAKEDAM" } }

   -- Lines/Dialog Stream
   PIERCE_COMPLAINING_DIALOG_STREAM = { { "SOS8_GRIPE_L1", PIERCE_NAME } }
   PLAYER_RESPONSE_TO_GRIPE_DIALOG_STREAM = { { "PLAYER_SOS8_GRIPE_L2", LOCAL_PLAYER } }

   GET_THE_TRUCK_DIALOG_STREAM = { { "SOS8_TRUCK_L1", SHAUNDI_NAME, 0 },
                                   { "PLAYER_SOS8_TRUCK_L2", LOCAL_PLAYER, 0 },
                                   { "SOS8_TRUCK_L3", PIERCE_NAME, 0 } }

   PIERCE_RETURNS_DIALOG_STREAM = { { "SOS8_RETURN_L1", PIERCE_NAME },
                                    { "PLAYER_SOS8_RETURN_L2", LOCAL_PLAYER } }

   SHAUNDI_AND_PIERCE_ARGUE_DIALOG_STREAM = { { "SOS8_BICKER_L1", SHAUNDI_NAME },
                                              { "SOS8_BICKER_L2", PIERCE_NAME },
                                              { "SOS8_BICKER_L3", SHAUNDI_NAME },
                                              { "SOS8_BICKER_L4", PIERCE_NAME },
                                              { "SOS8_BICKER_L5", SHAUNDI_NAME },
                                              { "SOS8_BICKER_L6", PIERCE_NAME },
                                              { "SOS8_BICKER_L7", SHAUNDI_NAME },
                                              { "SOS8_BICKER_L8", PIERCE_NAME } }

   TRUCK_LOADED_DIALOG_STREAM = { { "SOS8_COMPLETE_L1", PIERCE_NAME },
                                  { "PLAYER_SOS8_COMPLETE_L2", LOCAL_PLAYER } }

   END_MISSION_DIALOG_STREAM = { { "SOS8_END_L1", PIERCE_NAME },
                                 { "SOS8_END_L2", SHAUNDI_NAME },
                                 { "SOS8_END_L3", PIERCE_NAME } }

   SHAUNDI_DEFENDING_LINES = "SHAUNDI_SOS8_DEFEND"
   SHAUNDI_WHATS_TAKING_SO_LONG_LINE = "SHAUNDI_SOS8_TRUCK_02"

   -- Sound effects

-- Distances
   WAREHOUSE_AREA_TRIGGER_RADIUS_METERS = 34.8
   DRUG_TRUCK_MAX_DISTANCE_METERS = 50.0
   TO_HQ_WIN_DISTANCE_METERS = 10

-- Percents and multipliers

-- Time values
   FAILURE_TIME_MS = 30000

   TIME_PER_ABANDONED_UPDATE_SECONDS = 5

   BEFORE_ATTACK_DELAY_SECONDS = 6.0
   BEFORE_DEFEND_PROMPT_SECONDS = 3.5

   WAIT_FOR_PIERCE_TIME_MS = 120000
   WHERE_IS_PIERCE_MESSAGE_DELAY_SECONDS = 60.0
   NEW_ENTRANCE_ATTACK_DELAY_SECONDS = 30.0
   -- The delay before spawning a new wave if the attackers
   -- during the siege falls below a certain number.
   BELOW_MIN_ATTACKERS_FORCE_SPAWN_DELAY_SECONDS = 10.0
   OUT_OF_RANGE_OF_TRUCK_FAIL_TIME_MS = 30000
   MIN_BETWEEN_LINES_DELAY_SECONDS = 8
   MAX_BETWEEN_LINES_DELAY_SECONDS = 16
   BEFORE_LOAD_PACKAGES_CONVERSATION_TIME_SECONDS = 15
   RANDOM_CHASE_SQUAD_SPAWN_INTERVAL_SECONDS = 15.0

-- Speeds
   DRUG_TRUCK_INITIAL_SPEED_MPH = 20
   DRUG_TRUCK_DESIRED_SPEED_MPH = 30

-- Constant values and counts
   -- The minimum number of attackers allowed during the siege.
   -- If the attackers fall below this number, a timer is
   -- started for a new attack wave.
   MIN_ATTACKERS = 3
   NUM_ATTACK_DIRECTIONS = 3
   NUM_DRUG_BOXES = sizeof_table( DRUG_BOXES )
   INITIAL_DRUG_TRUCK_HP = 48000

   CHASE_SQUAD_MEMBER_COUNTS = { 2, 2, 2, 2, 2, 2, 2, 2,
                                 2, 2, 2, 2, 2, 2, 2 }
   NUM_CHASE_SQUADS = sizeof_table( CHASE_SQUAD_MEMBER_COUNTS )
   MAX_CHASING_CARS = 2

   WAVES_BEFORE_DUAL_ATTACK = 2

   FAILURE_TIME_INDEX = 0
   OBJECTIVE_TIME_INDEX = 1

   RANDOM_CHASE_SQUAD_COUNT = sizeof_table( RANDOM_CHASE_SQUAD_GROUPS )

   -- The number of dropoffs available in each direction
   DROPOFF_COUNTS = { [WEST] = sizeof_table( DROPOFF_POINTS[WEST] ),
                      [EAST] = sizeof_table( DROPOFF_POINTS[EAST] ),
                      [SOUTH] = sizeof_table( DROPOFF_POINTS[SOUTH] ) }

-- Global variables
   Initial_junkies_remaining = sizeof_table( INITIAL_ATTACK_JUNKIE_NAMES )
   Players_in_warehouse_area = { [LOCAL_PLAYER] = true, [REMOTE_PLAYER] = true }
   Abandoned_warehouse_failure_threads = { [LOCAL_PLAYER] = INVALID_THREAD_HANDLE, [REMOTE_PLAYER] = INVALID_THREAD_HANDLE }

   Cur_attack_directions = {}
   Cur_attackers_remaining = 0
   Cur_drug_boxes_remaining = NUM_DRUG_BOXES

   Homie_drug_carry_states = { [PIERCE_NAME] = LS_NONE, [SHAUNDI_NAME] = LS_NONE }
   Homie_drug_carry_threads = { [PIERCE_NAME] = INVALID_THREAD_HANDLE, [SHAUNDI_NAME] = INVALID_THREAD_HANDLE }

   Player_failure_countdown_threads = { [LOCAL_PLAYER] = INVALID_THREAD_HANDLE, [REMOTE_PLAYER] = INVALID_THREAD_HANDLE }
   Assault_turned_on = false
   Pierce_leaves_thread_handle = INVALID_THREAD_HANDLE
   Chase_squad_cars_chasing = {}
   Force_spawn_thread_handle = INVALID_THREAD_HANDLE
   Force_spawn_wave_index = 0

   Num_junkie_attack_waves_defeated = 0

   Num_chasing_cars = 0
   Last_random_chase_group_index = 0

   Players_in_range_of_drug_truck = { [LOCAL_PLAYER] = false, [REMOTE_PLAYER] = false }
   Players_in_vehicle = { [LOCAL_PLAYER] = false, [REMOTE_PLAYER] = false }
   Followers_incapacitated = { [PIERCE_NAME] = false, [SHAUNDI_NAME] = false }
   Garage_door_open = false
   Whos_carrying_drug_boxes = { [DRUG_BOXES[1]] = nil, [DRUG_BOXES[2]] = nil, [DRUG_BOXES[3]] = nil,
                                [DRUG_BOXES[4]] = nil, [DRUG_BOXES[5]] = nil, [DRUG_BOXES[6]] = nil,
                                [DRUG_BOXES[7]] = nil, [DRUG_BOXES[8]] = nil, [DRUG_BOXES[9]] = nil,
                                [DRUG_BOXES[10]] = nil, [DRUG_BOXES[11]] = nil, [DRUG_BOXES[12]] = nil }


   -- Index into DROPOFF_POINTS - the last dropoff index that was used
   -- from each direction. Initial value of zero denotes no dropoffs yet used
   Last_dropoff_indices = { [WEST] = 0, [EAST] = 0, [SOUTH] = 0 }
   Mission_won = false
   Drug_boxes_queued = 0
   Drug_boxes_loaded = 0
   Truck_waiting = false
   Group_spawning = false
	Pierce_has_returned = false
   Argue_converstation_thread_handle = INVALID_THREAD_HANDLE

function ss08_mission_critical_follower_dismissed( follower_name )
   if ( follower_name == PIERCE_NAME ) then
      mission_end_failure( MISSION_NAME, HT_PIERCE_ABANDONED )
   elseif ( follower_name == SHAUNDI_NAME ) then
      mission_end_failure( MISSION_NAME, HT_SHAUNDI_ABANDONED )
   end
end

function ss08_mission_critical_homie_died( homie_name )
   if ( homie_name == PIERCE_NAME ) then
      mission_end_failure( MISSION_NAME, HT_PIERCE_DIED )
   elseif ( homie_name == SHAUNDI_NAME ) then
      mission_end_failure( MISSION_NAME, HT_SHAUNDI_DIED )
   end
end

function ss08_all_players( player_conditions )
   if ( player_conditions[LOCAL_PLAYER] ) then
      if ( coop_is_active() ) then
         if ( player_conditions[REMOTE_PLAYER] ) then
            return true
         end
      else
         return true
      end
   end
   return false
end

function ss08_all_players_not( player_conditions )
   if ( player_conditions[LOCAL_PLAYER] == false ) then
      if ( coop_is_active() ) then
         if ( player_conditions[REMOTE_PLAYER] == false ) then
            return true
         end
      else
         return true
      end
   end
   return false
end

-- Returns true if all active players are out of range of the 
-- drug truck, false otherwise.
--
function ss08_all_players_out_of_range_of_truck()
   return ss08_all_players_not( Players_in_range_of_drug_truck )
end

function ss08_all_players_in_of_range_of_truck()
   return ss08_all_players( Players_in_range_of_drug_truck )
end

function ss08_all_players_in_vehicle()
   return ss08_all_players( Players_in_vehicle )
end

function ss08_all_players_in_warehouse_area()
   return ss08_all_players( Players_in_warehouse_area )
end


function ss08_all_players_outside_warehouse_area()
   return ss08_all_players_not( Players_in_warehouse_area )
end

-- Tracks incapacitation while the boxes are being loaded
-- so that the boxes won't be 'loaded' when one of the people
-- isn't loading them.
-- 
function ss08_follower_incapacitated( follower_name )
   local drug_thread_handle = Homie_drug_carry_threads[follower_name]
   if ( drug_thread_handle ~= INVALID_THREAD_HANDLE ) then
      thread_kill( drug_thread_handle )
      Homie_drug_carry_threads[follower_name] = INVALID_THREAD_HANDLE
   end

   for drug_box, whos_carrying in pairs( Whos_carrying_drug_boxes ) do
      if ( whos_carrying == follower_name ) then
         Drug_boxes_queued = Drug_boxes_queued - 1
         Whos_carrying_drug_boxes[drug_box] = nil
         item_drop( drug_box, follower_name )
         item_reset( drug_box )
      end
   end
end

-- If a follower is revived while the boxes are being loaded,
-- this function checks to see if both followers are not
-- incapacitated and if so, resumes the loading.
--
function ss08_follower_revived( follower_name )
   Homie_drug_carry_threads[follower_name] = thread_new( "ss08_homie_load_drugs", follower_name )
end

function ss08_shaundi_revived()
end

function ss08_open_doors( open )
   if ( open == nil ) then
      open = true
   end

   if ( open ) then
      for index, name in pairs( DOORS ) do
         door_open( name )
      end
   else
      for index, name in pairs( DOORS ) do
         door_close( name )
      end
   end
end

function ss08_hide_doors( hide )
   if ( hide == nil ) then
      hide = true
   end

   if ( hide ) then
      for index, name in pairs( DOORS ) do
         door_lock( name, true )
         mesh_mover_hide( name )
      end
   else
      for index, name in pairs( DOORS ) do
         door_lock( name, false )
         mesh_mover_show( name )
      end
   end
end

-- Works for numbers 0-99.
function ss08_get_zero_prefixed( number )
   local prefixed = nil
   if ( number < 10 ) then
      prefixed = "0"..number
   else
      prefixed = number
   end

   return prefixed
end

function ss08_generate_chase_squad_trigger_and_group_names()
   for i = 1, NUM_CHASE_SQUADS do
      local index = ss08_get_zero_prefixed( i )
      CHASE_SQUAD_TRIGGER_NAMES[i] = CHASE_GROUP_OBJECT_PREFIX..index..CHASE_GROUP_TRIGGER_SUFFIX
      CHASE_SQUAD_GROUP_NAMES[i] = CHASE_GROUP_GROUP_PREFIX..index
   end
end

function ss08_generate_chase_squad_vehicle_names()
   for i = 1, NUM_CHASE_SQUADS do
      local index = ss08_get_zero_prefixed( i )
      CHASE_SQUAD_GROUP_VEHICLES[i] = CHASE_GROUP_OBJECT_PREFIX..index..CHASE_GROUP_VEHICLE_SUFFIX
   end
end

function ss08_generate_chase_squad_group_member_names()
   -- Go through all the group member counts
   for group_index, member_count in pairs( CHASE_SQUAD_MEMBER_COUNTS ) do
      -- For each member in the group
      local group_members = {}
      local group_index_prefixed = ss08_get_zero_prefixed( group_index )
      for member_index = 1, member_count do
         -- Construct its name
         local member_index_prefixed = ss08_get_zero_prefixed( member_index )
         group_members[member_index] = CHASE_GROUP_OBJECT_PREFIX..group_index_prefixed..CHASE_GROUP_NPC_SUFFIX..member_index_prefixed
      end

      -- Add this group's members to the overall list
      CHASE_SQUAD_GROUP_MEMBERS[group_index] = group_members
   end
end

function ss08_entered_warehouse_area( triggerer_name, trigger_name )
   Players_in_warehouse_area[triggerer_name] = true
   local sync_type = sync_from_player( triggerer_name )
   minimap_icon_remove_navpoint( WAREHOUSE_AREA, sync_type )
   ss08_stop_failure_countdown( triggerer_name )
end

function ss08_left_warehouse_area( triggerer_name, trigger_name )
   Players_in_warehouse_area[triggerer_name] = false
   local sync_type = sync_from_player( triggerer_name )
   minimap_icon_add_navpoint_radius( WAREHOUSE_AREA, MINIMAP_ICON_LOCATION, WAREHOUSE_AREA_TRIGGER_RADIUS_METERS, nil, sync_type )
   ss08_start_failure_countdown( triggerer_name )
end

-- This function starts a failure countdown for the passed-in player.
--
-- player_name: Name of the player to start failure countdown for.
--
function ss08_start_failure_countdown( player_name )
   local sync_type = sync_from_player( player_name )

   Abandoned_warehouse_failure_threads[player_name] = thread_new( "ss08_abandoned_warehouse_fail_timer", sync_type )
end

function ss08_abandoned_warehouse_fail_timer( sync_type )
   local cur_time_left_seconds = FAILURE_TIME_MS / 1000
   mission_help_table_nag( HT_GET_BACK_TO_WAREHOUSE, cur_time_left_seconds, "", sync_type )
   while ( cur_time_left_seconds > 0 ) do
      delay( TIME_PER_ABANDONED_UPDATE_SECONDS )
      cur_time_left_seconds = cur_time_left_seconds - TIME_PER_ABANDONED_UPDATE_SECONDS
      mission_help_table_nag( HT_GET_BACK_TO_WAREHOUSE, cur_time_left_seconds, "", sync_type )
   end

   mission_end_failure( MISSION_NAME, HT_WAREHOUSE_ABANDONED )
end

-- This function stops the failure countdown if one is on.
--
-- player_name: Name of the player to stop the failure timer of.
--
function ss08_stop_failure_countdown( player_name )
   if ( Abandoned_warehouse_failure_threads[player_name] ~= INVALID_THREAD_HANDLE ) then
      thread_kill( Abandoned_warehouse_failure_threads[player_name] )
      Abandoned_warehouse_failure_threads[player_name] = INVALID_THREAD_HANDLE
   end
end

function ss08_abandoned_drugs()
   mission_end_failure( MISSION_NAME, HT_WAREHOUSE_ABANDONED )
end

function ss08_create_start_and_checkpoint_shared_groups( blocking_load )
	if ( group_is_loaded( ESCAPE_CAR_GROUP ) == false ) then
		group_create_hidden( ESCAPE_CAR_GROUP, blocking_load )
	end
	group_create_hidden( OUTSIDE_OF_WAREHOUSE_AMBUSHER_GROUP, blocking_load )
	for index, group_name in pairs( PATH_AMBUSHER_GROUPS ) do
		group_create_hidden( group_name, blocking_load )
	end
	for index, name in pairs( RANDOM_CHASE_SQUAD_GROUPS ) do
		group_create_hidden( name, blocking_load )
	end
end

function ss08_start( checkpoint_name, is_restart )
   -- Start trigger is hit...the activate button was hit
   set_mission_author("Mark G. & Brad Johnson")

   party_allow_max_followers( true )

   mission_start_fade_out()
   if ( checkpoint_name == MISSION_START_CHECKPOINT ) then
		-- Cutscene and blocking group creation
		if (not is_restart) then
			cutscene_play( CT_INTRO, { HOMIES_GROUP, JUNKIES_GROUP, DRUG_BOXES_GROUP }, { PLAYER1_START, PLAYER2_START }, false )
		else
			teleport_coop(PLAYER1_START, PLAYER2_START)
			group_create_hidden( HOMIES_GROUP, true )
			group_create_hidden( JUNKIES_GROUP, true )
			group_create_hidden( DRUG_BOXES_GROUP, true )
		end

		-- Show groups that should be visible at mission start checkpoint
		group_show( HOMIES_GROUP )
		group_show( JUNKIES_GROUP )
		group_show( DRUG_BOXES_GROUP )

		parking_spot_enable( "parking_spots_$parking_341 (1)", false )
		parking_spot_enable( "parking_spots_$parking_341 (0)", false )

		-- Non-blocking group creation for mission start
		ss08_create_start_and_checkpoint_shared_groups( false )
   end

   ss08_generate_chase_squad_trigger_and_group_names()
   ss08_generate_chase_squad_group_member_names()
   ss08_generate_chase_squad_vehicle_names()
   ss08_hide_doors()

   local next_state = nil
   local dont_play_cutscene = false

   -- Create the ambush groups
   if ( checkpoint_name == MISSION_START_CHECKPOINT ) then
      teleport_coop( PLAYER1_START, PLAYER2_START )
      next_state = MS_INIT
   else --if ( checkpoint_name == CP_TRUCK_LOADED ) then
		teleport_coop( ARRIVAL_NAVPOINTS[LOCAL_PLAYER], ARRIVAL_NAVPOINTS[REMOTE_PLAYER] )

		-- Create these groups blocking, because we need them right after the checkpoint
		-- blocking_load = true
		ss08_create_start_and_checkpoint_shared_groups( true )

		group_create( DRUG_TRUCK_GROUP, true )

      follower_make_independent( PIERCE_NAME, true )
      follower_make_independent( SHAUNDI_NAME, true )		
		teleport( SHAUNDI_NAME, MP.."Pre_Enter_Shaundi", true )
		teleport( PIERCE_NAME, MP.."Pre_Enter_Pierce", true )

      vehicle_enter_group_teleport( { PIERCE_NAME, SHAUNDI_NAME }, DRUG_TRUCK )
      vehicle_suppress_npc_exit( DRUG_TRUCK, true )
      set_unjackable_flag( DRUG_TRUCK, true )

      dont_play_cutscene = true
      next_state = MS_TRUCK_LOADED
   end

   mission_start_fade_in()

	mission_debug( "switching to initial state from start function", 15 )
   ss08_switch_state( next_state, dont_play_cutscene )
end

function ss08_argue_conversation()
   delay( BEFORE_LOAD_PACKAGES_CONVERSATION_TIME_SECONDS )
   audio_play_conversation( SHAUNDI_AND_PIERCE_ARGUE_DIALOG_STREAM, NOT_CALL )
end

-- Switches to a new mission state.
--
-- new_state: The state to switch to.
-- extra_data: Extra information on the state change.
--             For MS_TRUCK_LOADED, sets whether or not
--             to play the cutscene ( default yes. )
--
function ss08_switch_state( new_state, extra_data )
   if ( new_state == MS_INIT ) then
      -- Spawn the junkies
      for index, name in INITIAL_ATTACK_JUNKIE_NAMES do
	      on_death( "ss08_initial_junkie_died", name )
      end
      on_death( "ss08_mission_critical_homie_died", PIERCE_NAME )
      on_death( "ss08_mission_critical_homie_died", SHAUNDI_NAME )

      trigger_enable( WAREHOUSE_AREA, true )
      on_trigger( "ss08_entered_warehouse_area", WAREHOUSE_AREA )
      on_trigger_exit( "ss08_left_warehouse_area", WAREHOUSE_AREA )

      if ( coop_is_active() ) then
         party_add( SHAUNDI_NAME, REMOTE_PLAYER )
      else
         party_add( SHAUNDI_NAME, LOCAL_PLAYER )
      end
      party_add( PIERCE_NAME, LOCAL_PLAYER )
      on_dismiss( "ss08_mission_critical_follower_dismissed", PIERCE_NAME )
      on_dismiss( "ss08_mission_critical_follower_dismissed", SHAUNDI_NAME )
      thread_new( "ss08_before_attack_delay" )
   elseif ( new_state == MS_INITIAL_JUNKIES_ATTACK ) then

      -- Have them come at the player
      -- Track their status so that we know when they all die
      for index, name in INITIAL_ATTACK_JUNKIE_NAMES do
         attack_closest_player( name )
      end

      delay( BEFORE_DEFEND_PROMPT_SECONDS )
      audio_play_conversation( PLAYER_RESPONSE_TO_GRIPE_DIALOG_STREAM, NOT_CALL )
      mission_help_table( HT_DEFEND_THE_DUST, "", "", SYNC_ALL )

   elseif( new_state == MS_REAL_ATTACK_STARTS ) then
      audio_play_conversation( GET_THE_TRUCK_DIALOG_STREAM, NOT_CALL )

		-- Don't have Pierce run away until he's alive and well
		repeat
			thread_yield()
		until( character_is_ragdolled( PIERCE_NAME ) == false and character_is_dead( PIERCE_NAME ) == false )

		mission_debug( "Pierce is not ragdolled or dead." )
		-- Now make sure he can't be killed and have him run off
		turn_invulnerable( PIERCE_NAME )
      -- Have Pierce run away and then disappear when he gets far enough away
      Pierce_leaves_thread_handle = thread_new( "ss08_pierce_leaves" )
      -- Start a timer for Pierce's return.
      hud_timer_set( OBJECTIVE_TIME_INDEX, WAIT_FOR_PIERCE_TIME_MS, "ss08_pierce_returns" )
      -- Make the timer hidden
      hud_timer_hide( OBJECTIVE_TIME_INDEX, true )

      for index, override in pairs( SHAUNDI_JUNKIE_COMBAT_PERSONA_OVERRIDES ) do
         persona_override_character_start( SHAUNDI_NAME, override[1], override[2] )
      end

      -- Start the junkie attack
      ss08_start_junkie_attack()
   elseif ( new_state == MS_LOADING_TRUCK ) then
      -- This has to be set to allow box loading to work
      set_dont_drop_havok_weapons_on_idle( true )

      for index, override in pairs( SHAUNDI_JUNKIE_COMBAT_PERSONA_OVERRIDES ) do
         persona_override_character_stop( SHAUNDI_NAME, override[1] )
      end

      hud_timer_stop( OBJECTIVE_TIME_INDEX )
      hud_timer_hide( OBJECTIVE_TIME_INDEX, false )

      if ( Pierce_leaves_thread_handle ~= INVALID_THREAD_HANDLE ) then
         thread_kill( Pierce_leaves_thread_handle )
         Pierce_leaves_thread_handle = INVALID_THREAD_HANDLE
      end
      -- Get ready for the cutscene
      vehicle_mark_as_players( ESCAPE_CAR_NAME )
      spawning_vehicles( false )
      spawning_vehicles( true )
		spawning_pedestrians( false )
		spawning_pedestrians( true )
		trigger_enable(WAREHOUSE_AREA,false)
		on_trigger( "", WAREHOUSE_AREA )
      on_trigger_exit( "", WAREHOUSE_AREA )
		ss08_stop_failure_countdown( LOCAL_PLAYER )
		if coop_is_active() then
			ss08_stop_failure_countdown( REMOTE_PLAYER )
		end
      cutscene_play( ARRIVAL_CUTSCENE_NAME, DRUG_TRUCK_LOADING_GROUP, { ARRIVAL_NAVPOINTS[LOCAL_PLAYER], ARRIVAL_NAVPOINTS[REMOTE_PLAYER] } )
      -- Have every living junkie attack the player again, because the cutscene can stop them
		ss08_all_living_junkies_attack()

		on_trigger( "ss08_entered_warehouse_area", WAREHOUSE_AREA )
      on_trigger_exit( "ss08_left_warehouse_area", WAREHOUSE_AREA )
		trigger_enable(WAREHOUSE_AREA,true)
      group_hide("ss08_$Arrival_Cutscene")
      group_destroy("ss08_$Arrival_Cutscene")

      mesh_mover_play_action( GARAGE_DOOR, "start1")
      Garage_door_open = true
      
      -- Place the truck in the driveway with Pierce in the seat
      group_show( DRUG_TRUCK_LOADING_GROUP )
      on_vehicle_destroyed( "ss08_drug_truck_destroyed", DRUG_TRUCK_LOADING )
		teleport( PIERCE_NAME, "ss08_$cutscene_truck_half2" )
      character_show( PIERCE_NAME )
      --vehicle_enter_teleport( PIERCE_NAME, DRUG_TRUCK_LOADING, 0, true )
		--teleport_vehicle( DRUG_TRUCK_LOADING, DRUG_TRUCK_LOADING )

      -- Have Pierce come out of the truck and into the main area
      --vehicle_exit( PIERCE_NAME )
      party_add( PIERCE_NAME, LOCAL_PLAYER )
      follower_make_independent( PIERCE_NAME, true )
      set_unjackable_flag( DRUG_TRUCK_LOADING, true )
      vehicle_prevent_explosion_fling( DRUG_TRUCK_LOADING, true )
      vehicle_infinite_mass( DRUG_TRUCK_LOADING, true )

      local run = 2
      local retry_on_failure = true
      local move_and_fire = false
      move_to( PIERCE_NAME, PIERCE_RETURN_TO_LOAD_TRUCK_PATH, run, retry_on_failure, move_and_fire )

         character_show( SHAUNDI_NAME )

      audio_play_conversation( PIERCE_RETURNS_DIALOG_STREAM, NOT_CALL )
      mission_help_table( HT_PROTECT_WHILE_LOADING, "", "", SYNC_ALL )

      -- Once he's there, set him up to be the player's follower and start the loading sequence
      set_ignore_ai_flag( PIERCE_NAME, false )
      turn_vulnerable( PIERCE_NAME )
      on_dismiss( "ss08_mission_critical_follower_dismissed", PIERCE_NAME )

      -- Load up the drugs
         character_show( SHAUNDI_NAME )
      set_ignore_ai_flag( SHAUNDI_NAME, true )
      set_ignore_ai_flag( PIERCE_NAME, true )
      local walk = 1
      follower_make_independent( SHAUNDI_NAME, true )
		-- Have Shaundi get off a vehicle so that she doesn't get stuck on after she's 
		-- made independent
		vehicle_exit( SHAUNDI_NAME )
         character_show( SHAUNDI_NAME )
      on_incapacitated( "ss08_follower_incapacitated", PIERCE_NAME )
      on_incapacitated( "ss08_follower_incapacitated", SHAUNDI_NAME )
      on_revived( "ss08_follower_revived", PIERCE_NAME )
      on_revived( "ss08_follower_revived", SHAUNDI_NAME )
      objective_text( 0, HT_X_OF_Y_BOXES_LOADED, 0, NUM_DRUG_BOXES )
      Homie_drug_carry_threads[PIERCE_NAME] = thread_new( "ss08_homie_load_drugs", PIERCE_NAME )
      Homie_drug_carry_threads[SHAUNDI_NAME] = thread_new( "ss08_homie_load_drugs", SHAUNDI_NAME )
      Argue_converstation_thread_handle = thread_new( "ss08_argue_conversation" )

   elseif ( new_state == MS_TRUCK_LOADED ) then
      if ( Argue_converstation_thread_handle ~= INVALID_THREAD_HANDLE and
           thread_check_done( Argue_converstation_thread_handle ) == false ) then
         thread_kill( Argue_converstation_thread_handle )
      end
      Argue_converstation_thread_handle = INVALID_THREAD_HANDLE

      on_incapacitated( "", PIERCE_NAME )
      on_incapacitated( "", SHAUNDI_NAME )

      on_revived( "", PIERCE_NAME )
      on_revived( "", SHAUNDI_NAME )

      mission_debug( "Entered 'truck loaded' state.", 15 )

      -- Reset the "don't drop weapons on idle" flag because the boxes are done loading
      set_dont_drop_havok_weapons_on_idle( false )

      -- Wait until everyone is alive before stopping the attack and such
      repeat
         thread_yield()
      until ( ss08_homies_alive() )

      notoriety_force_no_spawn( POLICE_GANG, true )
      mission_debug( "Pierce and Shaundi alive. Spawning disabled...", 15 )

      -- Disable the in/out-of-warehouse tracking
      ss08_stop_failure_countdown( LOCAL_PLAYER )
      if ( coop_is_active() ) then
         ss08_stop_failure_countdown( REMOTE_PLAYER )
      end
      trigger_enable( WAREHOUSE_AREA, false )
      minimap_icon_remove_navpoint( WAREHOUSE_AREA )
      -- Turn off the assault
      Assault_turned_on = false

      -- Show the ambush groups
      group_show( OUTSIDE_OF_WAREHOUSE_AMBUSHER_GROUP )
      for index, group_name in pairs( PATH_AMBUSHER_GROUPS ) do
         group_show( group_name )
      end
      -- Setup the triggers for the path ambush groups
      for index, trigger_name in pairs( PATH_AMBUSHER_TRIGGERS ) do
         trigger_enable( trigger_name, true )
         on_trigger( "ss08_path_ambush_0"..index, trigger_name )
      end

      local skip_cutscene = false
      if ( extra_data == true ) then
         skip_cutscene = true
      end

      -- Don't play the conversation if the cutscene is skipped, because in this case
      -- Pierce and Shaundi are already in the truck
      if ( skip_cutscene == false ) then
         mission_debug( "Starting conversation...", 15 )
         -- Have the player tell Pierce that he's loaded the truck
         audio_play_conversation( TRUCK_LOADED_DIALOG_STREAM, NOT_CALL )
         mission_debug( "Conversation complete...", 15 )
      end

      -- Don't continue until Shaundi and Pierce are alive
      repeat
         thread_yield()
      until ( ss08_homies_alive() )
      mission_debug( "Pierce and Shaundi alive. Coming to cutscene...", 15 )

      if ( skip_cutscene == false ) then
         fade_out( 0 )
			teleport( SHAUNDI_NAME, MP.."Pre_Enter_Shaundi", true )
			teleport( PIERCE_NAME, MP.."Pre_Enter_Pierce", true )
         -- Hide all the boxes - in theory they should be "inside" the truck now
			group_hide( DRUG_BOXES_GROUP )
			group_destroy( DRUG_BOXES_GROUP )

         -- Hide Pierce and Shaundi so that there won't be any collision between them
         -- and the cutscene versions
         character_hide( SHAUNDI_NAME )
         character_hide( PIERCE_NAME )
         group_hide( DRUG_TRUCK_LOADING_GROUP )
         group_destroy( DRUG_TRUCK_LOADING_GROUP )
         -- Play the "Pierce and Shaundi board the truck" cutscene
         cutscene_play( SEATING_CUTSCENE_NAME, DRUG_TRUCK_GROUP, { ARRIVAL_NAVPOINTS[LOCAL_PLAYER], ARRIVAL_NAVPOINTS[REMOTE_PLAYER] } )

         -- The cutscene system leaves the group lying around for you to play with after the cutscene is done.
         -- Because we are working with imposters in the cutscene, we need to clean up the imposter group before using the real group.
         -- I group_hide the group first so that group_destroy will actually destroy the other objects, rather than just release-to-world.
         group_hide("ss08_$Cutscene")
         group_destroy("ss08_$Cutscene")

         -- Now that the cutscene is over, unhide the characters used by the cutscene.
         group_show( DRUG_TRUCK_GROUP )
         character_show( SHAUNDI_NAME )
         character_show( PIERCE_NAME )
      else
         -- Hide all the boxes - in theory they should be "inside" the truck now
			if ( group_is_loaded( DRUG_BOXES_GROUP ) ) then
				group_hide( DRUG_BOXES_GROUP )
				group_destroy( DRUG_BOXES_GROUP )
			end
      end

      -- Create the ambusher group
      group_show( OUTSIDE_OF_WAREHOUSE_AMBUSHER_GROUP )
      for index, name in pairs( OUTSIDE_OF_WAREHOUSE_AMBUSHER_MEMBERS ) do
         crouch_start( name )
         mission_debug( name.." was told to crouch.", 15 )
      end
      trigger_enable( OUTSIDE_OF_WAREHOUSE_AMBUSH_TRIGGER, true )
      on_trigger( "ss08_outside_of_warehouse_ambush", OUTSIDE_OF_WAREHOUSE_AMBUSH_TRIGGER )

      -- Put Shaundi and Pierce in the truck
      vehicle_speed_override( DRUG_TRUCK, 0 )
      vehicle_disable_chase( DRUG_TRUCK )
      vehicle_disable_flee( DRUG_TRUCK )
      vehicle_door_prevent_damage_detach( DRUG_TRUCK, "Door_BR", true )
      vehicle_door_prevent_damage_detach( DRUG_TRUCK, "Door_BL", true )
      vehicle_stop( DRUG_TRUCK )
      on_vehicle_destroyed( "ss08_drug_truck_destroyed", DRUG_TRUCK )

      if ( skip_cutscene == false ) then
         follower_make_independent( PIERCE_NAME, true )
         follower_make_independent( SHAUNDI_NAME, true )
			--delay( 2.0 )
			vehicle_enter_teleport( PIERCE_NAME, DRUG_TRUCK, 0 )
			vehicle_enter_teleport( SHAUNDI_NAME, DRUG_TRUCK, 1 )
         vehicle_suppress_npc_exit( DRUG_TRUCK, true )
         set_unjackable_flag( DRUG_TRUCK, true )
      end
      -- else: Pierce and Shaundi are already in the truck if the cutscene is skipped

      set_ignore_ai_flag( SHAUNDI_NAME, false )
      set_ignore_ai_flag( PIERCE_NAME, false )

      turn_invulnerable( PIERCE_NAME )
      turn_invulnerable( SHAUNDI_NAME )
      on_death( "", PIERCE_NAME )
      on_death( "", SHAUNDI_NAME )

      -- Let the player know what he should be doing
      if ( skip_cutscene == false ) then
         mission_help_table( HT_GET_DRUGS_TO_HQ, "", "", SYNC_ALL )
      end

      --mesh_mover_play_action( GARAGE_DOOR, "start2" )
      --Garage_door_open = false

      -- Show the player's escape car
      group_show( ESCAPE_CAR_GROUP )

      -- 
      thread_new( "ss08_check_for_state_change" )

      ss08_add_vehicle_enter_and_exit_callbacks( "ss08_entered_vehicle_escort_van_initial" )

      marker_add_vehicle( ESCAPE_CAR_NAME, MINIMAP_ICON_LOCATION, "" )
      waypoint_add( ESCAPE_CAR_NAME, SYNC_ALL )
      if ( skip_cutscene ) then
         mission_help_table_nag( HT_GET_A_CAR )
      else
         mission_help_table( HT_GET_A_CAR )
      end

      -- Have every living junkie attack the player again, because the cutscene can stop them
		ss08_all_living_junkies_attack()
      mission_set_checkpoint( CP_TRUCK_LOADED )

   elseif ( new_state == MS_TRAVELING_TO_BASE ) then
      thread_new( "ss08_maybe_spawn_random_chase_squad" )

      -- Add truck health display and tracking
      hud_bar_on(0, "Damage", HT_TRUCK_HEALTH )
      hud_bar_set_range(0, 0, 1.0, SYNC_ALL )
      hud_bar_set_value(0, 1.0, SYNC_ALL )
      set_max_hit_points( DRUG_TRUCK, INITIAL_DRUG_TRUCK_HP )
      set_current_hit_points( DRUG_TRUCK, INITIAL_DRUG_TRUCK_HP )
      on_take_damage( "ss08_drug_truck_damaged", DRUG_TRUCK )
      on_collision( "ss08_drug_truck_damaged", DRUG_TRUCK ) 

      -- Activate the obstacles and triggers for the trip back to HQ
      for index, name in pairs( CHASE_SQUAD_GROUP_NAMES ) do
         local chase_trigger_name = CHASE_SQUAD_TRIGGER_NAMES[index]
         trigger_enable( chase_trigger_name, true )
         on_trigger( "ss08_hit_chase_trigger", chase_trigger_name )
      end

      -- Activate the final objective trigger
      trigger_enable( SAINTS_HQ, true )
      on_trigger( "ss08_reached_hq", SAINTS_HQ )
      marker_add_trigger( SAINTS_HQ, "", INGAME_EFFECT_VEHICLE_LOCATION, SYNC_ALL )

      vehicle_infinite_mass( DRUG_TRUCK, true )
      set_cant_flee_flag( SHAUNDI_NAME, true )
      set_cant_flee_flag( PIERCE_NAME, true )
      vehicle_disable_chase( DRUG_TRUCK, true )
      vehicle_disable_flee( DRUG_TRUCK, true )
      vehicle_set_crazy( DRUG_TRUCK, true )

      -- Set the truck to pathfind to the Saints HQ
      vehicle_speed_override( DRUG_TRUCK, DRUG_TRUCK_INITIAL_SPEED_MPH )

      -- use_navmesh = true, stop_at_goal = false
      local p1_success = vehicle_pathfind_to( DRUG_TRUCK, BACK_TO_HQ_PATH_INITIAL, true, false )
      if ( p1_success == false ) then
         mission_debug( "Path one failed" )
      end
      vehicle_ignore_repulsors( DRUG_TRUCK, true )

      -- Require that the player be near the truck, once it gets out of the warehouse area
      distance_display_on( DRUG_TRUCK, 0, DRUG_TRUCK_MAX_DISTANCE_METERS, 0, DRUG_TRUCK_MAX_DISTANCE_METERS, SYNC_ALL )
      on_tailing_good( "ss08_in_range_of_truck" )
      on_tailing_too_far( "ss08_out_of_range_of_truck" )

      for index, path_name in pairs( BACK_TO_HQ_PATHS_MAIN ) do
         -- use_navmesh = false, stop_at_goal = false
         local p2_success = vehicle_pathfind_to( DRUG_TRUCK, path_name, false, false )
         if ( p2_success == false ) then
            mission_debug( "Path two failed" )
         end
      end

      ss08_add_vehicle_enter_and_exit_callbacks( "", "" )

      -- use_navmesh = true, stop_at_goal = true
      local p3_success = vehicle_pathfind_to( DRUG_TRUCK, BACK_TO_HQ_PATH_FINAL, true, true )
      if ( p3_success == false ) then
         mission_debug( "Path three failed" )
      end

      thread_new( "ss08_check_for_victory" )
   end
end

function ss08_all_living_junkies_attack()
	-- Go through all the squads in each direction
	for squad_index, squad in ATTACK_SQUADS_MEMBERS do
		-- Go through each member in each squad
		for junkie_index, junkie_name in pairs( squad ) do
			-- If this junkie isn't dead, then have him attack the player
			if ( character_is_released( junkie_name ) == false ) then
				if ( character_is_dead( junkie_name ) == false ) then
					local distance, player = get_dist_closest_player_to_object( junkie_name )
					attack_safe( junkie_name, player, false )
				end
			end
		end
	end
end

function ss08_homies_alive()
   if ( character_is_dead( PIERCE_NAME ) ) then
      return false
   end
   if ( character_is_dead( SHAUNDI_NAME ) ) then
      return false
   end

   return true
end

function ss08_add_vehicle_enter_and_exit_callbacks( enter_callback, exit_callback )
   if ( enter_callback == nil ) then
      enter_callback = ""
   end
   if ( exit_callback == nil ) then
      exit_callback = ""
   end

   -- Player callbacks
   on_vehicle_enter( enter_callback, LOCAL_PLAYER )
   on_vehicle_exit( exit_callback, LOCAL_PLAYER )
   if ( coop_is_active() ) then
      on_vehicle_enter( enter_callback, REMOTE_PLAYER )
      on_vehicle_exit( exit_callback, REMOTE_PLAYER )
   end

   -- Escape vehicle
   on_vehicle_enter( enter_callback, ESCAPE_CAR_NAME )
   on_vehicle_exit( exit_callback, ESCAPE_CAR_NAME )

   -- Attack squad vehicles
   for index, vehicle_name in pairs( ATTACK_SQUAD_VEHICLES ) do
      if ( vehicle_is_destroyed( vehicle_name ) == false ) then
         on_vehicle_enter( enter_callback, vehicle_name )
         on_vehicle_exit( exit_callback, vehicle_name )
      end
   end

   -- Chase squad vehicles
   for index, vehicle_name in pairs( CHASE_SQUAD_GROUP_VEHICLES ) do
      if ( vehicle_is_destroyed( vehicle_name ) == false ) then
         on_vehicle_enter( enter_callback, vehicle_name )
         on_vehicle_exit( exit_callback, vehicle_name )
      end
   end
end

function ss08_path_ambush_01( triggerer_name, trigger_name )
   if ( triggerer_name == SHAUNDI_NAME or triggerer_name == PIERCE_NAME or
        triggerer_name == LOCAL_PLAYER or triggerer_name == REMOTE_PLAYER ) then
      trigger_enable( trigger_name, false )

      for index, name in pairs( PATH_AMBUSHER_GROUPS_MEMBERS[1] ) do
         attack_safe( name, triggerer_name, false )
      end
   end
end

function ss08_path_ambush_02( triggerer_name, trigger_name )
   if ( triggerer_name == SHAUNDI_NAME or triggerer_name == PIERCE_NAME or
        triggerer_name == LOCAL_PLAYER or triggerer_name == REMOTE_PLAYER ) then
      trigger_enable( trigger_name, false )

      for index, name in pairs( PATH_AMBUSHER_GROUPS_MEMBERS[1] ) do
         attack_safe( name, triggerer_name, false )
      end
   end
end

-- Called when the "outside of warehouse ambush" trigger is hit - causes the-
-- ambushers lurking outside to attack the van.
--
function ss08_outside_of_warehouse_ambush( triggerer_name, trigger_name )
   if ( triggerer_name == SHAUNDI_NAME or triggerer_name == PIERCE_NAME or
        triggerer_name == LOCAL_PLAYER or triggerer_name == REMOTE_PLAYER ) then

      mission_debug( "ambush triggered by "..triggerer_name )

      trigger_enable( trigger_name, false )

      for index, name in pairs( OUTSIDE_OF_WAREHOUSE_AMBUSHER_MEMBERS ) do
         thread_new( "ss08_ambusher_ambush_truck", name, AMBUSHER_GOALS[index] )
      end
   end
end

function ss08_ambusher_ambush_truck( ambusher_name, ambusher_goal )
   npc_leash_remove( ambusher_name )
   crouch_stop( ambusher_name )

   attack_safe( ambusher_name, PIERCE_NAME, false )

   -- speed = run, retry_on_failure = false, move_and_fire = true
   move_to( ambusher_name, ambusher_goal, 2, false, true )
end


function ss08_entered_vehicle_during_escort( character_name, vehicle_name )
   Players_in_vehicle[character_name] = true
   mission_debug( character_name.." entered vehicle" )

   -- Add a callback for this vehicle if it's a script one. The random chase
   -- vehicles need their exit callbacks set to something else initially.
   if ( vehicle_name ~= nil ) then
      on_vehicle_exit( "ss08_left_vehicle_during_escort", vehicle_name )
   end

   if ( ss08_all_players_in_of_range_of_truck() and
        ss08_all_players_in_vehicle() ) then
      mission_debug( "Drug truck resuming" )
      vehicle_speed_override( DRUG_TRUCK, DRUG_TRUCK_DESIRED_SPEED_MPH )
      Truck_waiting = false
   end
end

function ss08_left_vehicle_during_escort( character_name )
   Players_in_vehicle[character_name] = false
   if ( ss08_all_players_in_vehicle() == false ) then
      mission_debug( "Left vehicle" )
      ss08_maybe_truck_start_waiting()
   end
end

function ss08_entered_vehicle_escort_van_initial( character_name )
   -- Update the "player in vehicle" status for both players
   if ( character_is_in_vehicle( LOCAL_PLAYER ) ) then
      Players_in_vehicle[LOCAL_PLAYER] = true
   end
   if ( coop_is_active() and character_is_in_vehicle( REMOTE_PLAYER ) ) then
      Players_in_vehicle[REMOTE_PLAYER] = true
   end
   -- Update the "player in range of truck" status for both players
   if ( get_dist( LOCAL_PLAYER, DRUG_TRUCK ) < DRUG_TRUCK_MAX_DISTANCE_METERS ) then
      Players_in_range_of_drug_truck[LOCAL_PLAYER] = true
   end
   if ( coop_is_active() and get_dist( REMOTE_PLAYER, DRUG_TRUCK ) < DRUG_TRUCK_MAX_DISTANCE_METERS ) then
      Players_in_range_of_drug_truck[REMOTE_PLAYER] = true
   end

   Players_in_vehicle[character_name] = true

   ss08_add_vehicle_enter_and_exit_callbacks( "ss08_entered_vehicle_during_escort",
                                              "ss08_left_vehicle_during_escort" )

   marker_remove_vehicle( ESCAPE_CAR_NAME )
   waypoint_remove( SYNC_ALL )

   mission_help_table( HT_ESCORT_TRUCK_TO_HIDEOUT )
   marker_add_vehicle( DRUG_TRUCK, MINIMAP_ICON_PROTECT_ACQUIRE, INGAME_EFFECT_VEHICLE_PROTECT_ACQUIRE, SYNC_ALL )
end

function ss08_check_for_victory()
   while ( get_dist_char_to_nav( PIERCE_NAME, SAINTS_HQ ) > TO_HQ_WIN_DISTANCE_METERS ) do
      delay( 0 )
   end

   Mission_won = true
   mission_end_success( MISSION_NAME, CT_OUTRO )
end

function ss08_check_for_state_change()
   local neither_player_in_vehicle_and_in_range = true

   while ( neither_player_in_vehicle_and_in_range ) do
      -- 
      local distance = get_dist_char_to_nav( LOCAL_PLAYER, DRUG_TRUCK ) 
      if ( distance < DRUG_TRUCK_MAX_DISTANCE_METERS ) then
         local vehicle_type = get_char_vehicle_type( LOCAL_PLAYER )
         if ( vehicle_type ~= VT_NONE ) then
            neither_player_in_vehicle_and_in_range = false
         end
      end

      if ( coop_is_active() and neither_player_in_vehicle_and_in_range ) then
         distance = get_dist_char_to_nav( REMOTE_PLAYER, DRUG_TRUCK ) 
         if ( distance < DRUG_TRUCK_MAX_DISTANCE_METERS ) then
            local vehicle_type = get_char_vehicle_type( REMOTE_PLAYER )
            if ( vehicle_type ~= VT_NONE ) then
               neither_player_in_vehicle_and_in_range = false
	         end
         end
      end

      delay( 0 )
   end

	mission_debug( "switching to state MS_TRAVELING_TO_BASE from check_for_state_change", 15 )
   ss08_switch_state( MS_TRAVELING_TO_BASE )
end

function ss08_maybe_truck_start_waiting()
   if ( Truck_waiting == false ) then
      mission_debug( "Drug truck waiting" )
      mission_help_table( HT_PIERCE_WAITING_ON_YOU, SYNC_ALL )
      vehicle_speed_override( DRUG_TRUCK, 0 )
      Truck_waiting = true
   end
end

function ss08_in_range_of_truck( triggerer_name )
   mission_debug( triggerer_name.." in range" )
   Players_in_range_of_drug_truck[triggerer_name] = true

   if ( ss08_all_players_in_of_range_of_truck() and
        ss08_all_players_in_vehicle() ) then
      vehicle_speed_override( DRUG_TRUCK, DRUG_TRUCK_DESIRED_SPEED_MPH )
      Truck_waiting = false
   end
end

function ss08_out_of_range_of_truck( triggerer_name )
   mission_debug( triggerer_name.." out of range" )
   Players_in_range_of_drug_truck[triggerer_name] = false

   ss08_maybe_truck_start_waiting()
end

function ss08_get_chase_group_index_from_trigger_name( trigger_name )
   for index, name in pairs( CHASE_SQUAD_TRIGGER_NAMES ) do
      if ( name == trigger_name ) then
         return index
      end
   end
   return nil
end

function ss08_get_vehicle_group_index_from_name( vehicle_name )
   for index, name in pairs( CHASE_SQUAD_GROUP_VEHICLES ) do
      if ( name == vehicle_name ) then
         return index
      end
   end

   for index, name in pairs( RANDOM_CHASE_SQUAD_VEHICLES ) do
      if ( name == vehicle_name ) then
         return index + NUM_CHASE_SQUADS
      end
   end
   return nil
end

function ss08_get_npc_group_index_from_name( npc_name )
   for group_index, npc_list in pairs ( CHASE_SQUAD_GROUP_MEMBERS ) do
      for index, name in pairs( npc_list ) do
         if ( name == npc_name ) then
            return group_index
         end
      end
   end

   for group_index, npc_list in pairs( RANDOM_CHASE_SQUAD_MEMBERS ) do
      for index, name in pairs( npc_list ) do
         if ( name == npc_name ) then
            return group_index + NUM_CHASE_SQUADS
         end
      end
   end

   return nil
end

function ss08_hit_chase_trigger( triggerer_name, trigger_name )
   ss08_maybe_spawn_random_chase_squad()
   trigger_enable( trigger_name, false )
   --[[
   if ( Num_chasing_cars < MAX_CHASING_CARS ) then
      -- Disable the trigger so that this chase group only spawns once!
      trigger_enable( trigger_name, false )

      -- Find out which group we should spawn for this trigger
      local group_index = ss08_get_chase_group_index_from_trigger_name( trigger_name )

      Chase_squad_cars_chasing[group_index] = true

      -- 
      group_show( CHASE_SQUAD_GROUP_NAMES[group_index] )
      vehicle_enter_group_teleport( CHASE_SQUAD_GROUP_MEMBERS[group_index], CHASE_SQUAD_GROUP_VEHICLES[group_index] )

      on_vehicle_destroyed( "ss08_chase_car_destroyed", CHASE_SQUAD_GROUP_VEHICLES[group_index] )
      on_vehicle_exit( "ss08_attacker_leaves_chase_car", CHASE_SQUAD_GROUP_VEHICLES[group_index] )

      delay( 0 )
      local driver = get_char_in_vehicle( CHASE_SQUAD_GROUP_VEHICLES[group_index], 0)
      on_death( "ss08_chase_car_driver_killed", driver )

      -- 
--      local distance
--      local player
--      distance, player = get_dist_closest_player_to_object( driver )
      attack_safe( driver, SHAUNDI_NAME, false )
      Num_chasing_cars = Num_chasing_cars + 1
   end
   ]]
end

function ss08_find_nearest_chase_trigger_to_drug_truck()
   local closest_location = RANDOM_CHASE_SQUAD_SPAWN_LOCATIONS[1]
   local closest_dist = get_dist( DRUG_TRUCK, closest_location )

   for index, nav_name in pairs( RANDOM_CHASE_SQUAD_SPAWN_LOCATIONS ) do
      local cur_dist = get_dist( DRUG_TRUCK, nav_name )
      if ( cur_dist <= closest_dist --[[and ss08_navpoint_out_of_players_fov( nav_name )]] ) then
         closest_dist = cur_dist
         closest_location = nav_name
      end
   end

   return closest_location
end

function ss08_maybe_spawn_random_chase_squad()
   mission_debug( "rc spawning - waiting" )
   -- Only spawn one squad at a time in order to prevent overlap
   repeat
      thread_yield()
   until ( Group_spawning == false )

   if ( Num_chasing_cars < MAX_CHASING_CARS ) then
      Num_chasing_cars = Num_chasing_cars + 1

      mission_debug( "rc spawning - started", 15 )

      Group_spawning = true
      delay( RANDOM_CHASE_SQUAD_SPAWN_INTERVAL_SECONDS )

      -- Choose and create one of the chase groups
      local group_index = Last_random_chase_group_index + 1
      if ( group_index > RANDOM_CHASE_SQUAD_COUNT ) then
         group_index = 1
      end

      -- We record the random chase squads after the chase squads in the list
      -- of chasing cars
      Chase_squad_cars_chasing[group_index + NUM_CHASE_SQUADS] = true

      local group_to_load = RANDOM_CHASE_SQUAD_GROUPS[group_index]
      mission_debug( "rc spawning - decided to load group "..group_to_load, 15 )
      if ( group_is_loaded( group_to_load ) ) then
         release_to_world( group_to_load )
      end

      group_create( group_to_load, true )
      mission_debug( "rc spawning - loaded group "..group_to_load, 15 )

      local member_count = sizeof_table( RANDOM_CHASE_SQUAD_MEMBERS[group_index] )
      local num_with_heavy_weapons = rand_int( 2, member_count )
      local num_with_light_weapons = member_count - num_with_heavy_weapons

      -- Arm the members of the chase squad
      local function give_random_weapon( member_name, weapon_types )
         local weapon_index = rand_int( 1, sizeof_table( weapon_types ) )
         inv_item_add( weapon_types[weapon_index], 1, member_name )
         inv_item_add_ammo( member_name, weapon_types[weapon_index], 100 )
      end
      for index, member_name in pairs( RANDOM_CHASE_SQUAD_MEMBERS[group_index] ) do
         if ( index <= num_with_heavy_weapons ) then
            give_random_weapon( member_name, CHASE_SQUAD_HEAVY_WEAPONS )
         else
            give_random_weapon( member_name, CHASE_SQUAD_LIGHT_WEAPONS )
         end
         give_random_weapon( member_name, CHASE_SQUAD_THROWN_WEAPONS )
      end

      -- 
      vehicle_enter_group_teleport( RANDOM_CHASE_SQUAD_MEMBERS[group_index],
                                    RANDOM_CHASE_SQUAD_VEHICLES[group_index] )

      on_vehicle_enter( "ss08_entered_vehicle_during_escort", RANDOM_CHASE_SQUAD_VEHICLES[group_index] )

      on_vehicle_destroyed( "ss08_chase_car_destroyed", RANDOM_CHASE_SQUAD_VEHICLES[group_index] )
      on_vehicle_exit( "ss08_attacker_leaves_chase_car", RANDOM_CHASE_SQUAD_VEHICLES[group_index] )

      -- Wait for the driver to be seated
      delay( 0 )
      local driver = get_char_in_vehicle( RANDOM_CHASE_SQUAD_VEHICLES[group_index], 0)
      on_death( "ss08_chase_car_driver_killed", driver )

      -- Teleport the chase squad vehicle to the location and give chase
      -- Find the nearest chase trigger
      local location = ss08_find_nearest_chase_trigger_to_drug_truck()

      teleport_vehicle( RANDOM_CHASE_SQUAD_VEHICLES[group_index], location )
      mission_debug( "rc attacking" )
      for index, member_name in pairs( RANDOM_CHASE_SQUAD_MEMBERS[group_index] ) do
         attack_safe( member_name, PIERCE_NAME, false )
      end

      Last_random_chase_group_index = group_index

      -- Give the car some time to start chasing
      mission_debug( "rc delay" )
      delay( 3.0 )
      Group_spawning = false
      mission_debug( "rc spawning - done", 15 )
   end
end

function ss08_chase_car_removed( group_index )
   Num_chasing_cars = Num_chasing_cars - 1
   Chase_squad_cars_chasing[group_index] = false

   ss08_maybe_spawn_random_chase_squad()
end

function ss08_chase_car_driver_killed( driver_name )
   -- If a chase car's driver is killed, then remove the car's destroyed callback
   local group_index = ss08_get_npc_group_index_from_name( driver_name )

   if ( Chase_squad_cars_chasing[group_index] ) then
      if ( group_index <= NUM_CHASE_SQUADS ) then
         on_vehicle_destroyed( "", CHASE_SQUAD_GROUP_VEHICLES[group_index] )
         on_vehicle_exit( "", CHASE_SQUAD_GROUP_VEHICLES[group_index] )
         -- Remove the exit 
         for index, member_name in CHASE_SQUAD_GROUP_MEMBERS[group_index] do
            on_death( "", member_name )
         end
      else
         local rc_group_index = group_index - NUM_CHASE_SQUADS
         on_vehicle_destroyed( "", RANDOM_CHASE_SQUAD_VEHICLES[rc_group_index] )
         on_vehicle_exit( "ss08_left_vehicle_during_escort", RANDOM_CHASE_SQUAD_VEHICLES[rc_group_index] )
         -- Remove the exit 
         for index, member_name in RANDOM_CHASE_SQUAD_MEMBERS[rc_group_index] do
            on_death( "", member_name )
         end
      end

      ss08_chase_car_removed( group_index )
   end
end

function ss08_attacker_leaves_chase_car( attacker, chase_car )
   local group_index = ss08_get_vehicle_group_index_from_name( chase_car )

   if ( Chase_squad_cars_chasing[group_index] ) then
      on_vehicle_destroyed( "", chase_car )
      on_vehicle_exit( "ss08_left_vehicle_during_escort", chase_car )

      if ( group_index <= NUM_CHASE_SQUADS ) then
         -- Remove callbacks on every member... should get the driver :)
         for index, member_name in CHASE_SQUAD_GROUP_MEMBERS[group_index] do
            on_death( "", member_name )
         end
      else
         local rc_group_index = group_index - NUM_CHASE_SQUADS

         -- Remove callbacks on every member... should get the driver :)
         for index, member_name in RANDOM_CHASE_SQUAD_MEMBERS[rc_group_index] do
            on_death( "", member_name )
         end
      end

      ss08_chase_car_removed( group_index )
   end
end

function ss08_chase_car_destroyed( vehicle_name )
   -- If a chase car is destroyed, then remove its driver's callback
   local group_index = ss08_get_vehicle_group_index_from_name( vehicle_name )

   if ( Chase_squad_cars_chasing[group_index] ) then

      if ( group_index <= NUM_CHASE_SQUADS ) then
         on_vehicle_exit( "", CHASE_SQUAD_GROUP_VEHICLES[group_index] )
         -- Remove callbacks on every member... should get the driver :)
         for index, member_name in CHASE_SQUAD_GROUP_MEMBERS[group_index] do
            on_death( "", member_name )
         end
      else
         local rc_group_index = group_index - NUM_CHASE_SQUADS
         on_vehicle_exit( "", RANDOM_CHASE_SQUAD_VEHICLES[rc_group_index] )

         -- Remove callbacks on every member... should get the driver :)
         for index, member_name in RANDOM_CHASE_SQUAD_MEMBERS[rc_group_index] do
            on_death( "", member_name )
         end
      end

      ss08_chase_car_removed( group_index )
   end
end

function ss08_drug_truck_destroyed()
   mission_end_failure( MISSION_NAME, HT_TRUCK_DESTROYED )
end

function ss08_drug_truck_damaged()
   local cur_truck_hp = get_current_hit_points( DRUG_TRUCK )
   local percent_remaining = cur_truck_hp / INITIAL_DRUG_TRUCK_HP

   hud_bar_set_value(0, percent_remaining, SYNC_ALL )
end

function ss08_reached_hq( triggerer_name, trigger_name )
   -- Check to see if the person who triggered it is in the drug truck
   local character_driving_drug_truck = get_char_in_vehicle( DRUG_TRUCK, 0 )
   -- If so, we win the mission
   if ( character_driving_drug_truck == triggerer_name ) then
      audio_play_conversation( END_MISSION_DIALOG_STREAM, NOT_CALL )
      Mission_won = true
      mission_end_success( MISSION_NAME, CT_OUTRO )
   end
end

-- This function gets Pierce to leave the warehouse, obstensibly to get a
-- truck to cart the drugs away with.
--
function ss08_pierce_leaves()
   -- Have Pierce leave the player
   turn_invulnerable( PIERCE_NAME )
	thread_yield()
   on_dismiss( "", PIERCE_NAME )
   party_dismiss( PIERCE_NAME )
   set_ignore_ai_flag( PIERCE_NAME, true )
   character_prevent_flinching( PIERCE_NAME, true )
   character_prevent_explosion_fling( PIERCE_NAME, true )
   character_prevent_kneecapping( PIERCE_NAME, true )
	if ( crouch_is_crouching( PIERCE_NAME ) ) then
		crouch_stop( PIERCE_NAME )
		delay( 0.5 )
	end
	-- Set up the "where's Pierce" audio line
   thread_new( "ss08_where_is_pierce_delay" )

   -- Pathfind him to a location
   local run = 2
   local retry_on_failure = true
   local move_and_fire = false
   move_to( PIERCE_NAME, PIERCE_GET_TRUCK_PATH, run, retry_on_failure, move_and_fire )
   -- Hide him
   character_hide( PIERCE_NAME )
   Pierce_leaves_thread_handle = INVALID_THREAD_HANDLE

   character_prevent_flinching( PIERCE_NAME, false )
   character_prevent_explosion_fling( PIERCE_NAME, false )
   character_prevent_kneecapping( PIERCE_NAME, false )
end

-- Delay before Shaundi wonders where Pierce is.
--
function ss08_where_is_pierce_delay()
   local where_is_pierce_time_seconds = WHERE_IS_PIERCE_MESSAGE_DELAY_SECONDS
   while ( where_is_pierce_time_seconds > 0 ) do
      where_is_pierce_time_seconds = where_is_pierce_time_seconds - get_frame_time()
      delay( 0 )
   end

   -- Shaundi complains
   audio_play_for_character( SHAUNDI_WHATS_TAKING_SO_LONG_LINE, SHAUNDI_NAME, "voice", false, false )
end

-- This function is called when Pierce is due to return. It causes him to come back
-- and spawns the truck that the player uses to escape with the drugs.
--
function ss08_pierce_returns()
	--repeat
	--	thread_yield()
	--until ( thread_check_done( Pierce_leaves_thread_handle ) == true )

	if ( Pierce_has_returned == false ) then
		Pierce_has_returned = true

		mission_debug( "switching to state MS_LOADING_TRUCK from pierce_returns", 15 )
		ss08_switch_state( MS_LOADING_TRUCK )
	end
end

-- Callback when the truck has been loaded.
-- TBD: by a timer or by the homies collecting sufficient drugs
--
function ss08_truck_loaded()
   objective_text_clear( 0 )

	mission_debug( "switching to state MS_TRUCK_LOADED from truck_loaded", 15 )
   ss08_switch_state( MS_TRUCK_LOADED )
end

-- Returns the index of the next un-collected drug box.
--
function ss08_get_next_drug_box_index()
   return ( NUM_DRUG_BOXES - Cur_drug_boxes_remaining ) + 1
end

function ss08_homie_load_drugs( homie_name )
   -- Check to see if enough packages have been queued to be dropped of
      -- If so, stop loading.
      -- If not, repeat...
   while ( Drug_boxes_queued + Drug_boxes_loaded < NUM_DRUG_BOXES ) do
      local target_box = nil
      -- Target a package that's not currently targeted
      for index, box_name in pairs( DRUG_BOXES ) do
         if ( Whos_carrying_drug_boxes[box_name] == nil ) then
            target_box = box_name
            Whos_carrying_drug_boxes[box_name] = homie_name
            break
         end
      end
      if ( target_box == nil ) then
         return
      end
      Drug_boxes_queued = Drug_boxes_queued + 1

      local walk = 1
      local run = 2
      local retry_on_failure = true
      local move_and_fire = false
      -- Run toward the package
      move_to( homie_name, BOX_PICKUP_NAV, run, retry_on_failure, move_and_fire )

      -- Pick up the package
	   item_wield( target_box, homie_name, false )

      -- Walk toward the dropoff
      move_to( homie_name, BOX_DROPOFFS[homie_name], walk, retry_on_failure, move_and_fire )

      if ( character_is_dead( homie_name ) ) then
         return
      end

      -- Drop off the package
      turn_to( homie_name, BOX_LOADING_TARGET )
      item_throw( homie_name, BOX_LOADING_TARGET )
      delay( 2.0 )

--      item_drop( target_box, homie_name )
--      BOX_LOADING_TARGET
--      item_hide( target_box )
      Whos_carrying_drug_boxes[target_box] = DRUG_TRUCK

      -- Mark the package as dropped off and inform the mission (help text, etc)
      Drug_boxes_queued = Drug_boxes_queued - 1
      Drug_boxes_loaded = Drug_boxes_loaded + 1
      objective_text( 0, HT_X_OF_Y_BOXES_LOADED, Drug_boxes_loaded, NUM_DRUG_BOXES )

      if ( Drug_boxes_loaded == NUM_DRUG_BOXES ) then
         ss08_truck_loaded()
      end
   end
end

-- This function begins the junkie attack and sets us the callbacks such that
-- the attack will continue until the player escapes with the truck.
--
function ss08_start_junkie_attack()
   -- Calculate which attack squad we should be attacking with
   ss08_attack_squad_spawn( SOUTH )

   -- Set death tracking up
   ss08_add_death_tracking( SOUTH )

   -- Have the west squad come and attack
   ss08_attack_squad_attack( SOUTH )

   -- Set up time to be allowed to attack from another direction
   --thread_new( "ss08_other_direction_allowed_delay" )
   Cur_attack_directions[1] = SOUTH

   Assault_turned_on = true
end

-- Adds death tracking for junkie attack squads.
--
-- attack_direction: The direction of the squad to add callbacks for
--
function ss08_add_death_tracking( attack_direction )
   for index, name in pairs( ATTACK_SQUADS_MEMBERS[attack_direction] ) do
      Cur_attackers_remaining = Cur_attackers_remaining + 1
      on_death( "ss08_squad_member_died", name )
   end
   mission_debug( "Cur_attackers_remaining = "..Cur_attackers_remaining..".", 5 )
end

-- Gets the next dropoff point in the list. Once the list runs out,
-- starts getting from the beginning of the list.
--
-- attack_direction: Which direction the dropoff point should be
--                   located in.
--
function ss08_get_next_dropoff_point( attack_direction )
   -- Find the next dropoff index in this direction based on the previous one
   local next_dropoff_index_in_direction = Last_dropoff_indices[attack_direction] + 1

   -- Check to see if this is in range
   if ( next_dropoff_index_in_direction > DROPOFF_COUNTS[attack_direction] ) then
      -- Out-of-range - roll over the counter
      next_dropoff_index_in_direction = 1
   end

   local next_dropoff_point = DROPOFF_POINTS[attack_direction][next_dropoff_index_in_direction]

   -- We've found the index of the next dropoff point - update the last dropoff index used for this
   -- direction
   Last_dropoff_indices[attack_direction] = next_dropoff_index_in_direction

   return next_dropoff_point
end

function ss08_navpoint_out_of_players_fov( navpoint_name )
   if ( navpoint_in_player_fov( navpoint_name, LOCAL_PLAYER ) == false ) then
      if ( coop_is_active() ) then
         if ( navpoint_in_player_fov( navpoint_name, REMOTE_PLAYER ) == false ) then
            return true
         end
      else
         return true
      end
   end

   return false
end

function ss08_attack_squad_spawn( attack_direction )
   group_create_hidden( ALL_ATTACK_SQUADS[attack_direction], true )
end

function ss08_attack_squad_attack( attack_direction )
   -- Have the members board the car
   vehicle_enter_group_teleport( ATTACK_SQUADS_MEMBERS[attack_direction],
                                 ATTACK_SQUAD_VEHICLES[attack_direction] )

   repeat
      thread_yield()
   until ( ss08_all_players_in_warehouse_area() or
           ss08_navpoint_out_of_players_fov( ATTACK_SQUAD_VEHICLES[attack_direction] ) )

   -- Make the squad visible
   group_show( ALL_ATTACK_SQUADS[attack_direction] )

   -- Lead it along the initial path
   vehicle_pathfind_to( ATTACK_SQUAD_VEHICLES[attack_direction],
                        ATTACK_VEHICLE_PATHS[attack_direction], true, false )

   -- Select a dropoff point
   local dropoff_point = ss08_get_next_dropoff_point( attack_direction )

   mission_debug( "Direction: "..attack_direction.." squad pathing to dropoff "..dropoff_point, 15 )

   -- Have it pathfind here
   vehicle_pathfind_to( ATTACK_SQUAD_VEHICLES[attack_direction],
                        dropoff_point, true, true )

   -- Have the vehicle inhabitants attack
   for index, member in pairs( ATTACK_SQUADS_MEMBERS[attack_direction] ) do
      thread_new( "ss08_member_do_attack", member )
   end

   -- Release the car to the world to avoid congestion
   release_to_world( ATTACK_SQUAD_VEHICLES[attack_direction] )
end

function ss08_member_do_attack( member_name )
   if ( character_is_released( member_name ) == false ) then
      if ( character_is_dead( member_name ) == false ) then
         if ( character_is_in_vehicle( member_name ) == true ) then
            vehicle_exit( member_name )
         end
         attack_closest_player( member_name )
      end
   end
end

function ss08_entered_drug_truck( player_name, vehicle_name )

	mission_debug( "switching to state MS_TRAVELING_TO_BASE from entered_drug_truck", 15 )
   ss08_switch_state( MS_TRAVELING_TO_BASE )
end

function ss08_next_junkie_wave_attack()
   -- Calculate the next attack directions.
   Cur_attack_directions = ss08_get_next_attack_directions()

   for index, direction in pairs( Cur_attack_directions ) do
      ss08_attack_squad_spawn( direction )

      -- Set death tracking up
      ss08_add_death_tracking( direction )
   end

   for index, direction in pairs( Cur_attack_directions ) do
      -- Have the squad come and attack
      thread_new( "ss08_attack_squad_attack", direction )
   end
end

function ss08_get_next_attack_directions()
   local attack_directions = {}

   -- Waves up to a point should only come from one direction
   if ( Num_junkie_attack_waves_defeated < 2 ) then
      if ( Cur_attack_directions[1] == NUM_ATTACK_DIRECTIONS ) then
         attack_directions[1] = 1
      else
         attack_directions[1] = Cur_attack_directions[1] + 1
      end
   -- Waves after the cutoff should come from two directions at once
   else
      -- Find a random direction
      attack_directions[1] = (rand_int( 1, NUM_ATTACK_DIRECTIONS ))
      -- Now, find another one that's different than the first
      repeat
         attack_directions[2] = (rand_int( 1, NUM_ATTACK_DIRECTIONS ))
      until ( attack_directions[2] ~= attack_directions[1] )
   end

   return attack_directions
end

function ss08_force_spawn_wave( wave_index_at_force_spawn )
   delay ( BELOW_MIN_ATTACKERS_FORCE_SPAWN_DELAY_SECONDS )

   local cur_wave_index = Num_junkie_attack_waves_defeated + 1

   -- If the force-spawn situation no longer exists, abort.
   if ( Cur_attackers_remaining >= MIN_ATTACKERS or
        Cur_attackers_remaining == 0 or
        -- Another wave has been spawned while we were waiting
        cur_wave_index > wave_index_at_force_spawn or
        Assault_turned_on == false ) then
      return
   end

   -- For each currently attacking direction
   for index, direction in pairs ( Cur_attack_directions ) do
      release_to_world( ALL_ATTACK_SQUADS[direction] )
   end

   Cur_attackers_remaining = 0
   mission_debug( "Cur_attackers_remaining = "..Cur_attackers_remaining..".", 5 )
   Num_junkie_attack_waves_defeated = Num_junkie_attack_waves_defeated + 1
   ss08_next_junkie_wave_attack()
end

function ss08_squad_member_died( member_name )
   if ( character_is_released( member_name ) == false ) then
      release_to_world( member_name )
   end
   Cur_attackers_remaining = Cur_attackers_remaining - 1
   mission_debug( "Cur_attackers_remaining = "..Cur_attackers_remaining..".", 5 )

   -- 
   if ( Cur_attackers_remaining < MIN_ATTACKERS ) then
      Force_spawn_thread_handle = thread_new( "ss08_force_spawn_wave", Num_junkie_attack_waves_defeated + 1 )
   end

   if ( Cur_attackers_remaining == 0 and Assault_turned_on == true ) then
      Num_junkie_attack_waves_defeated = Num_junkie_attack_waves_defeated + 1
      -- For each direction
      for index, direction in pairs ( Cur_attack_directions ) do
         release_to_world( ALL_ATTACK_SQUADS[direction] )
      end
      ss08_next_junkie_wave_attack()
   end
end

-- This function delays for a short time and then makes a callback,
-- switching the mission state to the "Three Junkies attack" state.
--
function ss08_before_attack_delay()
   --action_play_non_blocking( character_name, anim_name, morph_name, force_play, stand_still )
   action_play_non_blocking( PIERCE_NAME, "talk disrespect", "", true, true )
   audio_play_conversation( PIERCE_COMPLAINING_DIALOG_STREAM, NOT_CALL )

	mission_debug( "switching to state MS_INITIAL_JUNKIES_ATTACK from before_attack_delay", 15 )
   ss08_switch_state( MS_INITIAL_JUNKIES_ATTACK )
end

-- Callback on death of the initial junkies that are spawned
-- when the junkie attack starts.
--
-- junkie_name: Name of the junkie that died.
--
function ss08_initial_junkie_died( junkie_name )
   release_to_world( junkie_name )
   Initial_junkies_remaining = Initial_junkies_remaining - 1
   if ( Initial_junkies_remaining == 3 ) then
		mission_debug( "switching to state MS_REAL_ATTACK_STARTS from initial_junkie_died", 15 )
		ss08_switch_state( MS_REAL_ATTACK_STARTS )
   end
end

function ss08_cleanup()
   -- Cleanup mission here
   --for index, name in pairs( DRUG_BOXES ) do
   --   mesh_mover_show( name )
   --end

   -- Clean up any ambient junkies, since they may have been released to the world
   spawning_pedestrians( false )
   spawning_pedestrians( true )

   ss08_add_vehicle_enter_and_exit_callbacks( "", "" )
   if ( Garage_door_open ) then
      mesh_mover_play_action( GARAGE_DOOR, "start2" )
   end
   on_dismiss( "", PIERCE_NAME )
   on_dismiss( "", SHAUNDI_NAME )
   on_death( "", PIERCE_NAME )
   on_death( "", SHAUNDI_NAME )
   on_tailing_too_far( "" )
   on_tailing_good( "" )
   on_vehicle_destroyed( "", DRUG_TRUCK )
   on_take_damage( "", DRUG_TRUCK )
   on_collision( "", DRUG_TRUCK )
   distance_display_off(SYNC_ALL)
   hud_timer_stop( OBJECTIVE_TIME_INDEX)
   hud_timer_hide( OBJECTIVE_TIME_INDEX, false )
   hud_timer_stop( FAILURE_TIME_INDEX )
   for index, name in pairs( CHASE_SQUAD_GROUP_NAMES ) do
      local chase_trigger_name = CHASE_SQUAD_TRIGGER_NAMES[index]
      trigger_enable( chase_trigger_name, false )
      on_trigger( "", chase_trigger_name )
   end
   notoriety_force_no_spawn( POLICE_GANG, false )

   trigger_enable( WAREHOUSE_AREA, false )
   on_trigger( "", WAREHOUSE_AREA )
   on_trigger_exit( "", WAREHOUSE_AREA )
   -- Activate the final objective trigger
   trigger_enable( SAINTS_HQ, false )
   on_trigger( "", SAINTS_HQ )
   set_dont_drop_havok_weapons_on_idle( false )
   party_allow_max_followers( false )

   if ( vehicle_exists( DRUG_TRUCK ) ) then
      vehicle_door_prevent_damage_detach( DRUG_TRUCK, "Door_BR", false )
      vehicle_door_prevent_damage_detach( DRUG_TRUCK, "Door_BL", false )
   end

	parking_spot_enable( "parking_spots_$parking_341 (1)", true )
	parking_spot_enable( "parking_spots_$parking_341 (0)", true )

   ss08_hide_doors( false )
end

function ss08_success()
	-- Called when the mission has ended with success
end
