Files
2025-09-29 00:52:08 +02:00

774 lines
26 KiB
Python
Executable File

//////////////////////////////////////////////////////////////////////////////////////////
// //
// SCRIPT NAME : ambient_sonar.sc //
// AUTHOR : Joanna Wright //
// DESCRIPTION : Sets up 50 items scraps around the map for the //
// player to collect in a submarine //
// //
//////////////////////////////////////////////////////////////////////////////////////////
//Compile out Title Update changes to header functions.
//Must be before includes.
//CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R.
//----------------------
// INCLUDES
//----------------------
USING "email_public.sch"
USING "RC_Helper_Functions.sch"
USING "rgeneral_include.sch"
USING "commands_entity.sch"
USING "CompletionPercentage_public.sch"
USING "properties_private.sch"
USING "savegame_public.sch"
USING "scrap_common.sch"
USING "achievement_public.sch"
USING "net_system_activity_feed.sch"
//----------------------
// ENUMS
//----------------------
ENUM MISSION_STATUS
MS_INIT,
MS_IN_SUB,
MS_OUT_OF_SUB,
MS_CLEANUP
ENDENUM
//----------------------
// CONSTS
//----------------------
CONST_INT XVERSION_NUMBER 106
CONST_FLOAT CREATE_CULL_SPHERE_DISTANCE 100.0
CONST_FLOAT REMOVE_CULL_SPHERE_DISTANCE 105.0
//---------------------
// VARIABLES
//----------------------
SCRAP_MISSION_DATA sMissionData
SCRAP_PICKUP_DATA sSonarPickups[NUMBER_OF_SONAR_PICKUPS]
VEHICLE_INDEX viSub
BLIP_INDEX biSub
MISSION_STATUS eStage = MS_INIT
BOOL bTrkRestartHelpDisplayed = FALSE
INT iTrackifyUpdateCounter = 0
INT iNearestScrapIndex = -1
INT iScrapsPerFrame = 5
INT iMessageStage = 0
SCALEFORM_INDEX siMessage
INT iSphereIndexOnPickup[NUMBER_OF_SONAR_PICKUPS]
#IF IS_DEBUG_BUILD
WIDGET_GROUP_ID mWidgetGroup
BOOL bMapAllScraps
BOOL bWarpToScrap[NUMBER_OF_SONAR_PICKUPS]
BOOL bCreateSub
BOOL bDebugQuitScript
BOOL bDebugAllowWarping
BOOL bCollectAllScraps
BOOL bResetScrapCollection
BOOL bSimulateScrapCollect
INT iSimulateScrapCollect = 1
#ENDIF
//----------------------
// PLAYER FUNCTIONS
//----------------------
/// PURPOSE:
/// Set the correct stage and revert it to setup
PROC SET_STAGE(MISSION_STATUS stage)
eStage = stage
ENDPROC
/// PURPOSE:
/// Removes sub blip
PROC REMOVE_SUB_BLIP()
IF DOES_BLIP_EXIST(biSub)
REMOVE_BLIP(biSub)
ENDIF
ENDPROC
/// PURPOSE:
/// Remove blip and release sub
PROC RELEASE_SUB()
REMOVE_SUB_BLIP()
IF DOES_ENTITY_EXIST(viSub)
SET_VEHICLE_AS_NO_LONGER_NEEDED(viSub)
ENDIF
ENDPROC
/// PURPOSE:
/// Is the player inside a submersible
FUNC BOOL IS_PLAYER_IN_SUBMERSIBLE()
IF IS_PLAYER_PLAYING(PLAYER_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
VEHICLE_INDEX veh = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
IF DOES_ENTITY_EXIST(veh)
IF GET_ENTITY_MODEL(veh) = SUBMERSIBLE
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
//---------------------
// ARRAY FUNCTIONS
//----------------------
/// PURPOSE:
/// Returns the coordinate of the scrap piece specified by the index.
FUNC VECTOR GET_SONAR_COORD(INT index)
SWITCH index
CASE 0 RETURN << -1435.61, 5781.12, -29.87 >> BREAK
CASE 1 RETURN << -1956.54, -1125.07, -37.21 >> BREAK
CASE 2 RETURN << 2752.88, -1212.78, -22.41 >> BREAK
CASE 3 RETURN << 3188.04, -1668.19, -146.88 >> BREAK
CASE 4 RETURN << 2555.04, -2372.47, -112.01 >> BREAK
CASE 5 RETURN << 2945.90, 6537.41, -27.36 >> BREAK
CASE 6 RETURN << -1266.69, 6261.75, -34.17 >> BREAK
CASE 7 RETURN << 3034.72, 6550.42, -35.20 >> BREAK
CASE 8 RETURN << 1694.53, 6991.69, -137.62 >> BREAK
CASE 9 RETURN << 1233.43, 7081.15, -141.72 >> BREAK
CASE 10 RETURN << -3413.73, 830.23, -12.95 >> BREAK
CASE 11 RETURN << 1422.50, 6854.67, -38.20 >> BREAK
CASE 12 RETURN << -3345.10, 3547.80, -59.10 >> BREAK
CASE 13 RETURN << -3437.93, 3069.57, -54.85 >> BREAK
CASE 14 RETURN << -2909.28, 4204.32, -111.62 >> BREAK
CASE 15 RETURN << -3179.12, 2151.28, -31.86 >> BREAK
CASE 16 RETURN << 4146.09, 3825.86, -40.96 >> BREAK
CASE 17 RETURN << 2716.61, 6956.91, -157.17 >> BREAK
CASE 18 RETURN << 2487.50, 7001.69, -143.56 >> BREAK
CASE 19 RETURN << -3043.23, -212.16, -23.48 >> BREAK
CASE 20 RETURN << -2871.10, 4268.19, -152.47 >> BREAK
CASE 21 RETURN << -777.21, 6726.71, -30.89 >> BREAK
CASE 22 RETURN << -3008.33, 2877.73, -27.76 >> BREAK
CASE 23 RETURN << -1843.12, -1260.67, -22.17 >> BREAK
CASE 24 RETURN << -2591.62, -470.34, -30.40 >> BREAK
CASE 25 RETURN << 3824.99, 3729.17, -16.17 >> BREAK
CASE 26 RETURN << 3885.44, 3797.19, -24.26 >> BREAK
CASE 27 RETURN << 2153.90, -2826.37, -50.76 >> BREAK
CASE 28 RETURN << 1873.50, -3012.60, -47.00 >> BREAK
CASE 29 RETURN << -2325.06, -1046.70, -70.67 >> BREAK
ENDSWITCH
SCRIPT_ASSERT("Ambient Sonar: Invalid index passed to GET_SONAR_COORD()")
RETURN << 0.0, 0.0, 0.0 >>
ENDFUNC
/// PURPOSE:
/// Fill Sonar Scrap Array
PROC INITIALIZE_SONAR_SCRAP_POSITIONS()
sSonarPickups[0].vCoords = GET_SONAR_COORD(0) sSonarPickups[0].fHeading = 179.47
sSonarPickups[1].vCoords = GET_SONAR_COORD(1) sSonarPickups[1].fHeading = 104.00
sSonarPickups[2].vCoords = GET_SONAR_COORD(2) sSonarPickups[2].fHeading = 321.50
sSonarPickups[3].vCoords = GET_SONAR_COORD(3) sSonarPickups[3].fHeading = -29.79
sSonarPickups[4].vCoords = GET_SONAR_COORD(4) sSonarPickups[4].fHeading = -165.60
sSonarPickups[5].vCoords = GET_SONAR_COORD(5) sSonarPickups[5].fHeading = 116.00
sSonarPickups[6].vCoords = GET_SONAR_COORD(6) sSonarPickups[6].fHeading = -68.65
sSonarPickups[7].vCoords = GET_SONAR_COORD(7) sSonarPickups[7].fHeading = 40.00
sSonarPickups[8].vCoords = GET_SONAR_COORD(8) sSonarPickups[8].fHeading = 40.00
sSonarPickups[9].vCoords = GET_SONAR_COORD(9) sSonarPickups[9].fHeading = 40.00
sSonarPickups[10].vCoords = GET_SONAR_COORD(10) sSonarPickups[10].fHeading = 40.00
sSonarPickups[11].vCoords = GET_SONAR_COORD(11) sSonarPickups[11].fHeading = 27.04
sSonarPickups[12].vCoords = GET_SONAR_COORD(12) sSonarPickups[12].fHeading = 40.00
sSonarPickups[13].vCoords = GET_SONAR_COORD(13) sSonarPickups[13].fHeading = 40.00
sSonarPickups[14].vCoords = GET_SONAR_COORD(14) sSonarPickups[14].fHeading = 40.00
sSonarPickups[15].vCoords = GET_SONAR_COORD(15) sSonarPickups[15].fHeading = 40.00
sSonarPickups[16].vCoords = GET_SONAR_COORD(16) sSonarPickups[16].vRot = <<89.94, 61.93, 90.94>>
sSonarPickups[17].vCoords = GET_SONAR_COORD(17) sSonarPickups[17].fHeading = 40.00
sSonarPickups[18].vCoords = GET_SONAR_COORD(18) sSonarPickups[18].fHeading = 40.00
sSonarPickups[19].vCoords = GET_SONAR_COORD(19) sSonarPickups[19].fHeading = 40.00
sSonarPickups[20].vCoords = GET_SONAR_COORD(20) sSonarPickups[20].fHeading = 40.00
sSonarPickups[21].vCoords = GET_SONAR_COORD(21) sSonarPickups[21].fHeading = 40.00
sSonarPickups[22].vCoords = GET_SONAR_COORD(22) sSonarPickups[22].fHeading = 40.00
sSonarPickups[23].vCoords = GET_SONAR_COORD(23) sSonarPickups[23].fHeading = 40.00
sSonarPickups[24].vCoords = GET_SONAR_COORD(24) sSonarPickups[24].fHeading = 40.00
sSonarPickups[25].vCoords = GET_SONAR_COORD(25) sSonarPickups[25].fHeading = 198.00
sSonarPickups[26].vCoords = GET_SONAR_COORD(26) sSonarPickups[26].fHeading = 198.00
sSonarPickups[27].vCoords = GET_SONAR_COORD(27) sSonarPickups[27].fHeading = 198.00
sSonarPickups[28].vCoords = GET_SONAR_COORD(28) sSonarPickups[28].fHeading = 198.00
sSonarPickups[29].vCoords = GET_SONAR_COORD(29) sSonarPickups[29].fHeading = -109.43
SET_PICKUPS_ACTIVE_TO_FALSE(sSonarPickups)
// Init cull sphere tracking vars
INT i
REPEAT NUMBER_OF_SONAR_PICKUPS i
iSphereIndexOnPickup[i] = -1
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Sets the nearest coord on trackify device
PROC SET_NEAREST_SCRAP_COORD_ON_TRACKIFY()
SET_TRACKIFY_TARGET_VECTOR(GET_SONAR_COORD(iNearestScrapIndex), TRUE, TRUE)
iTrackifyUpdateCounter = 1
ENDPROC
/// PURPOSE:
/// Prevent certain pickups from creating the grass cull sphere
/// PARAMS:
/// iCurrentPickup - pickup to check
/// RETURNS:
/// TRUE if we need to create a cull sphere on this pickup
FUNC BOOL CULL_SPHERE_NEEDED_FOR_PICKUP(INT iCurrentPickup)
IF iCurrentPickup = 23 // End of the pier - not on proc mesh and right by a peyote pickup
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Handles which grass cull sphere is active, if any
/// PARAMS:
/// iCurrentScrap - scrap index to check
/// bCollected - if the scrap is collected (only need to worry about cleaning up existing cull sphere in this case)
PROC HANDLE_CULL_SPHERE(INT iCurrentPickup, BOOL bCollected)
IF CULL_SPHERE_NEEDED_FOR_PICKUP(iCurrentPickup) = FALSE
EXIT
ENDIF
IF iSphereIndexOnPickup[iCurrentPickup] = -1
IF NOT bCollected
AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), sSonarPickups[iCurrentPickup].vCoords) < (CREATE_CULL_SPHERE_DISTANCE*CREATE_CULL_SPHERE_DISTANCE)
INT iSphere
IF IS_A_CULLSPHERE_AVAILABLE(iSphere)
CPRINTLN(DEBUG_AMBIENT, "Adding grass cull sphere ", iSphere, " on pickup ", iCurrentPickup)
PROCGRASS_ENABLE_CULLSPHERE(iSphere, sSonarPickups[iCurrentPickup].vCoords, 8.0)
iSphereIndexOnPickup[iCurrentPickup] = iSphere
ENDIF
ENDIF
ENDIF
ELSE
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
IF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), sSonarPickups[iCurrentPickup].vCoords) > (REMOVE_CULL_SPHERE_DISTANCE*REMOVE_CULL_SPHERE_DISTANCE)
CPRINTLN(DEBUG_AMBIENT, "Removing the grass cull sphere ", iSphereIndexOnPickup[iCurrentPickup], " on pickup ", iCurrentPickup)
IF iSphereIndexOnPickup[iCurrentPickup] >= 0 AND iSphereIndexOnPickup[iCurrentPickup] < NUMBER_AVAILABLE_CULLSPHERES
PROCGRASS_DISABLE_CULLSPHERE(iSphereIndexOnPickup[iCurrentPickup])
iSphereIndexOnPickup[iCurrentPickup] = -1
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Updates the scrap array
/// PARAMS:
/// data - mission scrap data reference
/// array - reference to mission scrap array
/// extarray - reference to scrap extras array
/// iCurrentIndex - reference to the current index we are updating
FUNC BOOL UPDATE_SONAR_PICKUPS(SCRAP_MISSION_DATA &missionData, SCRAP_PICKUP_DATA &pickupData[])
INT i
VECTOR vPos
BOOL bScrapCollected
// cache the player position and do is injured check to stop asserts
IS_PED_INJURED(PLAYER_PED_ID())
vPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
REPEAT iScrapsPerFrame i
bScrapCollected = HAS_SCRAP_BEEN_COLLECTED(missionData.scrapData, missionData.iCurrentCheckIndex)
// If the pickup isn't active...
IF NOT pickupData[missionData.iCurrentCheckIndex].bActive
// And hasn't yet been collected...
IF NOT bScrapCollected
IF NOT ARE_VECTORS_EQUAL(pickupData[missionData.iCurrentCheckIndex].vRot, <<0,0,0>>)
CREATE_SCRAP_WHEN_IN_RANGE(pickupData[missionData.iCurrentCheckIndex], missionData.packageMdl, PICKUP_CUSTOM_SCRIPT, FALSE, TRUE, EULER_XYZ)
ELSE
CREATE_SCRAP_WHEN_IN_RANGE(pickupData[missionData.iCurrentCheckIndex], missionData.packageMdl)
ENDIF
ENDIF
ELSE
// Check for collecting pickup
IF (NOT bScrapCollected)
// Update trackify and credit bank account when collecting a pickup
IF UPDATE_SCRAP_PICKUP(missionData, pickupData, vPos)
IF GET_NEAREST_PICKUP_INDEX(missionData, pickupData, vPos, iNearestScrapIndex)
PROPERTY_PAY_INCOME(PROPERTY_SONAR_COLLECTIONS, 23000)
SET_NEAREST_SCRAP_COORD_ON_TRACKIFY()
ENDIF
ENDIF
ENDIF
ENDIF
// Toggle the grass cull sphere on or off
HANDLE_CULL_SPHERE(missionData.iCurrentCheckIndex, bScrapCollected)
// Increase the current index - make sure it doesn't overrun
missionData.iCurrentCheckIndex ++
IF (missionData.iCurrentCheckIndex >= COUNT_OF(pickupData))
missionData.iCurrentCheckIndex = 0
ENDIF
ENDREPEAT
IF NOT g_bResultScreenDisplaying
UPDATE_DISPLAY_MESSAGE(missionData.bDisplayMessage, missionData.bMessageOnDisplay, missionData.iMessageTimer, SCRAP_SUB, iMessageStage, siMessage, "SUBM_TITLE", "SUBM_COLLECT")
ELSE
CDEBUG1LN(debug_ambient,"Can't display diving message, results screen is currently active")
ENDIF
IF (missionData.scrapData.iScrapsCollected >= missionData.scrapData.iMaxScraps)
CPRINTLN(DEBUG_AMBIENT, "Sonar Pickups: Turning off Trackify")
REMOVE_TRACKIFY_TARGET()
ENABLE_SECOND_SCREEN_TRACKIFY_APP(FALSE)
HANG_UP_AND_PUT_AWAY_PHONE()
ENDIF
// Send the complete flag once everything is collected and messsage has stopped
IF NOT missionData.bMessageOnDisplay
AND NOT missionData.bDisplayMessage
RETURN (missionData.scrapData.iScrapsCollected >= missionData.scrapData.iMaxScraps)
ENDIF
RETURN FALSE
ENDFUNC
//----------------------
// DEBUG FUNCTIONS
//----------------------
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// Setups Debug Widgets
PROC SETUP_DEBUG_WIDGETS(SCRAP_MISSION_DATA &missionData, SCRAP_PICKUP_DATA& pickupData[])
INT iScrap
TEXT_LABEL_63 tlTemp
mWidgetGroup = START_WIDGET_GROUP("Ambient: Sonar Collections")
ADD_WIDGET_BOOL("Force Quit Script", bDebugQuitScript)
ADD_WIDGET_BOOL("Allow debug tty", bShowScrapDebugTTY)
ADD_WIDGET_BOOL("Allow Debug Warping", bDebugAllowWarping)
ADD_WIDGET_BOOL("Show all scraps on map", bMapAllScraps)
ADD_WIDGET_BOOL("Create Submersible", bCreateSub)
ADD_WIDGET_INT_SLIDER("Scraps Per Frame", iScrapsPerFrame, 1, COUNT_OF(pickupData), 1)
START_WIDGET_GROUP("Collection")
ADD_WIDGET_BOOL("Collect all scraps", bCollectAllScraps)
ADD_WIDGET_BOOL("Reset scraps collection", bResetScrapCollection)
ADD_WIDGET_BOOL("Simulate Scrap Collect", bSimulateScrapCollect)
ADD_WIDGET_INT_SLIDER("Sim Scraps to Collect", iSimulateScrapCollect, 1, COUNT_OF(pickupData), 1)
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Stats")
ADD_WIDGET_BOOL("Track Restart Help Shown", bTrkRestartHelpDisplayed)
ADD_WIDGET_INT_READ_ONLY("Scraps Collected", missionData.scrapData.iScrapsCollected)
ADD_WIDGET_INT_READ_ONLY("Total Scraps", missionData.scrapData.iMaxScraps)
ADD_WIDGET_INT_READ_ONLY("Nearest Scrap", iNearestScrapIndex)
ADD_WIDGET_INT_READ_ONLY("Trackify Update", iTrackifyUpdateCounter)
STOP_WIDGET_GROUP()
START_WIDGET_GROUP("Positions")
REPEAT COUNT_OF(pickupData) iScrap
tlTemp = "Scrap "
tlTemp += iScrap
START_WIDGET_GROUP(tlTemp)
ADD_WIDGET_BOOL("bWarp", bWarpToScrap[iScrap])
ADD_WIDGET_FLOAT_READ_ONLY("X Position", pickupData[iScrap].vCoords.x)
ADD_WIDGET_FLOAT_READ_ONLY("Y Position", pickupData[iScrap].vCoords.y)
ADD_WIDGET_FLOAT_READ_ONLY("Z Position", pickupData[iScrap].vCoords.z)
STOP_WIDGET_GROUP()
ENDREPEAT
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
ENDPROC
/// PURPOSE:
/// Updates all The Widgets
PROC UPDATE_DEBUG_WIDGETS(SCRAP_MISSION_DATA &missionData, SCRAP_PICKUP_DATA &pickupData[])
INT i
INT cnt = 0
VEHICLE_INDEX sub
VECTOR pos
IF (bResetScrapCollection)
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Resetting all sonar pickups...")
STAT_SET_INT(missionData.packageStat, 0)
REPEAT COUNT_OF(pickupData) i
SAFE_REMOVE_PICKUP(pickupData[i].pickup)
SAFE_REMOVE_BLIP(pickupData[i].blip)
SET_SCRAP_AS_COLLECTED(missionData.scrapData, i, FALSE)
pickupData[i].bActive = FALSE
ENDREPEAT
SET_PACKED_STATS_FROM_SCRAP_COLLECT_DATA(missionData.scrapData)
bResetScrapCollection = FALSE
bMapAllScraps = TRUE
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE)
MAKE_AUTOSAVE_REQUEST()
ENDIF
IF (bSimulateScrapCollect)
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Collecting sonar pickup: ", iSimulateScrapCollect)
REPEAT COUNT_OF(pickupData) i
IF NOT HAS_SCRAP_BEEN_COLLECTED(missionData.scrapData, i)
COLLECT_SCRAP(missionData, pickupData, i)
cnt ++
ENDIF
IF (cnt >= iSimulateScrapCollect)
i = COUNT_OF(pickupData) + 1 // so we break out of array
ENDIF
ENDREPEAT
bMapAllScraps = FALSE
bSimulateScrapCollect = FALSE
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE)
MAKE_AUTOSAVE_REQUEST()
ENDIF
IF (bCollectAllScraps)
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Collecting all sonar pickups...")
STAT_SET_INT(missionData.packageStat, 0)
REPEAT COUNT_OF(pickupData) i
COLLECT_SCRAP(missionData, pickupData, i)
ENDREPEAT
bCollectAllScraps = FALSE
bMapAllScraps = FALSE
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE)
MAKE_AUTOSAVE_REQUEST()
ENDIF
IF (bMapAllScraps)
BLIP_SCRAP_POSITIONS(missionData, pickupData)
bMapAllScraps = FALSE
ENDIF
// Handle warping
IF (bDebugAllowWarping)
REPEAT COUNT_OF(pickupData) i
IF (bWarpToScrap[i])
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Warping to sonar pickup: ", i)
LOAD_SCENE(pickupData[i].vCoords)
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF IS_PED_IN_ANY_SUB(PLAYER_PED_ID())
SET_ENTITY_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), pickupData[i].vCoords + <<0.0, 0.0, 10.0>>)
ELSE
SET_ENTITY_COORDS(PLAYER_PED_ID(), pickupData[i].vCoords + <<0.0, 0.0, 10.0>>)
bCreateSub = TRUE
ENDIF
SET_ENTITY_HEADING(PLAYER_PED_ID(), 0.0)
ENDIF
bWarpToScrap[i] = FALSE
ENDIF
ENDREPEAT
ENDIF
IF (bCreateSub)
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF NOT IS_PED_IN_ANY_SUB(PLAYER_PED_ID()) AND IS_ENTITY_IN_WATER(PLAYER_PED_ID())
SECURE_REQUEST_AND_LOAD_MODEL(SUBMERSIBLE)
i = 0
IS_ENTITY_OK(PLAYER_PED_ID())
pos = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(PLAYER_PED_ID(), <<0, 0, 5.0>>)
WHILE (i = 0)
sub = CREATE_VEHICLE(SUBMERSIBLE, pos)
IF DOES_ENTITY_EXIST(sub)
CPRINTLN(DEBUG_AMBIENT, "Sonar Pickups: Player warped into Submarine.")
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), sub)
i = 1
ENDIF
ENDWHILE
ENDIF
ENDIF
bCreateSub = FALSE
ENDIF
ENDPROC
/// PURPOSE:
/// Cleans up All The Widgets
PROC CLEANUP_DEBUG_WIDGETS()
IF DOES_WIDGET_GROUP_EXIST(mWidgetGroup)
DELETE_WIDGET_GROUP(mWidgetGroup)
ENDIF
ENDPROC
#ENDIF
//----------------------
// SCRIPT FUNCTIONS
//----------------------
/// PURPOSE:
/// Add rewards and clean up script
PROC SCRIPT_PASS()
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: All sonar pickups have been collected")
PROPERTY_PAY_INCOME(PROPERTY_SONAR_COLLECTIONS, 250000) //extra reward
REGISTER_SCRIPT_IN_COMPLETION_PERCENTAGE_TOTAL (CP_SONCOLL)
AWARD_ACHIEVEMENT(ACH17) // Waste Management
REQUEST_SYSTEM_ACTIVITY_TYPE_COLLECTED_SONAR() // Push a PS4 activity feed message.
SET_STAGE(MS_CLEANUP)
ENDPROC
/// PURPOSE:
/// Script Cleanup
PROC SCRIPT_CLEANUP()
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Cleanup!")
SET_MAX_WANTED_LEVEL(5)
#IF IS_DEBUG_BUILD
CLEANUP_DEBUG_WIDGETS()
#ENDIF
// Release submersible
RELEASE_SUB()
INT i
REPEAT COUNT_OF(sSonarPickups) i
SAFE_REMOVE_BLIP(sSonarPickups[i].blip)
SAFE_REMOVE_PICKUP(sSonarPickups[i].pickup)
IF iSphereIndexOnPickup[i] >= 0 AND iSphereIndexOnPickup[i] < NUMBER_AVAILABLE_CULLSPHERES
PROCGRASS_DISABLE_CULLSPHERE(iSphereIndexOnPickup[i])
ENDIF
ENDREPEAT
IF HAVE_ALL_SCRAPS_BEEN_COLLECTED(sMissionData.scrapData)
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: All Parts Collected - Removing Ambient Script")
Remove_Script_From_Relaunch_List(LAUNCH_BIT_RC_AMB_SONAR_COLLECTION)
ENDIF
// Ensure Trackify app is disabled
CPRINTLN(DEBUG_AMBIENT, "Sonar Pickups: Turning off Trackify")
REMOVE_TRACKIFY_TARGET()
ENABLE_SECOND_SCREEN_TRACKIFY_APP(FALSE)
HANG_UP_AND_PUT_AWAY_PHONE()
SET_MODEL_AS_NO_LONGER_NEEDED(sMissionData.packageMdl)
TERMINATE_THIS_THREAD()
ENDPROC
//----------------------
// STATES
//----------------------
/// PURPOSE:
/// Initialization
PROC DO_INITALIZE()
iMessageStage = 0
INITIALIZE_SONAR_SCRAP_POSITIONS()
SETUP_SCRAP_MISSION(sMissionData, SCRAP_SUB, Prop_Rad_Waste_Barrel_01, "SUBM_COLLECT")
SETUP_SCRAP_MISSION_STATS(sMissionData, NUM_HIDDEN_PACKAGES_3, PACKSTAT_SONAR_START, NUMBER_OF_SONAR_PICKUPS)
#IF IS_DEBUG_BUILD
SETUP_DEBUG_WIDGETS(sMissionData, sSonarPickups)
#ENDIF
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF IS_PED_IN_ANY_SUB(PLAYER_PED_ID())
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Initial stage set to MS_IN_SUB")
SET_MAX_WANTED_LEVEL(0)
SET_STAGE(MS_IN_SUB)
ELSE
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Initial stage set to MS_OUT_OF_SUB")
SET_MAX_WANTED_LEVEL(5)
SET_STAGE(MS_OUT_OF_SUB)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Set the position nearest sonar pickup on the Trackify app
/// Only updates when the player is in water
PROC UPDATE_TRACKIFY_APP()
iTrackifyUpdateCounter ++
IF (iTrackifyUpdateCounter % 30 = 0) OR (iNearestScrapIndex = -1)
IF GET_NEAREST_PICKUP_INDEX(sMissionData, sSonarPickups, GET_ENTITY_COORDS(PLAYER_PED_ID()), iNearestScrapIndex)
SET_NEAREST_SCRAP_COORD_ON_TRACKIFY()
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Handle player when they are in a submarine
PROC STAGE_IN_SUB()
// Detect the player exiting the submarine
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF NOT IS_PED_IN_ANY_SUB(PLAYER_PED_ID())
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Player exited submarine, deactivate Trackify...")
ENABLE_SECOND_SCREEN_TRACKIFY_APP(FALSE)
HANG_UP_AND_PUT_AWAY_PHONE()
SET_MAX_WANTED_LEVEL(5)
SET_STAGE(MS_OUT_OF_SUB)
ELSE
// Display help for using Trackify to locate sonar pickups
IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_SONAR_COLLECT_LOAD_TRACKIFY)
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Help - Follow the sonar blips on Trackify to locate treasure lost on the sea bed.")
ADD_HELP_TO_FLOW_QUEUE("SUBM_HELP1", FHP_MEDIUM)
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_SONAR_COLLECT_LOAD_TRACKIFY)
ENDIF
// Display help for restarting trackify if the player cancels it
IF NOT IS_CELLPHONE_TRACKIFY_IN_USE()
ENABLE_SECOND_SCREEN_TRACKIFY_APP(TRUE)
IF NOT bTrkRestartHelpDisplayed
AND NOT (sMissionData.scrapData.iScrapsCollected >= sMissionData.scrapData.iMaxScraps) //if completed all scraps, we don't want this message
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Help - To restart Trackify, select the Trackify app on the second page of the mobile phone.")
ADD_HELP_TO_FLOW_QUEUE("SUBM_TRKHELP", FHP_MEDIUM)
bTrkRestartHelpDisplayed = TRUE
ENDIF
ENDIF
// Update trackify app - all characters can use this now
UPDATE_TRACKIFY_APP()
// Update sonar pickups
IF UPDATE_SONAR_PICKUPS(sMissionData, sSonarPickups)
SCRIPT_PASS()
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Handles the player when outside of a submarine
PROC STAGE_OUT_OF_SUB()
// Reset help message when the player gets out of the submarine
bTrkRestartHelpDisplayed = FALSE
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF IS_PLAYER_PLAYING(PLAYER_ID())
// Update sonar pickups - currently we are allowing the player to collect whilst swimming...
IF UPDATE_SONAR_PICKUPS(sMissionData, sSonarPickups)
SCRIPT_PASS()
ELSE
// Player has entered submarine
IF IS_PED_IN_ANY_SUB(PLAYER_PED_ID())
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Player is in submarine, activate Trackify...")
viSub = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
// Launch trackify
ENABLE_SECOND_SCREEN_TRACKIFY_APP(TRUE)
LAUNCH_TRACKIFY_IMMEDIATELY()
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF GET_NEAREST_PICKUP_INDEX(sMissionData, sSonarPickups, GET_ENTITY_COORDS(PLAYER_PED_ID()), iNearestScrapIndex)
SET_NEAREST_SCRAP_COORD_ON_TRACKIFY()
ENDIF
ENDIF
// Cannot get wanted in submersible
SET_MAX_WANTED_LEVEL(0)
// Remove blip
REMOVE_SUB_BLIP()
// Player has entered submarine
SET_STAGE(MS_IN_SUB)
ELSE
// Blip the sub!
IF IS_ENTITY_ALIVE(viSub)
IF VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(viSub)) > 250*250
RELEASE_SUB()
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Sub status = OUT OF RANGE!")
ELSE
IF NOT DOES_BLIP_EXIST(biSub)
biSub = CREATE_BLIP_FOR_VEHICLE(viSub)
SET_BLIP_SPRITE(biSub, RADAR_TRACE_SUB)
ENDIF
ENDIF
ELSE
// Remove blip
REMOVE_SUB_BLIP()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
//----------------------
// MAIN SCRIPT
//----------------------
SCRIPT
IF HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_DEBUG_MENU|FORCE_CLEANUP_FLAG_SP_TO_MP|FORCE_CLEANUP_FLAG_REPEAT_PLAY|FORCE_CLEANUP_FLAG_DIRECTOR)
SCRIPT_CLEANUP()
ENDIF
IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH (HASH("ambient_Sonar")) > 1
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Attempting to launch with an instance already active...")
TERMINATE_THIS_THREAD()
ENDIF
// Register the script so that it can be relaunched when loading from a savegame.
Register_Script_To_Relaunch_List(LAUNCH_BIT_RC_AMB_SONAR_COLLECTION)
// Setup Arrays and everything else
CPRINTLN(DEBUG_AMBIENT, "Ambient Sonar: Initializing.. - Version:", XVERSION_NUMBER)
// Ensure Trackify app is disabled
ENABLE_SECOND_SCREEN_TRACKIFY_APP(FALSE)
// Main loop
WHILE (TRUE)
WAIT(0)
IS_ENTITY_OK(PLAYER_PED_ID())
SWITCH eStage
CASE MS_INIT
DO_INITALIZE()
BREAK
CASE MS_IN_SUB
STAGE_IN_SUB()
BREAK
CASE MS_OUT_OF_SUB
STAGE_OUT_OF_SUB()
BREAK
CASE MS_CLEANUP
SCRIPT_CLEANUP()
BREAK
ENDSWITCH
// Debug widgets
#IF IS_DEBUG_BUILD
UPDATE_DEBUG_WIDGETS(sMissionData, sSonarPickups)
IF (bDebugQuitScript)
SCRIPT_CLEANUP()
ENDIF
#ENDIF
ENDWHILE
ENDSCRIPT