Files
gtav-src/script/dev_ng/singleplayer/include/public/RC_Helper_Functions.sch
T
2025-09-29 00:52:08 +02:00

1789 lines
64 KiB
Scheme
Executable File

/// Common helper functions to be used by all RC missions
USING "rage_builtins.sch"
USING "globals.sch"
USING "commands_entity.sch"
USING "script_player.sch"
USING "script_ped.sch"
USING "cutscene_public.sch"
USING "dialogue_public.sch"
USING "flow_help_public.sch"
USING "commands_weapon.sch"
using "clearMissionArea.sch"
USING "cutscene_control_public.sch"
USING "replay_public.sch"
#if not USE_CLF_DLC
#if not USE_NRM_DLC
USING "randomChar_Public.sch"
#endif
#endif
USING "locates_public.sch"
// ---------------------------------------------------------------------------------------------
// -----------------ALIVE CHECKS----------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
/// PURPOSE:
/// Checks if the entity exists and is not dead.
/// PARAMS:
/// mEntity - the entity we are checking.
/// RETURNS:
/// True if the entity exists and is not dead.
FUNC BOOL IS_ENTITY_ALIVE(ENTITY_INDEX mEntity)
IF DOES_ENTITY_EXIST(mEntity)
IF NOT IS_ENTITY_DEAD(mEntity)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks that the ped exists, is alive and is not injured
/// PARAMS:
/// mPed - the ped we are checking
/// RETURNS:
/// True if the ped exists, is alive and is not injured. false otherwise.
FUNC BOOL IS_PED_UNINJURED(PED_INDEX mPed)
IF IS_ENTITY_ALIVE(mPed)
IF NOT IS_PED_INJURED(mPed)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks that the vehicle exists, is alive, driveable and not on fire
/// PARAMS:
/// mVehicle - the vehicle we are checking
/// RETURNS:
/// True if the vehicle exists, is alive, driveable and not on fire. false otherwise.
FUNC BOOL IS_VEHICLE_OK(VEHICLE_INDEX mVehicle)
IF IS_ENTITY_ALIVE(mVehicle)
IF IS_VEHICLE_DRIVEABLE(mVehicle)
IF NOT IS_ENTITY_ON_FIRE(mVehicle)
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
// ---------------------------------------------------------------------------------------------
// -----------------CUTSCENE FUNCTIONS----------------------------------------------------------
// ---------------------------------------------------------------------------------------------
WEAPON_TYPE mPlayerWeapon
/// PURPOSE:
/// Call this just before requesting a mocap cutscene (or just before starting a scripted cutscene)
/// Turns off player control, clears nearby explosions, disables phone and stops conversations
PROC RC_PRE_REQUEST_CUTSCENE(BOOL bKeepControl)
PLAYER_INDEX pId = GET_PLAYER_INDEX()
IF NOT IS_PLAYER_DEAD(pId)
IF bKeepControl
CPRINTLN(DEBUG_MISSION, "RC_PRE_REQUEST_CUTSCENE: Keeping player control..")
ELSE
CPRINTLN(DEBUG_MISSION, "RC_PRE_REQUEST_CUTSCENE: Disabling player control..")
ENDIF
// Remove projectiles and explosions
// Disable player control if this has been specified - now allowing player to
// move prior to cutscenes for lead-ins, etc.
SET_PLAYER_CONTROL(pId, bKeepControl, SPC_REMOVE_EXPLOSIONS)
SET_PLAYER_CONTROL(pId, bKeepControl, SPC_REMOVE_PROJECTILES)
ENDIF
// Make the phone system safe
SET_SCRIPTS_SAFE_FOR_CUTSCENE(TRUE, TRUE, FALSE)
ENDPROC
/// PURPOSE:
/// Call this just before requesting a mocap cutscene which plays out during a mission (not an intro)
/// This does all the same setup required as RC_PRE_REQUEST_CUTSCENE accept it doesn't call the player control commands
/// since this interfers with stopping the player's vehicle smoothly with RC_IS_CUTSCENE_OK_TO_START(see bug 995297)
/// PARAMS:
/// sCutscene - the name of the cut-scene we are loading
PROC RC_REQUEST_MID_MISSION_CUTSCENE(String sCutscene)
SET_SCRIPTS_SAFE_FOR_CUTSCENE(TRUE, DEFAULT, FALSE)
REQUEST_CUTSCENE(sCutscene)
ENDPROC
/// PURPOSE:
/// Call this when requesting a mocap cutscene in an RC mission
/// Disables player control and the phone, stops conversations, clears nearby explosions and loads the cutscene
/// PARAMS:
/// sCutscene - the name of the cut-scene we are loading
/// bAllowControl - allows player control (if we are using this with RC_TRIGGER_PLAYER_LOCK_IN() - set this to be true)
PROC RC_REQUEST_CUTSCENE(String sCutscene, BOOL bAllowControl = FALSE)
RC_PRE_REQUEST_CUTSCENE(bAllowControl)
REQUEST_CUTSCENE(sCutscene)
ENDPROC
/// PURPOSE:
/// Fades the screen from the game camera to black. For use in cutscenes.
/// PARAMS:
/// iTime - Milliseconds length of the fade.
/// bWaitForFade - Whether the mission script should wait until the fade is completed.
PROC SAFE_FADE_SCREEN_OUT_TO_BLACK(INT iTime = 500, BOOL bWaitForFade = TRUE)
IF IS_SCREEN_FADED_IN()
IF NOT IS_SCREEN_FADING_OUT()
DO_SCREEN_FADE_OUT(iTime)
IF bWaitForFade
WHILE NOT IS_SCREEN_FADED_OUT()
WAIT(0)
ENDWHILE
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Fades the screen from black, back to the game camera. For use in cutscenes.
/// PARAMS:
/// iTime - Milliseconds length of the fade.
/// bWaitForFade - Whether the mission script should wait until the fade is completed.
PROC SAFE_FADE_SCREEN_IN_FROM_BLACK(INT iTime = 500, BOOL bWaitForFade = TRUE)
IF IS_SCREEN_FADED_OUT()
OR IS_SCREEN_FADING_OUT()
IF NOT IS_SCREEN_FADING_IN()
DO_SCREEN_FADE_IN(iTime)
ENDIF
ENDIF
IF bWaitForFade
WHILE NOT IS_SCREEN_FADED_IN()
WAIT(0)
ENDWHILE
ENDIF
ENDPROC
/// PURPOSE:
/// Handles entering cutscenes. Turns player control off, disables phone
/// Clears area of peds, clears wanted level, hides radar + HUD, Clears Prints + Help
/// Puts widescreen borders on, handles hiding player's weapon
/// repositions player's last vehicle, fades in
/// PARAMS:
/// vTriggerLocation - where is the cutscene taking place
/// bUseWidescreenBorders - TRUE turn widescreen borders on
/// bPutPlayerWeaponAway - TRUE handle hiding the player's weapon
/// bFadeIn = should we fade the screen in?
/// bClearPeds = do we want to clear the nearby area of peds
/// bClearObjects = do we want to clear nearby area of objects (this also clears scenarios)
/// bRemoveParachutes - do we want to removed the player's parachutte
/// bRemovePlayerHelmet - do we want to removed the player's helmet
PROC RC_START_CUTSCENE_MODE(VECTOR vTriggerLocation, BOOL bUseWidescreenBorders = TRUE, BOOL bPutPlayerWeaponAway = TRUE, BOOL bFadeIn = TRUE, BOOL bClearPeds = TRUE, BOOL bClearObjects = TRUE, BOOL bRemoveParachutes = TRUE, BOOL bRemovePlayerHelmet = TRUE, BOOL bExtinguishFires = TRUE, BOOL bClearHelp = TRUE, BOOL bHideHUDRadar = TRUE)
PLAYER_INDEX pId = GET_PLAYER_INDEX()
IF IS_PLAYER_PLAYING(pId)
CPRINTLN(DEBUG_MISSION, "RC_START_CUTSCENE_MODE")
// Disable player control, clear area of projectiles, disable phone...
RC_PRE_REQUEST_CUTSCENE(FALSE)
// Remove player's bike helmet if he has one
IF bRemovePlayerHelmet
REMOVE_PLAYER_HELMET(GET_PLAYER_INDEX(), TRUE)
ENDIF
// Remove the parachute jacket if present
IF bRemoveParachutes
SWITCH GET_CURRENT_PLAYER_PED_ENUM()
CASE CHAR_MICHAEL
IF IS_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_SPECIAL, SPECIAL_P0_PARACHUTE)
SET_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_SPECIAL, SPECIAL_P0_NONE)
ENDIF
IF IS_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_SPECIAL2, SPECIAL2_P0_PARACHUTE_2)
SET_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_SPECIAL2, SPECIAL2_P0_NONE)
ENDIF
BREAK
CASE CHAR_FRANKLIN
IF IS_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_SPECIAL, SPECIAL_P1_PARACHUTE)
OR IS_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_SPECIAL, SPECIAL_P1_PARACHUTE_1)
SET_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_SPECIAL, SPECIAL_P1_DUMMY)
ENDIF
BREAK
CASE CHAR_TREVOR
IF IS_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_SPECIAL, SPECIAL_P2_PARACHUTE)
SET_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_SPECIAL, SPECIAL_P2_DUMMY)
ENDIF
BREAK
ENDSWITCH
ENDIF
// Clear area around player
IF bClearPeds = TRUE
CLEAR_AREA_OF_PEDS(GET_PLAYER_COORDS(GET_PLAYER_INDEX()), 50.0)
ENDIF
// Clear the cut-scene area of objects
IF bClearObjects = TRUE
CLEAR_AREA_OF_OBJECTS(vTriggerLocation, 30.0)
ENDIF
// Clear fires
IF bExtinguishFires
STOP_FIRE_IN_RANGE(vTriggerLocation, 30.0)
ENDIF
// Clear projectiles
CLEAR_AREA_OF_PROJECTILES(vTriggerLocation, 30.0)
// Clear the player's wanted level
SET_PLAYER_WANTED_LEVEL(pId,0)
SET_PLAYER_WANTED_LEVEL_NOW(pId)
// Stop anyone from attacking the player
SET_EVERYONE_IGNORE_PLAYER(pId, TRUE)
// Remove radar and HUD
IF bHideHUDRadar
DISPLAY_RADAR(FALSE)
DISPLAY_HUD(FALSE)
ENDIF
// Clear objective and help text
CLEAR_PRINTS()
IF bClearHelp = TRUE
CLEAR_HELP()
ENDIF
// Widescreen borders option
IF bUseWidescreenBorders = TRUE
SET_WIDESCREEN_BORDERS(TRUE, 0)
ENDIF
// Automatically put the player's weapon away
IF bPutPlayerWeaponAway = TRUE
mPlayerWeapon = WEAPONTYPE_INVALID
if IS_ENTITY_ALIVE(PLAYER_PED_ID()) // remove player's weapon
mPlayerWeapon = GET_SELECTED_PED_WEAPON(PLAYER_PED_ID()) // store current weapon
SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, TRUE)
ENDIF
ENDIF
IF bFadeIn = TRUE
SAFE_FADE_SCREEN_IN_FROM_BLACK(500, FALSE)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Handles exiting cutscenes.
/// shows radar + HUD, Clears Help, turns player control back on, re-enables phone
/// Puts widescreen borders off, handles re-eqipping player's weapon
/// PARAMS:
/// bUseWidescreenBorders - TRUE turn widescreen borders off
/// bReEquipPlayerWeapon - TRUE = reequip the weapon the player had before the cut-scene
PROC RC_END_CUTSCENE_MODE(BOOL bUseWidescreenBorders = TRUE, BOOL bReEquipPlayerWeapon= TRUE, BOOL bDisplayHudAndRadar= TRUE, BOOL bRestorePlayerControl = TRUE)
PLAYER_INDEX pId = GET_PLAYER_INDEX()
CPRINTLN(DEBUG_MISSION, "RC_END_CUTSCENE_MODE")
SET_EVERYONE_IGNORE_PLAYER(pId, FALSE)
SET_PLAYER_CONTROL(pId, bRestorePlayerControl)
SET_SCRIPTS_SAFE_FOR_CUTSCENE(FALSE,DEFAULT,FALSE)
IF bDisplayHudAndRadar= TRUE
DISPLAY_RADAR(TRUE)
DISPLAY_HUD(TRUE)
ENDIF
CLEAR_HELP()
IF bUseWidescreenBorders = TRUE
SET_WIDESCREEN_BORDERS(FALSE, 0)
ENDIF
IF bReEquipPlayerWeapon = TRUE
IF mPlayerWeapon <> WEAPONTYPE_INVALID
AND mPlayerWeapon <> WEAPONTYPE_OBJECT
AND mPlayerWeapon <> GADGETTYPE_PARACHUTE
if IS_ENTITY_ALIVE(PLAYER_PED_ID()) // put player's stored weapon back in his hand
IF HAS_PED_GOT_WEAPON(PLAYER_PED_ID(), mPlayerWeapon)
SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), mPlayerWeapon, FALSE)
ENDIF
ENDIF
ENDIF
ENDIF
IF IS_PED_UNINJURED(PLAYER_PED_ID()) //B*1057583 wrapped in an alive check
SET_PED_STEALTH_MOVEMENT(PLAYER_PED_ID(), FALSE) // B*1052570 Ensure stealth mode has been cancelled
ENDIF
ENDPROC
/// PURPOSE:
/// Sets proofs for RCM entities and the player
PROC RC_SET_ENTITY_PROOFS_FOR_CUTSCENE(g_structRCScriptArgs& sData, BOOL bProof, BOOL bHolsterWeapon=TRUE)
INT i
CPRINTLN(DEBUG_RANDOM_CHAR, "RC_SET_ENTITY_PROOFS_FOR_CUTSCENE called with bProof = ", bProof)
// Scene peds
REPEAT RC_MAX_SCENE_PEDS i
IF IS_ENTITY_ALIVE(sData.pedID[i])
SET_ENTITY_PROOFS(sData.pedID[i], bProof, bProof, bProof, bProof, bProof)
ENDIF
ENDREPEAT
// Scene vehicles
REPEAT RC_MAX_SCENE_VEHS i
IF IS_ENTITY_ALIVE(sData.vehID[i])
SET_ENTITY_PROOFS(sData.vehID[i], bProof, bProof, bProof, bProof, bProof)
ENDIF
ENDREPEAT
// Scene objects
REPEAT RC_MAX_SCENE_OBJS i
IF IS_ENTITY_ALIVE(sData.objID[i])
SET_ENTITY_PROOFS(sData.objID[i], bProof, bProof, bProof, bProof, bProof)
ENDIF
ENDREPEAT
// Set player proofs.
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
SET_ENTITY_PROOFS(PLAYER_PED_ID(), bProof, bProof, bProof, bProof, bProof)
SET_ENTITY_INVINCIBLE(PLAYER_PED_ID(), bProof)
IF bHolsterWeapon
SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, TRUE)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Disables attack, weapon select and certain movement controls when about to trigger a cutscene
PROC RC_DISABLE_CONTROL_ACTIONS_FOR_LEAD_IN()
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SPRINT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_AIM)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MELEE_ATTACK_HEAVY)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MELEE_ATTACK_LIGHT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ATTACK)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ATTACK2)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_JUMP)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ENTER)
ENDPROC
/// PURPOSE:
/// Gets the player out of vehicle when triggering a lead-in animation
PROC RC_EXIT_VEHICLE_FOR_LEAD_IN()
IF IS_PLAYER_PLAYING(PLAYER_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), DEFAULT_VEH_STOPPING_DISTANCE, 1) //stopping dist increase for B*113835
IF (GET_SCRIPT_TASK_STATUS(PLAYER_PED_ID(), SCRIPT_TASK_LEAVE_ANY_VEHICLE) <> PERFORMING_TASK)
TASK_LEAVE_ANY_VEHICLE(PLAYER_PED_ID())
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Disable certain player controls and force player to exit vehicle
PROC RC_PLAYER_TRIGGER_SCENE_LOCK_IN()
DISABLE_CELLPHONE_THIS_FRAME_ONLY()
RC_DISABLE_CONTROL_ACTIONS_FOR_LEAD_IN()
RC_EXIT_VEHICLE_FOR_LEAD_IN()
ENDPROC
/// PURPOSE:
/// Tests if a ped is either performing a script task or is waiting to start it
/// PARAMS:
/// testPed - the ped to test
/// testTask - the script task to check for
/// RETURNS:
/// TRUE if the ped is performing the task or waiting to start it, FALSE otherwise
FUNC BOOL IsPedPerformingTask(PED_INDEX testPed, SCRIPT_TASK_NAME testTask)
IF IS_PED_UNINJURED(testPed)
IF (GET_SCRIPT_TASK_STATUS(testPed, testTask) = PERFORMING_TASK) OR (GET_SCRIPT_TASK_STATUS(testPed, testTask) = WAITING_TO_START_TASK)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Handles delaying a cutscene until it's loaded, the last line of dialogue has finished, and the player's car has been halted.
/// PARAMS:
/// check_for_cutscene_loaded - if true waits on mocap being loaded
/// stopping_distance - for vehicles, need to use DEFAULT_VEH_STOPPING_DISTANCE unless special case
/// b_player_exit_vehicle - make the player leave the vehicle once it's stopped
/// RETURNS:
/// TRUE once all conditions are met
FUNC BOOL RC_IS_CUTSCENE_OK_TO_START(BOOL check_for_cutscene_loaded = TRUE, FLOAT stopping_distance = DEFAULT_VEH_STOPPING_DISTANCE, BOOL b_player_exit_vehicle = FALSE)
// See B*649704 - we need to do all this stuff rather than return false as soon as a condition returns false
BOOL b_cutscene_ok_to_start = TRUE
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF NOT IS_PED_IN_ANY_HELI(PLAYER_PED_ID()) AND NOT IS_PED_IN_ANY_BOAT(PLAYER_PED_ID()) AND NOT IS_PED_IN_ANY_PLANE(PLAYER_PED_ID())
IF NOT BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), stopping_distance, 1)
b_cutscene_ok_to_start = FALSE
ELSE // Vehicle has stopped
IF b_player_exit_vehicle = TRUE
b_cutscene_ok_to_start = FALSE
IF NOT IsPedPerformingTask(PLAYER_PED_ID(), SCRIPT_TASK_LEAVE_ANY_VEHICLE)
TASK_LEAVE_ANY_VEHICLE(PLAYER_PED_ID())
ENDIF
ENDIF
ENDIF
IF IS_ENTITY_IN_AIR(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
b_cutscene_ok_to_start = FALSE
ENDIF
ENDIF
ENDIF
// Disable attack controls
RC_DISABLE_CONTROL_ACTIONS_FOR_LEAD_IN()
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
KILL_ANY_CONVERSATION()
b_cutscene_ok_to_start = FALSE
ENDIF
IF b_cutscene_ok_to_start = FALSE
RETURN FALSE
ENDIF
// B*1521696 - swap over from HAS_CUTSCENE_LOADED
// HAS_CUTSCENE_LOADED_WITH_FAILSAFE()- Ensure you are only calling this check when your script is ready to play the cutscene
IF check_for_cutscene_loaded = TRUE
IF NOT HAS_CUTSCENE_LOADED_WITH_FAILSAFE()
RETURN FALSE
ENDIF
ENDIF
// Double check to make sure any conversations are killed when the function is returning TRUE
IF IS_SCRIPTED_CONVERSATION_ONGOING()
STOP_SCRIPTED_CONVERSATION(FALSE)
ENDIF
RETURN TRUE
ENDFUNC
// ---------------------------------------------------------------------------------------------
// -----------------CLEAN UP FUNCTIONS----------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
/// PURPOSE:
/// If a mocap cut-scene is active it will be stopped. Waits here until it has stopped.
/// This procedure is useful when debug passing / failing a mission while a mocap is playing
/// PARAMS:
/// bCall_RC_END_CUTSCENE_MODE - if TRUE RC_END_CUTSCENE_MODE will be called. Parameter added so proc can be called by RC_START_Z_SKIP
/// bUseWidescreenBorders - TRUE turn widescreen borders off. Note: requires bCall_RC_END_CUTSCENE_MODE = TRUE to take affect
/// bReEquipPlayerWeapon - TRUE = reequip the weapon the player had before the cut-scene. Note: requires bCall_RC_END_CUTSCENE_MODE = TRUE to take affect
PROC WAIT_FOR_CUTSCENE_TO_STOP(BOOL bCall_RC_END_CUTSCENE_MODE = TRUE, BOOL bUseWidescreenBorders = TRUE, BOOL bReEquipPlayerWeapon = TRUE)
BOOL bLoop = TRUE
IF IS_CUTSCENE_ACTIVE()
WHILE (bLoop)
bLoop = IS_CUTSCENE_ACTIVE()
IF IS_CUTSCENE_PLAYING()
STOP_CUTSCENE()
ENDIF
IF HAS_CUTSCENE_LOADED()
REMOVE_CUTSCENE()
ENDIF
IF IS_CUTSCENE_ACTIVE() AND NOT IS_CUTSCENE_PLAYING()
CPRINTLN(DEBUG_MISSION, "WAITING FOR CUTSCENE TO STOP - EMERGENCY BREAK OUT!")
bLoop = FALSE
ENDIF
CPRINTLN(DEBUG_MISSION, "WAITING FOR CUTSCENE TO STOP")
WAIT(0)
ENDWHILE
IF bCall_RC_END_CUTSCENE_MODE
RC_END_CUTSCENE_MODE(bUseWidescreenBorders, bReEquipPlayerWeapon)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Deletes the vehicle if it exists, and player isn't in it
/// PARAMS:
/// mVehicle - the vehicle to delete
PROC SAFE_DELETE_VEHICLE(VEHICLE_INDEX &mVehicle)
IF DOES_ENTITY_EXIST(mVehicle)
IF NOT IS_ENTITY_A_MISSION_ENTITY(mVehicle)
SET_ENTITY_AS_MISSION_ENTITY(mVehicle)
ENDIF
IF IS_VEHICLE_OK(mVehicle)
IF IS_ENTITY_A_MISSION_ENTITY(mVehicle) AND DOES_ENTITY_BELONG_TO_THIS_SCRIPT(mVehicle)
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), mVehicle)
SET_VEHICLE_AS_NO_LONGER_NEEDED(mVehicle) // player is in the vehicle- don't delete it
EXIT
ENDIF
ENDIF
DELETE_VEHICLE(mVehicle)
ENDIF
ELSE
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), mVehicle)
SET_VEHICLE_AS_NO_LONGER_NEEDED(mVehicle) // player is in the vehicle- don't delete it
EXIT
ENDIF
ENDIF
DELETE_VEHICLE(mVehicle)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// If a vehicle exists it is set as no longer needed
/// PARAMS:
/// mVehicle - the vehicle we are releasing
PROC SAFE_RELEASE_VEHICLE(VEHICLE_INDEX &mVehicle)
IF DOES_ENTITY_EXIST(mVehicle)
IS_ENTITY_DEAD(mVehicle) // we need call this or we get an assert...
IF IS_ENTITY_A_MISSION_ENTITY(mVehicle) AND DOES_ENTITY_BELONG_TO_THIS_SCRIPT(mVehicle)
SET_VEHICLE_AS_NO_LONGER_NEEDED(mVehicle)
ENDIF
ENDIF
/*
IF DOES_ENTITY_EXIST(mVehicle)
IF IS_VEHICLE_OK(mVehicle)
IF IS_ENTITY_A_MISSION_ENTITY(mVehicle) AND DOES_ENTITY_BELONG_TO_THIS_SCRIPT(mVehicle)
SET_VEHICLE_AS_NO_LONGER_NEEDED(mVehicle)
ENDIF
ELSE
SET_VEHICLE_AS_NO_LONGER_NEEDED(mVehicle)
ENDIF
ENDIF
*/
ENDPROC
/// PURPOSE:
/// If ped exists it is deleted
/// PARAMS:
/// mPed - ped to delete
PROC SAFE_DELETE_PED(ped_index &mPed)
IF DOES_ENTITY_EXIST(mPed)
IF NOT IS_ENTITY_DEAD(mPed)
SET_ENTITY_LOAD_COLLISION_FLAG(mPed, FALSE)
ENDIF
IF NOT IS_ENTITY_A_MISSION_ENTITY(mPed)
SET_ENTITY_AS_MISSION_ENTITY(mPed)
ENDIF
DELETE_PED(mPed)
ENDIF
ENDPROC
/// PURPOSE:
/// If a ped exists it is set as no longer needed
/// PARAMS:
/// mPed - ped to release
/// bKeepTask - whether or not the ped should keep its current task
///
/// bKeepSecondaryTask - whether or not the ped should keep it's secondary task
PROC SAFE_RELEASE_PED(PED_INDEX &mPed, BOOL bKeepTask = TRUE, BOOL bResetTempEvents = FALSE, BOOL bKeepSecondaryTask = TRUE)
IF DOES_ENTITY_EXIST(mPed)
IF NOT IS_PED_INJURED(mPed)
SET_ENTITY_LOAD_COLLISION_FLAG(mPed, FALSE)
IF bKeepSecondaryTask = FALSE
CLEAR_PED_SECONDARY_TASK(mPed) // fix for B*951280
ENDIF
SET_PED_KEEP_TASK(mPed, bKeepTask)
IF bResetTempEvents = TRUE
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(mPed, FALSE)
ENDIF
ENDIF
SET_PED_AS_NO_LONGER_NEEDED(mPed)
ENDIF
ENDPROC
/// PURPOSE:
/// If the object exists it is deleted
/// PARAMS:
/// mObject - the object to delete
PROC SAFE_DELETE_OBJECT(OBJECT_INDEX &mObject)
IF DOES_ENTITY_EXIST(mObject)
IF IS_ENTITY_ATTACHED_TO_ANY_PED(mObject)
DETACH_ENTITY(mObject)
ENDIF
DELETE_OBJECT(mObject)
ENDIF
ENDPROC
/// PURPOSE:
/// If the object exists it is released
/// PARAMS:
/// mObject - the object to release
/// bwaitForRange - wait till player is out of range to clean up object
PROC SAFE_RELEASE_OBJECT(OBJECT_INDEX &mObject,bool bwaitForRange = false)
IF DOES_ENTITY_EXIST(mObject)
IF IS_ENTITY_ATTACHED_TO_ANY_PED(mObject)
DETACH_ENTITY(mObject)
ENDIF
if not bwaitForRange
SET_OBJECT_AS_NO_LONGER_NEEDED(mObject)
else
ONLY_CLEAN_UP_OBJECT_WHEN_OUT_OF_RANGE(mObject)
endif
ENDIF
ENDPROC
/// PURPOSE:
/// remove blip from the game, setting the route to false in the process
/// PARAMS:
/// blipIndex - blip to remove
PROC SAFE_REMOVE_BLIP(BLIP_INDEX &blipIndex)
IF DOES_BLIP_EXIST(blipIndex)
SET_BLIP_ROUTE(blipIndex, FALSE)
REMOVE_BLIP(blipIndex)
ENDIF
ENDPROC
/// PURPOSE:
/// If the pickup exists it is removed
/// PARAMS:
/// pickupIndex - pickup to remove
PROC SAFE_REMOVE_PICKUP(PICKUP_INDEX &pickupIndex)
IF DOES_PICKUP_EXIST(pickupIndex)
REMOVE_PICKUP(pickupIndex)
ENDIF
ENDPROC
// ---------------------------------------------------------------------------------------------
// -----------------LAUNCHER CLEANUP FUNCTIONS--------------------------------------------------
// ---------------------------------------------------------------------------------------------
/// PURPOSE:
/// Cleans up an array of peds
/// PARAMS:
/// array - the array of peds
/// bDeletePeds - if true we delete peds, if false we release them
PROC RC_CleanupPedArray(PED_INDEX& array[],BOOL bDeletePeds)
INT i = 0
FOR i=0 TO COUNT_OF(array) - 1
IF bDeletePeds = TRUE
SAFE_DELETE_PED(array[i])
ELSE
SAFE_RELEASE_PED(array[i], FALSE, TRUE, FALSE)
ENDIF
ENDFOR
ENDPROC
/// PURPOSE:
/// Cleans up an array of vehicles
/// PARAMS:
/// array - the array of vehicles
/// bDeleteVehicles - if true we delete vehicles, if false we release them
PROC RC_CleanupVehicleArray(VEHICLE_INDEX& array[],BOOL bDeleteVehicles)
INT i = 0
FOR i=0 TO COUNT_OF(array) - 1
IF bDeleteVehicles
SAFE_DELETE_VEHICLE(array[i])
ELSE
SAFE_RELEASE_VEHICLE(array[i])
ENDIF
ENDFOR
ENDPROC
/// PURPOSE:
/// Cleans up an array of props
/// PARAMS:
/// array - the array of props
/// bDeleteObjects - if true we delete props, if false we release them
PROC RC_CleanupPropArray(OBJECT_INDEX& array[],BOOL bDeleteObjects)
INT i = 0
FOR i=0 TO COUNT_OF(array) - 1
IF bDeleteObjects
SAFE_DELETE_OBJECT(array[i])
ELSE
SAFE_RELEASE_OBJECT(array[i])
ENDIF
ENDFOR
ENDPROC
/// PURPOSE:
/// Cleans up the array of initial scene peds
/// PARAMS:
/// sData - mission data struct
/// bDeletePeds - if true we delete the peds, if false we release them
PROC RC_CleanupScene_PEDS(g_structRCScriptArgs& sData, BOOL bDeletePeds)
RC_CleanupPedArray(sData.pedID, bDeletePeds)
ENDPROC
/// PURPOSE:
/// Cleans up the array of initial scene vehicles
/// PARAMS:
/// sData - mission data struct
/// bDeleteVehicles - if true we delete the vehicles, if false we release them
PROC RC_CleanupScene_VEHICLES(g_structRCScriptArgs& sData, BOOL bDeleteVehicles)
RC_CleanupVehicleArray(sData.vehID, bDeleteVehicles)
ENDPROC
/// PURPOSE:
/// Cleans up the array of initial scene props
/// PARAMS:
/// sData - mission data struct
/// bDeleteObjects - if true we delete the props, if false we release them
PROC RC_CleanupScene_PROPS(g_structRCScriptArgs& sData, BOOL bDeleteObjects)
RC_CleanupPropArray(sData.objID, bDeleteObjects)
ENDPROC
/// PURPOSE:
/// Cleans up all entities within the scene data
/// PARAMS:
/// sData - mission data struct
/// bDeletePeds - if true we delete the peds, if false we release them
/// bDeleteVehicles - if true we delete the vehicles, if false we release them
/// bDeleteObjects - if true we delete the props, if false we release them
PROC RC_CleanupSceneEntities(g_structRCScriptArgs& sData, BOOL bDeletePeds=TRUE, BOOL bDeleteVehicles= FALSE, BOOL bDeleteObjects=FALSE)
RC_CleanupScene_PEDS(sData, bDeletePeds)
RC_CleanupScene_VEHICLES(sData, bDeleteVehicles)
RC_CleanupScene_PROPS(sData, bDeleteObjects)
ENDPROC
/// PURPOSE:
/// Sets array of entities to be mission entities
/// PARAMS:
/// array - the array of entities
PROC RC_TakeOwnershipArray(ENTITY_INDEX& array[])
INT i = 0
// Pass over all entities
FOR i=0 TO COUNT_OF(array) - 1
IF DOES_ENTITY_EXIST(array[i])
SET_ENTITY_AS_MISSION_ENTITY(array[i], FALSE, TRUE)
ENDIF
ENDFOR
ENDPROC
/// PURPOSE:
/// Sets all of the initial scene entities as mission entities and then cleans up the launcher
PROC RC_TakeEntityOwnership(g_structRCScriptArgs& sMissionData)
// Pass over entities to mission
RC_TakeOwnershipArray(sMissionData.pedID)
RC_TakeOwnershipArray(sMissionData.vehID)
RC_TakeOwnershipArray(sMissionData.objID)
ENDPROC
// ---------------------------------------------------------------------------------------------
// -----------------BLIP FUNCTIONS--------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
/// PURPOSE:
/// Adds a blip for a ped.
/// Checks if the ped is alive and whether he needs to be blipped based on blip standards.
/// Sets the correct size and colour of blip based on input variables.
/// PARAMS:
/// iPed - the ped we are adding a blip for
/// bCritical - whether or not the ped is mission critical
/// bFriendly - is the ped friendly or an enemy
/// bBlipPriority - priority of the blip
/// RETURNS:
/// the blip index of the new blip (null if blip was not created)
FUNC BLIP_INDEX CREATE_PED_BLIP(PED_INDEX iPed, BOOL bCritical=TRUE, BOOL bFriendly=FALSE, BLIP_PRIORITY bBlipPriority=BLIPPRIORITY_MED)
BLIP_INDEX bRetBlip = NULL
BOOL bShouldCreate = TRUE
IF bShouldCreate
IF IS_ENTITY_ALIVE(iPed)
bRetBlip = ADD_BLIP_FOR_ENTITY(iPed)
SET_BLIP_AS_FRIENDLY(bRetBlip,bFriendly)
SET_BLIP_PRIORITY(bRetBlip,bBlipPriority)
SET_BLIP_SCALE(bRetBlip, BLIP_SIZE_PED)
IF NOT bCritical
SET_BLIP_SCALE(bRetBlip, 0.5)
ENDIF
ENDIF
ENDIF
RETURN bRetBlip
ENDFUNC
/// PURPOSE:
/// Add a blip for a vehicle.
/// checks the vehicle is alive, then creates blip of correct size and colour
/// PARAMS:
/// iVeh - the vehicle we're adding a blip for
/// bFriendly - whether the vehicle is friendly or an enemy
/// bBlipPriority - priority of the blip
/// RETURNS:
/// the blip index of the new blip (null if blip was not created)
FUNC BLIP_INDEX CREATE_VEHICLE_BLIP(VEHICLE_INDEX iVeh,BOOL bFriendly=TRUE, BLIP_PRIORITY bBlipPriority=BLIPPRIORITY_MED)
BLIP_INDEX bRetBlip = NULL
IF IS_ENTITY_ALIVE(iVeh) //Ensure the entity is alive
bRetBlip = ADD_BLIP_FOR_ENTITY(iVeh)
SET_BLIP_AS_FRIENDLY(bRetBlip,bFriendly)
SET_BLIP_PRIORITY(bRetBlip,bBlipPriority)
SET_BLIP_SCALE(bRetBlip, BLIP_SIZE_VEHICLE)
ENDIF
RETURN bRetBlip
ENDFUNC
/// PURPOSE:
/// Creates a blip of the correct size and colour for a location
/// PARAMS:
/// vPos - where to create the blip
/// bBlipPriority - priority of the blip
/// bDisplayRoute - do we want to add a route for this blip?
/// RETURNS:
/// the blip index of the new blip (null if blip was not created)
FUNC BLIP_INDEX CREATE_COORD_BLIP(VECTOR vPos, BLIP_PRIORITY bBlipPriority=BLIPPRIORITY_MED, BOOL bDisplayRoute = TRUE)
BLIP_INDEX bRetBlip = NULL
bRetBlip = ADD_BLIP_FOR_COORD(vPos)
SET_BLIP_PRIORITY(bRetBlip,bBlipPriority)
SET_BLIP_SCALE(bRetBlip, BLIP_SIZE_COORD)
SET_BLIP_ROUTE(bRetBlip, bDisplayRoute)
RETURN bRetBlip
ENDFUNC
/// PURPOSE:
/// Sets up everything so that blips and text will change colour nicely
/// This is used when the player has a choice between killing a ped and letting them go
/// Call this function the frame before calling FLASH_BLIP_AND_TEXT
/// PARAMS:
/// thisBlip - the blip whose colour you want to flash
/// sTextRed - the text string with the ped's name in red
/// sTextBlue - the text string with the ped's name in blue
/// fbtTimer - keeps track of when to change colour
/// fbtTextTimer - keeps track of how long the text has been displayed
/// redTextFirst - TRUE if you want the blip/text to be initialised to red, FALSE if you want them blue
/// showText - TRUE if you want to link with an objective, FALSE if not
PROC INIT_FLASH_BLIP_AND_TEXT(BLIP_INDEX &thisBlip, STRING sTextRed, STRING sTextBlue, INT &fbtTimer, INT &fbtTextTimer, BOOL redTextFirst = TRUE, BOOL showText = TRUE)
IF DOES_BLIP_EXIST(thisBlip)
IF redTextFirst
SET_BLIP_COLOUR(thisBlip, BLIP_COLOUR_RED)
SET_BLIP_NAME_FROM_TEXT_FILE(thisBlip, "BLIP_ENEMY")
IF showText
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF NOT IS_MESSAGE_BEING_DISPLAYED()
OR IS_THIS_PRINT_BEING_DISPLAYED(sTextBlue)
PRINT_NOW(sTextRed, DEFAULT_GOD_TEXT_TIME, 0)
ENDIF
ENDIF
ELSE
SET_BLIP_COLOUR(thisBlip, BLIP_COLOUR_BLUE)
SET_BLIP_NAME_FROM_TEXT_FILE(thisBlip, "BLIP_FRIEND")
IF showText
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF NOT IS_MESSAGE_BEING_DISPLAYED()
OR IS_THIS_PRINT_BEING_DISPLAYED(sTextRed)
PRINT_NOW(sTextBlue, DEFAULT_GOD_TEXT_TIME, 0)
ENDIF
ENDIF
ENDIF
fbtTimer = GET_GAME_TIMER()
fbtTextTimer = GET_GAME_TIMER()
ENDIF
ENDPROC
/// PURPOSE:
/// Switches a blip and accompanying god text between red and blue
/// This is used when the player has a choice between killing a ped and letting them go
/// Call this function every frame for as long as you want the colour to flash
/// Before going into the loop that calls this function, call INIT_FLASH_BLIP_AND_TEXT for best results
/// If you don't want to use INIT_FLASH_BLIP_AND_TEXT, make sure the text and blip are the same colour and that fbtTimer has been set equal to GET_GAME_TIMER
/// PARAMS:
/// thisBlip - the blip whose colour you want to flash
/// sTextRed - the text string with the ped's name in red
/// sTextBlue - the text string with the ped's name in blue
/// fbtTimer - keeps track of when to change colour
/// fbtTextTimer - keeps track of how long the text has been displayed
/// showText - TRUE if you want to link with an objective, FALSE if not
PROC FLASH_BLIP_AND_TEXT(BLIP_INDEX &thisBlip, STRING sTextRed, STRING sTextBlue, INT &fbtTimer, INT fbtTextTimer, BOOL showText = TRUE)
IF DOES_BLIP_EXIST(thisBlip)
IF (GET_GAME_TIMER() - fbtTimer) > 500
IF GET_BLIP_COLOUR(thisBlip) = BLIP_COLOUR_RED
SET_BLIP_COLOUR(thisBlip, BLIP_COLOUR_BLUE)
SET_BLIP_NAME_FROM_TEXT_FILE(thisBlip, "BLIP_FRIEND")
IF (GET_GAME_TIMER() - fbtTextTimer) < DEFAULT_GOD_TEXT_TIME
AND showText
IF NOT IS_MESSAGE_BEING_DISPLAYED()
OR IS_THIS_PRINT_BEING_DISPLAYED(sTextRed)
PRINT_NOW(sTextBlue, DEFAULT_GOD_TEXT_TIME, 0)
ENDIF
ENDIF
fbtTimer = GET_GAME_TIMER()
ELSE
SET_BLIP_COLOUR(thisBlip, BLIP_COLOUR_RED)
SET_BLIP_NAME_FROM_TEXT_FILE(thisBlip, "BLIP_ENEMY")
IF (GET_GAME_TIMER() - fbtTextTimer) < DEFAULT_GOD_TEXT_TIME
AND showText
IF NOT IS_MESSAGE_BEING_DISPLAYED()
OR IS_THIS_PRINT_BEING_DISPLAYED(sTextBlue)
PRINT_NOW(sTextRed, DEFAULT_GOD_TEXT_TIME, 0)
ENDIF
ENDIF
fbtTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDIF
IF (GET_GAME_TIMER() - fbtTextTimer) > DEFAULT_GOD_TEXT_TIME
// Text has been displayed for long enough, get rid of it if necessary
IF IS_THIS_PRINT_BEING_DISPLAYED(sTextRed)
CLEAR_THIS_PRINT(sTextRed)
ENDIF
IF IS_THIS_PRINT_BEING_DISPLAYED(sTextBlue)
CLEAR_THIS_PRINT(sTextBlue)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Creates a coordinate blip at an entity's position then updates it each frame relative to the entity's new position
/// Use for entities that might need to be warped, the blip's position will move smoothly from the old position to the new
/// PARAMS:
/// iEntity - The entity that needs blipping
/// iBlip - The blip index, this should be empty when first calling the function
/// bFriendly - Is the entity being blipped friendly or not
/// fSlidyFactor - How quickly the blip will slide to catch up with the entity
PROC MANAGE_SLIDY_BLIP_FOR_ENTITY(BLIP_INDEX & biBlip, ENTITY_INDEX eiEntity, BOOL bFriendly = FALSE, FLOAT fSlidyFactor = 10.0, BOOL bAllowCreateBlip = TRUE)
IF bAllowCreateBlip = TRUE
AND NOT DOES_BLIP_EXIST(biBlip)
biBlip = CREATE_BLIP_FOR_COORD(GET_ENTITY_COORDS(eiEntity))
IF bFriendly
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_BLUE)
SET_BLIP_NAME_FROM_TEXT_FILE(biBlip, "BLIP_FRIEND")
ELSE
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_RED)
SET_BLIP_NAME_FROM_TEXT_FILE(biBlip, "BLIP_ENEMY")
ENDIF
IF IS_ENTITY_A_PED(eiEntity)
SET_BLIP_SCALE(biBlip, BLIP_SIZE_PED)
ENDIF
ENDIF
IF DOES_BLIP_EXIST(biBlip)
VECTOR vBlipPosition = GET_BLIP_COORDS(biBlip)
VECTOR vEntityPosition = GET_ENTITY_COORDS(eiEntity)
vBlipPosition.X = vBlipPosition.X + ((vEntityPosition.X - vBlipPosition.X) / fSlidyFactor)
vBlipPosition.Y = vBlipPosition.Y + ((vEntityPosition.Y - vBlipPosition.Y) / fSlidyFactor)
vBlipPosition.Z = vBlipPosition.Z + ((vEntityPosition.Z - vBlipPosition.Z) / fSlidyFactor)
SET_BLIP_COORDS(biBlip, vBlipPosition)
ENDIF
ENDPROC
// ---------------------------------------------------------------------------------------------
// ----------------- INITIAL SCENE SETUP----------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
/// PURPOSE:
/// Creates the NPC ped needed for this mission, sets their debug name and blocks temp events
/// Doesn't allow player to target the NPC
/// PARAMS:
/// mPed - ped index you want to use
/// ePed - the contact character
/// vPos - where to create the NPC
/// fHeading - NPC's start heading
/// sDebugName - NPC's debug name
/// bFriendly - is the NPC friendly to the player [if so, he cannot be targetted]- defaults to true.
/// RETURNS:
/// true if the ped was created, false otherwise. should be called repeatedly until returns true.
FUNC BOOL RC_CREATE_NPC_PED(PED_INDEX& mPed, enumCharacterList ePed, VECTOR vPos, FLOAT fHeading, STRING sDebugName, BOOL bFriendly=TRUE)
IF CREATE_NPC_PED_ON_FOOT(mPed, ePed, vPos, fHeading, TRUE)
IF DOES_ENTITY_EXIST(mPed)
IF NOT IS_ENTITY_DEAD(mPed)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(mPed, TRUE)
SET_PED_MONEY(mPed, 0)
IF bFriendly = TRUE
SET_PED_CAN_BE_TARGETTED(mPed, FALSE)
ENDIF
ENDIF
SET_PED_NAME_DEBUG(mPed, sDebugName)
ENDIF
RETURN TRUE // succesfully created NPC ped
ENDIF
RETURN FALSE // Failed to create NPC ped
ENDFUNC
/// PURPOSE:
/// Creates a vehicle and sets it on the ground properly
/// PARAMS:
/// mVehicle - Vehicle index of the vehicle we are creating
/// model - model of the vehicle
/// vPos - where to create it
/// fHeading - heading to create it with
PROC CREATE_SCENE_VEHICLE(VEHICLE_INDEX &mVehicle, MODEL_NAMES model, VECTOR vPos, FLOAT fHeading)
SAFE_DELETE_VEHICLE(mVehicle)
mVehicle = CREATE_VEHICLE(model, vPos, fHeading)
IF DOES_ENTITY_EXIST(mVehicle)
SET_VEHICLE_ON_GROUND_PROPERLY(mVehicle)
SET_ENTITY_HEALTH(mVehicle, 1000) // Required because CHECK_VEHICLES_OK in rc_launcher_public checks for the health being less than 990, if so player has tampered with scene
ENDIF
ENDPROC
/// PURPOSE:
/// Creates a ped for initial scene
/// PARAMS:
/// mPed - ped index of ped we are creating
/// model - model to use
/// vPos - where to create ped
/// fHeading - heading to use
/// mPedType - the pedtype to use for this ped. defaults to PEDTYPE_MISSION
PROC CREATE_SCENE_PED(PED_INDEX &mPed, MODEL_NAMES model, VECTOR vPos, FLOAT fHeading, PED_TYPE mPedType = PEDTYPE_MISSION)
SAFE_DELETE_PED(mPed)
mPed = CREATE_PED(mPedType, model, vPos, fHeading, FALSE, FALSE)
ENDPROC
/// PURPOSE:
/// Creates an object for initial scene
/// PARAMS:
/// mObject - object index of the object we are creating
/// model - model to use
/// vPos - where to create object
/// fHeading - heading to use
PROC CREATE_SCENE_PROP(OBJECT_INDEX &mObject, MODEL_NAMES model, VECTOR vPos, FLOAT fHeading)
SAFE_DELETE_OBJECT(mObject)
mObject = CREATE_OBJECT(model,vPos)
SET_ENTITY_HEADING(mObject, fHeading)
ENDPROC
/// PURPOSE:
/// Helper function for creating props in initial scene setups.
/// PARAMS:
/// mObject - object index of the object we are creatingt
/// model - desired prop model
/// vPos - location to spawn the prop
/// vAngles - euler angles for spawning prop
PROC CREATE_SCENE_PROP_WITH_ANGLES(OBJECT_INDEX &mObject, MODEL_NAMES model, VECTOR vPos, VECTOR vAngles)
CREATE_SCENE_PROP(mObject, model, vPos, vAngles.z)
SET_ENTITY_ROTATION(mObject, vAngles)
ENDPROC
// Used when making one ped index equal to another. This saves two variables pointing at the same entity.
// Helps with cleanup
PROC ASSIGN_PED_INDEX(PED_INDEX& target, PED_INDEX& source)
target = source
source = NULL
ENDPROC
// Used when making one vehicle index equal to another. This saves two variables pointing at the same entity.
// Helps with cleanup
PROC ASSIGN_VEHICLE_INDEX(VEHICLE_INDEX& target, VEHICLE_INDEX& source)
target = source
source = NULL
ENDPROC
// Used when making one object index equal to another. This saves two variables pointing at the same entity.
// Helps with cleanup
PROC ASSIGN_OBJECT_INDEX(OBJECT_INDEX& target, OBJECT_INDEX& source)
target = source
source = NULL
ENDPROC
// ---------------------------------------------------------------------------------------------
// -----------------DEBUG SKIPPING / REPLAYS----------------------------------------------------------
// ---------------------------------------------------------------------------------------------
/// PURPOSE:
/// Fades screen out, turns player control off, clears prints + wanted level etc
/// PURPOSE:
/// Setup used when starting a Z skip
/// Fades screen out, turns player control off, clears prints + wanted level etc
/// PARAMS:
/// bForceActiveMocapToStop - parameter added to fix bug 100674.
/// bRemovePlayerHelmet - parameter added to override the player's helmet being removed
PROC RC_START_Z_SKIP(BOOl bForceActiveMocapToStop = TRUE, BOOL bRemovePlayerHelmet = TRUE)
IF bForceActiveMocapToStop
WAIT_FOR_CUTSCENE_TO_STOP(FALSE)
ENDIF
IF NOT IS_SCREEN_FADED_OUT()
DO_SCREEN_FADE_OUT(0)
ENDIF
RC_START_CUTSCENE_MODE(<<0.0,0.0,0.0>>, FALSE, FALSE, FALSE, DEFAULT, DEFAULT, DEFAULT, bRemovePlayerHelmet)
CPRINTLN(DEBUG_MISSION,"Z skip started")
ENDPROC
/// PURPOSE:
/// Turns player control back on etc, fades in
/// PARAMS:
/// bResetCamera - do you want the camera to be reset behind the player
/// bFadeBackIn - do you want to fade back in (usually you do)
PROC RC_END_Z_SKIP(BOOL bResetCamera = TRUE, BOOL bFadeBackIn = TRUE, BOOL bDisplayHudAndRadar= TRUE)
RC_END_CUTSCENE_MODE(FALSE, FALSE, bDisplayHudAndRadar)
IF bResetCamera = TRUE
SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0) // reset camera behind player
SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0)
ENDIF
IF bFadeBackIn = TRUE
SAFE_FADE_SCREEN_IN_FROM_BLACK(500, FALSE)
ENDIF
CPRINTLN(DEBUG_MISSION,"Z skip finished")
ENDPROC
// ---------------------------------------------------------------------------------------------
// -----------------MISC----------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
/// PURPOSE:
/// Prints some debug output
/// PARAMS:
/// sOutput - the string to print
PROC PRINT_LAUNCHER_DEBUG(STRING sOutput)
IF NOT Is_String_Null_Or_Empty(sOutput)
CPRINTLN(DEBUG_RANDOM_CHAR, GET_THIS_SCRIPT_NAME(), ": ", sOutput)
ENDIF
ENDPROC
/// PURPOSE:
/// Sets an entities heading to be facing the given coord
/// PARAMS:
/// entity - the entity to be rotated
/// vLookAt - the point the entity should be turned to face
PROC SET_ENTITY_FACING(ENTITY_INDEX entity, vector vLookAt)
VECTOR vEntity = GET_ENTITY_COORDS(entity)
float fAngle
float dX = vLookAt.x - vEntity.x
float dY = vLookAt.y - vEntity.y
if dY != 0
fAngle = ATAN2(dX,dY)
ELSE
if dX < 0
fAngle = -90
ELSE
fAngle = 90
ENDIF
ENDIF
//flip because for some odd reason the coders think west is a heading of 90 degrees, so this'll match the output of commands such as GET_ENTITY_HEADING()
fAngle *= -1.0
SET_ENTITY_HEADING(entity, fAngle)
ENDPROC
/// PURPOSE:
/// Very efficient test for if two entities are with fRange metres of each other
/// Will be more efficient than doing IS_ENTITY_AT_ENTITY()
/// NOTE: This function doesn't do dead checks to keep it fast, make sure you do them yourself!
/// PARAMS:
/// e1 - First entity
/// e2 - Second entity
/// fRange - Test if the entities are this close to each other
FUNC BOOL IS_ENTITY_IN_RANGE_ENTITY(ENTITY_INDEX e1, ENTITY_INDEX e2, FLOAT fRange, BOOL bHealthCheck = TRUE)
RETURN ( VDIST2(GET_ENTITY_COORDS(e1, bHealthCheck), GET_ENTITY_COORDS(e2, bHealthCheck)) <= fRange*fRange )
ENDFUNC
/// PURPOSE:
/// Very efficient test for if two entities are with fRange metres of each other
/// Will be more efficient than doing IS_ENTITY_AT_ENTITY()
/// NOTE: This function doesn't do dead checks to keep it fast, make sure you do them yourself!
/// PARAMS:
/// e1 - First entity
/// e2 - Second entity
/// fRange - Test if the entities are this close to each other
FUNC BOOL IS_ENTITY_IN_RANGE_COORDS(ENTITY_INDEX e1, VECTOR vCoord, FLOAT fRange, BOOL bDoDeadCheck = TRUE)
RETURN ( VDIST2(GET_ENTITY_COORDS(e1, bDoDeadCheck), vCoord) <= fRange*fRange )
ENDFUNC
/// PURPOSE:
/// Tests the angle of an entity from another entity's forward vector
/// Imagine a cone coming out of the front of entity-1, centred on it's forward vector
/// If entity-2 is in this cone, the function returns true
/// The width of the cone is set by fArc, this is the maximum angle entity-2 can be from entity-1's forward vector
/// NOTE: This function doesn't do dead checks to keep it fast, make sure you do them yourself!
/// PARAMS:
/// e1 - First entity
/// e2 - Second entity
/// fArc - The maximum angle from e1's forward vector
FUNC BOOL IS_ENTITY_IN_ARC_2D(ENTITY_INDEX e1, ENTITY_INDEX e2, FLOAT fArc)
VECTOR vForward = GET_ENTITY_FORWARD_VECTOR(e1)
VECTOR vTo2 = GET_ENTITY_COORDS(e2) - GET_ENTITY_COORDS(e1)
RETURN (((vForward.x*vTo2.x)+(vForward.y*vTo2.y)) / VDIST(vTo2, <<0,0,0>>)) > COS(fArc)
ENDFUNC
/// PURPOSE:
/// Teleports the entity to the desired vector and heading
/// PARAMS:
/// entity - Entity handle
/// vCoord - Vector to teleport the entity to
/// fHeading - Heading to set the entity at after the teleport
/// bGetGroundZ - Get the ground z for the vCoord prior to performing SET_ENTITY_COORDS
/// RETURNS:
/// Returns false if entity is dead or if GET_GROUND_Z_FOR_3D_COORD() fails
FUNC BOOL SAFE_TELEPORT_ENTITY(ENTITY_INDEX entity, VECTOR vCoord, FLOAT fHeading = 0.0, BOOL bGetGroundZ = FALSE, BOOL bDoWarp = TRUE)
BOOL groundCheckOk = FALSE
IF IS_ENTITY_ALIVE(entity)
IF bGetGroundZ = TRUE
FLOAT fNewZ = 0.0
groundCheckOk = GET_GROUND_Z_FOR_3D_COORD(vCoord, fNewZ)
IF (groundCheckOk)
vCoord.z = fNewZ
ENDIF
ENDIF
SET_ENTITY_COORDS(entity, vCoord, DEFAULT, DEFAULT, DEFAULT, bDoWarp)
SET_ENTITY_HEADING(entity, fHeading)
IF (bGetGroundZ)
RETURN groundCheckOk
ENDIF
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Tests if a ped is either performing a script task or is waiting to start it
/// PARAMS:
/// testPed - the ped to test
/// testTask - the script task to check for
/// RETURNS:
/// TRUE if the ped is performing the task or waiting to start it, FALSE otherwise
FUNC BOOL HasPedCompletedTask(PED_INDEX testPed, SCRIPT_TASK_NAME testTask)
IF IS_PED_UNINJURED(testPed)
IF GET_SCRIPT_TASK_STATUS(testPed, testTask) = FINISHED_TASK
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Tests if the player is towing a specific vehicle using a tow truck
/// PARAMS:
/// viTestVehicle - The vehicle that might be getting towed
/// RETURNS:
/// TRUE if the vehicle is being towed by the player, FALSE otherwise
FUNC BOOL IS_PLAYER_TOWING_VEHICLE(VEHICLE_INDEX viTestVehicle)
IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_VEHICLE_OK(viTestVehicle)
VEHICLE_INDEX viPlayer = GET_PLAYERS_LAST_VEHICLE()
IF IS_VEHICLE_OK(viPlayer)
MODEL_NAMES Mod = GET_ENTITY_MODEL(viPlayer)
IF Mod = TOWTRUCK OR Mod = TOWTRUCK2
IF IS_VEHICLE_ATTACHED_TO_TOW_TRUCK(viPlayer, viTestVehicle)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Tests if the player is using the cargobob as a tow truck
/// PARAMS:
/// viTestVehicle - The vehicle that might be getting cargobobbed
/// RETURNS:
/// TRUE if the vehicle is being cargobobbed by the player, FALSE otherwise
FUNC BOOL IS_PLAYER_FLYING_WITH_ATTACHED_VEHICLE(VEHICLE_INDEX viTestVehicle)
IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_VEHICLE_OK(viTestVehicle)
VEHICLE_INDEX viPlayer = GET_PLAYERS_LAST_VEHICLE()
IF IS_VEHICLE_OK(viPlayer)
MODEL_NAMES Mod = GET_ENTITY_MODEL(viPlayer)
IF Mod = CARGOBOB
OR Mod = CARGOBOB2
OR Mod = CARGOBOB3
IF DOES_CARGOBOB_HAVE_PICK_UP_ROPE(viPlayer)
IF IS_VEHICLE_ATTACHED_TO_CARGOBOB(viPlayer, viTestVehicle)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Tests if the player is using the cargobob as a tow truck
/// PARAMS:
/// viTestVehicle - The vehicle to write to if there is a vehicle attached to the bob
/// RETURNS:
/// TRUE if any vehicle is being cargobobbed by the player, FALSE otherwise
FUNC BOOL IS_PLAYER_FLYING_WITH_ANY_ATTACHED_VEHICLE(VEHICLE_INDEX &viTestVehicle)
IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
VEHICLE_INDEX viPlayer = GET_PLAYERS_LAST_VEHICLE()
IF IS_VEHICLE_OK(viPlayer)
MODEL_NAMES Mod = GET_ENTITY_MODEL(viPlayer)
IF Mod = CARGOBOB
OR Mod = CARGOBOB2
OR Mod = CARGOBOB3
IF DOES_CARGOBOB_HAVE_PICK_UP_ROPE(viPlayer)
ENTITY_INDEX ent = GET_VEHICLE_ATTACHED_TO_CARGOBOB(viPlayer)
IF DOES_ENTITY_EXIST(ent)
viTestVehicle = GET_VEHICLE_INDEX_FROM_ENTITY_INDEX(ent)
IF IS_VEHICLE_OK(viTestVehicle)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Get Special Ability Bar Amount
/// PARAMS:
/// None
FUNC INT GET_PLAYER_SPECIAL_ABILITY_VALUE()
INT iStatValue
SWITCH GET_CURRENT_PLAYER_PED_ENUM()
CASE CHAR_MICHAEL
STAT_GET_INT(SP0_SPECIAL_ABILITY, iStatValue) // Michael
BREAK
CASE CHAR_FRANKLIN
STAT_GET_INT(SP1_SPECIAL_ABILITY, iStatValue) // Franklin
BREAK
CASE CHAR_TREVOR
STAT_GET_INT(SP2_SPECIAL_ABILITY, iStatValue) // Trevor
BREAK
ENDSWITCH
RETURN iStatValue
ENDFUNC
/// PURPOSE:
/// Waits for the world to load in around a given coordinate.
/// Call this before fading back in if you teleport the player for a checkpoint restart
/// PARAMS:
/// vLocation - the location, will usually be the player's location
/// fRadius - the radius around the location you need to be loaded, increase this if the world still doesn't properly load
/// satDataToLoad - the type of data that needs to be loaded: FLAG_COLLISIONS_MOVER, FLAG_COLLISIONS_WEAPON or FLAG_MAPDATA, can be OR'd together
/// iTimeout - how long the function should wait before timing out
/// bDisableSwitching - Turns of switching while this is loading
/// bDisablePhone - Turns off phone while this is loading
PROC WAIT_FOR_WORLD_TO_LOAD(VECTOR vLocation, FLOAT fRadius = 50.0, STREAMVOL_ASSET_TYPES satDataToLoad = FLAG_MAPDATA, INT iTimeout = 5000, BOOL bDisableSwitching = FALSE, BOOL bDisablePhone = FALSE)
STREAMVOL_ID streamVolID // ID for camera's stream vol ID
streamVolID = STREAMVOL_CREATE_SPHERE(vLocation, fRadius, satDataToLoad)
IF STREAMVOL_IS_VALID(streamVolID)
INT iWaitTime = GET_GAME_TIMER() + iTimeout
WHILE NOT STREAMVOL_HAS_LOADED(streamVolID) AND GET_GAME_TIMER() < iWaitTime
CPRINTLN(DEBUG_MISSION, "Loading world")
IF (bDisablePhone)
DISABLE_CELLPHONE_THIS_FRAME_ONLY()
ENDIF
IF (bDisableSwitching)
DISABLE_SELECTOR_THIS_FRAME()
ENDIF
WAIT(0)
ENDWHILE
IF GET_GAME_TIMER() < iWaitTime
CPRINTLN(DEBUG_MISSION, "World loaded")
ELSE
CPRINTLN(DEBUG_MISSION, "World loading timed out")
ENDIF
STREAMVOL_DELETE(streamVolID)
ELSE
CPRINTLN(DEBUG_MISSION, "Unable to create the streaming volume, cannot test for the world loading")
ENDIF
ENDPROC
/// PURPOSE:
/// Checks the ped and vehicle are alive.
/// Unfreezes the ped and puts him in the vehicle.
/// PARAMS:
/// mPed - ped to put in the vehicle.
/// mVehicle - vehicle to put him in.
/// seat - the seat the ped will sit in - Az added since we'd don't always want to set the ped as the driver
PROC SAFE_SET_PED_INTO_VEHICLE(PED_INDEX mPed, VEHICLE_INDEX mVehicle, VEHICLE_SEAT seat = VS_DRIVER, BOOL bNetworked = FALSE)
IF IS_PED_UNINJURED(mPed)
IF IS_ENTITY_ALIVE(mVehicle)
// unfreeze the ped
IF IS_ENTITY_ATTACHED(mPed)
IF (bNetworked)
IF NETWORK_HAS_CONTROL_OF_ENTITY(GET_ENTITY_ATTACHED_TO(mPed))
FREEZE_ENTITY_POSITION(GET_ENTITY_ATTACHED_TO(mPed), FALSE)
ENDIF
ELSE
FREEZE_ENTITY_POSITION(GET_ENTITY_ATTACHED_TO(mPed), FALSE)
ENDIF
ELSE
FREEZE_ENTITY_POSITION(mPed, FALSE)
ENDIF
SET_PED_INTO_VEHICLE(mPed, mVehicle, seat)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Starts a timer to check if a conversation has failed to trigger
/// PARAMS:
/// iConvFailedTimer - The timer variable the function uses, initialise this to -1 before calling the function for the first time
/// TIME_TO_WAIT - The amount of time the function will wait before returning TRUE, defaults to 5000 milliseconds
/// RETURNS:
/// TRUE when TIME_TO_WAIT has passed
FUNC BOOL CONVERSATION_TIMED_OUT(INT & iConvFailedTimer, INT TIME_TO_WAIT = 5000)
IF iConvFailedTimer < 0
iConvFailedTimer = GET_GAME_TIMER() + TIME_TO_WAIT
ELIF GET_GAME_TIMER() > iConvFailedTimer
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Makes a ped play a random scream
/// using "WAVELOAD_PAIN_MALE" , "SCREAM_TERROR"
/// handles male or female variation
/// PARAMS:
/// mPed - The ped we want to scream
/// bUseHighFallScream - if TRUE includes "SUPER_HIGH_FALL" in possible selection
PROC MAKE_PED_SCREAM(PED_INDEX mPed, BOOL bUseHighFallScream = TRUE)
IF IS_PED_UNINJURED(mPed)
STRING sScream
INT iRange = 2
IF bUseHighFallScream // only include
iRange = 3
ENDIF
INT iScream = GET_RANDOM_INT_IN_RANGE(0, iRange)
IF iScream = 0
sScream = "SCREAM_PANIC"
ELIF iScream = 1
sScream = "SCREAM_TERROR"
ELSE
sScream = "SUPER_HIGH_FALL"
ENDIF
IF IS_PED_MALE(mPed)
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(mPed, sScream, "WAVELOAD_PAIN_MALE")
ELSE
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(mPed, sScream, "WAVELOAD_PAIN_FEMALE")
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Generates a scenario blocking area based on a position and a radius
/// PARAMS:
/// pos - center point
/// rad - radius
/// RETURNS:
/// Scenario Block Index
FUNC SCENARIO_BLOCKING_INDEX ADD_SCENARIO_BLOCKING_AREA_FROM_POSITION_AND_RADIUS(VECTOR pos, FLOAT rad)
VECTOR rhalf = <<rad / 2.0, rad / 2.0, rad / 2.0>>
RETURN ADD_SCENARIO_BLOCKING_AREA(pos - rhalf, pos + rhalf)
ENDFUNC
/// PURPOSE:
/// If a scripted conversation is in progress and god text is printed, this will begin the check to avoid the dialogue subtitles overwriting the god text
PROC CHECK_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT_NOW(RC_CONV_RESTORE_STATE & stateRestoreConversation)
IF GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) <> 0 // Don't do any checking if the user isn't displaying conversation subtitles anyway
AND stateRestoreConversation != RC_CONV_STOP_CURRENT_CONV
AND IS_SCRIPTED_CONVERSATION_ONGOING()
#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_MISSION, "RC CONV CONFLICTS: Starting check for conversation and objective text conflicts") #ENDIF
stateRestoreConversation = RC_CONV_STOP_CURRENT_CONV
ENDIF
ENDPROC
/// PURPOSE:
/// If a scripted conversation is in progress and god text is printed, this will stop the check to avoid the dialogue subtitles overwriting the god text
PROC STOP_CHECKING_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT(RC_CONV_RESTORE_STATE & stateRestoreConversation)
IF stateRestoreConversation != RC_CONV_IDLE
#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_MISSION, "RC CONV CONFLICTS: Stopping check for conversation and objective text conflicts") #ENDIF
stateRestoreConversation = RC_CONV_IDLE
ENDIF
ENDPROC
/// PURPOSE:
/// If a scripted conversation is in progress and god text is printed, this will handle stopping & restarting the conversation without subtitles to prevent overwriting the god text, then stopping & restarting with subtitles after the text has cleared.
PROC HANDLE_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT(RC_CONV_RESTORE_STATE & stateRestoreConversation, structPedsForConversation & sConversationToUse, STRING sTextBlockToUse, TEXT_LABEL_23 & tSavedConversationRoot, TEXT_LABEL_23 & tSavedConversationLabel)
SWITCH stateRestoreConversation
CASE RC_CONV_IDLE
BREAK
CASE RC_CONV_STOP_CURRENT_CONV
IF IS_SCRIPTED_CONVERSATION_ONGOING()
tSavedConversationRoot = GET_CURRENTLY_PLAYING_STANDARD_CONVERSATION_ROOT()
tSavedConversationLabel = GET_STANDARD_CONVERSATION_LABEL_FOR_FUTURE_RESUMPTION()
IF ARE_STRINGS_EQUAL(tSavedConversationLabel, "")
OR ARE_STRINGS_EQUAL(tSavedConversationLabel, "NULL")
#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_MISSION, "RC CONV CONFLICTS: Already last line of the conversation so not stopping it") #ENDIF
stateRestoreConversation = RC_CONV_IDLE
ELSE
#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_MISSION, "RC CONV CONFLICTS: Stopping and storing conversation ", tSavedConversationRoot) #ENDIF
KILL_ANY_CONVERSATION()
stateRestoreConversation = RC_CONV_RESTART_WITHOUT_SUBS
ENDIF
ENDIF
BREAK
CASE RC_CONV_RESTART_WITHOUT_SUBS
IF NOT IS_SCRIPTED_CONVERSATION_ONGOING()
IF IS_MESSAGE_BEING_DISPLAYED() // Re-check to see if the god text has since gone offscreen
IF CREATE_CONVERSATION_FROM_SPECIFIC_LINE(sConversationToUse, sTextBlockToUse, tSavedConversationRoot, tSavedConversationLabel, CONV_PRIORITY_HIGH, DO_NOT_DISPLAY_SUBTITLES)
#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_MISSION, "RC CONV CONFLICTS: Restoring conversation ", tSavedConversationRoot, " from label ", tSavedConversationLabel, " without subtitles") #ENDIF
stateRestoreConversation = RC_CONV_RESTORE_WAIT_FOR_NO_TEXT
ENDIF
ELSE
#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_MISSION, "RC CONV CONFLICTS: God text removed before last line of dialogue was finished, so just restart with subtitles") #ENDIF
stateRestoreConversation = RC_CONV_RESTART_WITH_SUBS
ENDIF
ENDIF
BREAK
CASE RC_CONV_RESTORE_WAIT_FOR_NO_TEXT
IF NOT IS_MESSAGE_BEING_DISPLAYED()
AND IS_SCRIPTED_CONVERSATION_ONGOING()
tSavedConversationRoot = GET_CURRENTLY_PLAYING_STANDARD_CONVERSATION_ROOT()
tSavedConversationLabel = GET_STANDARD_CONVERSATION_LABEL_FOR_FUTURE_RESUMPTION()
IF ARE_STRINGS_EQUAL(tSavedConversationLabel, "")
OR ARE_STRINGS_EQUAL(tSavedConversationLabel, "NULL")
#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_MISSION, "RC CONV CONFLICTS: Already last line of the conversation so not stopping it") #ENDIF
ELSE
#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_MISSION, "RC CONV CONFLICTS: Stopping and storing conversation ", tSavedConversationRoot) #ENDIF
KILL_ANY_CONVERSATION()
stateRestoreConversation = RC_CONV_RESTART_WITH_SUBS
ENDIF
ENDIF
BREAK
CASE RC_CONV_RESTART_WITH_SUBS
IF NOT IS_SCRIPTED_CONVERSATION_ONGOING()
AND CREATE_CONVERSATION_FROM_SPECIFIC_LINE(sConversationToUse, sTextBlockToUse, tSavedConversationRoot, tSavedConversationLabel, CONV_PRIORITY_HIGH, DISPLAY_SUBTITLES)
#IF IS_DEBUG_BUILD CPRINTLN(DEBUG_MISSION, "RC CONV CONFLICTS: Restoring conversation ", tSavedConversationRoot, " from label ", tSavedConversationLabel, " with subtitles") #ENDIF
stateRestoreConversation = RC_CONV_IDLE
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Does this RCM have a lead-in sequence?
FUNC BOOL DOES_RC_MISSION_HAVE_LEAD_IN(g_eRC_MissionIDs eMission)
SWITCH eMission
CASE RC_ABIGAIL_1
CASE RC_ABIGAIL_2
CASE RC_BARRY_1
CASE RC_BARRY_2
CASE RC_BARRY_3
CASE RC_EPSILON_1
CASE RC_EPSILON_3
CASE RC_EPSILON_4
CASE RC_EPSILON_5
CASE RC_EXTREME_2
CASE RC_EXTREME_3
CASE RC_FANATIC_1
CASE RC_FANATIC_3
CASE RC_JOSH_1
CASE RC_JOSH_4
CASE RC_MINUTE_3
CASE RC_NIGEL_3
CASE RC_PAPARAZZO_1
CASE RC_PAPARAZZO_2
CASE RC_PAPARAZZO_3
RETURN TRUE
BREAK
ENDSWITCH
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Creates a replacement mission blip for a RCM that is displayed
/// for the duration of a lead-in sequence
PROC CREATE_BLIP_FOR_LEAD_IN(g_eRC_MissionIDs eMission, BLIP_INDEX &biBlip)
SWITCH eMission
// Abigail
CASE RC_ABIGAIL_1
biBlip = CREATE_BLIP_FOR_COORD(<< -1604.668, 5239.10, 3.01 >>)
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_RANDOM_CHARACTER)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_MICHAEL)
BREAK
CASE RC_ABIGAIL_2
biBlip = CREATE_BLIP_FOR_COORD(<< -1592.84, 5214.04, 3.01 >>)
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_ABIGAIL)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_MICHAEL)
BREAK
// Barry
CASE RC_BARRY_1
CASE RC_BARRY_2
biBlip = CREATE_BLIP_FOR_COORD(<< 190.26, -956.35, 29.63 >>)
IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_1].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED))
OR IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_3].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED))
OR IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_3].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED))
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_BARRY)
ELSE
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_RANDOM_CHARACTER)
ENDIF
IF eMission = RC_BARRY_1
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_MICHAEL)
ELSE
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_TREVOR)
ENDIF
BREAK
CASE RC_BARRY_3
biBlip = CREATE_BLIP_FOR_COORD(<< 414.00, -761.00, 29.00 >>)
IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_1].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED))
OR IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_BARRY_2].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED))
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_BARRY)
ELSE
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_RANDOM_CHARACTER)
ENDIF
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_FRANKLIN)
BREAK
// Epsilon
CASE RC_EPSILON_1
biBlip = CREATE_BLIP_FOR_COORD(<< -1622.89, 4204.87, 83.30 >>)
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_RANDOM_CHARACTER)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_MICHAEL)
BREAK
CASE RC_EPSILON_3
CASE RC_EPSILON_4
CASE RC_EPSILON_5
IF eMission = RC_EPSILON_3
biBlip = CREATE_BLIP_FOR_COORD(<< 1835.53, 4705.86, 38.1 >>)
ELIF eMission = RC_EPSILON_4
biBlip = CREATE_BLIP_FOR_COORD(<< 1826.13, 4698.88, 38.92 >>)
ELSE
biBlip = CREATE_BLIP_FOR_COORD(<< 637.02, 119.7093, 89.50 >>)
ENDIF
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_EPSILON)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_MICHAEL)
BREAK
// Extreme
CASE RC_EXTREME_2
CASE RC_EXTREME_3
IF eMission = RC_EXTREME_2
biBlip = CREATE_BLIP_FOR_COORD(<< -954.19, -2760.05, 14.64 >>)
ELSE
biBlip = CREATE_BLIP_FOR_COORD(<< -63.8, -809.5, 321.8 >>)
ENDIF
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_DOM)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_FRANKLIN)
BREAK
// Fanatic
CASE RC_FANATIC_1
CASE RC_FANATIC_3
IF eMission = RC_FANATIC_1
biBlip = CREATE_BLIP_FOR_COORD(<< -1877.82, -440.649, 45.05>>)
ELSE
biBlip = CREATE_BLIP_FOR_COORD(<< -915.6, 6139.2, 5.5 >>)
ENDIF
IF IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_FANATIC_1].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED))
OR IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_FANATIC_2].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED))
OR IS_BIT_SET(g_savedGlobals.sRandomChars.savedRC[RC_FANATIC_3].rcFlags, ENUM_TO_INT(RC_FLAG_COMPLETED))
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_FANATIC)
ELSE
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_RANDOM_CHARACTER)
ENDIF
IF eMission = RC_FANATIC_1
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_MICHAEL)
ELSE
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_FRANKLIN)
ENDIF
BREAK
// Josh
CASE RC_JOSH_1
biBlip = CREATE_BLIP_FOR_COORD(<< -1104.93, 291.25, 64.30 >>)
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_RANDOM_CHARACTER)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_TREVOR)
BREAK
CASE RC_JOSH_4
biBlip = CREATE_BLIP_FOR_COORD(<< -1104.93, 291.25, 64.30 >>)
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_JOSH)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_TREVOR)
BREAK
// Minute
CASE RC_MINUTE_3
biBlip = CREATE_BLIP_FOR_COORD(<< -303.82, 6211.29, 31.05>>)
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_MINUTE)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_TREVOR)
BREAK
// Nigel
CASE RC_NIGEL_3
biBlip = CREATE_BLIP_FOR_COORD(<< -44.75, -1288.67, 28.21 >>)
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_CELEBRITY_THEFT)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_TREVOR)
BREAK
// Paparazzo
CASE RC_PAPARAZZO_1
biBlip = CREATE_BLIP_FOR_COORD(<< -149.75, 285.81, 93.67 >>)
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_RANDOM_CHARACTER)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_FRANKLIN)
BREAK
CASE RC_PAPARAZZO_2
CASE RC_PAPARAZZO_3
IF eMission = RC_PAPARAZZO_2
biBlip = CREATE_BLIP_FOR_COORD(<< -70.71, 301.43, 106.79 >>)
ELSE
biBlip = CREATE_BLIP_FOR_COORD(<< -257.22, 292.85, 90.63 >>)
ENDIF
SET_BLIP_SPRITE(biBlip, RADAR_TRACE_PAPARAZZO)
SET_BLIP_COLOUR(biBlip, BLIP_COLOUR_FRANKLIN)
BREAK
ENDSWITCH
ENDPROC