////////////////////////////////////////////////////////////////////////////////////////// // // // SCRIPT NAME : ambient_diving.sc // // AUTHOR : David Roberts // // DESCRIPTION : Sets up submarine wreckage around the map for the player // // to collect via diving. // // // ////////////////////////////////////////////////////////////////////////////////////////// //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 "rgeneral_include.sch" USING "RC_Helper_Functions.sch" USING "CompletionPercentage_public.sch" USING "savegame_public.sch" USING "scrap_common.sch" //---------------------- // CONSTS //---------------------- CONST_INT XVERSION_NUMBER 107 CONST_INT DS_NOT_IN_DINGHY 0 // Boat state machine CONST_INT DS_IN_DINGHY 1 CONST_INT BLIP_WRECK_DISTANCE 200 // Range at which wreck sites can be seen on the main map CONST_INT DINGHY_CLEANUP_RANGE 250 // Range at which a registered unmanned dinghy will be cleaned up normally CONST_INT DINGHY_CLEANUP_RANGE_IN_WATER 500 // Range at which dinghy will be cleaned up when the player is still in the water CONST_FLOAT SONAR_MIN_SIZE_BOAT 20.0 // Minimum sonar blip size when in the dinghy CONST_FLOAT SONAR_MIN_SIZE_SWIM 10.0 // Minimum sonar blip size when swimming CONST_FLOAT SONAR_UPDATE_SPEED 0.025 // Increase this to make the sonar update faster //---------------------- // ENUMS //---------------------- ENUM MISSION_STATUS MS_INIT, MS_COLLECT_PICKUPS, MS_POST_COMPLETION, MS_CLEANUP ENDENUM //--------------------- // VARIABLES //---------------------- SCRAP_MISSION_DATA sMissionData SCRAP_PICKUP_DATA sPickupData[NUMBER_OF_DIVING_SCRAPS] MISSION_STATUS eStage = MS_INIT SCALEFORM_INDEX siMessage INT iNearestScrap = -1 INT iMessageStage = 0 BLIP_INDEX biWreckSite INT iBlippedSite BLIP_INDEX biSonarBlip BLIP_INDEX biSonarOutline[4] FLOAT fExtraBlipSize[4] FLOAT fCurrentRadius FLOAT fTargetRadius FLOAT fSonarIncrement BOOL bSonarUpdate = TRUE BOOL bCallRegistered = FALSE INT iSonarID = GET_SOUND_ID() VEHICLE_INDEX viCurrentDinghy BLIP_INDEX biDinghy INT iDinghyStatus = DS_NOT_IN_DINGHY BOOL bOnMissionCleanupDone = FALSE #IF IS_DEBUG_BUILD WIDGET_GROUP_ID mWidgetGroup BOOL bMapAllScraps BOOL bScrapsAreBlipped BOOL bCollectAllScraps BOOL bResetScrapCollection BOOL bDebugAllowWarping BOOL bWarpToScrap[NUMBER_OF_DIVING_SCRAPS] BOOL bDebugQuitScript BOOL bSimulateScrapCollect INT iSimulateScrapCollect = 1 #ENDIF //---------------------- // FUNCTIONS //---------------------- /// PURPOSE: /// Set the correct stage and revert it to setup PROC SET_STAGE(MISSION_STATUS stage) eStage = stage ENDPROC /// PURPOSE: /// Returns the coordinate of the scrap piece specified by the index. FUNC VECTOR GET_DIVING_COORD(INT index) SWITCH index CASE 0 RETURN << -1036.73, 6735.72, -100.52 >> BREAK CASE 1 RETURN << -908.86, 6655.98, -34.35 >> BREAK CASE 2 RETURN << -985.14, 6697.71, -41.57 >> BREAK CASE 3 RETURN << 1825.73, -2920.67, -36.82 >> BREAK CASE 4 RETURN << 1772.11, -2967.72, -46.81 >> BREAK CASE 5 RETURN << 3198.59, -385.05, -31.49 >> BREAK CASE 6 RETURN << 3170.43, -302.21, -25.99 >> BREAK CASE 7 RETURN << 3157.44, -268.54, -28.07 >> BREAK CASE 8 RETURN << -3180.20, 3010.90, -37.60 >> BREAK CASE 9 RETURN << -3178.30, 3044.86, -39.96 >> BREAK CASE 10 RETURN << 910.48, -3471.21, -17.57 >> BREAK CASE 11 RETURN << 1338.76, -3041.59, -19.23 >> BREAK CASE 12 RETURN << 1153.38, -2864.51, -18.96 >> BREAK CASE 13 RETURN << 958.56, -2847.78, -22.05 >> BREAK CASE 14 RETURN << 782.28, -2872.81, -9.577 >> BREAK CASE 15 RETURN << 581.28, -2471.50, -9.44 >> BREAK CASE 16 RETURN << 636.56, -2214.49, -7.87 >> BREAK CASE 17 RETURN << 371.06, -3226.67, -19.60 >> BREAK CASE 18 RETURN << 689.69, -3451.07, -27.85 >> BREAK CASE 19 RETURN << 180.17, -2255.91, -2.54 >> BREAK CASE 20 RETURN << -691.64, -2836.86, -15.67 >> BREAK CASE 21 RETURN << -3397.50, 3717.52, -86.14 >> BREAK CASE 22 RETURN << -3357.11, 3710.79, -96.14 >> BREAK CASE 23 RETURN << -3282.21, 3682.60, -82.87 >> BREAK CASE 24 RETURN << -3256.66, 3672.29, -35.06 >> BREAK CASE 25 RETURN << -3142.19, 3625.95, -26.31 >> BREAK CASE 26 RETURN << 3271.34, 6420.78, -50.78 >> BREAK CASE 27 RETURN << 3237.83, 6487.44, -43.90 >> BREAK CASE 28 RETURN << 1772.10, -2997.12, -50.44 >> BREAK CASE 29 RETURN << 3207.00, -415.17, -32.01 >> BREAK ENDSWITCH SCRIPT_ASSERT("Diving: Invalid index passed to GET_DIVING_COORD()") RETURN << 0.0, 0.0, 0.0 >> ENDFUNC /// PURPOSE: /// Setup DIVING scrap position and headings - set global variable for the mission being active PROC INITIALISE_DIVING_SCRAPS() // Initialise diving scraps INT i REPEAT NUMBER_OF_DIVING_SCRAPS i sPickupData[i].vCoords = GET_DIVING_COORD(i) sPickupData[i].bActive = FALSE ENDREPEAT sPickupData[0].vRot = << -16.40, 78.53, -146.67 >> sPickupData[1].vRot = << 0.0, 45.0, 10.0 >> sPickupData[2].vRot = << 0.72, 65.20, -50.26 >> sPickupData[3].vRot = << 0.00, 15.00, -132.16 >> sPickupData[4].vRot = << 166.37, -40.00, 168.81 >> sPickupData[5].vRot = << 90.00, 56.20, 90.00 >> sPickupData[6].vRot = << -20.00, 0.00, 89.95 >> sPickupData[7].vRot = << 4.08, 54.90, -65.35 >> sPickupData[8].vRot = << 174.15, -58.20, -144.66 >> sPickupData[9].vRot = << -28.22, 36.11, -90.22 >> sPickupData[10].vRot = << -5.00, 44.00, 65.00 >> sPickupData[11].vRot = << 0.00, -108.00, 45.36 >> sPickupData[12].vRot = << -10.90, 43.12, 131.52 >> sPickupData[13].vRot = << 12.37, 49.66, 126.88 >> sPickupData[14].vRot = << 4.35, 10.22, 27.51 >> sPickupData[15].vRot = << 0.00, 10.00, 60.73 >> sPickupData[16].vRot = << 150.56, -78.67, -174.35 >> sPickupData[17].vRot = << -0.00, 50.00, 46.41 >> sPickupData[18].vRot = << 6.26, 44.65, 8.88 >> sPickupData[19].vRot = << 90.00, 78.50, 16.04 >> sPickupData[20].vRot = << -1.36, 6.53, -70.94 >> sPickupData[21].vRot = << -61.86, 78.61, 126.50 >> sPickupData[22].vRot = << -10.00, -80.71, 69.70 >> sPickupData[23].vRot = << -76.43, -70.02, 29.74 >> sPickupData[24].vRot = << -28.00, -70.00, 107.53 >> sPickupData[25].vRot = << 4.19, 6.46, 110.43 >> sPickupData[26].vRot = << -3.19, 60.60, 25.00 >> sPickupData[27].vRot = << 0.00, -81.68, -20.16 >> sPickupData[28].vRot = << 7.39, 44.52, 19.65 >> sPickupData[29].vRot = << 89.74, 80.95, 151.74 >> ENDPROC /// PURPOSE: /// Updates the diving pickups, returns TRUE when they have all been collected FUNC BOOL UPDATE_DIVING_PICKUPS(SCRAP_MISSION_DATA &missionData, SCRAP_PICKUP_DATA &pickupData[]) INT i BOOL bScrapCollected VECTOR vPlayerPos // cache the player position and do is injured check to stop asserts IS_PED_INJURED(PLAYER_PED_ID()) vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) REPEAT SCRAPS_TO_CHECK_PER_FRAME i // Has this scrap already been collected? bScrapCollected = HAS_SCRAP_BEEN_COLLECTED(missionData.scrapData, missionData.iCurrentCheckIndex) // If the scrap isn't active... IF NOT pickupData[missionData.iCurrentCheckIndex].bActive // ...and hasn't 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 // Update pickup state IF NOT bScrapCollected UPDATE_SCRAP_PICKUP(missionData, pickupData, vPlayerPos) ENDIF ENDIF // Increase the current index - make sure it doesn't overrun missionData.iCurrentCheckIndex++ IF (missionData.iCurrentCheckIndex >= COUNT_OF(pickupData)) missionData.iCurrentCheckIndex = 0 ENDIF ENDREPEAT // We need to display that a pickup has been collected IF missionData.bDisplayMessage // Display collection message CDEBUG1LN(debug_ambient,"Displaying ambient diving message") IF NOT g_bResultScreenDisplaying UPDATE_DISPLAY_MESSAGE(missionData.bDisplayMessage, missionData.bMessageOnDisplay, missionData.iMessageTimer, SCRAP_DIVING, iMessageStage, siMessage, "DIVING_TITLE", "DIVING_COLLECT") ELSE CDEBUG1LN(debug_ambient,"Can't display diving message, results screen is currently active") ENDIF // Check for pickups in the vicinity // Return to a Dinghy to continue hunting for the submarine pieces. IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_DINGHY_HELP4) // Are there any remaining VECTOR vPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) INT iNearestPickup IF GET_NEAREST_PICKUP_INDEX(sMissionData, sPickupData, vPos, iNearestPickup) IF GET_DISTANCE_BETWEEN_COORDS(GET_DIVING_COORD(iNearestPickup), vPos, FALSE) > BLIP_WRECK_DISTANCE ADD_HELP_TO_FLOW_QUEUE("DIVING_HELP4", FHP_MEDIUM, DEFAULT_GOD_TEXT_TIME) SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_DINGHY_HELP4) ENDIF ENDIF ENDIF ENDIF IF NOT bCallRegistered IF missionData.scrapData.iScrapsCollected >= missionData.scrapData.iMaxScraps bCallRegistered = REGISTER_CALL_FROM_CHARACTER_TO_PLAYER(CALL_SONAR_COLLECT_DONE, CT_FLOW, BIT_MICHAEL, CHAR_ABIGAIL, 3, 1000, 10000, TEXT_ABIGAIL_MISSED, VID_BLANK, CID_ABIGAIL1_FOUND_SUB_WRECKAGE) ENDIF ENDIF // Send the complete flag once everything is collected and message has finished 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: /// Setup 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: Submarine Wreckage") ADD_WIDGET_BOOL("Show all scraps on map", bMapAllScraps) ADD_WIDGET_BOOL("Force Quit Script", bDebugQuitScript) ADD_WIDGET_BOOL("Allow debug warp", bDebugAllowWarping) ADD_WIDGET_BOOL("Allow debug tty", bShowScrapDebugTTY) 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_INT_READ_ONLY("Scraps Collected", missionData.scrapData.iScrapsCollected) ADD_WIDGET_INT_READ_ONLY("Total Scraps", missionData.scrapData.iMaxScraps) 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 IF (bResetScrapCollection) CPRINTLN(DEBUG_AMBIENT, "Resetting Scrap Collection") 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) UPDATE_GLOBAL_SCRAP_DATA(missionData.missionType, i, FALSE) pickupData[i].pickup = NULL 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, "Simulating Collecting ", iSimulateScrapCollect, "Scraps") 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 = TRUE bSimulateScrapCollect = FALSE SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE) MAKE_AUTOSAVE_REQUEST() ENDIF IF (bCollectAllScraps) CPRINTLN(DEBUG_AMBIENT, "Collecting All Scraps") STAT_SET_INT(missionData.packageStat, 0) REPEAT COUNT_OF(pickupData) i COLLECT_SCRAP(missionData, pickupData, i) ENDREPEAT bCollectAllScraps = FALSE bMapAllScraps = TRUE SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE) MAKE_AUTOSAVE_REQUEST() ENDIF // Blip handler IF (bMapAllScraps) IF NOT bScrapsAreBlipped BLIP_SCRAP_POSITIONS(missionData, pickupData) bScrapsAreBlipped = TRUE ENDIF ELSE IF bScrapsAreBlipped BLIP_SCRAP_POSITIONS(missionData, pickupData, FALSE) bScrapsAreBlipped = FALSE ENDIF ENDIF // Handle warping IF (bDebugAllowWarping = FALSE) EXIT ENDIF REPEAT COUNT_OF(pickupData) i IF (bWarpToScrap[i]) CPRINTLN(DEBUG_AMBIENT, "Warping To Scrap:", i) LOAD_SCENE(pickupData[i].vCoords) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) SET_ENTITY_COORDS(PLAYER_PED_ID(), pickupData[i].vCoords+<<0.0, -2.5, 0.0>>) FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_DIVING_IDLE) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) SET_ENTITY_HEADING(PLAYER_PED_ID(), 0.0) ENDIF ENDIF bWarpToScrap[i] = FALSE ENDIF ENDREPEAT ENDPROC /// PURPOSE: /// Cleans up all the widgets PROC CLEANUP_DEBUG_WIDGETS() IF DOES_WIDGET_GROUP_EXIST(mWidgetGroup) DELETE_WIDGET_GROUP(mWidgetGroup) ENDIF ENDPROC #ENDIF /// PURPOSE: /// Player is a dinghy vehicle FUNC BOOL IS_PLAYER_IN_DINGHY() IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) VEHICLE_INDEX vehIndex = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) IF DOES_ENTITY_EXIST(vehIndex) IF GET_ENTITY_MODEL(vehIndex) = DINGHY OR GET_ENTITY_MODEL(vehIndex) = DINGHY2 RETURN TRUE ELSE RETURN FALSE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks whether the player is currently in the dinghy associated with this mission script FUNC BOOL IS_PLAYER_IN_MISSION_DINGHY() IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) // Check for player remaining in current boat IF IS_ENTITY_ALIVE(viCurrentDinghy) IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viCurrentDinghy) RETURN TRUE ENDIF ELSE // Check for player getting into a new vehicle IF IS_PLAYER_IN_DINGHY() // Get handle viCurrentDinghy = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) IF DOES_ENTITY_EXIST(viCurrentDinghy) // Take ownership of boat SET_ENTITY_AS_MISSION_ENTITY(viCurrentDinghy, TRUE, TRUE) // Needed so we can check for anchoring when exiting the boat SET_ENTITY_RECORDS_COLLISIONS(viCurrentDinghy, TRUE) RETURN TRUE ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Removes boat blip PROC REMOVE_DINGHY_BLIP() IF DOES_BLIP_EXIST(biDinghy) CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: REMOVE_DINGHY_BLIP()") REMOVE_BLIP(biDinghy) ENDIF ENDPROC /// PURPOSE: /// Remove boat blip, unanchor and release boat (if it exists) PROC RELEASE_DINGHY() // Remove blip REMOVE_DINGHY_BLIP() // Release boat IF IS_ENTITY_ALIVE(viCurrentDinghy) CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: RELEASE_DINGHY()") IF IS_THIS_MODEL_A_BOAT(GET_ENTITY_MODEL(viCurrentDinghy)) SET_BOAT_ANCHOR(viCurrentDinghy, FALSE) ENDIF // No longer need to monitor for anchoring purposes SET_ENTITY_RECORDS_COLLISIONS(viCurrentDinghy, FALSE) // Release boat reference if created by this script IF IS_ENTITY_A_MISSION_ENTITY(viCurrentDinghy) SET_VEHICLE_AS_NO_LONGER_NEEDED(viCurrentDinghy) ENDIF ENDIF ENDPROC /// PURPOSE: /// Initialise everything PROC DO_INITALIZE() iMessageStage = 0 IF IS_PLAYER_IN_MISSION_DINGHY() iDinghyStatus = DS_IN_DINGHY ELSE iDinghyStatus = DS_NOT_IN_DINGHY ENDIF // Setup pickup positions and initialise mission details and stats INITIALISE_DIVING_SCRAPS() SETUP_SCRAP_MISSION(sMissionData, SCRAP_DIVING, PROP_SUB_CHUNK_01, "DIVING_COLLECT") SETUP_SCRAP_MISSION_STATS(sMissionData, NUM_HIDDEN_PACKAGES_4, PACKSTAT_DIVING_START, NUMBER_OF_DIVING_SCRAPS) SET_STAGE(MS_COLLECT_PICKUPS) fExtraBlipSize[0] = 0.25 fExtraBlipSize[1] = 0.5 fExtraBlipSize[2] = 0.75 fExtraBlipSize[3] = 1.0 #IF IS_DEBUG_BUILD ADD_CONTACT_TO_PHONEBOOK(CHAR_ABIGAIL, MICHAEL_BOOK, FALSE) #ENDIF ENDPROC /// PURPOSE: /// Handles blipping and anchoring the player's last boat PROC UPDATE_DINGHY() SWITCH iDinghyStatus CASE DS_NOT_IN_DINGHY IF IS_PLAYER_IN_MISSION_DINGHY() IF IS_ENTITY_ALIVE(viCurrentDinghy) // Unblip dinghy REMOVE_DINGHY_BLIP() // Allow dinghy to move away again... SET_BOAT_ANCHOR(viCurrentDinghy, FALSE) CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Dinghy status = DS_IN_DINGHY") iDinghyStatus = DS_IN_DINGHY // Complete script when back in the boat after collecting all pickups IF eStage = MS_POST_COMPLETION CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: MS_POST_COMPLETION->MS_CLEANUP") SET_STAGE(MS_CLEANUP) ENDIF ENDIF ELSE // Detect the player going far away from the dinghy IF IS_ENTITY_ALIVE(viCurrentDinghy) AND IS_ENTITY_ALIVE(PLAYER_PED_ID()) FLOAT fCleanupDist // Extend range if the player is swimming IF IS_ENTITY_IN_WATER(PLAYER_PED_ID()) fCleanupDist = DINGHY_CLEANUP_RANGE_IN_WATER ELSE fCleanupDist = DINGHY_CLEANUP_RANGE ENDIF // Check range IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), viCurrentDinghy, FALSE) > fCleanupDist CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Dinghy status = OUT OF RANGE!") CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Cleanup distance = ", fCleanupDist) CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Distance between player and mission dinghy = ", GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), viCurrentDinghy, FALSE)) RELEASE_DINGHY() // Complete script as moved away from the dinghy IF eStage = MS_POST_COMPLETION CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: MS_POST_COMPLETION->MS_CLEANUP") SET_STAGE(MS_CLEANUP) ENDIF ENDIF ELSE // Remove blip when destroyed REMOVE_DINGHY_BLIP() // Complete script as dinghy is no longer available IF eStage = MS_POST_COMPLETION CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Dinghy destroyed...") CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: MS_POST_COMPLETION->MS_CLEANUP") SET_STAGE(MS_CLEANUP) ENDIF ENDIF ENDIF BREAK CASE DS_IN_DINGHY // Complete script when back in the boat after collecting all pickups IF eStage = MS_POST_COMPLETION CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Player in dinghy...") CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: MS_POST_COMPLETION->MS_CLEANUP") SET_STAGE(MS_CLEANUP) ENDIF IF NOT IS_PLAYER_IN_MISSION_DINGHY() IF IS_ENTITY_ALIVE(viCurrentDinghy) // Blip the dinghy! IF NOT DOES_BLIP_EXIST(biDinghy) CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Creating blip for dinghy...") biDinghy = CREATE_BLIP_FOR_VEHICLE(viCurrentDinghy) ENDIF SET_VEHICLE_ENGINE_ON(viCurrentDinghy, FALSE, TRUE) // B*1789427 Ensure the engine is turned off // Set anchor so it doesn't float away! IF IS_THIS_MODEL_A_BOAT(GET_ENTITY_MODEL(viCurrentDinghy)) IF NOT HAS_ENTITY_COLLIDED_WITH_ANYTHING(viCurrentDinghy) CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Anchoring last player dinghy.") SET_BOAT_ANCHOR(viCurrentDinghy, TRUE) // B*1789427 Ensure the dinghy gets anchored ELSE CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Unable to anchor last player dinghy as it is colliding with something.") ENDIF ENDIF CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Dinghy status = DS_NOT_IN_DINGHY") iDinghyStatus = DS_NOT_IN_DINGHY ENDIF ENDIF BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Helper function to remove sonar blip and outline PROC REMOVE_CURRENT_SONAR_BLIP() // Main blip IF DOES_BLIP_EXIST(biSonarBlip) REMOVE_BLIP(biSonarBlip) ENDIF // Thickenened outline INT i FOR i=0 TO 3 IF DOES_BLIP_EXIST(biSonarOutline[i]) REMOVE_BLIP(biSonarOutline[i]) ENDIF ENDFOR ENDPROC /// PURPOSE: /// Update wreckage area blip when far away and sonar blips when nearby PROC UPDATE_SONAR_BLIPS() // Get current player location VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) // Work out the nearest submarine piece IF GET_NEAREST_PICKUP_INDEX(sMissionData, sPickupData, vPlayerPos, iNearestScrap) VECTOR vScrapPos = GET_DIVING_COORD(iNearestScrap) FLOAT fDistance = GET_DISTANCE_BETWEEN_COORDS(vScrapPos, vPlayerPos, FALSE) // Player is some distance away from the nearest wreck IF fDistance > BLIP_WRECK_DISTANCE // Remove close range blip REMOVE_CURRENT_SONAR_BLIP() // Ensure sonar is refreshed correctly when moving in range again IF NOT bSonarUpdate bSonarUpdate = TRUE ENDIF // Only update when player is in the dinghy IF IS_PLAYER_IN_DINGHY() // The nearest location where a submarine piece can be found is marked on the map when piloting the Dinghy. IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_DINGHY_HELP1) ADD_HELP_TO_FLOW_QUEUE("DIVING_HELP1", FHP_MEDIUM) SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_DINGHY_HELP1) ENDIF // Force a blip update if the nearest position has changed IF iNearestScrap <> iBlippedSite IF DOES_BLIP_EXIST(biWreckSite) REMOVE_BLIP(biWreckSite) ENDIF ENDIF // Area blip for closest wreck IF NOT DOES_BLIP_EXIST(biWreckSite) CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Creating wreckage site blip...") biWreckSite = ADD_BLIP_FOR_RADIUS(vScrapPos, 200) SET_BLIP_ALPHA(biWreckSite, 128) SET_BLIP_COLOUR(biWreckSite, BLIP_COLOUR_GREEN) SET_BLIP_HIDDEN_ON_LEGEND(biWreckSite, FALSE) SET_BLIP_NAME_FROM_TEXT_FILE(biWreckSite, "B_WRE") SHOW_HEIGHT_ON_BLIP(biWreckSite, FALSE) // Store which site is blipped iBlippedSite = iNearestScrap CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Blipped site at location ", iBlippedSite) ENDIF ELSE // Remove wreckage area blip in the event we have moved within range IF DOES_BLIP_EXIST(biWreckSite) REMOVE_BLIP(biWreckSite) ENDIF ENDIF ELSE // Use the Dinghy's sonar to help locate the missing submarine pieces. IF IS_PLAYER_IN_DINGHY() IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_DINGHY_HELP2) ADD_HELP_TO_FLOW_QUEUE("DIVING_HELP2", FHP_MEDIUM) SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_DINGHY_HELP2) ENDIF ENDIF // Dive underwater to search for the submarine pieces. IF HAS_ONE_TIME_HELP_DISPLAYED(FHM_DINGHY_HELP2) IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_DINGHY_HELP3) IF IS_ENTITY_IN_WATER(PLAYER_PED_ID()) AND NOT IS_PED_SWIMMING_UNDER_WATER(PLAYER_PED_ID()) ADD_HELP_TO_FLOW_QUEUE("DIVING_HELP3", FHP_MEDIUM, 2000) SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_DINGHY_HELP3) ENDIF ENDIF ENDIF // Remove area blip IF DOES_BLIP_EXIST(biWreckSite) CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Within range - removing wreckage site blip...") REMOVE_BLIP(biWreckSite) ENDIF IF iNearestScrap <> iBlippedSite REMOVE_CURRENT_SONAR_BLIP() iBlippedSite = iNearestScrap bSonarUpdate = TRUE CPRINTLN(DEBUG_AMBIENT, "Ambient Diving: Blipped site updated to location ", iBlippedSite) ENDIF // We haven't yet collected all submarine pieces IF (sMissionData.scrapData.iScrapsCollected < sMissionData.scrapData.iMaxScraps) // Trigger sonar update IF bSonarUpdate // Initialise sonar blip fCurrentRadius = 0 fTargetRadius = fDistance // Set minimum size based on whether player is in the dinghy or swimming IF IS_PLAYER_IN_DINGHY() fTargetRadius = CLAMP(fTargetRadius, SONAR_MIN_SIZE_BOAT, BLIP_WRECK_DISTANCE) ELSE fTargetRadius = CLAMP(fTargetRadius, SONAR_MIN_SIZE_SWIM, BLIP_WRECK_DISTANCE) ENDIF // Set update rate fSonarIncrement = fTargetRadius*0.025 bSonarUpdate = FALSE // Trigger sound from wreckage piece location IF IS_PLAYER_IN_DINGHY() PLAY_SOUND_FROM_COORD(iSonarID, "SINGLE_BLIP_FROM_BOAT", vScrapPos, "ABIGAIL_SONAR_SOUNDSET") ELSE PLAY_SOUND_FROM_COORD(iSonarID, "SCRIPT_TRIGGERED_FROM_PROP", vPlayerPos, "ABIGAIL_SONAR_SOUNDSET") ENDIF ELSE // Update size fCurrentRadius += fSonarIncrement fCurrentRadius = CLAMP(fCurrentRadius, 0, fTargetRadius) IF NOT DOES_BLIP_EXIST(biSonarBlip) biSonarBlip = ADD_BLIP_FOR_RADIUS(vScrapPos, fCurrentRadius) SET_BLIP_ALPHA(biSonarBlip, 255) SET_BLIP_COLOUR(biSonarBlip, BLIP_COLOUR_WHITE) SET_BLIP_AS_SHORT_RANGE(biSonarBlip, TRUE) SET_RADIUS_BLIP_EDGE(biSonarBlip, TRUE) SHOW_HEIGHT_ON_BLIP(biSonarBlip, FALSE) ELSE SET_BLIP_SCALE(biSonarBlip, fCurrentRadius) ENDIF INT i = 0 IF IS_PLAYER_IN_DINGHY() FOR i=0 TO 3 IF NOT DOES_BLIP_EXIST(biSonarOutline[i]) biSonarOutline[i] = ADD_BLIP_FOR_RADIUS(vScrapPos, fCurrentRadius + fExtraBlipSize[i]) SET_BLIP_ALPHA(biSonarOutline[i], 255) SET_BLIP_COLOUR(biSonarOutline[i], BLIP_COLOUR_WHITE) SET_BLIP_AS_SHORT_RANGE(biSonarOutline[i], TRUE) SET_RADIUS_BLIP_EDGE(biSonarOutline[i], TRUE) SHOW_HEIGHT_ON_BLIP(biSonarOutline[i], FALSE) ELSE SET_BLIP_SCALE(biSonarOutline[i], fCurrentRadius + fExtraBlipSize[i]) ENDIF ENDFOR ELSE FOR i=0 TO 3 IF DOES_BLIP_EXIST(biSonarOutline[i]) SET_BLIP_SCALE(biSonarOutline[i], fCurrentRadius) ENDIF ENDFOR ENDIF // We need to create a new blip IF fCurrentRadius >= fTargetRadius bSonarUpdate = TRUE ENDIF ENDIF ELSE // Collected all submarine wreckage pieces - make sure to remove last sonar blip REMOVE_CURRENT_SONAR_BLIP() ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// When all scraps are collected, advance to the next stage PROC UPDATE_PICKUPS() // Has the player collected all of the diving scraps? IF UPDATE_DIVING_PICKUPS(sMissionData, sPickupData) OR GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_DIVING_SCRAPS_DONE) = TRUE // Disable trackify IF IS_CELLPHONE_TRACKIFY_IN_USE() ENABLE_SECOND_SCREEN_TRACKIFY_APP(FALSE) ENDIF // Completion percentage CPRINTLN(DEBUG_AMBIENT, "All scraps have been collected") REGISTER_SCRIPT_IN_COMPLETION_PERCENTAGE_TOTAL (CP_DIVCOLL) // Register phonecall IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_DIVING_SCRAPS_DONE) IF NOT bCallRegistered bCallRegistered = REGISTER_CALL_FROM_CHARACTER_TO_PLAYER(CALL_SONAR_COLLECT_DONE, CT_FLOW, BIT_MICHAEL, CHAR_ABIGAIL, 3, 1000, 10000, TEXT_ABIGAIL_MISSED, VID_BLANK, CID_ABIGAIL1_FOUND_SUB_WRECKAGE) ENDIF ENDIF // Monitor player returning to the boat or moving out of range SET_STAGE(MS_POST_COMPLETION) ENDIF ENDPROC /// PURPOSE: /// Script Cleanup PROC SCRIPT_CLEANUP( BOOL bTerminate = TRUE ) CPRINTLN(DEBUG_MISSION, "Cleanup diving Scrap Collection") #IF IS_DEBUG_BUILD CLEANUP_DEBUG_WIDGETS() #ENDIF // Remove area blip IF DOES_BLIP_EXIST(biWreckSite) REMOVE_BLIP(biWreckSite) ENDIF // Remove sonar blip REMOVE_CURRENT_SONAR_BLIP() // Remove sound IF NOT HAS_SOUND_FINISHED(iSonarID) STOP_SOUND(iSonarID) ENDIF // Cleanup boat RELEASE_DINGHY() // Cleanup existing pickups INT i REPEAT COUNT_OF(sPickupData) i SAFE_REMOVE_BLIP(sPickupData[i].blip) SAFE_REMOVE_PICKUP(sPickupData[i].pickup) sPickupData[i].pickup = NULL ENDREPEAT IF( bTerminate ) // Have we collected all diving pickups? IF HAVE_ALL_SCRAPS_BEEN_COLLECTED(sMissionData.scrapData) OR GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_DIVING_SCRAPS_DONE) = TRUE // No longer require the script to be relaunched when loading from a savegame. Remove_Script_From_Relaunch_List(LAUNCH_BIT_AMB_DIVING_PICKUPS) ENDIF SET_MODEL_AS_NO_LONGER_NEEDED(sMissionData.packageMdl) TERMINATE_THIS_THREAD() ELSE CPRINTLN(DEBUG_AMBIENT, "SCRIPT_CLEANUP - Lite cleanup done") eStage = MS_INIT ENDIF ENDPROC //---------------------- // MAIN SCRIPT //---------------------- SCRIPT // Setup callbacks 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 // Close down in the event that this script is already running IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH (HASH("ambient_Diving")) > 1 CPRINTLN(DEBUG_AMBIENT, "diving is 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_AMB_DIVING_PICKUPS) // Setup arrays and everything else CPRINTLN(DEBUG_AMBIENT, "Initializing Diving Scrap Collection - Version:", XVERSION_NUMBER) // Setup debug widgets #IF IS_DEBUG_BUILD SETUP_DEBUG_WIDGETS(sMissionData, sPickupData) #ENDIF // Main loop WHILE (TRUE) WAIT(0) IF( IS_CURRENTLY_ON_MISSION_TO_TYPE( MISSION_TYPE_STORY ) ) IF( NOT bOnMissionCleanupDone ) SCRIPT_CLEANUP( FALSE ) bOnMissionCleanupDone = TRUE ENDIF ELSE bOnMissionCleanupDone = FALSE IS_ENTITY_OK(PLAYER_PED_ID()) SWITCH eStage CASE MS_INIT DO_INITALIZE() BREAK CASE MS_COLLECT_PICKUPS UPDATE_SONAR_BLIPS() UPDATE_DINGHY() UPDATE_PICKUPS() BREAK CASE MS_POST_COMPLETION UPDATE_DINGHY() BREAK CASE MS_CLEANUP SCRIPT_CLEANUP() BREAK ENDSWITCH // Debug widgets #IF IS_DEBUG_BUILD UPDATE_DEBUG_WIDGETS(sMissionData, sPickupData) IF bDebugQuitScript SCRIPT_CLEANUP() ENDIF #ENDIF ENDIF ENDWHILE ENDSCRIPT