USING "globals.sch" #if not USE_CLF_DLC #if not USE_NRM_DLC USING "randomChar_Public.sch" #endif #endif USING "commands_brains.sch" USING "RC_Helper_Functions.sch" USING "replay_public.sch" USING "RC_Area_public.sch" USING "RC_Threat_public.sch" USING "rich_presence_public.sch" // ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** // // MISSION NAME : rc_launcher_public.sch // CREATED : Sean F/ Dave R // MAINTAINED : Andrew Minghella // DESCRIPTION : Contains all public functions for the RC launcher. // // ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** // =========================================================================================================== // Idle / Beckon animation support // =========================================================================================================== /// PURPOSE: Has a launcher animation dictionary and idle animation been specified? /// RETURNS: TRUE if the initial scenes have specified a dictionary and animation. /// NOTE: The existence of valid strings does not guarantee that these are valid dictionaries/animations. FUNC BOOL IS_LAUNCHER_IDLE_ANIM_SETUP(RC_LAUNCHER_ANIMS &launcherAnims) IF IS_STRING_NULL_OR_EMPTY(launcherAnims.sDictionary) OR IS_STRING_NULL_OR_EMPTY(launcherAnims.sIdleAnim) RETURN FALSE ENDIF RETURN TRUE ENDFUNC /// PURPOSE: Has a launcher beckon animation been specified? /// RETURNS: TRUE if the initial scenes have specified a beckon animation. /// NOTE: The existence of a valid string does not guarantee that this is a valid animation. FUNC BOOL IS_LAUNCHER_BECKON_ANIM_SETUP(RC_LAUNCHER_ANIMS &launcherAnims) IF IS_STRING_NULL_OR_EMPTY(launcherAnims.sBeckonAnim) RETURN FALSE ENDIF RETURN TRUE ENDFUNC /// PURPOSE: Sets up the idle animation and beckon animation (if one exists) for the initial scenes. /// and loads the required animation dictionary. /// If you need to set vAnimPos and vAnimRot, make sure you set their values after this function, /// as they are initialised to zero vectors in here PROC SETUP_LAUNCHER_ANIMS(RC_LAUNCHER_ANIMS &launcherAnims, STRING sDictionary, STRING sIdleAnim, STRING sBeckonAnim=NULL) // Pass in dictionary and animation names launcherAnims.sDictionary = sDictionary launcherAnims.sIdleAnim = sIdleAnim launcherAnims.sBeckonAnim = sBeckonAnim // Request dictionary as priority REQUEST_ANIM_DICT(launcherAnims.sDictionary) // Reset position and rotation launcherAnims.vAnimPos = <<0,0,0>> launcherAnims.vAnimRot = <<0,0,0>> // Initialise state launcherAnims.eState = LAS_DONE_SETUP launcherAnims.bBeckonPerformed = FALSE ENDPROC /// PURPOSE: /// Checks if all of the launcher anims have loaded /// PARAMS: /// launcherAnims - launcher anim struct we're checking /// RETURNS: /// TRUE if anims loaded, false otherwise FUNC BOOL HAVE_LAUNCHER_ANIMS_LOADED(RC_LAUNCHER_ANIMS &launcherAnims) // Sanity check for valid strings IF IS_LAUNCHER_IDLE_ANIM_SETUP(launcherAnims) REQUEST_ANIM_DICT(launcherAnims.sDictionary) IF HAS_ANIM_DICT_LOADED(launcherAnims.sDictionary) RETURN TRUE ENDIF ELSE SCRIPT_ASSERT("HAVE_LAUNCHER_ANIMS_LOADED called without first calling SETUP_LAUNCHER_ANIMS") ENDIF RETURN FALSE ENDFUNC /// PURPOSE: Removes the RC launcher animation dictionary if one has been loaded. /// RETURNS: FALSE if the idle animations aren't specified or the dictionary has already unloaded. FUNC BOOL REMOVE_LAUNCHER_ANIM_DICT(RC_LAUNCHER_ANIMS &launcherAnims) // Sanity check for valid strings IF IS_LAUNCHER_IDLE_ANIM_SETUP(launcherAnims) IF HAS_ANIM_DICT_LOADED(launcherAnims.sDictionary) REMOVE_ANIM_DICT(launcherAnims.sDictionary) // clear the anim names launcherAnims.sDictionary = "" launcherAnims.sIdleAnim = "" RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: Checks if the RC ped needs to rotate to face the player. FUNC BOOL DOES_PED_NEED_TO_FACE_PLAYER(g_eRC_MissionIDs eMissionID) IF eMissionID = RC_EXTREME_1 OR eMissionID = RC_EXTREME_4 RETURN TRUE ENDIF RETURN FALSE ENDFUNC //PURPOSE: Checks that a particular conversation root is currently playing. //PARAMS: RootToCheck - The conversation root we want to check is playing. //RETURNS: TRUE if the root is currently playing, FALSE otherwise. FUNC BOOL RC_IS_THIS_CONVERSATION_ROOT_PLAYING(STRING RootToCheck) TEXT_LABEL_23 blah blah = GET_CURRENTLY_PLAYING_STANDARD_CONVERSATION_ROOT() IF ARE_STRINGS_EQUAL(blah,RootToCheck) RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks if the conversation passed is ongoing and stops it if it is /// PARAMS: /// sRootToCheck - the conversation we are checking for PROC RC_STOP_LAUNCHER_DIALOGUE(STRING sRootToCheck) IF NOT IS_STRING_NULL_OR_EMPTY(sRootToCheck) IF RC_IS_THIS_CONVERSATION_ROOT_PLAYING(sRootToCheck) CPRINTLN(DEBUG_RANDOM_CHAR, "RC_STOP_LAUNCHER_DIALOGUE: Killing conversation: ", sRootToCheck) KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ENDIF ENDIF ENDPROC /// PURPOSE: Play a conversation in full, looped, from the RC ped every so often /// v_ped_pos = Pass in the vInCoords from your launcher file /// s_dialogue_slot = Dialogue file to load eg EXT3AUD /// s_dialogue_to_play = Root to play eg EXT_AMB /// ped_dialogue_number = index of the ped in the Dialogue Star file /// ped_dialogue_name = string name of the ped in the Dialogue Star file /// i_time_delay_before_repeat = time delay before the ped will repeat dialogue FUNC BOOL PLAY_LAUNCHER_FULL_CONVERSATION(g_structRCScriptArgs& sData, VECTOR v_ped_pos, STRING s_dialogue_slot, STRING s_dialogue_to_play, INT ped_dialogue_number, STRING ped_dialogue_name, INT i_time_delay_before_repeat = 5000) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_ENTITY_ALIVE(sData.pedID[0]) AND (GET_GAME_TIMER() - sData.iConversationTimer) > i_time_delay_before_repeat AND GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), v_ped_pos) < 20.0 structPedsForConversation s_conversation ADD_PED_FOR_DIALOGUE(s_conversation, ped_dialogue_number, sData.pedID[0], ped_dialogue_name) ADD_NON_CRITICAL_STANDARD_CONVERSATION_TO_BUFFER(s_conversation, s_dialogue_slot, s_dialogue_to_play, CONV_PRIORITY_MEDIUM) sData.iConversationTimer = GET_GAME_TIMER() RETURN TRUE ENDIF ELSE IF RC_IS_THIS_CONVERSATION_ROOT_PLAYING(s_dialogue_to_play) IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), v_ped_pos) >= 20.0 KILL_ANY_CONVERSATION() ENDIF ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: Play ambient dialogue from the RC ped every so often /// v_ped_pos = Pass in the vInCoords from your launcher file /// s_dialogue_slot = Dialogue file to load eg EXT3AUD /// s_dialogue_to_play = Root to play eg EXT_AMB /// ped_dialogue_number = index of the ped in the Dialogue Star file /// ped_dialogue_name = string name of the ped in the Dialogue Star file /// i_time_delay_before_repeat = time delay before the ped will repeat dialogue /// f_distance = the distance at which the dialogue will play from (default 20m) FUNC BOOL PLAY_LAUNCHER_AMBIENT_DIALOGUE(g_structRCScriptArgs& sData, VECTOR v_ped_pos, STRING s_dialogue_slot, STRING s_dialogue_to_play, INT ped_dialogue_number, STRING ped_dialogue_name, INT i_time_delay_before_repeat = 5000, FLOAT f_distance = 20.0) IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_ENTITY_ALIVE(sData.pedID[0]) AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() AND (GET_GAME_TIMER() - sData.iConversationTimer) > i_time_delay_before_repeat AND GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), v_ped_pos) < f_distance structPedsForConversation s_conversation ADD_PED_FOR_DIALOGUE(s_conversation, ped_dialogue_number, sData.pedID[0], ped_dialogue_name) ADD_NON_CRITICAL_STANDARD_CONVERSATION_TO_BUFFER(s_conversation, s_dialogue_slot, s_dialogue_to_play, CONV_PRIORITY_MEDIUM) sData.iConversationTimer = GET_GAME_TIMER() RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: Updates the launcher animations on scene peds PROC UPDATE_LAUNCHER_ANIMS(PED_INDEX iPed, RC_LAUNCHER_ANIMS &launcherAnims, g_eRC_MissionIDs eMissionID) // Entity check IF IS_ENTITY_ALIVE(iPed) // Process launcher animations SWITCH launcherAnims.eState CASE LAS_DONE_SETUP // Does this mission have idle animations specified? IF IS_LAUNCHER_IDLE_ANIM_SETUP(launcherAnims) IF HAS_ANIM_DICT_LOADED(launcherAnims.sDictionary) CLEAR_PED_TASKS_IMMEDIATELY(iPed) // Want to disable leg and arm IK for Fanatic 1's idle animation, because the curb and fence at the location break the animation otherwise -IG IF eMissionID != RC_FANATIC_1 IF ARE_VECTORS_EQUAL(launcherAnims.vAnimPos, <<0,0,0>>) TASK_PLAY_ANIM(iPed, launcherAnims.sDictionary, launcherAnims.sIdleAnim, NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) ELSE //TASK_PLAY_ANIM_ADVANCED(iPed, launcherAnims.sDictionary, launcherAnims.sIdleAnim, launcherAnims.vAnimPos, launcherAnims.vAnimRot, INSTANT_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) // For some reason, the ped won't sit properly on his first anim task so using a sequence here // Playing the beckon anim if that exists as it's shorter (the full anim has to play or it doesn't work) SEQUENCE_INDEX siStart OPEN_SEQUENCE_TASK(siStart) IF IS_LAUNCHER_BECKON_ANIM_SETUP(launcherAnims) TASK_PLAY_ANIM_ADVANCED(null, launcherAnims.sDictionary, launcherAnims.sBeckonAnim, launcherAnims.vAnimPos, launcherAnims.vAnimRot, INSTANT_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) ELSE TASK_PLAY_ANIM_ADVANCED(null, launcherAnims.sDictionary, launcherAnims.sIdleAnim, launcherAnims.vAnimPos, launcherAnims.vAnimRot, INSTANT_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) ENDIF TASK_PLAY_ANIM_ADVANCED(null, launcherAnims.sDictionary, launcherAnims.sIdleAnim, launcherAnims.vAnimPos, launcherAnims.vAnimRot, NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) CLOSE_SEQUENCE_TASK(siStart) TASK_PERFORM_SEQUENCE(iPed, siStart) CLEAR_SEQUENCE_TASK(siStart) ENDIF ELSE TASK_PLAY_ANIM_ADVANCED(iPed, launcherAnims.sDictionary, launcherAnims.sIdleAnim, launcherAnims.vAnimPos, launcherAnims.vAnimRot, NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE, DEFAULT, DEFAULT, AIK_DISABLE_ARM_IK|AIK_DISABLE_LEG_IK) ENDIF launcherAnims.eState = LAS_PLAYING_IDLE ELSE SCRIPT_ASSERT("RC Launcher animations have failed to load.") launcherAnims.eState = LAS_INACTIVE ENDIF ELSE // This mission doesn't require any idle animations (in theory should never hit this part of the script) launcherAnims.eState = LAS_INACTIVE ENDIF BREAK CASE LAS_PLAYING_IDLE IF NOT IS_LAUNCHER_BECKON_ANIM_SETUP(launcherAnims) // Fix for B*845846 OR NOT IS_ENTITY_PLAYING_ANIM(iPed, launcherAnims.sDictionary, launcherAnims.sBeckonAnim) // Let the beckon play out before attempting to turn the ped IF DOES_PED_NEED_TO_FACE_PLAYER(eMissionID) AND NOT IS_PED_FACING_PED(iPed, PLAYER_PED_ID(), 25) TASK_TURN_PED_TO_FACE_ENTITY(iPed, PLAYER_PED_ID()) launcherAnims.eState = LAS_TURNING_TO_PLAYER ELSE IF IS_LAUNCHER_BECKON_ANIM_SETUP(launcherAnims) AND launcherAnims.bBeckonPerformed = FALSE AND GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(iPed)) < RC_BECKON_ANIM_DISTANCE // Player has walked near to the scene ped launcherAnims.eState = LAS_WAITING_FOR_BECKON ENDIF ENDIF ENDIF BREAK CASE LAS_WAITING_FOR_BECKON SEQUENCE_INDEX seq // Scene ped plays beckon animation and reverts back to looping idle animation OPEN_SEQUENCE_TASK(seq) IF ARE_VECTORS_EQUAL(launcherAnims.vAnimPos, <<0,0,0>>) TASK_PLAY_ANIM(null, launcherAnims.sDictionary, launcherAnims.sBeckonAnim, SLOW_BLEND_IN, SLOW_BLEND_OUT, -1, AF_USE_KINEMATIC_PHYSICS) // See B*887597 - changed to slow blends TASK_PLAY_ANIM(null, launcherAnims.sDictionary, launcherAnims.sIdleAnim, NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) ELSE TASK_PLAY_ANIM_ADVANCED(null, launcherAnims.sDictionary, launcherAnims.sBeckonAnim, launcherAnims.vAnimPos, launcherAnims.vAnimRot, SLOW_BLEND_IN, SLOW_BLEND_OUT, -1, AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) TASK_PLAY_ANIM_ADVANCED(null, launcherAnims.sDictionary, launcherAnims.sIdleAnim, launcherAnims.vAnimPos, launcherAnims.vAnimRot, NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) ENDIF CLOSE_SEQUENCE_TASK(seq) TASK_PERFORM_SEQUENCE(iPed, seq) CLEAR_SEQUENCE_TASK(seq) launcherAnims.bBeckonPerformed = TRUE IF DOES_PED_NEED_TO_FACE_PLAYER(eMissionID) launcherAnims.eState = LAS_PLAYING_IDLE ELSE launcherAnims.eState = LAS_INACTIVE ENDIF BREAK CASE LAS_TURNING_TO_PLAYER IF NOT DOES_PED_NEED_TO_FACE_PLAYER(eMissionID) OR IS_PED_FACING_PED(iPed, PLAYER_PED_ID(), 10) IF ARE_VECTORS_EQUAL(launcherAnims.vAnimPos, <<0,0,0>>) TASK_PLAY_ANIM(iPed, launcherAnims.sDictionary, launcherAnims.sIdleAnim, NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) ELSE TASK_PLAY_ANIM_ADVANCED(iPed, launcherAnims.sDictionary, launcherAnims.sIdleAnim, launcherAnims.vAnimPos, launcherAnims.vAnimRot, NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_USE_KINEMATIC_PHYSICS|AF_NOT_INTERRUPTABLE) ENDIF launcherAnims.eState = LAS_PLAYING_IDLE ENDIF BREAK ENDSWITCH ENDIF ENDPROC // =========================================================================================================== // General // =========================================================================================================== /// PURPOSE: /// Runs general script that must happen every time a new RC launcher script starts running. PROC RC_LAUNCHER_START() PRINT_LAUNCHER_DEBUG("Running start routines.") g_iNoRCLeadinsActive++ ENDPROC /// PURPOSE: /// Runs general script that must happen every time an RC launcher script stops running. PROC RC_LAUNCHER_END() PRINT_LAUNCHER_DEBUG("Running end routines.") g_iNoRCLeadinsActive-- ENDPROC /// PURPOSE: /// Checks if all models in array have loaded. (Used by RC initial scenes) /// PARAMS: /// mModel - array of model names /// RETURNS: /// TRUE if all have loaded, false otherwise FUNC BOOL HAVE_ALL_MODELS_IN_ARRAY_LOADED(MODEL_NAMES &mModel[]) INT iModel FOR iModel = 0 TO COUNT_OF(mModel) -1 IF NOT HAS_MODEL_LOADED(mModel[iModel]) RETURN FALSE ENDIF ENDFOR RETURN TRUE ENDFUNC /// PURPOSE: /// Loads the script specified /// PARAMS: /// sRCCommonData - launcher data struct /// RETURNS: /// TRUE if the script is loaded. FALSE if the script name is invalid. FUNC BOOL LOAD_REQUIRED_SCRIPT(STRING sScriptName) IF NOT Is_String_Null_Or_Empty(sScriptName) REQUEST_SCRIPT(sScriptName) WHILE NOT HAS_SCRIPT_LOADED(sScriptName) REQUEST_SCRIPT(sScriptName) WAIT(0) ENDWHILE CPRINTLN(DEBUG_RANDOM_CHAR, "******** LAUNCH *******", sScriptName) RETURN TRUE ENDIF // Invalid script file so terminate script PRINT_LAUNCHER_DEBUG("Attempting to launch invalid script file [TERMINATING]") SCRIPT_ASSERT("RC Launcher attempting to launch invalid script file") RETURN FALSE ENDFUNC /// PURPOSE: /// Whether the player's helmet should be removed when activating this RCM FUNC BOOL REMOVE_HELMET_FOR_RC_MISSION(g_eRC_MissionIDs eRCMission) SWITCH eRCMission CASE RC_BARRY_3A CASE RC_BARRY_3C CASE RC_NIGEL_1A CASE RC_NIGEL_1B CASE RC_NIGEL_1C CASE RC_NIGEL_1D CASE RC_PAPARAZZO_3A CASE RC_PAPARAZZO_3B CASE RC_TONYA_3 CASE RC_TONYA_4 RETURN FALSE BREAK ENDSWITCH RETURN TRUE ENDFUNC /// PURPOSE: /// Gets called when an RC mission is about to launch to handle common requirements /// Currently used by rampages + Ambient Hunting too. Will split this up if required. PROC RC_MISSION_STARTING(g_eRC_MissionIDs eMissionID) #if USE_CLF_DLC eMissionID = eMissionID #endif #if USE_NRM_DLC eMissionID = eMissionID #endif #if not USE_CLF_DLC #if not USE_NRM_DLC // Ensure cellphone isn't in sleep mode when starting this RC mission SET_CELLPHONE_PROFILE_TO_NORMAL() //Stop player fly through windscreens. IF NOT IS_PED_INJURED(PLAYER_PED_ID()) SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_WillFlyThroughWindscreen, FALSE) SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_WillTakeDamageWhenVehicleCrashes, FALSE) ENDIF // Make sure the player removes their helmet IF REMOVE_HELMET_FOR_RC_MISSION(eMissionID) REMOVE_PED_HELMET(PLAYER_PED_ID(), FALSE) ENDIF // Stop ambient peds attacking the player during mission SET_ALL_RANDOM_PEDS_FLEE(PLAYER_ID(), TRUE) // Ensure mission brief is cleared CLEAR_ADDITIONAL_TEXT(MISSION_TEXT_SLOT, TRUE) CLEAR_ADDITIONAL_TEXT(MINIGAME_TEXT_SLOT, TRUE) // Used on Tonya RCM CLEAR_ADDITIONAL_TEXT(ODDJOB_TEXT_SLOT, TRUE) // Sober the player up IF g_isPlayerDrunk = TRUE IF IS_PED_UNINJURED(PLAYER_PED_ID()) Make_Ped_Sober(PLAYER_PED_ID()) ENDIF ENDIF // mission title stuff- not needed on a replay IF NOT IS_REPLAY_IN_PROGRESS() // Reset mission title system ready to display title on mission IF eMissionID < MAX_RC_MISSIONS RANDOM_CHAR_DISPLAY_MISSION_TITLE(eMissionID) //Pass code the name of the mission we're on. TEXT_LABEL_7 tMissionName = GET_RC_MISSION_NAME_LABEL(INT_TO_ENUM(g_eRC_MissionIDs, eMissionID)) CPRINTLN(DEBUG_RANDOM_CHAR, "RC_MISSION_STARTING calling SET_MISSION_NAME, tMissionName= ", tMissionName) SET_MISSION_NAME(TRUE, tMissionName) ENDIF ENDIF #endif #endif ENDPROC /// PURPOSE: /// Whether the player's weapon should be holstered when activating this RCM FUNC BOOL HOLSTER_WEAPON_FOR_RC_MISSION(g_eRC_MissionIDs eRCMission = NO_RC_MISSION) SWITCH eRCMission CASE RC_BARRY_3A CASE RC_BARRY_3C CASE RC_EPSILON_6 CASE RC_NIGEL_1A CASE RC_NIGEL_1B CASE RC_NIGEL_1C CASE RC_NIGEL_1D CASE RC_PAPARAZZO_3A CASE RC_PAPARAZZO_3B CASE RC_RAMPAGE_1 CASE RC_RAMPAGE_2 CASE RC_RAMPAGE_3 CASE RC_RAMPAGE_4 CASE RC_RAMPAGE_5 RETURN FALSE BREAK ENDSWITCH RETURN TRUE ENDFUNC /// PURPOSE: /// Should the RC mission stop the player's vehicle upon activation FUNC BOOL RC_MISSION_SHOULD_HALT_VEHICLE(g_eRC_MissionIDs eMissionID) SWITCH eMissionID CASE RC_BARRY_3A CASE RC_BARRY_3C CASE RC_EPSILON_6 CASE RC_EPSILON_8 CASE RC_NIGEL_1A CASE RC_NIGEL_1B CASE RC_NIGEL_1C CASE RC_NIGEL_1D CASE RC_PAPARAZZO_3A CASE RC_PAPARAZZO_3B RETURN FALSE BREAK ENDSWITCH RETURN TRUE ENDFUNC /// PURPOSE: /// Loads the RC script, calls common startup function, launches script and passes cut-scene over to it. /// PARAMS: /// sRCLauncherData - launcher data struct /// RETURNS: /// TRUE if script is loaded and launched. FALSE if it fails to load. FUNC BOOL REQUEST_AND_LAUNCH_RC(g_structRCScriptArgs &sRCLauncherData) IF LOAD_REQUIRED_SCRIPT(sRCLauncherData.sScriptName) // Ensure missions that start with a lead-in, cutscene or scripted sequence // make the area safe and that all mission entities are invincible IF NOT IS_STRING_NULL_OR_EMPTY(sRCLauncherData.sIntroCutscene) // Clear area of projectiles - no longer disables player control RC_PRE_REQUEST_CUTSCENE(TRUE) // Make entities invincible as we go into the mission RC_SET_ENTITY_PROOFS_FOR_CUTSCENE(sRCLauncherData, TRUE, HOLSTER_WEAPON_FOR_RC_MISSION(sRCLauncherData.eMissionID)) ENDIF // Ensure player exits vehicle... IF sRCLauncherData.bAllowVehicleActivation IF RC_MISSION_SHOULD_HALT_VEHICLE(sRCLauncherData.eMissionID) WHILE NOT IS_PED_ON_FOOT(PLAYER_PED_ID()) RC_PLAYER_TRIGGER_SCENE_LOCK_IN() WAIT(0) ENDWHILE ENDIF ENDIF // Setup common requirements RC_MISSION_STARTING(sRCLauncherData.eMissionID) // Launch script THREADID rcThread = START_NEW_SCRIPT_WITH_ARGS(sRCLauncherData.sScriptName, sRCLauncherData, SIZE_OF(g_structRCScriptArgs), MISSION_STACK_SIZE) // Allow script to be released when no longer running SET_SCRIPT_AS_NO_LONGER_NEEDED(sRCLauncherData.sScriptName) // Allow script to trigger cutscene IF HAS_CUTSCENE_LOADED() PRINT_LAUNCHER_DEBUG("Initial cutscene loaded and passing to RC mission.") SET_SCRIPT_CAN_START_CUTSCENE(rcThread) ELSE PRINT_LAUNCHER_DEBUG("Initial cutscene wasn't loaded in time to pass to RC mission.") REMOVE_CUTSCENE() ENDIF #IF IS_DEBUG_BUILD //In debug build inform the autoplay system we are on a RC mission now. g_txtFlowAutoplayRunningMission = sRCLauncherData.sScriptName #ENDIF RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// checks that the mission is within tolerance range of the world point, it is active and not completed /// PARAMS: /// eRCMission - The RC mission we are checking /// vInCoords - world point position /// fTolerance - WORLD_POINT_COORD_TOLERANCE of this launcher /// eRCInfo - struct of launcher data /// RETURNS: /// TRUE if it finds an RC mission within range that is active and not completed FUNC BOOL IS_RC_IN_RANGE_AND_WAITING(g_eRC_MissionIDs eRCMission,VECTOR vInCoords, FLOAT fTolerance, g_structRCScriptArgs &eRCInfo) BOOL bMissionIsReady = FALSE g_structRCMissionsStatic sRCMissionDetails Retrieve_Random_Character_Static_Mission_Details(eRCMission, sRCMissionDetails) //CPRINTLN(DEBUG_RANDOM_CHAR, sRCMissionDetails.rcScriptName, " MissPos:", sRCMissionDetails.rcCoords, " TestPos:", vInCoords) IF ARE_VECTORS_ALMOST_EQUAL(sRCMissionDetails.rcCoords, vInCoords, fTolerance) IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_ACTIVATED)) IF NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eRCMission].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED)) // In range, active and not already completed. bMissionIsReady = TRUE ELSE CPRINTLN(DEBUG_RANDOM_CHAR, sRCMissionDetails.rcScriptName, " [Already complete]") ENDIF ELSE CPRINTLN(DEBUG_RANDOM_CHAR, sRCMissionDetails.rcScriptName, " [Not activated]") ENDIF // ok for mission to already be complete or not be activated if we are repeat playing it IF IsThisRCBeingRepeatPlayed(ENUM_TO_INT(eRCMission)) CPRINTLN(DEBUG_RANDOM_CHAR, sRCMissionDetails.rcScriptName, " is being repeat played") bMissionIsReady = TRUE ENDIF ELSE CPRINTLN(DEBUG_RANDOM_CHAR, sRCMissionDetails.rcScriptName, " [Position mismatch]") ENDIF IF bMissionIsReady = TRUE eRCInfo.eMissionID = eRCMission eRCInfo.sScriptName = sRCMissionDetails.rcScriptName RETURN TRUE ENDIF // Mission failed to meet requirements RETURN FALSE ENDFUNC /// PURPOSE: /// Determines which RC we are trying to launch. Also wiats for gameflow to finish configuring. /// PARAMS: /// eRCMissions - array of RC missions in this strand /// eRCInfo - struct of launcher data /// vInCoords - world point position /// fTolerance - WORLD_POINT_COORD_TOLERANCE of this launcher /// RETURNS: /// TRUE if it has found an RC that can launch. FALSE otherwise FUNC BOOL DETERMINE_RC_TO_LAUNCH(g_eRC_MissionIDs &eRCMissions[], g_structRCScriptArgs &eRCInfo, VECTOR vInCoords, FLOAT fTolerance) // If the flow is in the process of being configured, we wait for it to finish #IF IS_DEBUG_BUILD WHILE g_flowUnsaved.bUpdatingGameflow WAIT(0) ENDWHILE #ENDIF IF COUNT_OF(eRCMissions) = 1 // This strand only has 1 RC mission, so just check that IF IS_RC_IN_RANGE_AND_WAITING(eRCMissions[0], vInCoords, fTolerance, eRCInfo) // Valid mission found + set to launch. Return CPRINTLN(DEBUG_RANDOM_CHAR, "DetermineRCToLaunch: Found mission ", eRCInfo.sScriptName) RETURN TRUE ENDIF ELSE // Check if there is an RC mission in this strand that can be launched INT iMission = 0 WHILE iMission < COUNT_OF(eRCMissions) IF IS_RC_IN_RANGE_AND_WAITING(eRCMissions[iMission], vInCoords, fTolerance, eRCInfo) // Valid mission found + set to launch. Return CPRINTLN(DEBUG_RANDOM_CHAR, "DetermineRCToLaunch: Found mission ", eRCInfo.sScriptName) iMission = COUNT_OF(eRCMissions) RETURN TRUE ENDIF iMission++ ENDWHILE ENDIF // Failed to find an RC to launch PRINT_LAUNCHER_DEBUG("DETERMINE_RC_TO_LAUNCH - Unable to find mission to launch [TERMINATING]") CPRINTLN(DEBUG_RANDOM_CHAR, "Original Position ", vInCoords) RETURN FALSE ENDFUNC /// PURPOSE: /// Check with the Random Character Controller to see if this script is allowed to launch /// PARAMS: /// eRCMission - the RC mission we are checking /// RETURNS: /// TRUE if allowed, FALSE when denied. FUNC BOOL CAN_RC_LAUNCH(g_eRC_MissionIDs eRCMission = NO_RC_MISSION) // Safeguard against RC launchers ever running in MP. IF g_bInMultiplayer PRINT_LAUNCHER_DEBUG("STEP_3_COMMON_CanRCLaunch - Script denied. Multiplayer is running [TERMINATING]") RETURN FALSE ENDIF // Safeguard against RCs launching outside of flow IF NOT g_savedGlobals.sFlow.isGameflowActive AND NOT IS_REPEAT_PLAY_ACTIVE(TRUE) PRINT_LAUNCHER_DEBUG("STEP_3_COMMON_CanRCLaunch - Script denied, game flow is not active") RETURN FALSE ENDIF IF NOT (Random_Character_Is_Allowed_To_Launch(eRCMission)) // Force update in the blip controller to remove ? blip g_RandomChars[eRCMission].rcIsAwaitingTrigger = TRUE PRINT_LAUNCHER_DEBUG("STEP_3_COMMON_CanRCLaunch - Script denied by RC Controller [TERMINATING]") RETURN FALSE ENDIF //Is a RC replay for this mission in the process of being configured? If so delay launching. IF g_replay.replayType = REPLAY_TYPE_RANDOM_CHARACTER IF ENUM_TO_INT(g_replay.replayStageID) < ENUM_TO_INT(RS_ACTIVATE) g_structRCMissionsStatic sRCMissionDetails Retrieve_Random_Character_Static_Mission_Details(eRCMission, sRCMissionDetails) IF ARE_STRINGS_EQUAL(g_replay.replayScriptName, sRCMissionDetails.rcScriptName) PRINT_LAUNCHER_DEBUG("STEP_3_COMMON_CanRCLaunch - Script denied as a replay for this RC is being configured. [TERMINATING]") RETURN FALSE ENDIF ENDIF ENDIF // B*1594664 - Prevent mission requesting launch before candidate controller has started up IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("candidate_controller")) = 0 g_RandomChars[eRCMission].rcIsAwaitingTrigger = TRUE PRINT_LAUNCHER_DEBUG("STEP_3_COMMON_CanRCLaunch - Script denied as candidate_controller is not running. [TERMINATING]") RETURN FALSE ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// Handles Dom jumping off the Maze Tower PROC MAKE_DOM_JUMP(PED_INDEX pedID) IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_ENTITY_ALIVE(pedID) SEQUENCE_INDEX iSeq // Already requested by initial_scene_extreme.sch but request it just in case... REQUEST_ANIM_DICT("rcmextreme3") WHILE NOT HAS_ANIM_DICT_LOADED("rcmextreme3") WAIT(0) ENDWHILE // Task Dom to jump off the tower OPEN_SEQUENCE_TASK(iSeq) TASK_PLAY_ANIM(NULL, "rcmextreme3", "jump_fall", INSTANT_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE) TASK_SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(NULL, TRUE) // B*1958266 Prevent Dom reacting and trying to flee on foot if the player shoots at him while parachuting away TASK_PARACHUTE_TO_TARGET(NULL, <<64.6,-737.8,44.2>>) TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 10000, -1) CLOSE_SEQUENCE_TASK(iSeq) TASK_PERFORM_SEQUENCE(pedID, iSeq) CLEAR_SEQUENCE_TASK(iSeq) ENDIF ENDPROC /// PURPOSE: /// Makes all of the peds in the initial scene for this RC mission flee the player PROC MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(g_structRCScriptArgs& sData) INT i SEQUENCE_INDEX seqCustomPedFlee // special case for rampage 1 IF (sData.eMissionID = RC_RAMPAGE_1) CPRINTLN(DEBUG_RAMPAGE, "SPECIAL CASE - MAKE_ALL_INITIAL_SCENE_PEDS_FLEE - RAMPAGE 1") SAFE_DELETE_OBJECT(sData.objID[1]) SAFE_DELETE_OBJECT(sData.objID[2]) ENDIF IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) FOR i = 0 to COUNT_OF(sData.pedID) - 1 IF IS_PED_UNINJURED(sData.pedID[i]) IF NOT IS_PED_IN_ANY_VEHICLE(sData.pedID[i]) // Added to fix assert (can't turn on peds collision if they are in a vehicle) SET_ENTITY_COLLISION(sData.pedID[i], TRUE) // Turn ped's collision on (some launcher peds have collision turned off for playing anims) FREEZE_ENTITY_POSITION(sData.pedID[0], FALSE) ENDIF // Remove attached entities /* IF DOES_ENTITY_EXIST(sData.objID[i]) IF IS_ENTITY_ATTACHED_TO_ENTITY(sData.objID[i], sData.pedID[i]) DETACH_ENTITY(sData.objID[i]) ENDIF ENDIF */ // Keep scripted task SET_PED_KEEP_TASK(sData.pedID[i], TRUE) // Need to put collision back on for Manuel's chair IF sData.eMissionID = RC_MINUTE_3 IF IS_ENTITY_ALIVE(sData.objID[0]) SET_ENTITY_COLLISION(sData.objID[0], TRUE) FREEZE_ENTITY_POSITION(sData.objID[0], FALSE) ENDIF ENDIF SWITCH sData.eMissionID // To fix B*735172 - Dom has nowhere to flee to if player interferes with scene CASE RC_EXTREME_3 MAKE_DOM_JUMP(sData.pedID[i]) BREAK CASE RC_DREYFUSS_1 // To fix B*1176001 - Dreyfuss has to stand up from the lotus position REQUEST_ANIM_DICT("rcmcollect_paperleadinout@") // Already requested by initial_scene_dreyfuss.sch but request it just in case WHILE NOT HAS_ANIM_DICT_LOADED("rcmcollect_paperleadinout@") WAIT(0) ENDWHILE OPEN_SEQUENCE_TASK(seqCustomPedFlee) TASK_PLAY_ANIM(NULL, "rcmcollect_paperleadinout@", "meditate_getup", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE) TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 10000, -1) CLOSE_SEQUENCE_TASK(seqCustomPedFlee) TASK_PERFORM_SEQUENCE(sData.pedID[i], seqCustomPedFlee) CLEAR_SEQUENCE_TASK(seqCustomPedFlee) BREAK CASE RC_ABIGAIL_1 CASE RC_ABIGAIL_2 REQUEST_ANIM_DICT("rcmabigail") // Already requested by initial_scene_abigail.sch but request it just in case WHILE NOT HAS_ANIM_DICT_LOADED("rcmabigail") WAIT(0) ENDWHILE OPEN_SEQUENCE_TASK(seqCustomPedFlee) TASK_PLAY_ANIM(NULL, "rcmabigail", "breakout_base", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE) TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 10000, -1) CLOSE_SEQUENCE_TASK(seqCustomPedFlee) TASK_PERFORM_SEQUENCE(sData.pedID[i], seqCustomPedFlee) CLEAR_SEQUENCE_TASK(seqCustomPedFlee) BREAK CASE RC_MINUTE_1 REQUEST_ANIM_DICT("rcmminute1") // Already requested by initial_scene_minute.sch but request it just in case WHILE NOT HAS_ANIM_DICT_LOADED("rcmminute1") WAIT(0) ENDWHILE OPEN_SEQUENCE_TASK(seqCustomPedFlee) IF i = 0 TASK_PLAY_ANIM(NULL, "rcmminute1", "base_to_idle_joe", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE|AF_TAG_SYNC_OUT) ELSE TASK_PLAY_ANIM(NULL, "rcmminute1", "base_to_idle_josef", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE|AF_TAG_SYNC_OUT) ENDIF TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 10000, -1) CLOSE_SEQUENCE_TASK(seqCustomPedFlee) TASK_PERFORM_SEQUENCE(sData.pedID[i], seqCustomPedFlee) CLEAR_SEQUENCE_TASK(seqCustomPedFlee) BREAK CASE RC_HAO_1 REQUEST_ANIM_DICT("special_ped@hao@base") // Already requested by initial_scene_abigail.sch but request it just in case WHILE NOT HAS_ANIM_DICT_LOADED("special_ped@hao@base") WAIT(0) ENDWHILE OPEN_SEQUENCE_TASK(seqCustomPedFlee) TASK_PLAY_ANIM(NULL, "special_ped@hao@base", "hao_exit", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE | AF_TURN_OFF_COLLISION) TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 10000, -1) CLOSE_SEQUENCE_TASK(seqCustomPedFlee) TASK_PERFORM_SEQUENCE(sData.pedID[i], seqCustomPedFlee) CLEAR_SEQUENCE_TASK(seqCustomPedFlee) BREAK DEFAULT CLEAR_PED_SECONDARY_TASK(sData.pedID[i]) // fix for B*951280 TASK_SMART_FLEE_PED(sData.pedID[i], PLAYER_PED_ID(), 10000, -1) BREAK ENDSWITCH ENDIF ENDFOR ENDIF ENDPROC /// PURPOSE: /// Makes all of the peds in the initial scene for this RC mission attack the player PROC MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(g_structRCScriptArgs& sData) INT i IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) FOR i = 0 to COUNT_OF(sData.pedID) - 1 IF IS_PED_UNINJURED(sData.pedID[i]) SET_PED_COMBAT_ATTRIBUTES(sData.pedID[i],CA_USE_VEHICLE,FALSE) //Don't want them chasing you in a vehicle SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(sData.pedID[i],FALSE) SET_PED_KEEP_TASK(sData.pedID[i], TRUE) TASK_COMBAT_PED(sData.pedID[i], PLAYER_PED_ID()) SET_PED_AS_NO_LONGER_NEEDED(sData.pedID[i]) ENDIF ENDFOR ENDIF ENDPROC /// PURPOSE: /// Checks to see whether the vehicles in the initial scene have been destroyed, damaged or if the player is interfering with the vehicles FUNC BOOL CHECK_VEHICLES_OK(g_structRCScriptArgs& sData, BOOL bCheckAllCars, BOOL bCheckInterference=FALSE) INT i INT iLimit IF bCheckAllCars iLimit = COUNT_OF(sData.vehID) - 1 ELSE iLimit = 0 ENDIF IF IS_PED_UNINJURED(PLAYER_PED_ID()) FOR i = 0 to iLimit IF DOES_ENTITY_EXIST(sData.vehID[i]) // Check if the vehicle has been destroyed IF IS_ENTITY_DEAD(sData.vehID[i]) PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - CHECK_VEHICLES_OK() - Random character vehicle is dead [TERMINATING]") RETURN FALSE ENDIF // Check if the vehicle is driveable IF NOT IS_VEHICLE_DRIVEABLE(sData.vehID[i]) PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - CHECK_VEHICLES_OK() - Random character vehicle is not driveable [TERMINATING]") RETURN FALSE ENDIF // Check if the vehicle has been damaged // Don't check for the player's vehicle damaging the scene vehicle as this is done in the bCheckInterference checks IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(sData.vehID[i], PLAYER_PED_ID(), FALSE) PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - CHECK_VEHICLES_OK() - Random character vehicle has been damaged by player [TERMINATING]") RETURN FALSE ENDIF // Check if the vehicle health has been reduced more than 150HP - the player is allowed some leniency (see B*910454) IF GET_ENTITY_HEALTH(sData.vehID[i]) < 850 PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - CHECK_VEHICLES_OK() - Random character vehicle health is less than 850 [TERMINATING]") RETURN FALSE ENDIF // (Optional) Check for player interfering with scene vehicles IF bCheckInterference IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) // Player has collided with scene vehicle at speed, the player is allowed some leniency (see B*910454) IF IS_ENTITY_TOUCHING_ENTITY(sData.vehID[i], PLAYER_PED_ID()) AND GET_ENTITY_SPEED(PLAYER_PED_ID()) > 5 PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - CHECK_VEHICLES_OK() - Random character vehicle has collided with the player vehicle at speed [TERMINATING]") RETURN FALSE ENDIF // Player is towing scene vehicle VEHICLE_INDEX viPlayer = GET_PLAYERS_LAST_VEHICLE() IF IS_VEHICLE_OK(viPlayer) IF GET_ENTITY_MODEL(viPlayer) = TOWTRUCK OR GET_ENTITY_MODEL(viPlayer) = TOWTRUCK2 IF IS_VEHICLE_OK(sData.vehID[i]) IF IS_VEHICLE_ATTACHED_TO_TOW_TRUCK(viPlayer, sData.vehID[i]) PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - CHECK_VEHICLES_OK() - Random character vehicle is being towed by player [TERMINATING]") RETURN FALSE ENDIF ENDIF ENDIF ENDIF ELSE // Fix for B*1273632 - in case the player has bailed out of their vehicle at speed and it collides with a scene vehicle VEHICLE_INDEX veh = GET_PLAYERS_LAST_VEHICLE() IF IS_VEHICLE_OK(veh) IF IS_ENTITY_TOUCHING_ENTITY(sData.vehID[i], veh) AND GET_ENTITY_SPEED(veh) > 6 PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - CHECK_VEHICLES_OK() - Random character vehicle has collided with the player's last known vehicle at speed (player bailed out?) [TERMINATING]") RETURN FALSE ENDIF ENDIF IF sData.eMissionID = RC_EPSILON_8 IF IS_CHAR_USING_VEHICLE(PLAYER_PED_ID(),sData.vehID[i]) PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - CHECK_VEHICLES_OK() - Player attempting to jack Epsilon vehicle [TERMINATING]") RETURN FALSE ENDIF ENDIF ENDIF ENDIF ENDIF ENDFOR ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// For some missions the initial scene characters are seated, they can't flee properly from their seated anims /// Call this to check if the mission uses a seated ped /// RETURNS: /// TRUE if the mission ped is standing, FALSE if they're seated FUNC BOOL IS_PED_STANDING(g_eRC_MissionIDs missionID) IF missionID = RC_BARRY_1 OR missionID = RC_BARRY_2 OR missionID = RC_MINUTE_3 OR missionID = RC_EPSILON_3 OR missionID = RC_RAMPAGE_1 OR missionID = RC_RAMPAGE_2 RETURN FALSE ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// Checks if the RC mission is a rampage /// RETURNS: /// TRUE if the mission is a rampage, false if its any other RC mission FUNC BOOL IS_MISSION_A_RAMPAGE(g_eRC_MissionIDs missionID) IF missionID = RC_RAMPAGE_1 OR missionID = RC_RAMPAGE_2 OR missionID = RC_RAMPAGE_3 OR missionID = RC_RAMPAGE_4 OR missionID = RC_RAMPAGE_5 RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Should the RC ped ignore nearby explosions? (typically used for seated peds) FUNC BOOL SHOULD_RC_MISSION_IGNORE_EXPLOSIONS(g_eRC_MissionIDs missionID) IF missionID = RC_BARRY_1 OR MissionID = RC_BARRY_2 OR missionID = RC_RAMPAGE_1 OR missionID = RC_RAMPAGE_2 RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks to see whether the peds in the initial scene have been killed, damaged or pushed around /// PARAMS: /// bPedsAttack - If true peds will attack player, otherwise flee from player FUNC BOOL CHECK_PEDS_OK(g_structRCScriptArgs& sData, BOOL bCheckAllPeds, BOOL bPedsAttack = FALSE) INT i INT iLimit IF bCheckAllPeds iLimit = COUNT_OF(sData.pedID) - 1 ELSE iLimit = 0 ENDIF // For B*900468 - Security attack the player if he interferes with Epsilon 8 initial scene IF sData.eMissionID = RC_EPSILON_8 bPedsAttack = TRUE ENDIF // For B*968838 - Cops attack player and Josh runs off IF sData.eMissionID = RC_JOSH_4 bPedsAttack = TRUE ENDIF IF IS_PED_UNINJURED(PLAYER_PED_ID()) FOR i = 0 to iLimit IF DOES_ENTITY_EXIST(sData.pedID[i]) // Don't use is entity alive for this as it takes a while for ped to get created. IF NOT IS_PED_INJURED(sData.pedID[i]) // Check for player pushing them with their car IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) // Ignore player knocking them with car door (in vehicle, but not sitting= must be exiting) if IS_ENTITY_TOUCHING_ENTITY(PLAYER_PED_ID(), sData.pedID[i]) IF bPedsAttack = FALSE MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) ELSE MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sData) ENDIF IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_ANY_CONVERSATION() ENDIF PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - Random character is being pushed by car [TERMINATING]") RETURN FALSE ENDIF ENDIF // Check for RC ped taking damage IF HAS_ENTITY_BEEN_DAMAGED_BY_ANY_PED(sData.pedID[i]) OR HAS_ENTITY_BEEN_DAMAGED_BY_ANY_VEHICLE(sData.pedID[i]) OR HAS_ENTITY_BEEN_DAMAGED_BY_ANY_OBJECT(sData.pedID[i]) IF bPedsAttack = FALSE MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) ELSE MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sData) ENDIF PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - Random character has been damaged by something [TERMINATING]") RETURN FALSE ENDIF // check for RC ped being psuehd over by the player IF IS_PED_RAGDOLL(sData.pedID[i]) IF IS_ENTITY_AT_ENTITY(sData.pedID[i], PLAYER_PED_ID(), <<3.0, 3.0, 3.0>>) // Player close (so they bumped into them) IF bPedsAttack = FALSE MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) ELSE MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sData) ENDIF PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - Random character is in ragdoll [TERMINATING]") RETURN FALSE ENDIF ENDIF // Only perform these checks if the ped is standing IF IS_PED_STANDING(sData.eMissionID) IF NOT IS_MISSION_A_RAMPAGE(sData.eMissionID) // Check for player shooting nearby IF IS_PLAYER_SHOOTING_NEAR_PED(sData.pedID[i]) IF bPedsAttack = FALSE MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) ELSE MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sData) ENDIF PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - Player is shooting near the Random Character [TERMINATING]") RETURN FALSE ENDIF ENDIF // Check for explosions nearby IF IS_EXPLOSION_IN_SPHERE(EXP_TAG_DONTCARE, GET_ENTITY_COORDS(sData.pedID[i]), 15) IF bPedsAttack = FALSE MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) ELSE MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sData) ENDIF PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - There was an explosion near the Random Character [TERMINATING]") RETURN FALSE ENDIF // check for player aiming at RC character IF IS_PLAYER_VISIBLY_TARGETTING_PED(sData.pedID[i]) IF bPedsAttack = FALSE MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) ELSE MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sData) ENDIF PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - Random character is in combat [TERMINATING]") RETURN FALSE ENDIF ENDIF IF NOT SHOULD_RC_MISSION_IGNORE_EXPLOSIONS(sData.eMissionID) // Check for explosions nearby IF IS_EXPLOSION_IN_SPHERE(EXP_TAG_DONTCARE, GET_ENTITY_COORDS(sData.pedID[i]), 5) IF bPedsAttack = FALSE MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) ELSE MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sData) ENDIF PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - There was an explosion near the Random Character [TERMINATING]") RETURN FALSE ENDIF // Check for player having wanted level IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 IF bPedsAttack = FALSE MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) ELSE MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sData) ENDIF PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - Player has a wanted level [TERMINATING]") RETURN FALSE ENDIF ENDIF ELSE PRINT_LAUNCHER_DEBUG("STEP_5_COMMON_RCfineAndInRange - Random character injured / dead [TERMINATING]") // Need to put collision back on for Manuel's chair IF sData.eMissionID = RC_MINUTE_3 IF IS_ENTITY_ALIVE(sData.objID[0]) SET_ENTITY_COLLISION(sData.objID[0], TRUE) FREEZE_ENTITY_POSITION(sData.objID[0], FALSE) ENDIF ENDIF RETURN FALSE ENDIF ENDIF ENDFOR ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// Checks if there are any reasons for the script to terminate. /// Such as the initial scene peds being threatened/ damaged etc. /// PARAMS: /// sData - struct of launcher data /// bAutoUpdateLaunchAnims - set this to auto update launch anims /// RETURNS: /// FALSE if the launcher should now terminate, TRUE otherswise FUNC BOOL IS_RC_FINE_AND_IN_RANGE(g_structRCScriptArgs& sData, BOOL bAutoUpdateLaunchAnims = TRUE) // Safeguard against RC launchers ever running in MP. IF g_bInMultiplayer PRINT_LAUNCHER_DEBUG("IS_RC_FINE_AND_IN_RANGE(): The game is running Multiplayer [TERMINATING]") RETURN FALSE ENDIF g_structRCMissionsStatic sRCMissionDetails Retrieve_Random_Character_Static_Mission_Details(sData.eMissionID, sRCMissionDetails) // Skip these checks on replays or repeat play IF IsThisRCBeingRepeatPlayed(ENUM_TO_INT(sData.eMissionID)) OR IS_THIS_RC_MISSION_BEING_PROCESSED_FOR_REPLAY(sData.eMissionID) OR g_bSceneAutoTrigger = TRUE RETURN TRUE ENDIF // Check if the player is still in range of the random character IF NOT IS_WORLD_POINT_WITHIN_BRAIN_ACTIVATION_RANGE() PRINT_LAUNCHER_DEBUG("IS_RC_FINE_AND_IN_RANGE(): Player out of range [TERMINATING]") RETURN FALSE ENDIF // Does Controller still allow this Random Character to check for the mission being triggered? IF SHOULD_RC_TERMINATE(sData.eMissionID) // Ensure Dom jumps! IF (sData.eMissionID = RC_EXTREME_3) MAKE_DOM_JUMP(sData.pedID[0]) ENDIF PRINT_LAUNCHER_DEBUG("IS_RC_FINE_AND_IN_RANGE(): Script denied by RC Controller [TERMINATING]") RETURN FALSE ENDIF // We need to check all peds in this scene... IF sData.bPedsCritical = TRUE IF NOT CHECK_PEDS_OK(sData, TRUE) RETURN FALSE ENDIF ELSE // Just need to check main RC character IF sData.triggerType = RC_TRIG_CHAR IF NOT CHECK_PEDS_OK(sData, FALSE) RETURN FALSE ENDIF ENDIF ENDIF // Check interference with scene vehicles (e.g. colliding/towing) for certain RCM's IF sData.eMissionID = RC_EPSILON_8 OR sData.eMissionID = RC_EPSILON_1 OR sData.eMissionID = RC_EXTREME_2 OR sData.eMissionID = RC_FANATIC_2 OR sData.eMissionID = RC_MINUTE_1 OR sData.eMissionID = RC_PAPARAZZO_4 IF NOT CHECK_VEHICLES_OK(sData, TRUE, TRUE) IF sData.eMissionID = RC_EPSILON_8 MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sData) ELSE MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) ENDIF RETURN FALSE ENDIF ELIF sData.eMissionID = RC_HAO_1 IF NOT CHECK_VEHICLES_OK(sData, FALSE, TRUE) MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) RETURN FALSE ENDIF ELIF sData.eMissionID = RC_BARRY_3C // B*2034445 - don't fail for damaging tow truck, only the stash car IF NOT CHECK_VEHICLES_OK(sData, FALSE, TRUE) RETURN FALSE ENDIF // We need to check all scene vehicles .. ELIF sData.bVehsCritical = TRUE IF NOT CHECK_VEHICLES_OK(sData, TRUE) MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) RETURN FALSE ENDIF // Just need to check main RC vehicle ELSE IF sData.triggerType = RC_TRIG_ENTER_VEHICLE OR sData.triggerType = RC_TRIG_NEAR_VEHICLE IF NOT CHECK_VEHICLES_OK(sData, FALSE) MAKE_ALL_INITIAL_SCENE_PEDS_FLEE(sData) RETURN FALSE ENDIF ENDIF ENDIF // Check for Trigger vehicles being moved away from their initial position IF sData.triggerType = RC_TRIG_ENTER_VEHICLE OR sData.triggerType = RC_TRIG_NEAR_VEHICLE IF IS_ENTITY_ALIVE(sData.vehID[0]) IF NOT IS_ENTITY_AT_COORD(sData.vehID[0], sRCMissionDetails.rcCoords, <<8.0, 8.0, 8.0>> ) CPRINTLN(DEBUG_RANDOM_CHAR, "RC Trigger vehicle moved too far from initial position. [TERMINATING]") RETURN FALSE ENDIF ENDIF ENDIF // Special case detection of fire in mission trigger area IF sData.eMissionID = RC_EPSILON_2 IF IS_EXPLOSION_IN_SPHERE(EXP_TAG_DONTCARE, sData.triggerLocate[0], 8.0) PRINT_LAUNCHER_DEBUG("IS_RC_FINE_AND_IN_RANGE(): Explosion near mission trigger [TERMINATING]") RETURN FALSE ENDIF ENDIF // Check for the player character switching to an invalid character whilst launcher is active // Tonya is exception - to be removed when Michael/Trevor interaction is special ped script IF sRCMissionDetails.rcStrandID <> RCS_TONYA IF NOT IS_BIT_SET(sRCMissionDetails.rcPlayableChars, ENUM_TO_INT(GET_CURRENT_PLAYER_PED_ENUM())) PRINT_LAUNCHER_DEBUG("IS_RC_FINE_AND_IN_RANGE(): No longer a valid player character to launch mission") RETURN FALSE ENDIF ENDIF // Handle launcher anims - To be moved outside of this check... IF IS_LAUNCHER_IDLE_ANIM_SETUP(sData.sAnims) AND (bAutoUpdateLaunchAnims) // Update idle animations on the RC character. // If one exists, beckon animation triggered when the player gets within range. UPDATE_LAUNCHER_ANIMS(sData.pedID[0], sData.sAnims, sData.eMissionID) ENDIF // Whether mission is ok to proceed RETURN TRUE ENDFUNC /// PURPOSE: Checks whether the player is ok to activate the mission /// PARAMS: bAllowVehicle - Mission can be triggered in a vehicle /// RETURNS: TRUE if the mission can be activated, FALSE otherwise FUNC BOOL IS_PLAYER_OK_TO_ACTIVATE_MISSION(BOOL bAllowVehicle=FALSE) IF IS_PLAYER_PLAYING(GET_PLAYER_INDEX()) // Check for player being on foot IF IS_PED_ON_FOOT(PLAYER_PED_ID()) RETURN TRUE ELSE // Check for players vehicle being on the ground IF bAllowVehicle IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) VEHICLE_INDEX playerVehicle = GET_PLAYERS_LAST_VEHICLE() IF IS_VEHICLE_OK(playerVehicle) IF IS_PED_IN_ANY_HELI(PLAYER_PED_ID()) OR IS_PED_IN_ANY_PLANE(PLAYER_PED_ID()) IF NOT HAS_ENTITY_COLLIDED_WITH_ANYTHING(playerVehicle) AND NOT IS_ENTITY_IN_AIR(playerVehicle) AND (GET_ENTITY_SPEED(playerVehicle) < 1.0) RETURN TRUE ENDIF ELSE IF NOT IS_ENTITY_IN_AIR(playerVehicle) RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// If this vehicle allows vehicle activation and player is in vehicle it brings him to a halt /// And tells him to get out of the vehicle PROC RC_STOP_PLAYER_VEHICLE_CHECK(BOOL bAllowVehicleActivation, g_eRC_MissionIDs eMissionID) IF bAllowVehicleActivation = TRUE IF NOT RC_MISSION_SHOULD_HALT_VEHICLE(eMissionID) EXIT ENDIF IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) PRINT_LAUNCHER_DEBUG("RC_STOP_PLAYER_VEHICLE_CHECK: Stopping player's vehicle.") IF IS_PED_IN_ANY_HELI(PLAYER_PED_ID()) OR IS_PED_IN_ANY_PLANE(PLAYER_PED_ID()) PRINT_LAUNCHER_DEBUG("RC_STOP_PLAYER_VEHICLE_CHECK: Turning off engine for plane or helicopter.") SET_VEHICLE_ENGINE_ON(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()),FALSE, TRUE) ENDIF RC_PLAYER_TRIGGER_SCENE_LOCK_IN() ENDIF ENDIF ENDPROC FUNC BOOL IS_PLAYER_WITHIN_PED_ACTIVATION_RANGE(g_structRCScriptArgs& sData) IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND sData.bAllowVehicleActivation FLOAT fStopping // If Josh 1 or 4, only add 1 meter to the range so the player doesn't get sucked into the trigger while driving past on the road // Otherwise, add 5 meters for all other missions IF sData.eMissionID = RC_JOSH_1 OR sData.eMissionID = RC_JOSH_4 fStopping = 1.0 ELSE fStopping = 5.0 ENDIF // Add x.0m to activation range if in a vehicle (increased for bug 1113835) IF (GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sData.pedID[0])) < sData.activationRange + fStopping) RETURN TRUE ENDIF ELSE IF (GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sData.pedID[0])) < sData.activationRange) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks if the player has met the conditions necessary to launch this RC mission. /// PARAMS: /// sData - struct of launcher data /// bStoreVehicleSnapshot - do we want to store the vehicle snapshot for this mission? /// RETURNS: /// TRUE if the player has met the conditions to launch this RC mission. FALSE otherwise. FUNC BOOL ARE_RC_TRIGGER_CONDITIONS_MET(g_structRCScriptArgs& sData, BOOL bStoreVehicleSnapshot = FALSE) //Check if they are close enough SWITCH (sData.triggerType) // Triggers when player is near to Random Character CASE RC_TRIG_CHAR // Epsilon 4 - Check area behind the bush to see if the player is there, and make the activation range much smaller if this is the case IF sData.eMissionID = RC_EPSILON_4 IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<1826.630615,4699.115234,35.380890>>, <<1812.877563,4710.457031,42.053535>>, 23.75) IF(IS_ENTITY_ALIVE(sData.pedID[0])) IF (GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sData.pedID[0])) < 3.0) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) PRINT_LAUNCHER_DEBUG("ARE_RC_TRIGGER_CONDITIONS_MET: RC_TRIG_CHAR - Used special case Eps 4 trigger.") RETURN TRUE ENDIF ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("ARE_RC_TRIGGER_CONDITIONS_MET: RC_TRIG_CHAR - IS_ENTITY_ALIVE(sData.pedID[0]) failed.") RETURN FALSE ENDIF ELSE IF(IS_ENTITY_ALIVE(sData.pedID[0])) IF IS_PLAYER_WITHIN_PED_ACTIVATION_RANGE(sData) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("ARE_RC_TRIGGER_CONDITIONS_MET: RC_TRIG_CHAR - IS_ENTITY_ALIVE(sData.pedID[0]) failed.") RETURN FALSE ENDIF ENDIF // Fanatic 1 - Check along the cliffside of the fence and stop the mission launching there (B*1350755) ELIF sData.eMissionID = RC_FANATIC_1 IF NOT IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-1895.787964,-434.019226,40.301258>>, <<-1883.037598,-444.081116,50.245090>>, 8.5) AND NOT IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-1883.576416,-443.643372,36.405807>>, <<-1874.825806,-448.079712,49.151619>>, 8.5) AND NOT IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-1876.342651,-446.221405,35.646370>>, <<-1866.951904,-456.560059,49.044197>>, 8.5) AND NOT IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-1882.997314,-438.992157,44.172462>>, <<-1874.079346,-443.342041,48.691788>>, 0.750) OR IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-1878.822266,-441.765503,44.917503>>, <<-1877.940918,-439.952209,47.289818>>, 1.25) IF(IS_ENTITY_ALIVE(sData.pedID[0])) IF IS_PLAYER_WITHIN_PED_ACTIVATION_RANGE(sData) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("ARE_RC_TRIGGER_CONDITIONS_MET: RC_TRIG_CHAR - IS_ENTITY_ALIVE(sData.pedID[0]) failed.") RETURN FALSE ENDIF ELSE RETURN FALSE // Player is on the wrong side of the fence ENDIF // Fanatic 2 - Don't trigger the mission on the side of the hill ELIF sData.eMissionID = RC_FANATIC_2 IF NOT IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<837.073059,1261.086182,366.159180>>, <<780.838257,1260.828613,351.404999>>, 17.750) IF(IS_ENTITY_ALIVE(sData.pedID[0])) IF IS_PLAYER_WITHIN_PED_ACTIVATION_RANGE(sData) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("ARE_RC_TRIGGER_CONDITIONS_MET: RC_TRIG_CHAR - IS_ENTITY_ALIVE(sData.pedID[0]) failed.") RETURN FALSE ENDIF ELSE RETURN FALSE // Player is on the wrong side of the fence ENDIF // If this is any other mission, do what should be done normally ELSE IF(IS_ENTITY_ALIVE(sData.pedID[0])) IF IS_PLAYER_WITHIN_PED_ACTIVATION_RANGE(sData) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("ARE_RC_TRIGGER_CONDITIONS_MET: RC_TRIG_CHAR - IS_ENTITY_ALIVE(sData.pedID[0]) failed.") RETURN FALSE ENDIF ENDIF BREAK // Triggers when player enters specified vehicle CASE RC_TRIG_ENTER_VEHICLE IF IS_ENTITY_ALIVE(sData.vehID[0]) IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(),sData.vehID[0]) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RCM_VEHICLE) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ELSE IF bStoreVehicleSnapshot = TRUE // Not in vehicle, but script has not terminated yet (store player's vehicle for snapshot) STORE_START_PLAYER_VEHICLE_SNAPSHOT() ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("ARE_RC_TRIGGER_CONDITIONS_MET: RC_TRIG_ENTER_VEHICLE - IS_ENTITY_ALIVE(sData.vehID[0]) failed.") RETURN FALSE ENDIF BREAK // Triggers when player is near to a specified vehicle CASE RC_TRIG_NEAR_VEHICLE IF DOES_ENTITY_EXIST(sData.vehID[0]) IF NOT IS_ENTITY_DEAD(sData.vehID[0]) IF (GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sData.vehID[0])) < sData.activationRange) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ENDIF ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("ARE_RC_TRIGGER_CONDITIONS_MET: RC_TRIG_NEAR_VEHICLE - DOES_ENTITY_EXIST(sData.vehID[0]) failed.") RETURN FALSE ENDIF BREAK // Player has got within activation range of trigger coords CASE RC_TRIG_LOCATE_POINT IF (GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), sData.triggerLocate[0]) < sData.activationRange) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("ARE_RC_TRIGGER_CONDITIONS_MET: RC_TRIG_LOCATE_POINT - GET_DISTANCE_BETWEEN_COORDS() failed.") RETURN FALSE ENDIF BREAK // Player has entered axis aligned locate CASE RC_TRIG_LOCATE_AXIS IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), sData.triggerLocate[0], sData.triggerLocate[1]) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("RC5_IN_ACTIVATION_RANGE: RC_TRIG_LOCATE_AXIS - IS_ENTITY_AT_COORD failed.") RETURN FALSE ENDIF BREAK // Player has entered non-axis aligned locate CASE RC_TRIG_LOCATE_NONAXIS // Barry 3C can trigger if the player attaches a tow truck or cargobob to the stash car IF sData.eMissionID = RC_BARRY_3C IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) IF IS_ENTITY_ALIVE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) IF IS_VEHICLE_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), TOWTRUCK) OR IS_VEHICLE_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), TOWTRUCK2) IF IS_VEHICLE_ATTACHED_TO_TOW_TRUCK(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), sData.vehID[0]) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RCM_VEHICLE) RETURN TRUE ENDIF ENDIF ELIF IS_VEHICLE_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), CARGOBOB) OR IS_VEHICLE_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), CARGOBOB2) OR IS_VEHICLE_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), CARGOBOB3) IF DOES_CARGOBOB_HAVE_PICK_UP_ROPE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) AND IS_VEHICLE_ATTACHED_TO_CARGOBOB(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), sData.vehID[0]) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RCM_VEHICLE) RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF // B*1334138 - Special case for Epsilon 2 ELIF sData.eMissionID = RC_EPSILON_2 IF GET_PED_DESIRED_MOVE_BLEND_RATIO(PLAYER_PED_ID()) >= PEDMOVEBLENDRATIO_RUN IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<245.888489,371.903412,103.988426>>, <<241.589844,359.645752,107.346123>>, 1.25) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) PRINT_LAUNCHER_DEBUG("RC5_IN_ACTIVATION_RANGE: RC_TRIG_LOCATE_NONAXIS - Eps 2 special case trigger used") RETURN TRUE ENDIF ENDIF ENDIF ENDIF // B*1426354 - special case exclusion zone for Paparazzo 1 ELIF sData.eMissionID = RC_PAPARAZZO_1 IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-164.204559,277.486633,91.553215>>, <<-153.599960,277.406067,97.338135>>, 10.000000) RETURN FALSE ENDIF // B*1394562 - special case force launch in vehicle when close to Maude for Maude 1 ELIF sData.eMissionID = RC_MAUDE_1 IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<2728.948242,4143.439941,42.292946>>, <<2722.213379,4144.521484,45.431824>>, 10.000000) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(TRUE) RC_STOP_PLAYER_VEHICLE_CHECK(TRUE, sData.eMissionID) PRINT_LAUNCHER_DEBUG("RC_IN_ACTIVATION_RANGE: RC_TRIG_LOCATE_NONAXIS - RC_MAUDE_1 special case vehicle launch area") RETURN TRUE ENDIF ENDIF ENDIF // B*1533146 - special case launch extra area cover garden for Nigel 1B ELIF sData.eMissionID = RC_NIGEL_1B IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-992.499451,358.745453,96.373505>>, <<-1021.940125,361.888763,65.361481>>, 30.000000) IF NOT IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-983.542603,369.110352,68.460175>>, <<-1028.566284,395.461334,94.572449>>, 15.000000) // exclude the road (North side) IF NOT IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-983.875000,346.755646,68.020958>>, <<-1021.451416,336.345825,93.187141>>, 14.500000) // exclude the road (South side) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) PRINT_LAUNCHER_DEBUG("RC_IN_ACTIVATION_RANGE: RC_TRIG_LOCATE_NONAXIS - RC_NIGEL_1B special case vehicle launch area") RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), sData.triggerLocate[0], sData.triggerLocate[1], sData.triggerWidth) // Had to expand the trigger width for Omega 2 for B*1427155, but this means if you walk behind the trailer, the mission triggers // and the lead-in plays when Omega is obscured // So if the player is in the trigger area but in this special area, don't trigger the mission IF sData.eMissionID = RC_OMEGA_2 IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<2338.696533,2597.037354,45.390518>>, <<2324.003418,2597.185059,47.749607>>, 8.5) RETURN FALSE ENDIF ENDIF IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ENDIF ELSE //PRINT_LAUNCHER_DEBUG("RC5_IN_ACTIVATION_RANGE: RC_TRIG_LOCATE_NONAXIS - IS_ENTITY_IN_ANGLED_AREA failed.") RETURN FALSE ENDIF BREAK // Shouldn't reach this section... CASE RC_TRIG_NOT_SET // Invalid script file so terminate script SCRIPT_ASSERT("NO RC Trigger Type Set") BREAK ENDSWITCH RETURN FALSE ENDFUNC /// PURPOSE: /// Checks if the player has entered the custom polygon defined for this RCM FUNC BOOL ARE_RC_TRIGGER_POLY_CONDITIONS_MET(g_structRCScriptArgs& sData, TEST_POLY& pMissionTrigger) IF IS_POINT_IN_POLY_2D(pMissionTrigger, GET_ENTITY_COORDS(PLAYER_PED_ID())) IF IS_IT_SAFE_TO_TRIGGER_SCRIPT_TYPE(ST_RANDOM_CHARACTER) IF IS_PLAYER_OK_TO_ACTIVATE_MISSION(sData.bAllowVehicleActivation) RC_STOP_PLAYER_VEHICLE_CHECK(sData.bAllowVehicleActivation, sData.eMissionID) RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Common stat function shared amongst RC launcher and ambient launched RC missions PROC PRIME_STATS_FOR_RC_MISSION(g_eRC_MissionIDs eMissionID, STRING sScriptName) // Script name only referenced in debug output DUMMY_REFERENCE_STRING(sScriptName) //old stat procedure CPRINTLN(DEBUG_FLOW, "PRIME_STATS_FOR_RC_MISSION(", sScriptName, ")" ) CLEAR_BIT(g_savedGlobals.sRandomChars.savedRC[eMissionID].rcFlags, ENUM_TO_INT(RC_FLAG_STATWATCHER_RUNNING)) IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("mission_stat_watcher")) > 0 WHILE GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("mission_stat_watcher")) > 0 TERMINATE_STAT_WATCHER() CPRINTLN(DEBUG_FLOW, "PRIME_STATS_FOR_RC_MISSION(", sScriptName, "): Waiting for old stat watcher to terminate. Flag is : ", g_bMissionStatSystemResetFlag ) //IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eMissionID].rcFlags, RC_FLAG_STATWATCHER_RUNNING) WAIT(0) ENDWHILE ENDIF //watcher needs to be running IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("mission_stat_watcher")) < 1 g_bMissionStatSystemResetFlag = FALSE REQUEST_SCRIPT("mission_stat_watcher") WHILE NOT HAS_SCRIPT_LOADED("mission_stat_watcher") CPRINTLN(DEBUG_FLOW, "PRIME_STATS_FOR_RC_MISSION(", sScriptName, "): Waiting for stat watcher script to load.") WAIT(0) ENDWHILE START_NEW_SCRIPT("mission_stat_watcher", SPECIAL_ABILITY_STACK_SIZE) SET_SCRIPT_AS_NO_LONGER_NEEDED("mission_stat_watcher") ENDIF WHILE NOT IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[eMissionID].rcFlags, ENUM_TO_INT(RC_FLAG_STATWATCHER_RUNNING)) CPRINTLN(DEBUG_FLOW, "PRIME_STATS_FOR_RC_MISSION(", sScriptName, "): Waiting for watcher thread to start.") IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("mission_stat_watcher")) > 0 SET_BIT(g_savedGlobals.sRandomChars.savedRC[eMissionID].rcFlags, ENUM_TO_INT(RC_FLAG_STATWATCHER_RUNNING)) ENDIF ENDWHILE //WAIT(10) // Setup mission stats //IF NOT IS_REPLAY_IN_PROGRESS() // (not needed for replays) //yes it needed is due to priming issue // This condition was the cause of 1381672 FLOW_PRIME_STATS_FOR_RC_MISSION(eMissionID) //ENDIF ENDPROC /// PURPOSE: /// Attempts to launch the specified RC mission. /// If successful it also updates playstats system and stores starting snapshot. /// PARAMS: /// sData - struct of launcher data. /// RETURNS: /// TRUE if mission launch is succesful, FALSE otherwise. FUNC BOOL LAUNCH_RC_MISSION(g_structRCScriptArgs& sData) IF NOT IS_REPLAY_IN_PROGRESS() //(replays already have permission to run) // NOTE: Need to stay in this loop until the mission is given permission to run. // After first asking permission to run, a decision is usually made // within a few frames - if it returns FALSE, check if it should terminate or not. WHILE NOT RC_REQUEST_PERMISSION_TO_RUN(sData.eMissionID) //Prevent player from still running after focus push during rampages IF IS_MISSION_A_RAMPAGE( sData.eMissionID ) RC_PLAYER_TRIGGER_SCENE_LOCK_IN() ENDIF // Not yet given permission to run, should the script terminate? IF NOT IS_RC_FINE_AND_IN_RANGE(sData, sData.eMissionID <> RC_BARRY_1) PRINT_LAUNCHER_DEBUG("LAUNCH_RC_MISSION - NOT IS_RC_FINE_AND_IN_RANGE() [TERMINATING]") RETURN FALSE ENDIF WAIT(0) ENDWHILE ENDIF // Kill any conversation, e.g. AMB dialogue IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_ANY_CONVERSATION() ENDIF // NOTE: The Random Character mission is now safe to start so request the script and launch. // The activity MUST trigger because scripts now think the game is OnMission. IF NOT REQUEST_AND_LAUNCH_RC(sData) PRINT_LAUNCHER_DEBUG("STEP_7_COMMON_LaunchMission - Trying to launch a null script string name") RETURN FALSE ENDIF // Tell the playstats system that we're starting an RC mission. g_structRCMissionsStatic sRCMissionDetails Retrieve_Random_Character_Static_Mission_Details(sData.eMissionID, sRCMissionDetails) TEXT_LABEL tStatLabel = GET_RC_STAT_ID(sData.eMissionID) SCRIPT_PLAYSTATS_MISSION_STARTED(tStatLabel, sRCMissionDetails.rcStatVariation) CPRINTLN(DEBUG_FLOW, "Flagging playstat MISSION STARTED for RC mission. Script:", sRCMissionDetails.rcScriptName, " Variation:", sRCMissionDetails.rcStatVariation, " RC Stat ID = ",tStatLabel) // Set console rich presence values as we go on mission (friend dashboard status message). SET_RICH_PRESENCE_FOR_SP_RC_MISSION(sData.eMissionID) // Store start snapshot if this isn't a replay IF NOT IS_REPLAY_IN_PROGRESS() IF sData.triggerType = RC_TRIG_ENTER_VEHICLE Store_RC_Replay_Starting_Snapshot(sData.sScriptName, FALSE) // enter vehicle missions, don't store vehicle info ELSE Store_RC_Replay_Starting_Snapshot(sData.sScriptName, TRUE) // normal missions, store vehicle info ENDIF ENDIF // Setup mission ready for stats PRIME_STATS_FOR_RC_MISSION(sData.eMissionID, sRCMissionDetails.rcScriptName) RETURN TRUE ENDFUNC /// PURPOSE: /// Waits until launcher is safe to terminate. /// This gets set by RC_CLEANUP_LAUNCHER(). /// PARAMS: /// eRCMissionToLaunch - the RC mission that is being launched. /// RETURNS: /// TRUE when the launcher should terminate. FUNC BOOL IS_RC_LAUNCHER_SAFE_TO_TERMINATE(g_eRC_MissionIDs& eRCMissionToLaunch) CPRINTLN(DEBUG_RANDOM_CHAR, "IS_RC_LAUNCHER_SAFE_TO_TERMINATE() - WAITING...") WHILE NOT (g_RandomChars[eRCMissionToLaunch].rcTerminateLauncher) WAIT(0) ENDWHILE CPRINTLN(DEBUG_RANDOM_CHAR, "IS_RC_LAUNCHER_SAFE_TO_TERMINATE() - RETURNING TRUE") RETURN TRUE ENDFUNC /// PURPOSE: Reset all basic values of the data, so each scene has to set them up correctly. PROC RC_Reset_LauncherData(g_structRCScriptArgs& sData) sData.eMissionID = NO_RC_MISSION sData.sScriptName = "" sData.activationRange = RANDOMCHAR_ACTIVATE_MISSION_RANGE sData.triggerType = RC_TRIG_NOT_SET sData.bPedsCritical = FALSE sData.bVehsCritical = FALSE sData.bAllowVehicleActivation = FALSE ENDPROC /// PURPOSE: Sets the visibility states of all entities within a scene. PROC RC_SetScenePedsVisible(g_structRCScriptArgs& sData, Bool bOn) INT i = 0 FOR i=0 TO COUNT_OF(sData.pedID) - 1 IF DOES_ENTITY_EXIST(sData.pedID[i]) SET_ENTITY_VISIBLE(sData.pedID[i], bOn) ENDIF ENDFOR ENDPROC