//Compile out Title Update changes to header functions. //Must be before includes. //CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R. USING "rage_builtins.sch" USING "globals.sch" USING "commands_camera.sch" USING "commands_pad.sch" USING "commands_script.sch" USING "commands_vehicle.sch" USING "flow_public_core_override.sch" USING "script_ped.sch" USING "script_blips.sch" USING "dialogue_public.sch" USING "comms_control_public.sch" USING "chase_hint_cam.sch" USING "RC_Helper_Functions.sch" USING "rc_threat_public.sch" USING "family_public.sch" USING "buddy_head_track_public.sch" USING "taxi_functions.sch" USING "player_scene_schedule.sch" USING "commands_recording.sch" #IF IS_DEBUG_BUILD USING "select_mission_stage.sch" #ENDIF // ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** // // MISSION NAME : ME_Tracey1.sc // AUTHOR : Tom Waters // DESCRIPTION : Tracey has phoned Michael in a panic - she is being stalked by // a lunatic/loser as she drives around Los Santos. Michael must // reach her, find the stalker and deal with him. // // ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** //************************************************************************************************************************************************* // :ENUMS: //************************************************************************************************************************************************* // Track progress through the mission ENUM MISSION_STAGE_TRACK MST_INIT, MST_DRIVE_TO_TRACEY, MST_WAIT_FOR_PLAYER, MST_DRIVE_TO_STALKER, MST_TRIGGER_STALKER, MST_CHASE, MST_STALKER_WRECKED, MST_DRIVE_HOME, MST_AT_HOME, MST_FAIL_CALL, // MST_FAIL_TRACEY_DRIVE_OFF, MST_LOSE_WANTED, MST_FAIL_FADE ENDENUM // Progression within a stage ENUM STAGE_PROGRESS SP_SETUP, SP_RUNNING, SP_CLEANUP ENDENUM // Looped route conversation progress track ENUM CONVERSATION_PROGRESS_TRACK CPT_WAIT_TO_TRIGGER, CPT_PICK_CONVERSATION, CPT_START_CONVERSATION_STALKER, CPT_START_RANDOM_STALKER, // Specific to stalker on foot chat CPT_START_CONVERSATION_TRACEY_WTF, CPT_START_CONVERSATION_TRACEY, CPT_START_CONVERSATION_RAMARK, CPT_START_CONVERSATION_STOPPED, CPT_START_CONVERSATION_ESCAPING, CPT_START_CONVERSATION, CPT_WAIT_TO_FINISH, CPT_SPENT ENDENUM // Warning/fail call track ENUM WARNING_FAIL_CALLS WFC_SETUP, WFC_START_WARNING_CALL, WFC_WAIT_FOR_WARNING, WFC_CHECK_FOR_FAIL, WFC_ARRIVED_WAIT, WFC_ARRIVED_WARN, WFC_ARRIVED_CHECK_FOR_FAIL, WFC_DONE ENDENUM // Track progress in meeting up with Tracey stage ENUM TRACEY_CAR_ENTRY TCE_WAIT_FOR_PLAYER_RANGE, TCE_WAIT_FOR_CONVERSATION_START, TCE_WAIT_FOR_PLAYER_IN_CAR ENDENUM // Tracks the conversation and destination driving to ENUM TRACEY_DESTINATION_STATE TDS_START_CHAT, TDS_WAITING_FOR_CHAT_TO_START, TDS_WAITING_FOR_BLIP_LINE, TDS_WAITING_TO_DELAY_QUEUING_EXTRA_CHAT, TDS_WAITING_TO_QUEUE_EXTRA_CHAT, TDS_DRIVING_TO_POINT, TDS_DO_DELAY, TDS_LOOK_AROUND ENDENUM // Tracks the head IK lookat on the stalker ENUM STALKER_HEAD_TRACK_CONTROL SHTC_WAIT_FOR_TRIGGER_EVENT, SHTC_PROX_LOOKAT, SHTC_RAM_LOOKAT ENDENUM //************************************************************************************************************************************************* // :STRUCTS: //************************************************************************************************************************************************* // Stores info needed for spawning a vehicle STRUCT MISSION_VEHICLE VEHICLE_INDEX vehicle MODEL_NAMES model BOOL carModelRequestActive PED_INDEX driver MODEL_NAMES driverModel BOOL pedModelRequestActive VECTOR location FLOAT heading FLOAT initialSpeed BLIP_INDEX blip ENDSTRUCT // Objectives STRUCT MISSION_OBJECTIVE INT iDisplayMax INT iDisplayCount STRING sTextLabel ENDSTRUCT // Holds converstaion info STRUCT CONVERSATION_INFO INT startDelay STRING txtBlock STRING rootBlock ENDSTRUCT // Stores a non-axially aligned volume STRUCT NAA_VOLUME VECTOR vEnds[2] FLOAT fWidth ENDSTRUCT // Holds road disabler info STRUCT ROAD_BLOCK NAA_VOLUME trigBox NAA_VOLUME blockBox[2] ENDSTRUCT // Holds info for the places Tracey wants player to drive to STRUCT DESTINATION_POINT VECTOR location FLOAT range STRING chatLabel STRING extraChatLabel STRING bonkersChatLabel INT blipUpdateLine ENDSTRUCT //************************************************************************************************************************************************* // :CONSTANTS: //************************************************************************************************************************************************* // Checkpoints CONST_INT CP_MET_TRACEY 2 // Met Tracey at Vinewood plaza CONST_INT CP_STALKER_APPEARS 3 // Stalker gets spawned CONST_INT CP_DRIVE_HOME 4 // Stalker scared off, drive Tracey home CONST_INT CP_DRIVE_HOME_DEAD 5 // Stalker dead, drive Tracey home // Distances CONST_FLOAT SAFE_TRIGGER_DISTANCE 200.0 // Close enough that Tracey will actually spawn if we ask CONST_FLOAT TRIGGER_OFF_DISTANCE 300.0 // Flop back to reenable warning/fail calls at this range CONST_FLOAT TRACEY_MET_DIST 20.0 // Close enough to Tracey to start mission proper CONST_FLOAT WARN_DIS_TOO_FAR 60.0 // Getting too far from Tracey CONST_FLOAT ABANDON_TRACEY_DIST 160.0 // Fail for abandoning Tracey CONST_FLOAT STALKER_ESCAPE_DIST 220.0 // Stalker car escape range CONST_FLOAT CHASE_FLASH_DIST 0.75 // Distance that blip should flash at CONST_FLOAT STALKER_FOOT_ESCAPE_DIST 80.0 // Stalker on-foot escape range CONST_FLOAT STALKER_FOOT_MUTE_DIST 25.0 // Cut off distance for stalker on-foot chat triggering // Timings CONST_INT RENDEZVOUS_TIMER 5 // Time the player has to reach Tracey, in in-game hours CONST_INT WARNING_TIMER 2 // Time until player gets warning call from Tracey, in in-game hours CONST_INT STALKER_SPOT_TIMER 8000 // Maximum time it takes Tracey to spot the stalker in milliseconds, if range trigger does not fire first //CONST_INT TRACEY_BORED_DELAY 20000 // Time delay for Tracey waiting for player to get back in a car CONST_INT ARRIVED_TIMER_WARN 15000 // How long will Tracey wait in the car park before complaining about the player screwing around on foot CONST_INT ARRIVED_TIMER_FAIL 120000 // How long will Tracey wait in the car park if the player is screwing around on foot CONST_INT DIRECTIONS_DELAY 4000 // Time that must pass between Tracey direction clips CONST_INT BANTER_DELAY 4000 // Time that must pass between banter conversation clips CONST_INT TOO_FAST_DELAY 4000 // Time that must pass between too fast conversation clips CONST_INT NOT_GOING_DELAY 18000 // Time that must pass between not moving complaint clips in drive to stalker CONST_INT NOT_GOING_DELAY_CHASE 6000 // Time that must pass between not moving complaint clips in chase section CONST_INT CHASE_COMMENT_DELAY 4000 // Time that must pass between chase comment clips CONST_INT CHASE_PROX_CHECK_TIME 10000 // Time gap between checks on stalker position vs player position in on-foot chase section CONST_INT CHASE_AREA_CHECK_TIME 2000 // Time gap between checks on player car in front of stalker // Video Editor timings CONST_FLOAT SNUFF_TIMER_RETRORECORD 2.5 // How far back from the time of death should we record stalker murder incident (s) CONST_INT SNUFF_TIMER_TRACEY_SAW 8000 // Wait for Tracey reaction dialogue if she saw the stalker being killed (ms) CONST_INT SNUFF_TIMER_DIDNT_SEE 2000 // No need to record so much if stalker killed out of sight of Tracey (ms) // CONST_INT CT_PROX_CHECK 0 CONST_INT CT_AREA_CHECK 1 // Objective constants - if you add or remove any do not leave gaps and update NUM_MISSION_OBJECTIVES CONST_INT MO_MET1INITDRV 0 // Go to the Vinewood Plaza. CONST_INT MO_MET1TCAR 1 // Get in Tracey's car. CONST_INT MO_MET1WAIT 2 // Wait for Tracey. CONST_INT MO_MET1WANT 3 // Lose the cops. CONST_INT MO_MET1CHASE 4 // Stop the stalker's car. CONST_INT MO_MET1GETBKT 5 // Get back in Tracey's car. CONST_INT MO_MET1DLT 6 // Return to Tracey. CONST_INT MO_MET1HOME 7 // Go home. CONST_INT MO_MET1HOTEL 8 // Go to the hotel. CONST_INT NUM_MISSION_OBJECTIVES 9 // Array sizes CONST_INT NUM_MICHAEL_COMMENTS 3 // Number of Michael monologues before meetup CONST_INT NUM_ROUTE_CONVERSATIONS 3 // Number of Michael/Tracey conversations after meetup CONST_INT NUM_BANTER_CHUNKS 10 // Max number of banter chunks available during conversations while driving to stalker CONST_INT NUM_DESTINATIONS 4 // Number of destinations that Tracey suggests to Michael CONST_INT NUM_CHASE_CONVERSATIONS_S 5 // Number of Michael/Stalker conversations in car chase CONST_INT NUM_CHASE_CONVERSATIONS_T 4 // Number of Michael/Tracey conversations in car chase CONST_INT NUM_FOOT_CONVERSATIONS_S 3 // Number of Michael/stalker conversations once stalker is on foot CONST_INT NUM_FOOT_CONVERSATIONS_T 3 // Number of Michael/Tracey conversations once stalker is on foot CONST_INT NUM_DRIVEHOME_CONVERSATIONS 9 // Number of Michael/Tracey conversation elements available in drive home CONST_INT NUM_AUDIOSCENES 8 // Number of different audioscene states // Audio scenes CONST_INT AUDIOSCENE_NONE 0 // None CONST_INT AUDIOSCENE_GO_TO_TRACEY 1 // M_E_TRACEY_GO_TO_TRACEY CONST_INT AUDIOSCENE_ENTER_TRACEYS_CAR 2 // M_E_TRACEY_ENTER_TRACEYS_CAR CONST_INT AUDIOSCENE_DRIVE_TO_STALKER 3 // M_E_TRACEY_FIND_STALKER CONST_INT AUDIOSCENE_CHASE 4 // M_E_TRACEY_STOP_STALKERS_CAR CONST_INT AUDIOSCENE_CHASE_FOOT 5 // M_E_TRACEY_DEAL_WITH_STALKER CONST_INT AUDIOSCENE_DRIVE_HOME 6 // M_E_TRACEY_TAKE_TRACEY_HOME CONST_INT AUDIOSCENE_DONE 7 // None // Vehicle restriction CONST_INT RESTRICTION_STALKER 0 CONST_INT RESTRICTION_TRACEY 1 //************************************************************************************************************************************************* // :VARIABLES: //************************************************************************************************************************************************* // Progression stuff MISSION_STAGE_TRACK msTrack = MST_INIT // track what mission stage we are at STAGE_PROGRESS sProgress = SP_SETUP // used to track what bit of the current mission stage we're at WARNING_FAIL_CALLS wfcProgress // Tracks progression of warning call and fail call BOOL bWFCOnHold // Suspends warning fail calls when we're within grace distance. // Conversation struct structPedsForConversation mConversationStruct // Speaker/Listener IDs: 0 Michael, 3 Tracey, 4 Stalker // Hint cam struct CHASE_HINT_CAM_STRUCT localChaseHintCamStruct // Cars VEHICLE_INDEX viTraceyCar BOOL bStuckCheckActive = FALSE BOOL bVehicleOnRoofLastFrame = FALSE INT iStuckTimer MISSION_VEHICLE mvStalkerCar // Peds PED_INDEX pedTracey PED_INDEX pedStalker MODEL_NAMES mnStalkerModel = A_M_O_ACult_01 BOOL bStalkerModelRequested = FALSE BOOL bTraceyIsCurrentlySpawned = FALSE BOOL bRelGroupExists = FALSE REL_GROUP_HASH relGroupFriendly STRING sTraceyAnimDict = "rcmme_tracey1" // Blips BLIP_INDEX biBlip // General blip BLIP_INDEX biTraceyBlip // Specific blip for Tracey's car for stalker section onwards INT iFlashTick // For flashing stalker blip INT iFlashTimeout // For flashing stalker blip // In-game clock times that player started the mission at, i.e. "3pm" not "7454568ms" INT iStartDate INT iStartHours INT iStartMinutes TRACEY_CAR_ENTRY traceyCarEntry // Progression within the substage where player meets Tracey BOOL bPlayerOnFoot // Track player being on foot. BOOL bTraceyOnFoot // Track Tracey being on foot. BOOL bTraceyAttemptingReentry // Track Tracey attempting to get back in car. INT iFootDawdleTimer // Timer for player dawdling in car park on foot BOOL bPlayerWanted // Used for tracking player being wanted in drive home step BOOL bWantedObjectiveNeeded // Have we shown a wanted objective yet on becoming wanted in drive home section BOOL bMichaelCommentPlayed // Michael comment on getting in car // For tracking whether the player has driven weirdly with Tracey outside the chase stages BOOL bBonkersDriving INT iPedsDamaged INT iPedDamageTimeOut FLOAT fTotalTimeOverSpeedLimit TRACEY_DESTINATION_STATE traceyDestinationState // Control chatter and objective progress //INT iLookAroundTimer // Timer for waiting at each point before proceeding //INT iLookAroundDelay = 2000 //4500 // How long they should wait at each point (ms) // Stalker stuck check BOOL bStalkerStuckCheckActive = FALSE BOOL bStalkerOnRoofLastFrame = FALSE INT iStalkerStuckTimer // Monitor Tracey's car moving - used to make her comment if player is idle VECTOR vecTraceyPositionTrack[3] INT iTraceyPositionTimer // Spaces out position check updates INT iComplainTimer // Timer for immobile state before a complaint // Whether stalker knows player is after him BOOL bPlayerWiseToStalker // Controls when stalker starts to flee BOOL bStalkerFleeing // Has the stalker started to flee from the player BOOL bMichaelArrivalLinePlayed // Michael has said his arrival line for hitting the final destination BOOL bStalkerSpotChatStarted // Tracey has ID'ed the stalker and tells the player BOOL bStalkerDead // Stalker has been killed BOOL bTraceySawOutcome = FALSE // Whether Tracey witnessed the stalker's death/escape //INT iStalkerBlipTimer // Timeout for blipping stalker regardless of whether he's in range // Video editor event for player killing stalker BOOL bStalkerSnuffMovieStarted = FALSE // Video Editor - Have we started a recording for the stalker's death? BOOL bStalkerSnuffMovieFinished = FALSE // Video Editor - Have we ended a recording for the stalker's death? INT iStalkerSnuffTimer // Timer for video editor movie // Objective display structure MISSION_OBJECTIVE moObjectives[NUM_MISSION_OBJECTIVES] // Tracey muttering to herself in car park INT iTraceyWaitingChatTimer INT iTraceyWaitingConversationCount CONVERSATION_PROGRESS_TRACK cptTraceyWaitingComments = CPT_WAIT_TO_TRIGGER // Vehicle chase conversation stuff INT iChaseStalkerChatCount // Stalker's comment counter INT iChaseTraceyChatCount // Tracey's comment counter INT iChaseChatTimer BOOL bStalkerChatting // TRUE while a stalker/Michael conversation is ongoing BOOL bTraceyChatting // TRUE while a Tracey/Michael conversation is ongoing BOOL bQuickRamComment // TRUE if a collision has occured INT iLastCollisionTime // The last time we detected the car colliding with something INT iTimeSinceCollision // The time elapsed since last colliding with something CONVERSATION_PROGRESS_TRACK cptChaseTrack CONVERSATION_INFO ciChaseConversations[NUM_CHASE_CONVERSATIONS_S] // Stalker/Michael chase banter CONVERSATION_INFO ciTraceyChaseConversations[NUM_CHASE_CONVERSATIONS_T] // Tracey/Michael chase banter // Monitoring Michael shooting and Tracey complaining about it BOOL bShootingComment INT iShootingTimer INT iShootingComplaintGap CONST_INT RECENT_SHOOTING_TIMEOUT 4500 CONST_INT SHOOTING_COMPLAINT_GAP 15000 // Stalker on foot chase conversation stuff BOOL bTraceyOnFootAlertDone // Tracey has said her comment when the stalker gets out of his car BOOL bTraceyEscapeCommentDone // Tracey has said her comment about whether they are letting the stalker go now he's on foot INT iFootChaseStalkerChat // Stalker's comment counter INT iFootChaseTraceyChat // Tracey's comment counter CONVERSATION_PROGRESS_TRACK cptFootChaseTrack CONVERSATION_INFO ciFootChaseConversations[NUM_FOOT_CONVERSATIONS_S] CONVERSATION_INFO ciTraceyFootChaseConversations[NUM_FOOT_CONVERSATIONS_T] // Conversations on drive home CONVERSATION_INFO ciDriveHomeChat[NUM_DRIVEHOME_CONVERSATIONS] INT iDriveHomeChatStep INT iDriveHomeChatTimer BOOL bNeedWantedRemark = FALSE BOOL bNeedCrazyDrivingComment = FALSE BOOL bConversationKilled = FALSE // Has any ongoing conversation been killed at the point we need to instant the dead stalker reaction. // Nearly home comment BOOL bNearlyHomeCommentDone BOOL bAtHomeCommentDone // At home cutscene CAMERA_INDEX ciHomeCam INT iCutTimer BOOL bOutroWasSkipped BOOL bFPFlashNeeded // First person BOOL bFPFlashTimerStarted // First person INT iFPFlashTimer // First person // Locations VECTOR vecTraceyStartPoint = << 238.1823, -34.5401, 68.7233 >> // Where Tracey's car is spawned in car park FLOAT fTraceyStartHeading = 160.6 VECTOR vecTraceyPedStart = << 236.23, -34.25, 69.71 >> // Where Tracey ped is spawned in car park FLOAT fTraceyPedStartHead = 154.19 DESTINATION_POINT dpLocates[NUM_DESTINATIONS] // Locations that Tracey suggests the player drives to INT iCurrentDestination // The current destination in the array VECTOR vecHouseLocation = << -825.07, 180.32, 70.52>> // Michael's house VECTOR vecHotelLocation = <<-1316.5687, 391.5938, 68.7507>> // Back of hotel VECTOR vecReturnLocation, vecTraceyDest // Destination of Drive home stage / Point tracey walks to in outro cut BOOL bGoingToHotel = FALSE // Set this to true to go to hotel instead of house NAA_VOLUME naaCarPark // Disables road nodes in car park where you meet Tracey SCENARIO_BLOCKING_INDEX sbiCarpark // Disable parking scenario in car park where you meet Tracey INT iLookAroundTimer // Timer for looking around at each point INT iLookAroundDelay = 2000 // How long they should wait at each point (ms) BOOL bDoingDelay // Controls whether conversation delays are needed // Stalker spawn stuff VECTOR vecStalkerSpawnPoint[6] FLOAT fStalkerSpawnHead[6] // General purpose counter INT iCount // Fail reason tracking - will either be an ID or "DEFAULT" if no fail reason set. STRING sFailReason // Audio scene handling INT iCurrentAudioScene STRING sAudioScenes[NUM_AUDIOSCENES] // Monitor whether player has trapped stalker car in chase section and general route progress VECTOR vecStalkerPositionTrack[6] INT iStalkerPositionTimer // Frequency of position check BOOL bStalkerCowering // On foot stalker has started cowering BOOL bStalkerOnPedFleeTask // The stalker has been set to TASK_SMART_FLEE_PED instead of TASK_SMART_FLEE_COORD INT iChaseTaskTimer[2] // Stalker task check timer in on-foot chase // Monitor player ramming stalker in chase section BOOL bStalkerRammedLastFrame INT iStalkerRamTimer INT iStalkerRamCount FLOAT fRamClosingSpeedLastFrame // Monitor stalker looking at player in chase section INT iStalkerLookTimer // The timer for controlling look repeats INT iStalkerLookAtTime // The time for which a given look should last INT iStalkerRamLookDelay // How long to wait between ram-triggered looks INT iStalkerProxLookDelay // How long to wait between proximity-triggered looks STALKER_HEAD_TRACK_CONTROL shtcProgress // Has Tracey started driving when she gets fed up waiting for player in car park //BOOL bTDFStarted // Replay player placement VECTOR vecReplayPlayerLocation FLOAT fReplayPlayerHeading BOOL bReplayInVehicle VEHICLE_INDEX vehReplayCar // Replay timer INT iMeetTimer BOOL bMeetReplayIsGoing = FALSE INT iDisableReplayCameraTimer //Fix for bug 2227778 //************************************************************************************************************************************************* // :DEBUG VARS: //************************************************************************************************************************************************* #IF IS_DEBUG_BUILD // Mission specific z-skip enum ENUM MISSION_SKIP_STAGE MSS_RESTART, MSS_RESTART_CAR, MSS_MEET_TRACEY, MSS_STALKER_APPEARS, MSS_STALKER_WRECK, MSS_STALKER_STUCK, MSS_DRIVE_HOME, // Driving home if stalker escaped on foot MSS_DRIVE_HOME_DEAD, // Driving home if stalker dead MSS_ARRIVE_HOME ENDENUM CONST_INT MAX_SKIP_MENU_LENGTH 9 //BOOL bFinishedSkipping MISSION_SKIP_STAGE eTargetStage MissionStageMenuTextStruct mSkipMenu[MAX_SKIP_MENU_LENGTH] // Car model to be spawned by debug skips MODEL_NAMES debugPlayerCarModel = TAILGATER // Debug widgets BOOL bDebugTraceyTTY = FALSE BOOL bDebugStalkerTTY = FALSE BOOL bDebugCallTimeDisplay = FALSE BOOL bDebugFlipStalkerCar = FALSE WIDGET_GROUP_ID widgetGroup #ENDIF //************************************************************************************************************************************************* // :DEBUG RENDERING PROCS: //************************************************************************************************************************************************* #IF IS_DEBUG_BUILD /// PURPOSE: /// Draw debug box for non-axis aligned locate, useful for rendering triggers and telling which is which /// Will only be called if you set the bool for them /// PARAMS: /// vec1 - locate vector 1 /// vec2 - locate vector 2 /// width - locate width /// colR - Red value 0-255 /// colG - Green value 0-255 /// colB - Blue value 0-255 PROC DRAW_DEBUG_LOCATE_SPECIAL(VECTOR vec1, VECTOR vec2, FLOAT width, INT colR, INT colG, INT colB) IF colR > 255 OR colR < 0 OR colG > 255 OR colG < 0 OR colB > 255 OR colB < 0 SCRIPT_ASSERT("Trying to set an illegal RGB value for locate rendering, so no boxes for you!") ELSE VECTOR vBottom[2] VECTOR vTop[2] vBottom[0] = vec1 vBottom[1] = vec2 vTop[0] = vec1 vTop[1] = vec2 IF vec1.z > vec2.z vBottom[0].z = vec2.z vBottom[1].z = vec2.z vTop[0].z = vec1.z vTop[1].z = vec1.z ELSE vBottom[0].z = vec1.z vBottom[1].z = vec1.z vTop[0].z = vec2.z vTop[1].z = vec2.z ENDIF VECTOR fwd = NORMALISE_VECTOR(vBottom[1] - vBottom[0]) // normalize to get distance VECTOR side = <<-fwd.y, fwd.x, fwd.z>> VECTOR w = side * (width / 2.0) // Bottom points VECTOR c1 = vBottom[0] - w // base left VECTOR c2 = vBottom[0] + w // base right VECTOR c3 = vBottom[1] + w // top rt VECTOR c4 = vBottom[1] - w // top lt // Top points VECTOR d1 = vTop[0] - w // base left VECTOR d2 = vTop[0] + w // base right VECTOR d3 = vTop[1] + w // top rt VECTOR d4 = vTop[1] - w // top lt // Draw bottom lines DRAW_DEBUG_LINE(c1, c2, colR, colG, colB) DRAW_DEBUG_LINE(c2, c3, colR, colG, colB) DRAW_DEBUG_LINE(c3, c4, colR, colG, colB) DRAW_DEBUG_LINE(c4, c1, colR, colG, colB) // Draw top lines DRAW_DEBUG_LINE(d1, d2, colR, colG, colB) DRAW_DEBUG_LINE(d2, d3, colR, colG, colB) DRAW_DEBUG_LINE(d3, d4, colR, colG, colB) DRAW_DEBUG_LINE(d4, d1, colR, colG, colB) // Draw uprights DRAW_DEBUG_LINE(c1, d1, colR, colG, colB) DRAW_DEBUG_LINE(c2, d2, colR, colG, colB) DRAW_DEBUG_LINE(c3, d3, colR, colG, colB) DRAW_DEBUG_LINE(c4, d4, colR, colG, colB) ENDIF ENDPROC #ENDIF //************************************************************************************************************************************************* // :OBJECTIVE FUNCS/PROCS: //************************************************************************************************************************************************* /// PURPOSE: /// Returns a completed struct that holds an objective's info /// PARAMS: /// stTextLabel - The name of the text label that will be displayed as God text /// iDisMax - Maximum number of times it can display. Set to -1 for no limit. FUNC MISSION_OBJECTIVE CREATE_MISSION_OBJECTIVE(STRING stTextLabel, INT iDisMax = 1) MISSION_OBJECTIVE tmpMissionObj tmpMissionObj.sTextLabel = stTextLabel tmpMissionObj.iDisplayMax = iDisMax tmpMissionObj.iDisplayCount = 0 RETURN tmpMissionObj ENDFUNC /// PURPOSE: /// Display an objective unless it has already been displayed as many times as allowed /// PARAMS: /// iObj - index for the objective (use the CONSTs) PROC DISPLAY_MISSION_OBJECTIVE(INT iObj) IF moObjectives[iObj].iDisplayCount < moObjectives[iObj].iDisplayMax OR moObjectives[iObj].iDisplayMax = -1 PRINT_NOW(moObjectives[iObj].sTextLabel, DEFAULT_GOD_TEXT_TIME, 1) moObjectives[iObj].iDisplayCount++ ENDIF ENDPROC /// PURPOSE: /// Test whether an objective will display /// Saves having a seperate bool for blip updates, or lets you see whether you need to clear an objective /// PARAMS: /// iObj - index for the objective (use the CONSTs) /// RETURNS: /// TRUE if calling DISPLAY_MISSION_OBJECTIVE would trigger a PRINT FUNC BOOL MISSION_OBJECTIVE_WILL_DISPLAY(INT iObj) IF moObjectives[iObj].iDisplayCount < moObjectives[iObj].iDisplayMax OR moObjectives[iObj].iDisplayMax = -1 RETURN TRUE ELSE RETURN FALSE ENDIF ENDFUNC /// PURPOSE: /// Clear a specific objective print that is being displayed /// PARAMS: /// iObj - index for the objective (use the CONSTs) PROC CLEAR_MISSION_OBJECTIVE(INT iObj) CLEAR_THIS_PRINT(moObjectives[iObj].sTextLabel) ENDPROC /// PURPOSE: /// Are any objectives from this mission currently on screen? /// RETURNS: /// TRUE if a PRINT from this mission is on screen FUNC BOOL MISSION_OBJECTIVES_CURRENTLY_DISPLAYED() // Check the prints in sequence FOR iCount = 0 TO NUM_MISSION_OBJECTIVES-1 IF IS_THIS_PRINT_BEING_DISPLAYED(moObjectives[iCount].sTextLabel) RETURN TRUE ENDIF ENDFOR // Didn't find any prints RETURN FALSE ENDFUNC /// PURPOSE: /// Allows skip procs to reset objective counter /// PARAMS: /// iObj - index for the objective (use the CONSTs) /// iNewCount - optionally set the display count to a specific value PROC MISSION_OBJECTIVE_RESET(INT iObj, INT iNewCount = 0) moObjectives[iObj].iDisplayCount = iNewCount ENDPROC /// PURPOSE: /// Allows skip procs to set an objective to act as if it has already displayed /// PARAMS: /// iObj - index for the objective (use the CONSTs) PROC MISSION_OBJECTIVE_EXPIRE(INT iObj) IF moObjectives[iObj].iDisplayMax = -1 CPRINTLN(DEBUG_MISSION, "Trying to expire an objective that has unlimited repeats - index ", iObj) ELSE moObjectives[iObj].iDisplayCount = moObjectives[iObj].iDisplayMax ENDIF ENDPROC /// PURPOSE: /// Set up all the mission objectives PROC STORE_MISSION_OBJECTIVE_DATA() moObjectives[MO_MET1INITDRV] = CREATE_MISSION_OBJECTIVE("MET1INITDRV", 1) // Drive towards Vinewood. moObjectives[MO_MET1TCAR] = CREATE_MISSION_OBJECTIVE("MET1TCAR", 1) // Get in Tracey's car. moObjectives[MO_MET1WAIT] = CREATE_MISSION_OBJECTIVE("MET1WAIT", 1) // Wait for Tracey. moObjectives[MO_MET1WANT] = CREATE_MISSION_OBJECTIVE("MET1WANT", -1) // Lose the cops. moObjectives[MO_MET1CHASE] = CREATE_MISSION_OBJECTIVE("MET1CHASE", 1) // Stop the stalker's car. moObjectives[MO_MET1GETBKT] = CREATE_MISSION_OBJECTIVE("MET1GETBKT", 1) // Get back in Tracey's car. moObjectives[MO_MET1DLT] = CREATE_MISSION_OBJECTIVE("MET1DLT", 1) // Return to Tracey. moObjectives[MO_MET1HOME] = CREATE_MISSION_OBJECTIVE("MET1HOME", 1) // Take Tracey home. moObjectives[MO_MET1HOTEL] = CREATE_MISSION_OBJECTIVE("MET1HOTEL", 1) // Take Tracey to the hotel. ENDPROC //************************************************************************************************************************************************* // :UTILITY FUNCS/PROCS: //************************************************************************************************************************************************* /// PURPOSE: /// Are we at a point in flow that means we should go to the hotel instead of the house? /// RETURNS: /// TRUE if family are in hiding, otherwise false FUNC BOOL SHOULD_GO_TO_HOTEL() // I think we'll need new flowflags for this RETURN FALSE ENDFUNC /// PURPOSE: /// Checks a vehicle to see if it has any busted tyres /// RETURNS: /// TRUE if any tyres are busted FUNC BOOL VEHICLE_TYRE_BUSTED(VEHICLE_INDEX viCheck) IF IS_VEHICLE_TYRE_BURST(viCheck, SC_WHEEL_CAR_FRONT_LEFT) OR IS_VEHICLE_TYRE_BURST(viCheck, SC_WHEEL_CAR_FRONT_RIGHT) OR IS_VEHICLE_TYRE_BURST(viCheck, SC_WHEEL_CAR_REAR_LEFT) OR IS_VEHICLE_TYRE_BURST(viCheck, SC_WHEEL_CAR_REAR_RIGHT) RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Check whether the stalker car is damaged enough that he needs to abandon it /// RETURNS: /// TRUE if it's trashed, stuck or has burst tyres FUNC BOOL STALKER_CAR_IS_TRASHED() // Basic trashed checks IF DOES_ENTITY_EXIST(mvStalkerCar.vehicle) IF IS_ENTITY_DEAD(mvStalkerCar.vehicle) OR NOT IS_VEHICLE_DRIVEABLE(mvStalkerCar.vehicle) RETURN TRUE ENDIF // Do player ram counting IF HAS_PLAYER_RAMMED_ENEMY_ENOUGH(mvStalkerCar.vehicle, bStalkerRammedLastFrame, iStalkerRamTimer, iStalkerRamCount, fRamClosingSpeedLastFrame) RETURN TRUE ENDIF // Trigger a ram comment if bStalkerRammedLastFrame has been set IF bStalkerRammedLastFrame bQuickRamComment = TRUE ENDIF // Keep track of vehicle on roof IF IS_VEHICLE_STUCK_ON_ROOF(mvStalkerCar.vehicle) IF bStalkerOnRoofLastFrame IF GET_GAME_TIMER() - iStalkerStuckTimer > ROOF_TIME RETURN TRUE ENDIF ELSE CPRINTLN(DEBUG_MISSION, "Stalker is now stuck on roof!") bStalkerOnRoofLastFrame = TRUE iStalkerStuckTimer = GET_GAME_TIMER() ENDIF ELSE IF bStalkerOnRoofLastFrame CPRINTLN(DEBUG_MISSION, "MET_TRACEY1::: Stalker is no longer stuck on roof.") ENDIF bStalkerOnRoofLastFrame = FALSE ENDIF // Check for tyre bursts IF VEHICLE_TYRE_BUSTED(mvStalkerCar.vehicle) RETURN TRUE ENDIF ENDIF // No problems found: RETURN FALSE ENDFUNC /// PURPOSE: /// Perform location based checks to ensure we aren't trying to set IK when it would look awful FUNC BOOL MAKE_SURE_THIS_WONT_LOOK_STUPID(BOOL bStrictCheck) IF bStrictCheck = TRUE OR bStrictCheck = FALSE RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Makes the stalker look at the player after a ram or if he drives right alongside him for a while PROC STALKER_HEAD_TRACK_CONTROLLER() IF shtcProgress = SHTC_WAIT_FOR_TRIGGER_EVENT // Check for ram look IF bStalkerRammedLastFrame AND GET_GAME_TIMER() - iStalkerLookTimer > iStalkerRamLookDelay iStalkerLookTimer = GET_GAME_TIMER() shtcProgress = SHTC_RAM_LOOKAT CPRINTLN(DEBUG_MISSION, "STALKER_HEAD_TRACK_CONTROLLER: Go to SHTC_RAM_LOOKAT") // Check for player cruising alongside look ELIF GET_GAME_TIMER() - iStalkerLookTimer > iStalkerProxLookDelay AND IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(mvStalkerCar.vehicle, << 0.0, -0.5, -1.5 >>), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(mvStalkerCar.vehicle, << 0.0, 6.0, 2.0 >>), 12.0) iStalkerLookTimer = GET_GAME_TIMER() shtcProgress = SHTC_PROX_LOOKAT CPRINTLN(DEBUG_MISSION, "STALKER_HEAD_TRACK_CONTROLLER: Go to SHTC_PROX_LOOKAT") ENDIF ENDIF IF shtcProgress = SHTC_PROX_LOOKAT // Check for being rammed last frame IF bStalkerRammedLastFrame CPRINTLN(DEBUG_MISSION, "STALKER_HEAD_TRACK_CONTROLLER: Stalker was rammed in SHTC_PROX_LOOKAT- fall through to SHTC_RAM_LOOKAT") shtcProgress = SHTC_RAM_LOOKAT // Check if the prox lookat is still good ELIF GET_GAME_TIMER() - iStalkerLookTimer < iStalkerLookAtTime AND MAKE_SURE_THIS_WONT_LOOK_STUPID(TRUE) // Lookat still good to go, keep setting //SET_PED_CAN_HEAD_IK(pedStalker, FALSE) SET_IK_TARGET(pedStalker, IK_PART_HEAD, PLAYER_PED_ID(), 0, << 0.0, 0.0, 0.0 >>, ITF_DEFAULT, 300, 300) ELSE // Lookat timed out or would look bad, go back to waiting CPRINTLN(DEBUG_MISSION, "STALKER_HEAD_TRACK_CONTROLLER: SHTC_PROX_LOOKAT timed out or cancelled, back to SHTC_WAIT_FOR_TRIGGER_EVENT after", GET_GAME_TIMER() - iStalkerLookTimer, "ms") iStalkerLookTimer = GET_GAME_TIMER() shtcProgress = SHTC_WAIT_FOR_TRIGGER_EVENT ENDIF ENDIF IF shtcProgress = SHTC_RAM_LOOKAT // Check if the ram lookat is still good IF GET_GAME_TIMER() - iStalkerLookTimer < iStalkerLookAtTime AND MAKE_SURE_THIS_WONT_LOOK_STUPID(FALSE) // Lookat still good to go, keep setting //SET_PED_CAN_HEAD_IK(pedStalker, FALSE) SET_IK_TARGET(pedStalker, IK_PART_HEAD, PLAYER_PED_ID(), 0, << 0.0, 0.0, 0.0 >>, ITF_DEFAULT, 150, 400) ELSE // Lookat timed out or would look bad, go back to waiting CPRINTLN(DEBUG_MISSION, "STALKER_HEAD_TRACK_CONTROLLER: SHTC_RAM_LOOKAT timed out or cancelled, back to SHTC_WAIT_FOR_TRIGGER_EVENT after", GET_GAME_TIMER() - iStalkerLookTimer, "ms") iStalkerLookTimer = GET_GAME_TIMER() shtcProgress = SHTC_WAIT_FOR_TRIGGER_EVENT ENDIF ENDIF ENDPROC /// PURPOSE: /// Checks that it's still relevant whether Tracey's car is driveable, then checks whether it's wrecked /// RETURNS: /// TRUE if Tracey's car is spawned and wrecked, and the stalker is not yet fleeing the player. Otherwise FALSE FUNC BOOL TRACEY_CAR_WRECKED() IF NOT IS_ENTITY_ALIVE(viTraceyCar) RETURN TRUE ENDIF IF NOT IS_VEHICLE_DRIVEABLE(viTraceyCar) RETURN TRUE ENDIF // Either not trashed, or stalker is already fleeing so we don't care RETURN FALSE ENDFUNC /// PURPOSE: /// Checks that Tracey's car hasn't got stuck /// RETURNS: /// TRUE if car is stuck FUNC BOOL TRACEY_CAR_STUCK() // Keep track of vehicle on roof IF IS_VEHICLE_STUCK_ON_ROOF(viTraceyCar) IF bVehicleOnRoofLastFrame IF GET_GAME_TIMER() - iStuckTimer > ROOF_TIME RETURN TRUE ENDIF ELSE CPRINTLN(DEBUG_MISSION, "Vehicle is now stuck on roof!") bVehicleOnRoofLastFrame = TRUE iStuckTimer = GET_GAME_TIMER() ENDIF ELSE IF bVehicleOnRoofLastFrame CPRINTLN(DEBUG_MISSION, "Vehicle is no longer stuck on roof.") ENDIF bVehicleOnRoofLastFrame = FALSE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// A 'safe' check for whether Tracey's car is on its roof. /// RETURNS: /// TRUE only if the stuck check is active and the car's on its roof - cannot return TRUE when stuck check isn't active FUNC BOOL CAR_CURRENTLY_ON_ROOF() IF bStuckCheckActive AND IS_VEHICLE_STUCK_ON_ROOF(viTraceyCar) RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks the stalker's car's roll to see if it's probably on its roof /// RETURNS: /// TRUE if reasonably sure the stalker is upside down FUNC BOOL STALKER_CAR_UPSIDE_DOWN() IF IS_ENTITY_ALIVE(mvStalkerCar.vehicle) FLOAT fStalkRoll = WRAP(GET_ENTITY_ROLL(mvStalkerCar.vehicle), 0, 360) CPRINTLN(DEBUG_MISSION, "Clamped 0-360 stalker car roll is ", fStalkRoll) IF fStalkRoll > 150 AND fStalkRoll < 210 RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Sets the fail reason, mission stage track and stage progress /// PARAMS: /// sFailString - PROC SET_MISSION_FAILED(STRING sFailString) sFailReason = sFailString msTrack = MST_FAIL_FADE sProgress = SP_SETUP ENDPROC /// PURPOSE: /// Checks for player or Tracey death etc. /// RETURNS: /// TRUE if the mission is failed FUNC BOOL MISSION_FAIL_CHECKS() IF NOT IS_ENTITY_ALIVE(PLAYER_PED_ID()) // Player dead - FAIL SET_MISSION_FAILED("DEFAULT") RETURN TRUE ELIF bTraceyIsCurrentlySpawned // Tracey is currently spawned - do health checks etc. IF NOT IS_ENTITY_ALIVE(pedTracey) // Tracey dead - FAIL SET_MISSION_FAILED("MET1TRAKILL") // Tracey was killed. RETURN TRUE ELIF TRACEY_CAR_WRECKED() // Tracey's car was wrecked - Mission Fail SET_MISSION_FAILED("MET1TWRECK") // Tracey's car was wrecked. RETURN TRUE ELIF TRACEY_CAR_STUCK() // Tracey's car got stuck SET_MISSION_FAILED("MET1STUCK") RETURN TRUE ELSE // Stop Tracey using inappropriate idles SET_PED_CAN_PLAY_AMBIENT_BASE_ANIMS(pedTracey, FALSE) ENDIF ENDIF // None of the fail conditions have been met RETURN FALSE ENDFUNC /// PURPOSE: /// If the player becomes wanted while following Tracey, the stalker is scared off /// RETURNS: /// TRUE if the function detects and triggers the wanted fail state FUNC BOOL CHECK_WANTED_FAIL() IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 // Player is wanted - mission fail! sFailReason = "MET1CPSTALK" // The cops have scared off the stalker msTrack = MST_FAIL_FADE sProgress = SP_SETUP RETURN TRUE ELSE RETURN FALSE ENDIF ENDFUNC /// PURPOSE: /// Create friendly group if it doesn't exist, add Tracey to it PROC DO_FRIENDLY_GROUP_SETUP() IF NOT bRelGroupExists ADD_RELATIONSHIP_GROUP("FRIENDLIES", relGroupFriendly) SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, relGroupFriendly, RELGROUPHASH_PLAYER) SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, RELGROUPHASH_PLAYER, relGroupFriendly) bRelGroupExists = TRUE ENDIF IF IS_PED_IN_GROUP(pedTracey) REMOVE_PED_FROM_GROUP(pedTracey) ENDIF SET_PED_RELATIONSHIP_GROUP_HASH(pedTracey, relGroupFriendly) ENDPROC /// PURPOSE: /// Checks the distance between two locations is less than a given amount /// RETURNS: /// TRUE if in range FUNC BOOL ARE_PROGRESS_COORDS_IN_RANGE(VECTOR v1, VECTOR v2, FLOAT fRange) RETURN ( VDIST2(v1, v2) <= fRange*fRange ) ENDFUNC /// PURPOSE: /// Keep a set of points for tracking the stalker being stuck in the chase section. /// Also resets timer to delay the next check PROC UPDATE_STALKER_SAVED_POSITIONS(BOOL bOnFoot = FALSE) // Save timer for delaying next check iStalkerPositionTimer = GET_GAME_TIMER() // Shuffle stored positions vecStalkerPositionTrack[0] = vecStalkerPositionTrack[1] vecStalkerPositionTrack[1] = vecStalkerPositionTrack[2] vecStalkerPositionTrack[2] = vecStalkerPositionTrack[3] vecStalkerPositionTrack[3] = vecStalkerPositionTrack[4] vecStalkerPositionTrack[4] = vecStalkerPositionTrack[5] IF bOnFoot vecStalkerPositionTrack[5] = GET_ENTITY_COORDS(pedStalker) ELSE vecStalkerPositionTrack[5] = GET_ENTITY_COORDS(mvStalkerCar.vehicle) ENDIF ENDPROC /// PURPOSE: /// Set some arbitrary values to prevent him cowering instantly - for stuff like B*1115258/1115282 PROC FORCE_INIT_STALKER_FOOT_TRACKING() VECTOR vTmpSPos vTmpSPos = GET_ENTITY_COORDS(pedStalker) vecStalkerPositionTrack[0] = << vTmpSPos.x, vTmpSPos.y, vTmpSPos.z+15 >> vecStalkerPositionTrack[1] = << vTmpSPos.x, vTmpSPos.y, vTmpSPos.z+12 >> vecStalkerPositionTrack[2] = << vTmpSPos.x, vTmpSPos.y, vTmpSPos.z+9 >> vecStalkerPositionTrack[3] = << vTmpSPos.x, vTmpSPos.y, vTmpSPos.z+6 >> vecStalkerPositionTrack[4] = << vTmpSPos.x, vTmpSPos.y, vTmpSPos.z+3 >> vecStalkerPositionTrack[5] = vTmpSPos ENDPROC /// PURPOSE: /// Checks whether Tracey's car is in a position directly ahead of or behind the stalker. /// RETURNS: /// TRUE if the player is in a position that would mean he'd wedged him in FUNC BOOL PLAYER_HAS_WEDGED_STALKER_IN() IF IS_ENTITY_IN_RANGE_COORDS(viTraceyCar, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(mvStalkerCar.vehicle, << 0.0, 3.2, 0.5 >>), 3) OR IS_ENTITY_IN_RANGE_COORDS(viTraceyCar, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(mvStalkerCar.vehicle, << 0.0, -3.2, 0.5 >>), 3) RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Keep ticking the ped see ped checks for PROC TICK_TRACEY_OUTCOME_TESTS() CAN_PED_SEE_PED(pedTracey, PLAYER_PED_ID()) CAN_PED_SEE_PED(pedTracey, pedStalker) ENDPROC /// PURPOSE: /// Check whether Tracey was close to player when stalker died/escaped /// RETURNS: /// TRUE if Tracey would reasonably be expected to see what happened FUNC BOOL DID_TRACEY_SEE_OUTCOME() IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) AND IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) CPRINTLN(DEBUG_MISSION, "DID_TRACEY_SEE_OUTCOME: Michael is in car with Tracey.") RETURN TRUE ELSE IF bStalkerDead IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, 10.0) CPRINTLN(DEBUG_MISSION, "DID_TRACEY_SEE_OUTCOME: Stalker dead, Michael within 10m of Tracey.") RETURN TRUE ELIF IS_ENTITY_IN_RANGE_COORDS(pedTracey, GET_ENTITY_COORDS(pedStalker, FALSE), 10.0) CPRINTLN(DEBUG_MISSION, "DID_TRACEY_SEE_OUTCOME: Stalker dead,Tracey within 10m of stalker.") RETURN TRUE ELIF CAN_PED_SEE_PED(pedTracey, PLAYER_PED_ID()) CPRINTLN(DEBUG_MISSION, "DID_TRACEY_SEE_OUTCOME: Stalker dead, Tracey has LOS to Michael.") RETURN TRUE ELIF CAN_PED_SEE_PED(pedTracey, pedStalker) CPRINTLN(DEBUG_MISSION, "DID_TRACEY_SEE_OUTCOME: Stalker dead, Tracey has LOS to stalker.") RETURN TRUE ENDIF ELSE IF CAN_PED_SEE_PED(pedTracey, PLAYER_PED_ID()) CPRINTLN(DEBUG_MISSION, "DID_TRACEY_SEE_OUTCOME: Stalker alive, Tracey has LOS to Michael.") RETURN TRUE ENDIF ENDIF ENDIF CPRINTLN(DEBUG_MISSION, "DID_TRACEY_SEE_OUTCOME: Didn't see outcome") RETURN FALSE ENDFUNC /// PURPOSE: /// Initialise the bonkers driving tracking variables PROC INIT_BONKERS_DRIVING_CHECK() bBonkersDriving = FALSE iPedsDamaged = 0 iPedDamageTimeOut = GET_GAME_TIMER() + 2000 fTotalTimeOverSpeedLimit = 0 ENDPROC /// PURPOSE: /// Monitors whether the player is driving crazily outside the chase sections PROC PLAYER_BONKERS_DRIVING_CHECK() // Once we have established the player's bonkers credentials, stop checking IF bBonkersDriving = FALSE IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) AND IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) AND GET_ENTITY_SPEED(viTraceyCar) > 30 fTotalTimeOverSpeedLimit = fTotalTimeOverSpeedLimit +@ 1.0 ENDIF IF GET_GAME_TIMER() > iPedDamageTimeOut AND HAS_PLAYER_DAMAGED_AT_LEAST_ONE_PED(PLAYER_ID()) iPedsDamaged++ CLEAR_PLAYER_HAS_DAMAGED_AT_LEAST_ONE_PED(PLAYER_ID()) iPedDamageTimeOut = GET_GAME_TIMER() + 2000 ENDIF // Check bonkers rating IF iPedsDamaged > 2 OR fTotalTimeOverSpeedLimit > 10.0 bBonkersDriving = TRUE ENDIF ENDIF ENDPROC /// PURPOSE: /// Checks that Stalker is moving sensibly in car PROC STALKER_DRIVE_CHECK() IF IS_ENTITY_ALIVE(mvStalkerCar.vehicle) // See if it's time to check positions IF GET_GAME_TIMER() - iStalkerPositionTimer > 3000 UPDATE_STALKER_SAVED_POSITIONS() IF ARE_PROGRESS_COORDS_IN_RANGE(vecStalkerPositionTrack[3], vecStalkerPositionTrack[5], 2) AND PLAYER_HAS_WEDGED_STALKER_IN() CPRINTLN(DEBUG_MISSION, "STALKER_DRIVE_CHECK::: Stalker has moved less than 2m in last 6 seconds and the player has them boxed in") msTrack = MST_STALKER_WRECKED sProgress = SP_SETUP ELIF ARE_PROGRESS_COORDS_IN_RANGE(vecStalkerPositionTrack[0], vecStalkerPositionTrack[5], 2) CPRINTLN(DEBUG_MISSION, "STALKER_DRIVE_CHECK::: Stalker has moved less than 2m in last 15 seconds") msTrack = MST_STALKER_WRECKED sProgress = SP_SETUP #IF IS_DEBUG_BUILD ELIF bDebugStalkerTTY CPRINTLN(DEBUG_MISSION, "STALKER_DRIVE_CHECK::: Stalker OK, moved over 2m during last 6 seconds") #ENDIF ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Update the flee task given to the stalker /// PARAMS: /// bSetFootFlee - Whether we are setting the ped to flee the player instead of a coord PROC STALKER_REFRESH_FLEE_TASK(BOOL bSetFootFlee = FALSE, BOOL bForceLongTimer = FALSE) IF bSetFootFlee = FALSE // Update flee coordinates TASK_SMART_FLEE_COORD(pedStalker, GET_ENTITY_COORDS(PLAYER_PED_ID()), 2000.0, -1, FALSE) iChaseTaskTimer[CT_PROX_CHECK] = GET_GAME_TIMER() + CHASE_PROX_CHECK_TIME IF bForceLongTimer iChaseTaskTimer[CT_AREA_CHECK] = GET_GAME_TIMER() + CHASE_PROX_CHECK_TIME ELSE iChaseTaskTimer[CT_AREA_CHECK] = GET_GAME_TIMER() + CHASE_AREA_CHECK_TIME ENDIF bStalkerOnPedFleeTask = FALSE ELSE // Set to flee ped TASK_SMART_FLEE_PED(pedStalker, PLAYER_PED_ID(), 2000.0, -1, FALSE) iChaseTaskTimer[CT_PROX_CHECK] = GET_GAME_TIMER() + CHASE_PROX_CHECK_TIME IF bForceLongTimer iChaseTaskTimer[CT_AREA_CHECK] = GET_GAME_TIMER() + CHASE_PROX_CHECK_TIME ELSE iChaseTaskTimer[CT_AREA_CHECK] = GET_GAME_TIMER() + CHASE_AREA_CHECK_TIME ENDIF bStalkerOnPedFleeTask = TRUE ENDIF ENDPROC /// PURPOSE: /// Checks that Stalker is moving sensibly on foot PROC STALKER_FLEE_CHECK() IF NOT bStalkerCowering // See if it's time to check positions IF GET_GAME_TIMER() - iStalkerPositionTimer > 3000 // // Check stalker not trapped in car somehow // IF DOES_ENTITY_EXIST(mvStalkerCar.vehicle) // AND IS_PED_IN_VEHICLE(pedStalker, mvStalkerCar.vehicle) // CPRINTLN(DEBUG_MISSION, "STALKER_FLEE_CHECK: Stalker seems to be trapped in vehicle, emergency warp out!") // SEQUENCE_INDEX siTmpStuck // OPEN_SEQUENCE_TASK(siTmpStuck) // TASK_LEAVE_VEHICLE(NULL, mvStalkerCar.vehicle, ECF_WARP_IF_DOOR_IS_BLOCKED) // TASK_SMART_FLEE_COORD(NULL, GET_ENTITY_COORDS(PLAYER_PED_ID()), 2000.0, -1, FALSE) // CLOSE_SEQUENCE_TASK(siTmpStuck) // CLEAR_PED_TASKS(pedStalker) // // ELSE // UPDATE_STALKER_SAVED_POSITIONS(TRUE) IF ARE_PROGRESS_COORDS_IN_RANGE(vecStalkerPositionTrack[0], vecStalkerPositionTrack[2], 1) AND NOT IS_PED_IN_MELEE_COMBAT(pedStalker) AND NOT IS_PED_RAGDOLL(pedStalker) // Prevents firing if player has knocked him over AND NOT IS_PED_GETTING_UP(pedStalker) CPRINTLN(DEBUG_MISSION, "STALKER_FLEE_CHECK::: Stalker has moved less than 1m in last 6 seconds, not fighting") TASK_COWER(pedStalker) bStalkerCowering = TRUE #IF IS_DEBUG_BUILD ELIF bDebugStalkerTTY CPRINTLN(DEBUG_MISSION, "STALKER_FLEE_CHECK::: Stalker OK, moved over 1m during last 6 seconds") #ENDIF ENDIF ENDIF // ENDIF // Check for stalker direction change if we haven't set him to cower now IF NOT bStalkerCowering // Checks for when the player's stayed in the car IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT IS_PED_IN_ANY_VEHICLE(pedStalker) // Periodic check to update flee coordinates if the player car is nearby IF (GET_GAME_TIMER() > iChaseTaskTimer[CT_PROX_CHECK] AND IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, 20)) AND NOT IS_PED_RAGDOLL(pedStalker) // Prevents task spamming if player has knocked him over AND NOT IS_PED_GETTING_UP(pedStalker) // Prevents task spamming if player has knocked him over CPRINTLN(DEBUG_MISSION, "STALKER_FLEE_CHECK: Player in vehicle near fleeing stalker, periodically refreshing flee task") STALKER_REFRESH_FLEE_TASK(FALSE) ELSE // Periodic angled area check update - solidly timed, won't lurk once valid like the proximity check IF GET_GAME_TIMER() > iChaseTaskTimer[CT_AREA_CHECK] IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(pedStalker, <<0.0, 1.0, -2.0>>), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(pedStalker, <<0.0, 7.0, 5.0>>), 5) AND NOT IS_PED_RAGDOLL(pedStalker) // Prevents task spamming if player has knocked him over AND NOT IS_PED_GETTING_UP(pedStalker) // Prevents task spamming if player has knocked him over CPRINTLN(DEBUG_MISSION, "STALKER_FLEE_CHECK: Player in vehicle in front of fleeing stalker, doing faster refresh check") STALKER_REFRESH_FLEE_TASK(FALSE, TRUE) ELSE // Reset timer iChaseTaskTimer[CT_AREA_CHECK] = GET_GAME_TIMER() + CHASE_AREA_CHECK_TIME ENDIF // // Touching check // ELIF IS_ENTITY_TOUCHING_ENTITY(pedStalker, PLAYER_PED_ID()) // AND NOT IS_PED_RAGDOLL(pedStalker) // Prevents task spamming if player has knocked him over // AND NOT IS_PED_GETTING_UP(pedStalker) // Prevents task spamming if player has knocked him over // CPRINTLN(DEBUG_MISSION, "STALKER_FLEE_CHECK: Player vehicle touching fleeing stalker, doing faster refresh check") // STALKER_REFRESH_FLEE_TASK(FALSE, TRUE) ENDIF ENDIF // Check for when the stalker is on foot - leave him on a ped flee task for this ELIF NOT bStalkerOnPedFleeTask AND NOT IS_PED_IN_ANY_VEHICLE(pedStalker) CPRINTLN(DEBUG_MISSION, "STALKER_FLEE_CHECK: Player on foot, set to ped flee task") STALKER_REFRESH_FLEE_TASK(TRUE, TRUE) ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Checks whether the player is heading up or down the hill the stalker should spawn on /// RETURNS: /// TRUE if downhill FUNC BOOL PLAYER_IS_DOWNHILL() VECTOR tmpPlyrPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) IF tmpPlyrPos.z < dpLocates[NUM_DESTINATIONS-1].location.z RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks that the stalker car spawn point isn't on screen, and that the player isn't miles away PROC CHECK_STALKER_SPAWN_OCCLUSION() INT iTmpSpawnIndex // Check player is in range of initial spawn point IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), dpLocates[NUM_DESTINATIONS-1].location, dpLocates[NUM_DESTINATIONS-1].range) CPRINTLN(DEBUG_MISSION, "CHECK_STALKER_SPAWN_OCCLUSION: Player in range of standard trigger point") // If the preferred point is in view of player, spawn opposite IF WOULD_ENTITY_BE_OCCLUDED(mvStalkerCar.model, vecStalkerSpawnPoint[0], FALSE) iTmpSpawnIndex = 0 ELSE iTmpSpawnIndex = 1 ENDIF // Set the points mvStalkerCar.location = vecStalkerSpawnPoint[iTmpSpawnIndex] mvStalkerCar.heading = fStalkerSpawnHead[iTmpSpawnIndex] mvStalkerCar.initialSpeed = 15.0 ELSE CPRINTLN(DEBUG_MISSION, "CHECK_STALKER_SPAWN_OCCLUSION: Player OUT OF RANGE of standard trigger point") // Check whether we should be looking further up or down the hill IF PLAYER_IS_DOWNHILL() // Check the downhill spawns IF WOULD_ENTITY_BE_OCCLUDED(mvStalkerCar.model, vecStalkerSpawnPoint[2], FALSE) iTmpSpawnIndex = 2 ELSE iTmpSpawnIndex = 3 ENDIF ELSE // Check the uphill spawns IF WOULD_ENTITY_BE_OCCLUDED(mvStalkerCar.model, vecStalkerSpawnPoint[4], FALSE) iTmpSpawnIndex = 4 ELSE iTmpSpawnIndex = 5 ENDIF ENDIF // Set the points mvStalkerCar.location = vecStalkerSpawnPoint[iTmpSpawnIndex] mvStalkerCar.heading = fStalkerSpawnHead[iTmpSpawnIndex] mvStalkerCar.initialSpeed = 25.0 ENDIF CPRINTLN(DEBUG_MISSION, "Stalker spawnpoint set to ", iTmpSpawnIndex) ENDPROC /// PURPOSE: /// Make them look around for the stalker PROC LOOK_AROUND_FOR_STALKER() SEQUENCE_INDEX seqLook[2] VECTOR vLookAt[4] INT iTimings[2][4] INT iSeqOrder[2][3] // Get some points to look at vLookAt[0] = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(viTraceyCar, << -8.0, 2.0, 0.0 >>) // Left vLookAt[1] = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(viTraceyCar, << -8.0, 8.0, 0.0 >>) // Left/forward vLookAt[2] = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(viTraceyCar, << 8.0, 2.0, 0.0 >>) // Right vLookAt[3] = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(viTraceyCar, << 8.0, 8.0, 0.0 >>) // Right/forward // Set up Tracey - pick indexes to choose lookat points in the array of points we just set up // Pick initial point entirely at random iSeqOrder[0][0] = GET_RANDOM_INT_IN_RANGE(0,3) // Pick second point on opposite side IF iSeqOrder[0][0] < 2 iSeqOrder[0][1] = GET_RANDOM_INT_IN_RANGE(2,3) ELSE iSeqOrder[0][1] = GET_RANDOM_INT_IN_RANGE(0,1) ENDIF // Pick third point on original side IF iSeqOrder[0][0] > 1 iSeqOrder[0][2] = GET_RANDOM_INT_IN_RANGE(2,3) ELSE iSeqOrder[0][2] = GET_RANDOM_INT_IN_RANGE(0,1) ENDIF // Set up some timings iTimings[0][0] = GET_RANDOM_INT_IN_RANGE(300,600) iTimings[0][1] = GET_RANDOM_INT_IN_RANGE(400,1000) iTimings[0][2] = GET_RANDOM_INT_IN_RANGE(500,1000) iTimings[0][3] = GET_RANDOM_INT_IN_RANGE(500,1000) // Create Tracey's Task sequence OPEN_SEQUENCE_TASK(seqLook[0]) TASK_PAUSE(NULL, iTimings[0][0]) TASK_LOOK_AT_COORD(NULL, vLookAt[iSeqOrder[0][0]], iTimings[0][1], SLF_WHILE_NOT_IN_FOV) TASK_LOOK_AT_COORD(NULL, vLookAt[iSeqOrder[0][1]], iTimings[0][2], SLF_WHILE_NOT_IN_FOV) TASK_LOOK_AT_COORD(NULL, vLookAt[iSeqOrder[0][2]], iTimings[0][3], SLF_WHILE_NOT_IN_FOV) CLOSE_SEQUENCE_TASK(seqLook[0]) TASK_PERFORM_SEQUENCE(pedTracey, seqLook[0]) CLEAR_SEQUENCE_TASK(seqLook[0]) // Set up Michael - pick indexes to choose lookat points in the array of points we just set up // Pick initial point entirely at random iSeqOrder[1][0] = GET_RANDOM_INT_IN_RANGE(0,3) // Pick again if it exactly matches Tracey's IF iSeqOrder[0][0] = iSeqOrder[1][0] iSeqOrder[1][0] = GET_RANDOM_INT_IN_RANGE(0,3) ENDIF // Pick second point on opposite side IF iSeqOrder[1][0] < 2 iSeqOrder[1][1] = GET_RANDOM_INT_IN_RANGE(2,3) ELSE iSeqOrder[1][1] = GET_RANDOM_INT_IN_RANGE(0,1) ENDIF // Pick third point on original side IF iSeqOrder[1][0] > 1 iSeqOrder[1][1] = GET_RANDOM_INT_IN_RANGE(2,3) ELSE iSeqOrder[1][1] = GET_RANDOM_INT_IN_RANGE(0,1) ENDIF // Set up some timings iTimings[1][0] = 0 // We don't pause the player iTimings[1][1] = GET_RANDOM_INT_IN_RANGE(500,1000) iTimings[1][2] = GET_RANDOM_INT_IN_RANGE(500,1000) iTimings[1][3] = GET_RANDOM_INT_IN_RANGE(500,1000) // Create Tracey's Task sequence OPEN_SEQUENCE_TASK(seqLook[1]) TASK_PAUSE(NULL, iTimings[1][0]) TASK_LOOK_AT_COORD(NULL, vLookAt[iSeqOrder[1][0]], iTimings[1][1], SLF_WHILE_NOT_IN_FOV) TASK_LOOK_AT_COORD(NULL, vLookAt[iSeqOrder[1][1]], iTimings[1][2], SLF_WHILE_NOT_IN_FOV) TASK_LOOK_AT_COORD(NULL, vLookAt[iSeqOrder[1][2]], iTimings[1][3], SLF_WHILE_NOT_IN_FOV) CLOSE_SEQUENCE_TASK(seqLook[1]) TASK_PERFORM_SEQUENCE(PLAYER_PED_ID(), seqLook[1]) CLEAR_SEQUENCE_TASK(seqLook[1]) ENDPROC /// PURPOSE: /// Sets the audio scene to match the mission stage specified /// PARAMS: /// audioScene - index for the audio scene state, use the constants beginning "AUDIOSCENE_" PROC UPDATE_AUDIO_SCENE(INT iNewAudioScene) // Check we aren't already using the requested scene IF iCurrentAudioScene <> iNewAudioScene // Check for deactivating active scenes FOR iCount = 0 TO NUM_AUDIOSCENES-1 // See if this is the scene state to change to IF iCount = iNewAudioScene IF NOT ARE_STRINGS_EQUAL(sAudioScenes[iCount], "NONE") CPRINTLN(DEBUG_MISSION, "Starting audioscene ", sAudioScenes[iCount]) START_AUDIO_SCENE(sAudioScenes[iCount]) ENDIF iCurrentAudioScene = iNewAudioScene // See if we need to kill an audio scene ELIF IS_AUDIO_SCENE_ACTIVE(sAudioScenes[iCount]) CPRINTLN(DEBUG_MISSION, "Stopping audioscene ", sAudioScenes[iCount]) STOP_AUDIO_SCENE(sAudioScenes[iCount]) ENDIF ENDFOR ENDIF ENDPROC /// PURPOSE: /// Toggles the audio scene overlay for the focus cam on and off /// PARAMS: /// bEnable - TRUE to toggle on, FALSE for off PROC TOGGLE_FOCUS_AUDIO_SCENE(BOOL bEnable = TRUE) IF bEnable AND NOT IS_AUDIO_SCENE_ACTIVE("M_E_TRACEY_FOCUS_CAM") CPRINTLN(DEBUG_MISSION, "Starting audioscene M_E_TRACEY_FOCUS_CAM") START_AUDIO_SCENE("M_E_TRACEY_FOCUS_CAM") ELIF bEnable = FALSE AND IS_AUDIO_SCENE_ACTIVE("M_E_TRACEY_FOCUS_CAM") CPRINTLN(DEBUG_MISSION, "Stopping audioscene M_E_TRACEY_FOCUS_CAM") STOP_AUDIO_SCENE("M_E_TRACEY_FOCUS_CAM") ENDIF ENDPROC /// PURPOSE: /// Video Editor: Mark point when the stalker got killed PROC START_STALKER_SNUFF_MOVIE() CPRINTLN(DEBUG_MISSION, "START_STALKER_SNUFF_MOVIE: Marking required start point") bStalkerSnuffMovieStarted = TRUE iStalkerSnuffTimer = GET_GAME_TIMER() ENDPROC /// PURPOSE: /// If the stalker is dead and we marked a start point for the movie, this will stop it when appropriate PROC MONITOR_STALKER_SNUFF_MOVIE() // If we never started, nothing else to check IF NOT bStalkerSnuffMovieStarted EXIT ENDIF // If we triggered the recording, nothing else to check IF bStalkerSnuffMovieFinished EXIT ENDIF // The movie is still running - is it time to stop yet? // Test to see if Tracey saw the stalker die - note that the outcome was always "death" if the movie started IF bTraceySawOutcome AND GET_GAME_TIMER() - iStalkerSnuffTimer > SNUFF_TIMER_TRACEY_SAW CPRINTLN(DEBUG_MISSION, "MONITOR_STALKER_SNUFF_MOVIE: Kicking in the retro record, bTraceySawOutcome=TRUE and timer>SNUFF_TIMER_TRACEY_SAW") REPLAY_RECORD_BACK_FOR_TIME(SNUFF_TIMER_RETRORECORD+(SNUFF_TIMER_TRACEY_SAW/1000)) bStalkerSnuffMovieFinished = TRUE ENDIF // When Tracey didn't see, ends recording sooner IF NOT bTraceySawOutcome AND GET_GAME_TIMER() - iStalkerSnuffTimer > SNUFF_TIMER_DIDNT_SEE CPRINTLN(DEBUG_MISSION, "MONITOR_STALKER_SNUFF_MOVIE: Kicking in the retro record, bTraceySawOutcome=FALSE and timer>SNUFF_TIMER_DIDNT_SEE") REPLAY_RECORD_BACK_FOR_TIME(SNUFF_TIMER_RETRORECORD+(SNUFF_TIMER_DIDNT_SEE/1000)) bStalkerSnuffMovieFinished = TRUE ENDIF ENDPROC //************************************************************************************************************************************************* // // Data setup procs // //************************************************************************************************************************************************* /// PURPOSE: /// Store setup for Stalker's car and any other NPC cars that get added PROC SETUP_NPC_CARS() mvStalkerCar.model = TORNADO2 mvStalkerCar.carModelRequestActive = FALSE mvStalkerCar.location = << -58.8963, -191.2678, 51.1096 >> mvStalkerCar.heading = 66.9 ENDPROC /// PURPOSE: /// Stores audio scene names PROC STORE_AUDIOSCENES() sAudioScenes[AUDIOSCENE_NONE] = "NONE" sAudioScenes[AUDIOSCENE_GO_TO_TRACEY] = "M_E_TRACEY_GO_TO_TRACEY" sAudioScenes[AUDIOSCENE_ENTER_TRACEYS_CAR] = "M_E_TRACEY_ENTER_TRACEYS_CAR" sAudioScenes[AUDIOSCENE_DRIVE_TO_STALKER] = "M_E_TRACEY_FIND_STALKER" sAudioScenes[AUDIOSCENE_CHASE] = "M_E_TRACEY_STOP_STALKERS_CAR" // sAudioScenes[AUDIOSCENE_CHASE_FOCUS_CAM] = "M_E_TRACEY_FOCUS_CAM" sAudioScenes[AUDIOSCENE_CHASE_FOOT] = "M_E_TRACEY_DEAL_WITH_STALKER" sAudioScenes[AUDIOSCENE_DRIVE_HOME] = "M_E_TRACEY_TAKE_TRACEY_HOME" sAudioScenes[AUDIOSCENE_DONE] = "NONE" ENDPROC /// PURPOSE: /// Fills in structs for the destinations that Tracey guides the player to PROC STORE_DESTINATION_POINTS() iCount = 0 // Hawaiian Snow/Oeuvre Gallery dpLocates[iCount].location = <<245.6922, -209.0348, 52.8895>> dpLocates[iCount].range = 20 dpLocates[iCount].chatLabel = "MET1_LOC1" dpLocates[iCount].extraChatLabel = "MET1_CHAT1" dpLocates[iCount].bonkersChatLabel = "NULL" dpLocates[iCount].blipUpdateLine = 1 iCount++ // Motel dpLocates[iCount].location = <<52.7660, -283.8273, 46.6203>> dpLocates[iCount].range = 20 dpLocates[iCount].chatLabel = "MET1_LOC2" dpLocates[iCount].extraChatLabel = "MET1_CHAT2" dpLocates[iCount].bonkersChatLabel = "MET1_CHAT2C" dpLocates[iCount].blipUpdateLine = 2 iCount++ // Cluckin' Bell dpLocates[iCount].location = <<-129.7824, -259.7662, 42.2812>> dpLocates[iCount].range = 20 dpLocates[iCount].chatLabel = "MET1_LOC3" dpLocates[iCount].extraChatLabel = "MET1_CHAT3" dpLocates[iCount].bonkersChatLabel = "MET1_CHAT3C" dpLocates[iCount].blipUpdateLine = 2 iCount++ // Rockford past Croq-a-hoop dpLocates[iCount].location = <<-160.4700, -75.1948, 52.7966>> dpLocates[iCount].range = 40 dpLocates[iCount].chatLabel = "MET1_LOC4" dpLocates[iCount].extraChatLabel = "MET1_CHAT4" dpLocates[iCount].bonkersChatLabel = "MET1_CHAT4C" dpLocates[iCount].blipUpdateLine = 2 iCount++ iCurrentDestination = 0 ENDPROC /// PURPOSE: /// Stores the information needed for a non-axis aligned area PROC SETUP_NAA_VOLUME(NAA_VOLUME& naaVol, VECTOR v1, VECTOR v2, FLOAT fWidth) naaVol.vEnds[0] = v1 naaVol.vEnds[1] = v2 naaVol.fWidth = fWidth ENDPROC /// PURPOSE: /// set up the stalker trigger volumes and spawn locations PROC STORE_STALKER_TRIGGERS() // Standard spawns vecStalkerSpawnPoint[0] = <<-224.0988, -62.9169, 48.8994>> fStalkerSpawnHead[0] = 250.2 vecStalkerSpawnPoint[1] = <<-98.7688, -90.0482, 56.5581>> fStalkerSpawnHead[1] = 72.7 // Downhill spawns vecStalkerSpawnPoint[2] = <<-190.0195, -64.3358, 50.6959>> fStalkerSpawnHead[2] = 70.37 vecStalkerSpawnPoint[3] = <<-254.3389, -16.5055, 48.7322>> fStalkerSpawnHead[3] = 170.42 // Uphill spawns vecStalkerSpawnPoint[4] = <<-145.0999, -91.2274, 54.1001>> fStalkerSpawnHead[4] = 249.33 vecStalkerSpawnPoint[5] = <<-35.9104, -97.4508, 56.3653>> fStalkerSpawnHead[5] = 163.63 ENDPROC /// PURPOSE: /// Stores the data needed for all the conversations that use the CONVERSATION_INFO struct PROC SETUP_ENROUTE_CHAT() // Michael/Stalker conversations during the chase ciChaseConversations[0].startDelay = 0 ciChaseConversations[0].txtBlock = "MET1AUD" ciChaseConversations[0].rootBlock = "MET1_TRCC1" ciChaseConversations[1].startDelay = 0 ciChaseConversations[1].txtBlock = "MET1AUD" ciChaseConversations[1].rootBlock = "MET1_TRCC2" ciChaseConversations[2].startDelay = 0 ciChaseConversations[2].txtBlock = "MET1AUD" ciChaseConversations[2].rootBlock = "MET1_TRCC3" ciChaseConversations[3].startDelay = 0 ciChaseConversations[3].txtBlock = "MET1AUD" ciChaseConversations[3].rootBlock = "MET1_TRCC4" ciChaseConversations[4].startDelay = 0 ciChaseConversations[4].txtBlock = "MET1AUD" ciChaseConversations[4].rootBlock = "MET1_TRCC5" // Tracey/Michael conversations during the chase ciTraceyChaseConversations[0].startDelay = 0 ciTraceyChaseConversations[0].txtBlock = "MET1AUD" ciTraceyChaseConversations[0].rootBlock = "MET1_ST1" ciTraceyChaseConversations[1].startDelay = 0 ciTraceyChaseConversations[1].txtBlock = "MET1AUD" ciTraceyChaseConversations[1].rootBlock = "MET1_ST2" ciTraceyChaseConversations[2].startDelay = 0 ciTraceyChaseConversations[2].txtBlock = "MET1AUD" ciTraceyChaseConversations[2].rootBlock = "MET1_ST3" ciTraceyChaseConversations[3].startDelay = 0 ciTraceyChaseConversations[3].txtBlock = "MET1AUD" ciTraceyChaseConversations[3].rootBlock = "MET1_ST4" // Michael/stalker conversations once stalker is on foot ciFootChaseConversations[0].startDelay = 0 ciFootChaseConversations[0].txtBlock = "MET1AUD" ciFootChaseConversations[0].rootBlock = "MET1_STW1" ciFootChaseConversations[1].startDelay = 0 ciFootChaseConversations[1].txtBlock = "MET1AUD" ciFootChaseConversations[1].rootBlock = "MET1_STW2" ciFootChaseConversations[2].startDelay = 0 ciFootChaseConversations[2].txtBlock = "MET1AUD" ciFootChaseConversations[2].rootBlock = "MET1_STW3" // Tracey/Michael conversations once stalker is on foot ciTraceyFootChaseConversations[0].startDelay = 0 ciTraceyFootChaseConversations[0].txtBlock = "MET1AUD" ciTraceyFootChaseConversations[0].rootBlock = "MET1_TRFC1" ciTraceyFootChaseConversations[1].startDelay = 0 ciTraceyFootChaseConversations[1].txtBlock = "MET1AUD" ciTraceyFootChaseConversations[1].rootBlock = "MET1_TRFC2" ciTraceyFootChaseConversations[2].startDelay = 0 ciTraceyFootChaseConversations[2].txtBlock = "MET1AUD" ciTraceyFootChaseConversations[2].rootBlock = "MET1_TRFC3" // Tracey/Michael conversations during drive home ciDriveHomeChat[0].startDelay = 0 ciDriveHomeChat[0].txtBlock = "MET1AUD" ciDriveHomeChat[0].rootBlock = "MET1_TSDEAD1" // Initial dead comment - if Tracey saw ciDriveHomeChat[1].startDelay = 0 ciDriveHomeChat[1].txtBlock = "MET1AUD" ciDriveHomeChat[1].rootBlock = "MET1_TSDEAD2" // Initial dead comment - if Tracey didn't see ciDriveHomeChat[2].startDelay = 0 ciDriveHomeChat[2].txtBlock = "MET1AUD" ciDriveHomeChat[2].rootBlock = "MET1_TSESCP1" // Initial escape comment - if Tracey didn't see ciDriveHomeChat[3].startDelay = 5000 ciDriveHomeChat[3].txtBlock = "MET1AUD" ciDriveHomeChat[3].rootBlock = "MET1_GOHOM1" // Delayed secondary kill comment ciDriveHomeChat[4].startDelay = 8000 ciDriveHomeChat[4].txtBlock = "MET1AUD" ciDriveHomeChat[4].rootBlock = "MET1_GOHOM2" // Delayed car trashed comment ciDriveHomeChat[5].startDelay = 8000 ciDriveHomeChat[5].txtBlock = "MET1AUD" ciDriveHomeChat[5].rootBlock = "MET1_GOHOM3" // Delayed secondary escape comment ciDriveHomeChat[6].startDelay = 8000 ciDriveHomeChat[6].txtBlock = "MET1AUD" ciDriveHomeChat[6].rootBlock = "MET1_GOHOM4" // Tracey asks if anyone's trying to kill Michael ciDriveHomeChat[7].startDelay = 8000 ciDriveHomeChat[7].txtBlock = "MET1AUD" ciDriveHomeChat[7].rootBlock = "MET1_GOHOM5" // Michael asks if Tracey has heard from Lazlow ciDriveHomeChat[8].startDelay = 0 ciDriveHomeChat[8].txtBlock = "MET1AUD" ciDriveHomeChat[8].rootBlock = "MET1_GOHOMC" // Special comment if player's driving crazily ENDPROC //************************************************************************************************************************************************* // // Flow/progression procs // //************************************************************************************************************************************************* /// PURPOSE: /// Initialise the tracking variables needed for checking elapsed in-game clock time PROC INIT_DRIVE_TIMERS() iStartDate = GET_CLOCK_DAY_OF_MONTH() iStartHours = GET_CLOCK_HOURS() iStartMinutes = GET_CLOCK_MINUTES() ENDPROC /// PURPOSE: /// Checks whether more than a certain amount of in-game clock time has passed. Good for up to 23 hours. /// PARAMS: /// hoursAllowed - the elapsed time we are looking for /// RETURNS: /// TRUE if the requested amount of time has passed FUNC BOOL GAMECLOCK_TIMER_EXCEEDED(INT hoursAllowed) INT iTimePassed//, iTmpStartTime IF GET_CLOCK_DAY_OF_MONTH() <> iStartDate iTimePassed = 60*((24 - iStartHours) + GET_CLOCK_HOURS()) iTimePassed = iTimePassed - iStartMinutes + GET_CLOCK_MINUTES() ELSE // Can just subtract the minute total for the start time away from the end time iTimePassed = ((60*GET_CLOCK_HOURS()) + GET_CLOCK_MINUTES()) - (iStartMinutes + (60*iStartHours)) ENDIF // iMinutesPassed = GET_CLOCK_MINUTES() - iStartMinutes // IF iMinutesPassed < 0 // iMinutesPassed = iMinutesPassed + 60 // ENDIF // // iTimePassed = iTimePassed + iMinutesPassed #IF IS_DEBUG_BUILD IF bDebugCallTimeDisplay DISPLAY_TEXT_WITH_FLOAT(0.9, 0.125, "DM_NUM", TO_FLOAT(iTimePassed), 0) ENDIF #ENDIF IF iTimePassed >= 60*hoursAllowed RETURN TRUE ELSE RETURN FALSE ENDIF ENDFUNC /// PURPOSE: /// Checks whether the player should fail for taking too long, after triggering a call warning them to hurry up first /// RETURNS: /// TRUE if the failure call has been triggered. FUNC BOOL CHECK_WARNING_CALL() SWITCH wfcProgress CASE WFC_SETUP IF NOT bWFCOnHold // As progress might have been paused, see if we need to skip on to the fail call IF GAMECLOCK_TIMER_EXCEEDED(RENDEZVOUS_TIMER) wfcProgress = WFC_CHECK_FOR_FAIL // Check for standard warning call ELIF GAMECLOCK_TIMER_EXCEEDED(WARNING_TIMER) CPRINTLN(DEBUG_MISSION, "Warning call time!") IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() wfcProgress = WFC_START_WARNING_CALL ENDIF ENDIF ENDIF BREAK CASE WFC_START_WARNING_CALL IF NOT bWFCOnHold // Player still far enough away to call REMOVE_PED_FOR_DIALOGUE(mConversationStruct, 3) ADD_PED_FOR_DIALOGUE(mConversationStruct, 3, NULL, "TRACEY") IF CHAR_CALL_PLAYER_CELLPHONE_FORCE_ANSWER(mConversationStruct, CHAR_TRACEY, "MET1AUD", "MET1_WARN2", CONV_PRIORITY_MEDIUM, DISPLAY_SUBTITLES) wfcProgress = WFC_WAIT_FOR_WARNING ENDIF ENDIF BREAK CASE WFC_WAIT_FOR_WARNING IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() wfcProgress = WFC_CHECK_FOR_FAIL ENDIF BREAK CASE WFC_CHECK_FOR_FAIL IF NOT bWFCOnHold IF GAMECLOCK_TIMER_EXCEEDED(RENDEZVOUS_TIMER) REMOVE_PED_FOR_DIALOGUE(mConversationStruct,3) ADD_PED_FOR_DIALOGUE(mConversationStruct, 3, NULL, "TRACEY") msTrack = MST_FAIL_CALL sProgress = SP_SETUP RETURN TRUE ENDIF ENDIF BREAK CASE WFC_ARRIVED_WAIT IF GET_GAME_TIMER() - iFootDawdleTimer > ARRIVED_TIMER_WARN REMOVE_PED_FOR_DIALOGUE(mConversationStruct, 3) ADD_PED_FOR_DIALOGUE(mConversationStruct, 3, pedTracey, "TRACEY") wfcProgress = WFC_ARRIVED_WARN ENDIF BREAK CASE WFC_ARRIVED_WARN // Player is close enough to Tracey that a phone call would be ridiculous IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_WARNC", CONV_PRIORITY_MEDIUM)//, DO_NOT_DISPLAY_SUBTITLES) iFootDawdleTimer = GET_GAME_TIMER() wfcProgress = WFC_ARRIVED_WAIT ENDIF BREAK // Not currently allowing time out fails once player has reached car park // CASE WFC_ARRIVED_CHECK_FOR_FAIL // // IF GET_GAME_TIMER() - iFootDawdleTimer > ARRIVED_TIMER_FAIL // We'll need to replace with a new timer if this goes back in // ADD_PED_FOR_DIALOGUE(mConversationStruct, 3, pedTracey, "TRACEY") // msTrack = MST_FAIL_TRACEY_DRIVE_OFF // sProgress = SP_SETUP // RETURN TRUE // ENDIF // BREAK CASE WFC_DONE // Don't run these checks any more BREAK ENDSWITCH // If we reach the end, no time-up fail yet RETURN FALSE ENDFUNC /// PURPOSE: /// Tracey mutters to herself while waiting for Michael PROC TRACEY_WAITING_DIALOGUE() SWITCH cptTraceyWaitingComments CASE CPT_WAIT_TO_TRIGGER IF GET_GAME_TIMER() - iTraceyWaitingChatTimer > 5000 AND IS_ENTITY_IN_RANGE_ENTITY(pedTracey, PLAYER_PED_ID(), 25) CPRINTLN(DEBUG_MISSION, "ME_TRACEY1::: Starting Tracey waiting comment") cptTraceyWaitingComments = CPT_START_CONVERSATION ENDIF BREAK CASE CPT_START_CONVERSATION IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_PACE", CONV_PRIORITY_MEDIUM) IF iCurrentAudioScene <> AUDIOSCENE_ENTER_TRACEYS_CAR UPDATE_AUDIO_SCENE(AUDIOSCENE_ENTER_TRACEYS_CAR) ENDIF cptTraceyWaitingComments = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK CASE CPT_WAIT_TO_FINISH IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() iTraceyWaitingConversationCount++ IF iTraceyWaitingConversationCount < 4 iTraceyWaitingChatTimer = GET_GAME_TIMER() cptTraceyWaitingComments = CPT_WAIT_TO_TRIGGER ELSE cptTraceyWaitingComments = CPT_SPENT ENDIF ENDIF BREAK CASE CPT_SPENT BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Tracks Tracey's car moving for purposes of triggering complaint conversations PROC UPDATE_TRACEYCAR_SAVED_COORDS() IF GET_GAME_TIMER() - iTraceyPositionTimer > 3000 vecTraceyPositionTrack[0] = vecTraceyPositionTrack[1] vecTraceyPositionTrack[1] = vecTraceyPositionTrack[2] vecTraceyPositionTrack[2] = GET_ENTITY_COORDS(viTraceyCar) iTraceyPositionTimer = GET_GAME_TIMER() ENDIF ENDPROC /// PURPOSE: /// Checks whether Tracey's car is more or less stationary /// RETURNS: /// TRUE if moved less than 2m in 6 seconds FUNC BOOL NOT_GOING_ANYWHERE() IF ARE_PROGRESS_COORDS_IN_RANGE(vecTraceyPositionTrack[0], vecTraceyPositionTrack[2], 2) RETURN TRUE ENDIF iComplainTimer = GET_GAME_TIMER() RETURN FALSE ENDFUNC /// PURPOSE: /// Trigger incidental banter during the drive. PROC BANTER_CONTROLLER() // If no dialogue playing and situation is generally OK for it, check for Tracey complaint about player idling IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() AND NOT CAR_CURRENTLY_ON_ROOF() AND IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) // See if we've been sitting still for too long IF NOT_GOING_ANYWHERE() AND GET_GAME_TIMER() - iComplainTimer > NOT_GOING_DELAY CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_NOTGO", CONV_PRIORITY_AMBIENT_HIGH) iComplainTimer = GET_GAME_TIMER() ENDIF ENDIF ENDPROC /// PURPOSE: /// Checks whether the player is shooting /// RETURNS: /// TRUE if player has fired a weapon in last few seconds FUNC BOOL PLAYER_SHOT_RECENTLY() // Update shooting timer IF IS_PED_SHOOTING(PLAYER_PED_ID()) iShootingTimer = GET_GAME_TIMER() RETURN TRUE // Check if time since we last detected firing is less that timeout ELSE INT iTmpTime = GET_GAME_TIMER() - iShootingTimer IF iTmpTime > 0 AND iTmpTime < RECENT_SHOOTING_TIMEOUT RETURN TRUE ENDIF ENDIF // Player hasn't shot recently RETURN FALSE ENDFUNC /// PURPOSE: /// Used as part of checks to make Tracey complain if the player rams things that aren't the stalker's car. /// Safe test to prevent assert on stalker's car if it's dead. /// (Tracey's car has a death check higher up so not a concern) /// RETURNS: /// TRUE for collisions that aren't a live stalker car FUNC BOOL TRACEY_CAR_COLLISION_CHECK() IF HAS_ENTITY_COLLIDED_WITH_ANYTHING(viTraceyCar) IF IS_ENTITY_ALIVE(mvStalkerCar.vehicle) AND IS_ENTITY_TOUCHING_ENTITY(viTraceyCar, mvStalkerCar.vehicle) // Bashing the stalker doesn't count as a collision RETURN FALSE ENDIF // Either the stalker's car is dead or it's not what we collided with! RETURN TRUE ENDIF // No collision has occured RETURN FALSE ENDFUNC /// PURPOSE: /// Triggers dialogue in the car chase - /// - Michael shouting at stalker /// - Tracey fretting/banter /// - Tracey commenting if stalker is getting away /// - Tracey commenting if they ram the stalker's car PROC STALKER_CHASE_CHAT() // Check for wait override chat types first - these can short-circuit the switch if no other conversation is running // Quick ram comment IF bQuickRamComment = TRUE AND (cptChaseTrack = CPT_WAIT_TO_TRIGGER OR cptChaseTrack = CPT_PICK_CONVERSATION) cptChaseTrack = CPT_START_CONVERSATION_RAMARK ELSE // Can't trigger a remark just now - reset the flag bQuickRamComment = FALSE ENDIF // Check for other collisions stopping the player car iTimeSinceCollision = GET_GAME_TIMER() - iLastCollisionTime IF iTimeSinceCollision > 0 AND iTimeSinceCollision < 250 AND (cptChaseTrack = CPT_WAIT_TO_TRIGGER OR cptChaseTrack = CPT_PICK_CONVERSATION) AND GET_ENTITY_SPEED(viTraceyCar) < 1.5 // 1.0 AND GET_ENTITY_SPEED(mvStalkerCar.vehicle) > 3.0 // 2.0 // Crashed complaint CPRINTLN(DEBUG_MISSION, "Tracey car smash - play an escape conversation") cptChaseTrack = CPT_START_CONVERSATION_ESCAPING ENDIF // IF HAS_ENTITY_COLLIDED_WITH_ANYTHING(viTraceyCar) // AND NOT IS_ENTITY_TOUCHING_ENTITY(viTraceyCar, mvStalkerCar.vehicle) IF TRACEY_CAR_COLLISION_CHECK() CPRINTLN(DEBUG_MISSION, "Tracey's car collided with something this frame") iLastCollisionTime = GET_GAME_TIMER() ENDIF // Check for shooting and trigger a complaint if it's been long enough since the last one // Not inside the case statement so we can keep updating the timer in PLAYER_SHOT_RECENTLY IF PLAYER_SHOT_RECENTLY() AND GET_GAME_TIMER() > iShootingComplaintGap CPRINTLN(DEBUG_MISSION, "Player shot recently and it's been a while since we last scolded them, checking if safe to trigger") IF cptChaseTrack = CPT_WAIT_TO_TRIGGER OR cptChaseTrack = CPT_PICK_CONVERSATION CPRINTLN(DEBUG_MISSION, "Player shot recently and it's been a while since we last scolded them, safe to trigger Tracey complaint") cptChaseTrack = CPT_START_CONVERSATION_TRACEY_WTF ENDIF ENDIF SWITCH cptChaseTrack // Wait for a decent time to pass since last comment CASE CPT_WAIT_TO_TRIGGER // Wait to trigger conversation IF GET_GAME_TIMER() - iChaseChatTimer > CHASE_COMMENT_DELAY // ciChaseConversations[iChaseStalkerChatCount].startDelay AND IS_ENTITY_ALIVE(pedStalker) AND NOT MISSION_OBJECTIVES_CURRENTLY_DISPLAYED() // So subtitles cannot override chase objective AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() // We might have only just triggered the stalker spotted exchange CPRINTLN(DEBUG_MISSION, "Starting chase dialogue") ADD_PED_FOR_DIALOGUE(mConversationStruct, 4, pedStalker, "Stalker") cptChaseTrack = CPT_PICK_CONVERSATION ENDIF BREAK // Pick a conversation type CASE CPT_PICK_CONVERSATION IF IS_ENTITY_ALIVE(pedStalker) // Check if Stalker is getting away first IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_ESCAPE_DIST*CHASE_FLASH_DIST) // Changed from 100m to be the same as the flash distance IF IS_PED_IN_ANY_VEHICLE(pedStalker) // Tracey "getting away" comment cptChaseTrack = CPT_START_CONVERSATION_ESCAPING ENDIF // See if the player car isn't moving ELIF (NOT_GOING_ANYWHERE() AND GET_GAME_TIMER() - iComplainTimer > NOT_GOING_DELAY_CHASE) // Immobile complaint cptChaseTrack = CPT_START_CONVERSATION_STOPPED ELSE // Stalker not getting away, see if we're close enough to stalker for Michael to shout at him IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, 50.0) // Has there been more stalker+Michael than Michael+Tracey // Chat should more or less alternate for as long as there is chat left in each set IF iChaseStalkerChatCount > iChaseTraceyChatCount // We would prefer to trigger Tracey+Michael banter as the stalker's had most so far... IF iChaseTraceyChatCount < NUM_CHASE_CONVERSATIONS_T // Tracey still has banter left, trigger that cptChaseTrack = CPT_START_CONVERSATION_TRACEY ELSE // Tracey+Michael list is empty - check stalker list IF iChaseStalkerChatCount < NUM_CHASE_CONVERSATIONS_S // Stalker still has banter left, trigger that cptChaseTrack = CPT_START_CONVERSATION_STALKER ELSE // Neither has any banter left CPRINTLN(DEBUG_MISSION, "All chase dialogue exhausted - wait to see if we need a warning comment next time") bStalkerChatting = FALSE iChaseChatTimer = GET_GAME_TIMER() cptChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF ENDIF ELSE // We would prefer to trigger Stalker+Michael banter as either Tracey has had most or scores are tied... IF iChaseStalkerChatCount < NUM_CHASE_CONVERSATIONS_S // Stalker still has banter left, trigger that cptChaseTrack = CPT_START_CONVERSATION_STALKER ELSE // Stalker+Michael list is empty - check Tracey list IF iChaseTraceyChatCount < NUM_CHASE_CONVERSATIONS_T // Tracey still has banter left, trigger that cptChaseTrack = CPT_START_CONVERSATION_TRACEY ELSE // Neither has any banter left CPRINTLN(DEBUG_MISSION, "All chase dialogue exhausted - wait to see if we need a warning comment next time") bTraceyChatting = FALSE iChaseChatTimer = GET_GAME_TIMER() cptChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF ENDIF ENDIF ELSE // Stalker isn't close enough for Michael to shout at him - see if there's still Tracey dialogue IF iChaseTraceyChatCount < NUM_CHASE_CONVERSATIONS_T // Tracey cptChaseTrack = CPT_START_CONVERSATION_TRACEY ELSE // Tracey has no banter left, roll back to beginning CPRINTLN(DEBUG_MISSION, "Would like to trigger Tracey banter but none left - roll back to wait state") bTraceyChatting = FALSE iChaseChatTimer = GET_GAME_TIMER() cptChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF ENDIF ENDIF ENDIF BREAK // Play a Michael/stalker interaction CASE CPT_START_CONVERSATION_STALKER IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, ciChaseConversations[iChaseStalkerChatCount].txtBlock, ciChaseConversations[iChaseStalkerChatCount].rootBlock, CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES, DO_ADD_TO_BRIEF_SCREEN) CPRINTLN(DEBUG_MISSION, "Starting chase conversation ", iChaseStalkerChatCount, " with no subtitles.") bStalkerChatting = TRUE bTraceyChatting = FALSE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, ciChaseConversations[iChaseStalkerChatCount].txtBlock, ciChaseConversations[iChaseStalkerChatCount].rootBlock, CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting chase conversation ", iChaseStalkerChatCount, " with subtitles.") bStalkerChatting = TRUE bTraceyChatting = FALSE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK // Play a Tracey/Michael interaction CASE CPT_START_CONVERSATION_TRACEY IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, ciTraceyChaseConversations[iChaseTraceyChatCount].txtBlock, ciTraceyChaseConversations[iChaseTraceyChatCount].rootBlock, CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES, DO_ADD_TO_BRIEF_SCREEN) CPRINTLN(DEBUG_MISSION, "Starting Tracey chase conversation ", iChaseTraceyChatCount, " with no subtitles.") bStalkerChatting = FALSE bTraceyChatting = TRUE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, ciTraceyChaseConversations[iChaseTraceyChatCount].txtBlock, ciTraceyChaseConversations[iChaseTraceyChatCount].rootBlock, CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting Tracey chase conversation ", iChaseStalkerChatCount, " with subtitles.") bStalkerChatting = FALSE bTraceyChatting = TRUE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK // Tracey warning Michael that stalker is escaping CASE CPT_START_CONVERSATION_ESCAPING IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_GETHIM", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES) CPRINTLN(DEBUG_MISSION, "Starting Tracey escape warning conversation with no subtitles.") bStalkerChatting = FALSE bTraceyChatting = FALSE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_GETHIM", CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting Tracey escape warning conversation with subtitles.") bStalkerChatting = FALSE bTraceyChatting = FALSE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK // Tracey remarks on Michael successfully ramming stalker's car CASE CPT_START_CONVERSATION_RAMARK IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_BASH", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES) CPRINTLN(DEBUG_MISSION, "Starting Tracey ram comment with no subtitles.") bStalkerChatting = FALSE bTraceyChatting = FALSE bQuickRamComment = FALSE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_BASH", CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting Tracey ram comment with subtitles.") bStalkerChatting = FALSE bTraceyChatting = FALSE bQuickRamComment = FALSE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK // Tracey complains if Michael has stopped CASE CPT_START_CONVERSATION_STOPPED IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_STOP", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES) CPRINTLN(DEBUG_MISSION, "Starting Tracey stopped complaint with no subtitles.") iComplainTimer = GET_GAME_TIMER() bStalkerChatting = FALSE bTraceyChatting = FALSE bQuickRamComment = FALSE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_STOP", CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting Tracey stopped complaint with subtitles.") iComplainTimer = GET_GAME_TIMER() bStalkerChatting = FALSE bTraceyChatting = FALSE bQuickRamComment = FALSE bShootingComment = FALSE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK // Tracey complaint about Michael going psycho CASE CPT_START_CONVERSATION_TRACEY_WTF IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_MESS", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES) CPRINTLN(DEBUG_MISSION, "Starting Tracey player psycho complaint with no subtitles.") iComplainTimer = GET_GAME_TIMER() bStalkerChatting = FALSE bTraceyChatting = FALSE bQuickRamComment = FALSE bShootingComment = TRUE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_MESS", CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting Tracey player psycho complaint with subtitles.") iComplainTimer = GET_GAME_TIMER() bStalkerChatting = FALSE bTraceyChatting = FALSE bQuickRamComment = FALSE bShootingComment = TRUE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK // Wait for the current conversation to finish CASE CPT_WAIT_TO_FINISH IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() // Current conversation completed - increment counter for whoever was yakking IF bStalkerChatting iChaseStalkerChatCount++ ELIF bTraceyChatting iChaseTraceyChatCount++ ENDIF IF bShootingComment iShootingComplaintGap = GET_GAME_TIMER() + SHOOTING_COMPLAINT_GAP ENDIF iChaseChatTimer = GET_GAME_TIMER() cptChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF BREAK CASE CPT_SPENT // Finished BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Stalker/Michael dialogue if the stalker has abandoned his car PROC STALKER_ON_FOOT_CHAT() // Check for shooting and trigger a complaint if it's been long enough since the last one // Not inside the case statement so we can keep updating the timer in PLAYER_SHOT_RECENTLY IF PLAYER_SHOT_RECENTLY() AND GET_GAME_TIMER() > iShootingComplaintGap CPRINTLN(DEBUG_MISSION, "Player shot recently and it's been a while since we last scolded them, checking if safe to trigger") IF cptChaseTrack = CPT_WAIT_TO_TRIGGER OR cptChaseTrack = CPT_PICK_CONVERSATION IF IS_ENTITY_ALIVE(viTraceyCar) AND (IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) OR IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), viTraceyCar, 15.0)) CPRINTLN(DEBUG_MISSION, "Player shot recently and it's been a while since we last scolded them, safe to trigger Tracey complaint") cptChaseTrack = CPT_START_CONVERSATION_TRACEY_WTF ENDIF ENDIF ENDIF SWITCH cptFootChaseTrack CASE CPT_WAIT_TO_TRIGGER // Wait to trigger conversation IF GET_GAME_TIMER() - iChaseChatTimer > CHASE_COMMENT_DELAY CPRINTLN(DEBUG_MISSION, "Time to try triggering foot chase dialogue...") ADD_PED_FOR_DIALOGUE(mConversationStruct, 4, pedStalker, "Stalker") cptFootChaseTrack = CPT_PICK_CONVERSATION ENDIF BREAK CASE CPT_PICK_CONVERSATION // Remember whether player is in the car... BOOL bPlayerInCar IF IS_ENTITY_ALIVE(viTraceyCar) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerInCar = TRUE ELSE // CPRINTLN(DEBUG_MISSION, "Player not currently in Tracey's car, this will limit dialogue options.") bPlayerInCar = FALSE ENDIF IF IS_ENTITY_ALIVE(pedStalker) // Stalker not getting away, see if we're close enough to stalker for Michael to shout at him IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_FOOT_MUTE_DIST) // Has there been more stalker+Michael than Michael+Tracey // Chat should more or less alternate for as long as there is chat left in each set unless player is on foot IF bPlayerInCar AND iFootChaseStalkerChat > iFootChaseTraceyChat // We would prefer to trigger Tracey+Michael banter as the stalker's had most so far... IF iFootChaseTraceyChat < NUM_FOOT_CONVERSATIONS_T // Tracey still has banter left, trigger that cptFootChaseTrack = CPT_START_CONVERSATION_TRACEY ELSE // Tracey+Michael list is empty - check stalker list IF iFootChaseStalkerChat < NUM_FOOT_CONVERSATIONS_S // Stalker still has banter left, trigger that cptFootChaseTrack = CPT_START_CONVERSATION_STALKER ELSE // Neither has any banter left CPRINTLN(DEBUG_MISSION, "Sequenced chase dialogue exhausted - trigger a random stalker line") cptFootChaseTrack = CPT_START_RANDOM_STALKER // // Neither has any banter left // CPRINTLN(DEBUG_MISSION, "All valid chase dialogue exhausted - wait to see if we need a warning comment next time") // bStalkerChatting = FALSE // iChaseChatTimer = GET_GAME_TIMER() // cptFootChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF ENDIF ELSE // We would prefer to trigger Stalker+Michael banter as either Tracey has had most, scores are tied, or player is on foot so Tracey is unavailable... IF iFootChaseStalkerChat < NUM_FOOT_CONVERSATIONS_S // Stalker still has banter left, trigger that cptFootChaseTrack = CPT_START_CONVERSATION_STALKER ELSE // Stalker+Michael list is empty - check Tracey list if player in car IF bPlayerInCar AND iFootChaseTraceyChat < NUM_FOOT_CONVERSATIONS_T // Tracey still has banter left, trigger that cptFootChaseTrack = CPT_START_CONVERSATION_TRACEY ELSE // Neither has any banter left CPRINTLN(DEBUG_MISSION, "Sequenced chase dialogue exhausted - trigger a random stalker line") cptFootChaseTrack = CPT_START_RANDOM_STALKER // // Neither has any banter left // CPRINTLN(DEBUG_MISSION, "All valid chase dialogue exhausted - wait to see if we need a warning comment next time") // bStalkerChatting = FALSE // iChaseChatTimer = GET_GAME_TIMER() // cptFootChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF ENDIF ENDIF ELSE // Do Tracey dialogue as long as player's in car IF bPlayerInCar // Check whether he's escaping IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_FOOT_ESCAPE_DIST*0.75) IF NOT bTraceyEscapeCommentDone // Tracey should do escape comment cptFootChaseTrack = CPT_START_CONVERSATION_ESCAPING ELSE // Tracey has done her escape comment - see if she has other dialogue left IF iFootChaseTraceyChat < NUM_FOOT_CONVERSATIONS_T // Tracey cptFootChaseTrack = CPT_START_CONVERSATION_TRACEY ELSE // Tracey has no banter left, roll back to beginning CPRINTLN(DEBUG_MISSION, "Would like to trigger Tracey banter but none left - roll back to wait state") bTraceyChatting = FALSE bShootingComment = FALSE iChaseChatTimer = GET_GAME_TIMER() cptFootChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF ENDIF ELSE // Stalker isn't close enough for Michael to shout at him - see if there's still Tracey dialogue IF iFootChaseTraceyChat < NUM_FOOT_CONVERSATIONS_T // Tracey cptFootChaseTrack = CPT_START_CONVERSATION_TRACEY ELSE // Tracey has no banter left, roll back to beginning CPRINTLN(DEBUG_MISSION, "Would like to trigger Tracey banter but none left - roll back to wait state") bTraceyChatting = FALSE bShootingComment = FALSE iChaseChatTimer = GET_GAME_TIMER() cptFootChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF ENDIF // See if we could do "getting away" chat ELIF NOT bTraceyEscapeCommentDone AND NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_FOOT_ESCAPE_DIST*0.5) AND IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, 15.0) // Tracey should do escape comment cptFootChaseTrack = CPT_START_CONVERSATION_ESCAPING ENDIF ENDIF ENDIF BREAK CASE CPT_START_CONVERSATION_STALKER IF IS_ENTITY_ALIVE(pedStalker) IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_FOOT_MUTE_DIST) IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, ciFootChaseConversations[iFootChaseStalkerChat].txtBlock, ciFootChaseConversations[iFootChaseStalkerChat].rootBlock, CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES, DO_ADD_TO_BRIEF_SCREEN) CPRINTLN(DEBUG_MISSION, "Starting stalker foot chase conversation ", iFootChaseStalkerChat, " with no subtitles.") bStalkerChatting = TRUE bTraceyChatting = FALSE bShootingComment = FALSE cptFootChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, ciFootChaseConversations[iFootChaseStalkerChat].txtBlock, ciFootChaseConversations[iFootChaseStalkerChat].rootBlock, CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting stalker foot chase conversation ", iFootChaseStalkerChat) bStalkerChatting = TRUE bTraceyChatting = FALSE bShootingComment = FALSE cptFootChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF ELSE CPRINTLN(DEBUG_MISSION, "Stalker wasn't in range for dialogue in CPT_START_CONVERSATION_STALKER, go back to start and wait for another go.") bStalkerChatting = FALSE bTraceyChatting = FALSE bShootingComment = FALSE iChaseChatTimer = GET_GAME_TIMER() cptFootChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF ENDIF BREAK CASE CPT_START_RANDOM_STALKER IF IS_ENTITY_ALIVE(pedStalker) IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_FOOT_MUTE_DIST) IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_STWR", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES, DO_ADD_TO_BRIEF_SCREEN) CPRINTLN(DEBUG_MISSION, "Starting stalker foot chase random conversation with no subtitles.") bStalkerChatting = TRUE bTraceyChatting = FALSE bShootingComment = FALSE cptFootChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_STWR", CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting stalker foot chase random conversation.") bStalkerChatting = TRUE bTraceyChatting = FALSE bShootingComment = FALSE cptFootChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF ELSE CPRINTLN(DEBUG_MISSION, "Stalker wasn't in range for dialogue in CPT_START_CONVERSATION_STALKER, go back to start and wait for another go.") bStalkerChatting = FALSE bTraceyChatting = FALSE bShootingComment = FALSE iChaseChatTimer = GET_GAME_TIMER() cptFootChaseTrack = CPT_WAIT_TO_TRIGGER ENDIF ENDIF BREAK CASE CPT_START_CONVERSATION_TRACEY IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, ciTraceyFootChaseConversations[iFootChaseTraceyChat].txtBlock, ciTraceyFootChaseConversations[iFootChaseTraceyChat].rootBlock, CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES, DO_ADD_TO_BRIEF_SCREEN) CPRINTLN(DEBUG_MISSION, "Starting Tracey foot chase conversation ", iFootChaseTraceyChat, " with no subtitles.") bStalkerChatting = FALSE bTraceyChatting = TRUE bShootingComment = FALSE cptFootChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, ciTraceyFootChaseConversations[iFootChaseTraceyChat].txtBlock, ciTraceyFootChaseConversations[iFootChaseTraceyChat].rootBlock, CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting Tracey foot chase conversation ", iFootChaseTraceyChat) bStalkerChatting = FALSE bTraceyChatting = TRUE bShootingComment = FALSE cptFootChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK CASE CPT_START_CONVERSATION_ESCAPING // Need to play Tracey's "Are we letting him go?" comment IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_TNOGOF", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES, DO_ADD_TO_BRIEF_SCREEN) CPRINTLN(DEBUG_MISSION, "Playing Tracey's letting-him-go conversation with no subtitles.") bTraceyEscapeCommentDone = TRUE bStalkerChatting = FALSE bTraceyChatting = FALSE bShootingComment = FALSE cptFootChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_TNOGOF", CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Playing Tracey's letting-him-go conversation.") bTraceyEscapeCommentDone = TRUE bStalkerChatting = FALSE bTraceyChatting = FALSE bShootingComment = FALSE cptFootChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK // Tracey complaint about Michael going psycho CASE CPT_START_CONVERSATION_TRACEY_WTF IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_MESS", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES) CPRINTLN(DEBUG_MISSION, "Starting Tracey player psycho complaint with no subtitles.") iComplainTimer = GET_GAME_TIMER() bStalkerChatting = FALSE bTraceyChatting = FALSE bQuickRamComment = FALSE bShootingComment = TRUE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_MESS", CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "Starting Tracey player psycho complaint with subtitles.") iComplainTimer = GET_GAME_TIMER() bStalkerChatting = FALSE bTraceyChatting = FALSE bQuickRamComment = FALSE bShootingComment = TRUE cptChaseTrack = CPT_WAIT_TO_FINISH ENDIF ENDIF BREAK CASE CPT_WAIT_TO_FINISH IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() // Current conversation completed - increment counter for whoever was yakking CPRINTLN(DEBUG_MISSION, "Conversation finished.") IF bStalkerChatting iFootChaseStalkerChat++ ELIF bTraceyChatting iFootChaseTraceyChat++ ENDIF IF bShootingComment iShootingComplaintGap = GET_GAME_TIMER() + SHOOTING_COMPLAINT_GAP ENDIF iChaseChatTimer = GET_GAME_TIMER() cptFootChaseTrack = CPT_WAIT_TO_TRIGGER ELSE // Check if we need to interrupt stalker conversations IF bStalkerChatting AND IS_ENTITY_ALIVE(pedStalker) // Proximity kill IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_FOOT_MUTE_DIST) CPRINTLN(DEBUG_MISSION, "Killing a stalker conversation due to being too far away...") KILL_FACE_TO_FACE_CONVERSATION() ENDIF // Check if we need to interrupt a stalker line due to injury IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(pedStalker, PLAYER_PED_ID()) IF GET_SPEAKER_INT_FOR_CURRENT_STANDARD_CONVERSATION_LINE() = 4 // Stalker has been injured while speaking CPRINTLN(DEBUG_MISSION, "Killing a stalker conversation due to injury/death") KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ENDIF CLEAR_ENTITY_LAST_DAMAGE_ENTITY(pedStalker) ENDIF // Check if we need to interrupt Tracey conversations ELIF bTraceyChatting AND IS_ENTITY_ALIVE(viTraceyCar) // Proximity kill IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar, TRUE) AND NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_FOOT_MUTE_DIST) CPRINTLN(DEBUG_MISSION, "Killing a Tracey conversation due to being too far away...") KILL_FACE_TO_FACE_CONVERSATION() ENDIF ENDIF ENDIF BREAK CASE CPT_SPENT // Finished BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Plays a series of chat events on the way home PROC DRIVING_HOME_CHAT() // Simple int controlled progression. If you change this, don't remove the breaks in the ELIF chain. // These allow us to skip to starting next conversation if the one in the current step isn't needed without having to wait a frame. // Keep this linear instead of a loop so it's easier to have checks for whether specific comments should play. // First comment - dependent on stalker outcome // Split into two parts so first part can be unsubtitled if needed // This initial two-part conversation is allowed to progress from part 1 to part 2 while wanted - B*1054078 IF iDriveHomeChatStep = 0 // Check which comment to trigger IF bStalkerDead IF bTraceySawOutcome // Stalker dead - Tracey saw IF NOT bConversationKilled IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ENDIF bConversationKilled = TRUE ENDIF IF CREATE_CONVERSATION(mConversationStruct, ciDriveHomeChat[0].txtBlock, ciDriveHomeChat[0].rootBlock, CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Triggered drive home comment 0 with subtitles") SEQUENCE_INDEX siTrReact OPEN_SEQUENCE_TASK(siTrReact) TASK_PLAY_ANIM(NULL, sTraceyAnimDict, "react_intro", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, 4900, AF_NOT_INTERRUPTABLE) TASK_PLAY_ANIM(NULL, sTraceyAnimDict, "react_loop", NORMAL_BLEND_IN, SLOW_BLEND_OUT, 12400, AF_NOT_INTERRUPTABLE) CLOSE_SEQUENCE_TASK(siTrReact) CLEAR_PED_TASKS(pedTracey) TASK_PERFORM_SEQUENCE(pedTracey, siTrReact) iDriveHomeChatStep+=4 ENDIF ELSE // Stalker dead - Tracey didn't see IF CREATE_CONVERSATION(mConversationStruct, ciDriveHomeChat[1].txtBlock, ciDriveHomeChat[1].rootBlock, CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Triggered drive home comment 1 with subtitles") iDriveHomeChatStep+=4 ENDIF ENDIF ELSE IF bTraceySawOutcome // Stalker ran off - Tracey saw // Did she already say escape comment? IF bTraceyEscapeCommentDone CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Stalker escaped on foot and Tracey saw so no immediate comment") iDriveHomeChatStep+=4 ELSE // Play the initial escape query now IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_TNOGOF", CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Stalker escaped on foot and Tracey saw") iDriveHomeChatStep+=4 bTraceyEscapeCommentDone = TRUE ENDIF ENDIF ELSE IF NOT bTraceyEscapeCommentDone // Prevent fringe case where stalker escapes while Tracey is saying the let go comment and stalker not in LOS - B*1437058 // Stalker ran off - Tracey didn't see IF CREATE_CONVERSATION(mConversationStruct, ciDriveHomeChat[2].txtBlock, ciDriveHomeChat[2].rootBlock, CONV_PRIORITY_MEDIUM) // MET1_TSESCP1 CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Triggered drive home comment 2 with subtitles") iDriveHomeChatStep+=4 ENDIF ENDIF ENDIF ENDIF ELIF iDriveHomeChatStep = 4 // Wait for comment to finish IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Initial comment completed") iDriveHomeChatStep++ ENDIF ENDIF // End first comment // Remainder of comments not allowed while wanted IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 // Trigger wanted remark? IF bNeedWantedRemark AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() IF MISSION_OBJECTIVES_CURRENTLY_DISPLAYED() IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_TRCOPS", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES) iDriveHomeChatTimer = GET_GAME_TIMER() bNeedWantedRemark = FALSE ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_TRCOPS", CONV_PRIORITY_MEDIUM) iDriveHomeChatTimer = GET_GAME_TIMER() bNeedWantedRemark = FALSE ENDIF ENDIF ENDIF // Remainder of comments lower priority than crazy driving complaint ELIF bNeedCrazyDrivingComment IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() IF CREATE_CONVERSATION(mConversationStruct, ciDriveHomeChat[8].txtBlock, ciDriveHomeChat[8].rootBlock, CONV_PRIORITY_MEDIUM) // Special comment if player's driving crazily CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Triggered drive home comment 8 (crazy driving) with subtitles") bNeedCrazyDrivingComment = FALSE iDriveHomeChatTimer = GET_GAME_TIMER() ENDIF ENDIF // OK to do rest of stuff ELSE // Second comment - Tracey further comment if stalker has been killed IF iDriveHomeChatStep = 5 // Check that starting this conversation chunk is valid IF bStalkerDead // Stalker dead - go to wait for chat iDriveHomeChatStep++ iDriveHomeChatTimer = GET_GAME_TIMER() ELSE // Stalker wasn't killed - go straight to next comment iDriveHomeChatStep += 3 ENDIF ELIF iDriveHomeChatStep = 6 // Wait to trigger comment IF GET_GAME_TIMER() - iDriveHomeChatTimer > ciDriveHomeChat[3].startDelay AND NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecReturnLocation, 50.0) IF CREATE_CONVERSATION(mConversationStruct, ciDriveHomeChat[3].txtBlock, ciDriveHomeChat[3].rootBlock, CONV_PRIORITY_MEDIUM) // Delayed secondary kill comment CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Triggered drive home comment 3 with subtitles") IF NOT bTraceySawOutcome // Tracey hasnt done reaction anim yet SEQUENCE_INDEX siTrReact OPEN_SEQUENCE_TASK(siTrReact) TASK_PLAY_ANIM(NULL, sTraceyAnimDict, "react_intro", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, 4900, AF_NOT_INTERRUPTABLE) TASK_PLAY_ANIM(NULL, sTraceyAnimDict, "react_loop", NORMAL_BLEND_IN, SLOW_BLEND_OUT, 12400, AF_NOT_INTERRUPTABLE) CLOSE_SEQUENCE_TASK(siTrReact) CLEAR_PED_TASKS(pedTracey) TASK_PERFORM_SEQUENCE(pedTracey, siTrReact) ENDIF iDriveHomeChatStep++ ENDIF ENDIF ELIF iDriveHomeChatStep = 7 // Wait for comment to finish IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() iDriveHomeChatStep++ ENDIF ENDIF // End second comment // Third comment - Tracey comments if her car is banged up IF iDriveHomeChatStep = 8 // Check that starting this conversation chunk is valid IF IS_ENTITY_ALIVE(viTraceyCar) IF GET_ENTITY_HEALTH(viTraceyCar) < 900 OR GET_VEHICLE_ENGINE_HEALTH(viTraceyCar) < 900 OR GET_VEHICLE_PETROL_TANK_HEALTH(viTraceyCar) < 900 // Car is at least moderately damaged - go to wait for chat iDriveHomeChatStep++ iDriveHomeChatTimer = GET_GAME_TIMER() ELSE // Car isn't really trashed - go straight to next comment CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Not doing trashed car complaint, car health is ", GET_ENTITY_HEALTH(viTraceyCar)) iDriveHomeChatStep += 3 ENDIF ENDIF ELIF iDriveHomeChatStep = 9 // Wait to trigger comment IF GET_GAME_TIMER() - iDriveHomeChatTimer > ciDriveHomeChat[4].startDelay AND NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecReturnLocation, 50.0) IF CREATE_CONVERSATION(mConversationStruct, ciDriveHomeChat[4].txtBlock, ciDriveHomeChat[4].rootBlock, CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Triggered drive home comment 4 with subtitles") iDriveHomeChatStep++ ENDIF ENDIF ELIF iDriveHomeChatStep = 10 // Wait for comment to finish IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() iDriveHomeChatStep++ ENDIF ENDIF // End third comment // Fourth comment - Tracey comments on stalker running off (only if he's still alive) IF iDriveHomeChatStep = 11 // Check that starting this conversation chunk is valid IF NOT bStalkerDead // Stalker fled on foot - go to wait for chat iDriveHomeChatStep++ iDriveHomeChatTimer = GET_GAME_TIMER() ELSE // Stalker dead - skip comment CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Stalker dead skipping to general banter.") iDriveHomeChatStep += 3 ENDIF ELIF iDriveHomeChatStep = 12 // Wait to trigger comment IF GET_GAME_TIMER() - iDriveHomeChatTimer > ciDriveHomeChat[5].startDelay AND NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecReturnLocation, 50.0) IF CREATE_CONVERSATION(mConversationStruct, ciDriveHomeChat[5].txtBlock, ciDriveHomeChat[5].rootBlock, CONV_PRIORITY_MEDIUM) CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Triggered drive home comment 5 with subtitles") iDriveHomeChatStep++ ENDIF ENDIF ELIF iDriveHomeChatStep = 13 // Wait for comment to finish IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Drive home chatter going to next comment.") iDriveHomeChatStep++ ENDIF ENDIF // End fourth comment // Fifth comment - Tracey asks if Michael is in danger IF iDriveHomeChatStep = 14 // Timer iDriveHomeChatStep++ iDriveHomeChatTimer = GET_GAME_TIMER() ELIF iDriveHomeChatStep = 15 // Wait to trigger comment IF GET_GAME_TIMER() - iDriveHomeChatTimer > ciDriveHomeChat[6].startDelay AND NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecReturnLocation, 50.0) IF CREATE_CONVERSATION(mConversationStruct, ciDriveHomeChat[6].txtBlock, ciDriveHomeChat[6].rootBlock, CONV_PRIORITY_MEDIUM) // Tracey asks if anyone's trying to kill Michael CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Triggered drive home comment 6 with subtitles") iDriveHomeChatStep++ ENDIF ENDIF ELIF iDriveHomeChatStep = 16 // Wait for comment to finish IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Drive home chatter going to next comment.") iDriveHomeChatStep++ ENDIF ENDIF // End fifth comment // Sixth comment - Tracey asks if Michael is in danger IF iDriveHomeChatStep = 17 // Timer iDriveHomeChatStep++ iDriveHomeChatTimer = GET_GAME_TIMER() ELIF iDriveHomeChatStep = 18 // Wait to trigger comment IF GET_GAME_TIMER() - iDriveHomeChatTimer > ciDriveHomeChat[7].startDelay AND NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecReturnLocation, 50.0) IF CREATE_CONVERSATION(mConversationStruct, ciDriveHomeChat[7].txtBlock, ciDriveHomeChat[7].rootBlock, CONV_PRIORITY_MEDIUM) // Michael asks if Tracey has heard from Lazlow CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Triggered drive home comment 7 with subtitles") iDriveHomeChatStep++ ENDIF ENDIF ELIF iDriveHomeChatStep = 19 // Wait for comment to finish IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() CPRINTLN(DEBUG_MISSION, "DRIVING_HOME_CHAT: Drive home chatter is done.") iDriveHomeChatStep++ ENDIF ENDIF // End sixth comment ENDIF ENDPROC /// PURPOSE: /// Checks whether player has reached the destination that we're heading for /// RETURNS: /// TRUE if arrived FUNC BOOL REACHED_DESTINATION_CHECK() IF bGoingToHotel IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), vecReturnLocation, << 3.5, 3.5, LOCATE_SIZE_HEIGHT >>, TRUE) RETURN TRUE ENDIF ELSE // House - needs wall proximity bodges IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), vecReturnLocation, << 4.5, 4.5, LOCATE_SIZE_HEIGHT >>, TRUE) //AND IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecReturnLocation, 3.8) // Added for B*1267303 - to prevent parking right by wall - revised to angled areas AND (IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-828.706909,176.641754,69.662125>>, <<-824.074707,184.566589,72.918724>>, 5.75) OR IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-827.930786,182.045395,70.089088>>, <<-820.238708,180.178085,72.715431>>, 6.50)) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Handle the nearly there comment appropriately for the current destination /// RETURNS: /// TRUE if we are in range for triggering the comment FUNC BOOL DESTINATION_COMMENT_TRIGGER() IF bGoingToHotel IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecHotelLocation, 30.0) RETURN TRUE ENDIF ELSE // Check proximity to house gate not destination on drive IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), <<-842.5665, 159.2974, 65.9426>>, 11.0) // B*1306840 RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Spawns the stalker dudes car and him in it /// PARAMS: /// spawnCoords - spawn location /// fSpawnHead - spawn facing /// RETURNS: /// TRUE if the stalker has been successfully spawned FUNC BOOL SPAWN_STALKER(VECTOR spawnCoords, FLOAT fSpawnHead = 0.0, BOOL bRequestModelsOnly = FALSE) IF bRequestModelsOnly AND NOT bStalkerModelRequested CPRINTLN(DEBUG_MISSION, "Requesting stalker car/ped models") REQUEST_MODEL(mnStalkerModel) REQUEST_MODEL(mvStalkerCar.model) bStalkerModelRequested = TRUE ENDIF IF IS_ENTITY_ALIVE(mvStalkerCar.vehicle) AND IS_ENTITY_ALIVE(pedStalker) // Stalker has already been created - nothing to do RETURN TRUE ELSE IF bStalkerModelRequested IF HAS_MODEL_LOADED(mnStalkerModel) AND HAS_MODEL_LOADED(mvStalkerCar.model) // Clear space CLEAR_AREA_OF_VEHICLES(mvStalkerCar.location, 5) // Create vehicle mvStalkerCar.vehicle = CREATE_VEHICLE(mvStalkerCar.model, spawnCoords, fSpawnHead) SET_MODEL_AS_NO_LONGER_NEEDED(mvStalkerCar.model) // Configure vehicle SET_VEHICLE_COLOURS(mvStalkerCar.vehicle, 145, 111) SET_VEHICLE_ON_GROUND_PROPERLY(mvStalkerCar.vehicle) LOWER_CONVERTIBLE_ROOF(mvStalkerCar.vehicle, TRUE) SET_CONVERTIBLE_ROOF_LATCH_STATE(mvStalkerCar.vehicle, TRUE) // Lock it open SET_VEHICLE_ENGINE_ON(mvStalkerCar.vehicle, TRUE, TRUE) SET_ENTITY_LOAD_COLLISION_FLAG(mvStalkerCar.vehicle, TRUE) ADD_VEHICLE_UPSIDEDOWN_CHECK(mvStalkerCar.vehicle) SET_VEHICLE_AS_RESTRICTED(mvStalkerCar.vehicle, RESTRICTION_STALKER) ADD_ENTITY_TO_AUDIO_MIX_GROUP(mvStalkerCar.vehicle, "M_E_TRACEY_STALKERS_CAR_GROUP") bStalkerStuckCheckActive = TRUE // Create stalker pedStalker = CREATE_PED_INSIDE_VEHICLE(mvStalkerCar.vehicle, PEDTYPE_MISSION, mnStalkerModel) SET_PED_COMPONENT_VARIATION(pedStalker, PED_COMP_SPECIAL2, 0, 0) // "task" comp - No knob please SET_PED_COMPONENT_VARIATION(pedStalker, PED_COMP_SPECIAL, 0, 0) // Belt SET_PED_COMPONENT_VARIATION(pedStalker, PED_COMP_HEAD, 0, 0) SET_PED_COMPONENT_VARIATION(pedStalker, PED_COMP_HAIR, 1, 0) SET_PED_COMPONENT_VARIATION(pedStalker, PED_COMP_TORSO, 0, 0) SET_PED_COMPONENT_VARIATION(pedStalker, PED_COMP_LEG, 1, 0) SET_MODEL_AS_NO_LONGER_NEEDED(mnStalkerModel) // Configure stalker SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(pedStalker, TRUE) SET_PED_KEEP_TASK(pedStalker, TRUE) ADD_PED_FOR_DIALOGUE(mConversationStruct, 4, pedStalker, "Stalker") SET_PED_CONFIG_FLAG(pedStalker, PCF_DisableGoToWritheWhenInjured, TRUE) bStalkerModelRequested = FALSE iDisableReplayCameraTimer = GET_GAME_TIMER() + 1000 //Fix for bug 2227778 RETURN TRUE #IF IS_DEBUG_BUILD ELIF bDebugStalkerTTY CPRINTLN(DEBUG_MISSION, "Waiting for stalker models to load...") #ENDIF ENDIF ELSE CPRINTLN(DEBUG_MISSION, "Requesting stalker car/ped models") REQUEST_MODEL(mnStalkerModel) REQUEST_MODEL(mvStalkerCar.model) bStalkerModelRequested = TRUE ENDIF ENDIF // Still loading something if we've not returned TRUE by now RETURN FALSE ENDFUNC /// PURPOSE: /// Suppresses the models for a list of stupidly big vehicles that can really snarl up traffic /// PARAMS: /// bSuppress - TRUE to suppress, FALSE to remove suppression PROC TOGGLE_VEHICLE_SUPPRESSION(BOOL bSuppress) // Services/buses SET_VEHICLE_MODEL_IS_SUPPRESSED(BUS, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(COACH, bSuppress) // Industrial SET_VEHICLE_MODEL_IS_SUPPRESSED(MIXER, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(MIXER2, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(RUBBLE, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(TIPTRUCK2, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(TIPTRUCK, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(SCRAP, bSuppress) // Trucks SET_VEHICLE_MODEL_IS_SUPPRESSED(BIFF, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(PACKER, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(PHANTOM, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(BENSON, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(TRASH, bSuppress) SET_VEHICLE_MODEL_IS_SUPPRESSED(POUNDER, bSuppress) ENDPROC /// PURPOSE: /// Creates a coord blip for Tracey's start point - faked to look like a ped blip /// PARAMS: /// vCoords - Coords requiring blip. /// bSetRoute - creates a satNav route for this blip /// RETURNS: /// Blip Index. FUNC BLIP_INDEX CREATE_FAKE_TRACEY_PED_BLIP(VECTOR vCoords, BOOL bSetRoute = FALSE) BLIP_INDEX bRetBlip = ADD_BLIP_FOR_COORD(vCoords) SET_BLIP_PRIORITY(bRetBlip,BLIPPRIORITY_HIGH) SET_BLIP_SCALE(bRetBlip, BLIP_SIZE_PED) SET_BLIP_COLOUR(bRetBlip, BLIP_COLOUR_BLUE) SET_BLIP_ROUTE(bRetBlip, bSetRoute) SET_BLIP_NAME_FROM_TEXT_FILE(bRetBlip, "MET1LBTRAC") RETURN bRetBlip ENDFUNC /// PURPOSE: /// Local replacement for CREATE_NPC_PED functions so I can specify a specific outfit /// RETURNS: /// TRUE when spawned FUNC BOOL CREATE_TRACEY(PED_INDEX &TraceyPed, VECTOR vCoords, FLOAT fHeading = 0.0, BOOL bCleanupModel = TRUE) // Load the required model MODEL_NAMES model = GET_NPC_PED_MODEL(CHAR_TRACEY) REQUEST_MODEL(model) IF HAS_MODEL_LOADED(model) // Delete ped in case of weirdness- should be OK though SAFE_DELETE_PED(TraceyPed) TraceyPed = CREATE_PED(PEDTYPE_MISSION, model, vCoords, fHeading, FALSE, FALSE) // Set up outfit SET_PED_COMPONENT_VARIATION(TraceyPed, PED_COMP_TORSO, 1, 1) SET_PED_COMPONENT_VARIATION(TraceyPed, PED_COMP_LEG, 5, 0) SET_PED_COMPONENT_VARIATION(TraceyPed, PED_COMP_FEET, 2, 0) // No feet - trainers are in leg comp SET_PED_COMPONENT_VARIATION(TraceyPed, PED_COMP_SPECIAL, 1, 0) // No accessories // StoreAsGlobalFriend(TraceyPed, CHAR_TRACEY) IF bCleanupModel SET_MODEL_AS_NO_LONGER_NEEDED(model) ENDIF iDisableReplayCameraTimer = GET_GAME_TIMER() + 1000 //Fix for bug 2227778 RETURN TRUE ENDIF RETURN FALSE ENDFUNC //************************************************************************************************************************************************* // // Skip procs // //************************************************************************************************************************************************* // Check for and delete stalker ped, vehicle and blip PROC SKIP_REMOVE_STALKER() // Remove stalker SAFE_DELETE_PED(pedStalker) IF DOES_ENTITY_EXIST(mvStalkerCar.vehicle) IF bStalkerStuckCheckActive REMOVE_VEHICLE_UPSIDEDOWN_CHECK(mvStalkerCar.vehicle) bStalkerStuckCheckActive = FALSE ENDIF REMOVE_ENTITY_FROM_AUDIO_MIX_GROUP(mvStalkerCar.vehicle) SAFE_DELETE_VEHICLE(mvStalkerCar.vehicle) ENDIF ENDPROC /// PURPOSE: /// Check for and delete Tracey ped, vehicle and blip PROC SKIP_REMOVE_TRACEY() bTraceyIsCurrentlySpawned = FALSE IF IS_ENTITY_ALIVE(pedTracey) IF IS_PED_IN_GROUP(pedTracey) REMOVE_PED_FROM_GROUP(pedTracey) ENDIF ENDIF SAFE_DELETE_PED(pedTracey) IF bStuckCheckActive REMOVE_VEHICLE_UPSIDEDOWN_CHECK(viTraceyCar) bStuckCheckActive = FALSE ENDIF SAFE_DELETE_VEHICLE(viTraceyCar) ENDPROC /// PURPOSE: /// (Re)spawn Tracey in her car for skips and checkpoints /// PARAMS: /// vecRSLoc - coordinates to respawn at /// fRSHead - direction car faces /// bAddAsPassenger - Tracey is spawned in the passenger seat PROC SKIP_RESPAWN_TRACEY(VECTOR vecRSLoc, FLOAT fRSHead, BOOL bAddAsPassenger = FALSE) // Remove Tracey/car SKIP_REMOVE_TRACEY() WHILE NOT CREATE_NPC_VEHICLE(viTraceyCar, CHAR_TRACEY, vecRSLoc, fRSHead, TRUE) WAIT(0) ENDWHILE IF bAddAsPassenger WHILE NOT CREATE_TRACEY(pedTracey, << vecRSLoc.x, vecRSLoc.y, vecRSLoc.z+5 >>) WAIT(0) ENDWHILE IF IS_ENTITY_ALIVE(pedTracey) AND IS_ENTITY_ALIVE(viTraceyCar) SET_PED_INTO_VEHICLE(pedTracey, viTraceyCar, VS_FRONT_RIGHT) ENDIF ELSE WHILE NOT CREATE_TRACEY(pedTracey, << vecRSLoc.x, vecRSLoc.y, vecRSLoc.z+5 >>) WAIT(0) ENDWHILE IF IS_ENTITY_ALIVE(pedTracey) AND IS_ENTITY_ALIVE(viTraceyCar) SET_PED_INTO_VEHICLE(pedTracey, viTraceyCar, VS_FRONT_RIGHT) ENDIF ENDIF IF IS_ENTITY_ALIVE(pedTracey) SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(pedTracey, TRUE) ADD_PED_FOR_DIALOGUE(mConversationStruct, 3, pedTracey, "TRACEY") // Tracey can't fly through windscreen or be jacked SET_PED_CONFIG_FLAG(pedTracey, PCF_WillFlyThroughWindscreen, FALSE) SET_PED_CONFIG_FLAG(pedTracey, PCF_DontAllowToBeDraggedOutOfVehicle, TRUE) // Should load collision SET_ENTITY_LOAD_COLLISION_FLAG(viTraceyCar, TRUE) // Should be in friendly rel group DO_FRIENDLY_GROUP_SETUP() ENDIF IF IS_ENTITY_ALIVE(viTraceyCar) LOWER_CONVERTIBLE_ROOF(viTraceyCar, TRUE) SET_VEHICLE_STRONG(viTraceyCar, TRUE) SET_VEHICLE_ENGINE_ON(viTraceyCar, TRUE, TRUE) ADD_VEHICLE_UPSIDEDOWN_CHECK(viTraceyCar) SET_VEHICLE_HAS_STRONG_AXLES(viTraceyCar, TRUE) SET_VEHICLE_AS_RESTRICTED(viTraceyCar, RESTRICTION_TRACEY) bStuckCheckActive = TRUE ENDIF bTraceyIsCurrentlySpawned = TRUE ENDPROC #IF IS_DEBUG_BUILD // Respawn stalker PROC SKIP_RESPAWN_STALKER(VECTOR vecRSLoc, FLOAT fRSHead) SKIP_REMOVE_STALKER() WHILE NOT SPAWN_STALKER(vecRSLoc, fRSHead) WAIT(0) ENDWHILE ENDPROC // Player wanted level cleared PROC SKIP_CLEAR_WANTED() // Clear wanted level IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 0) SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID()) ENDIF ENDIF ENDPROC // Stamp on any active conversation when skipping PROC SKIP_KILL_CONVERSATION() IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() HANG_UP_AND_PUT_AWAY_PHONE() ENDIF ENDPROC /// PURPOSE: /// DEBUG SKIP: Restart mission skip. /// Warps player to arbitrary point as if they'd just finished phone call. PROC SKIP_TO_MS_INIT(BOOL bGiveCar = FALSE) CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: Restarting mission") IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF bGiveCar // Give the player a car REQUEST_MODEL(debugPlayerCarModel) SET_ENTITY_COORDS(PLAYER_PED_ID(), << 90.6710, -215.2205, 56.4915 >>) WHILE NOT HAS_MODEL_LOADED(debugPlayerCarModel) WAIT(0) ENDWHILE CLEAR_AREA_OF_VEHICLES(<< 90.6710, -215.2205, 53.4915 >>, 10, TRUE, FALSE, TRUE, TRUE) VEHICLE_INDEX viTmp viTmp = CREATE_VEHICLE(debugPlayerCarModel, << 90.6710, -215.2205, 53.4915 >>, 338.3) SET_MODEL_AS_NO_LONGER_NEEDED(debugPlayerCarModel) WHILE NOT DOES_ENTITY_EXIST(viTmp) WAIT(0) ENDWHILE IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), viTmp) ENDIF SAFE_RELEASE_VEHICLE(viTmp) ELSE // Warp player IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) OR (IS_ENTITY_ALIVE(viTraceyCar) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar)) CLEAR_AREA_OF_VEHICLES(<< 90.6710, -215.2205, 53.4915 >>, 10, TRUE, FALSE, TRUE, TRUE) SET_ENTITY_COORDS(PLAYER_PED_ID(), << 90.6710, -215.2205, 53.4915 >>) SET_ENTITY_HEADING(PLAYER_PED_ID(), 338.3) ELSE // Maintain player's vehicle (as it's not Tracey's car) CLEAR_AREA_OF_VEHICLES(<< 90.6710, -215.2205, 53.4915 >>, 10, TRUE, FALSE, TRUE, TRUE) REPOSITION_PLAYERS_VEHICLE(<< 90.6710, -215.2205, 53.4915 >>, 338.3) ENDIF ENDIF ENDIF SKIP_REMOVE_TRACEY() SKIP_REMOVE_STALKER() SAFE_REMOVE_BLIP(biBlip) bTraceyIsCurrentlySpawned = FALSE // Vehicle density may be nobbled depending where we came from // Commented out as SET_VEHICLE_DENSITY_MULTIPLIER has been replaced with SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME //SET_VEHICLE_DENSITY_MULTIPLIER(1.0) // Reset timeout warning call wfcProgress = WFC_SETUP INIT_DRIVE_TIMERS() bWFCOnHold = FALSE MISSION_OBJECTIVE_RESET(MO_MET1INITDRV)// Drive towards Vinewood. MISSION_OBJECTIVE_RESET(MO_MET1TCAR) // Get into Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1WANT) // Lose the cops. MISSION_OBJECTIVE_RESET(MO_MET1CHASE) // Chase off the stalker. MISSION_OBJECTIVE_RESET(MO_MET1HOME) // Take Tracey home. MISSION_OBJECTIVE_RESET(MO_MET1HOTEL) // Take Tracey to the Hotel. MISSION_OBJECTIVE_RESET(MO_MET1GETBKT) // Get back in Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1DLT) // Return to Tracey's car. msTrack = MST_DRIVE_TO_TRACEY sProgress = SP_SETUP ENDPROC #ENDIF /// PURPOSE: /// DEBUG SKIP: Warps to point that player meets Tracey at the Vinewood Plaza. /// THIS IS ALSO A CHECKPOINT SKIP /// If the player is in a vehicle, they will be warped in it; If not then they will be warped on foot. PROC SKIP_TO_MEET_TRACEY(BOOL bDoCheckpoint = FALSE) CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: Skipping to STAGE_DRIVE_TO_STALKER") SAFE_REMOVE_BLIP(biBlip) bReplayInVehicle = FALSE // Set now so it never has dodgy value for setting up audio scene later IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF bDoCheckPoint // Get the player's car if available IF IS_REPLAY_CHECKPOINT_VEHICLE_AVAILABLE() // In vehicle vecReplayPlayerLocation = <<99.6208, -21.0027, 67.0114>> fReplayPlayerHeading = 251.1 bReplayInVehicle = TRUE CLEAR_AREA_OF_VEHICLES(<<99.6208, -21.0027, 67.0114>>, 7.0) // Previous bug about ambient vehicles driving into back of player's car // Get the car REQUEST_REPLAY_CHECKPOINT_VEHICLE_MODEL() WHILE NOT HAS_REPLAY_CHECKPOINT_VEHICLE_LOADED() WAIT(0) ENDWHILE vehReplayCar = CREATE_REPLAY_CHECKPOINT_VEHICLE(vecReplayPlayerLocation, fReplayPlayerHeading) ELSE // On foot CLEAR_AREA(<<181.2331, -33.9939, 67.2522>>, 3.0, TRUE) // Previous bug about ambient ped collisions vecReplayPlayerLocation = <<181.2331, -33.9939, 67.2522>> fReplayPlayerHeading = 255.3 ENDIF START_REPLAY_SETUP(vecReplayPlayerLocation, fReplayPlayerHeading) ELSE IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) // Respot player on foot if they are in Tracey's car or a trashed vehicle IF (IS_ENTITY_ALIVE(viTraceyCar) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar)) OR (IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT IS_VEHICLE_DRIVEABLE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))) // Warp player on foot near Tracey CLEAR_AREA(<<181.2331, -33.9939, 67.2522>>, 3.0, TRUE) SET_ENTITY_COORDS(PLAYER_PED_ID(), <<181.2331, -33.9939, 67.2522>>) SET_ENTITY_HEADING(PLAYER_PED_ID(), 255.3) vecReplayPlayerLocation = <<181.2331, -33.9939, 67.2522>> ELSE // Move vehicle CLEAR_AREA_OF_VEHICLES(<<99.6208, -21.0027, 67.0114>>, 7.0) vehReplayCar = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) SET_ENTITY_COORDS(vehReplayCar, <<99.6208, -21.0027, 67.0114>>) SET_ENTITY_HEADING(vehReplayCar, 251.1) SET_VEHICLE_ON_GROUND_PROPERLY(vehReplayCar) vecReplayPlayerLocation = <<99.6208, -21.0027, 67.0114>> bReplayInVehicle = TRUE ENDIF ELSE // Player is on foot - warp nearer Tracey CLEAR_AREA(<<181.2331, -33.9939, 67.2522>>, 3.0, TRUE) SET_ENTITY_COORDS(PLAYER_PED_ID(), <<181.2331, -33.9939, 67.2522>>) SET_ENTITY_HEADING(PLAYER_PED_ID(), 255.3) vecReplayPlayerLocation = <<181.2331, -33.9939, 67.2522>> ENDIF ENDIF ENDIF SKIP_REMOVE_STALKER() SKIP_REMOVE_TRACEY() // Reset timeout warning call wfcProgress = WFC_SETUP INIT_DRIVE_TIMERS() bWFCOnHold = TRUE msTrack = MST_DRIVE_TO_TRACEY sProgress = SP_SETUP IF (IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())) OR bReplayInVehicle UPDATE_AUDIO_SCENE(AUDIOSCENE_GO_TO_TRACEY) ELSE UPDATE_AUDIO_SCENE(AUDIOSCENE_NONE) ENDIF MISSION_OBJECTIVE_EXPIRE(MO_MET1INITDRV)// Drive towards Vinewood. MISSION_OBJECTIVE_RESET(MO_MET1TCAR) // Get into Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1WANT) // Lose the cops. MISSION_OBJECTIVE_RESET(MO_MET1CHASE) // Chase off the stalker. MISSION_OBJECTIVE_RESET(MO_MET1HOME) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1HOTEL) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1GETBKT) // Get back in Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1DLT) // Return to Tracey's car. IF bDoCheckpoint WHILE NOT HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT) WAIT(0) ENDWHILE IF bReplayInVehicle END_REPLAY_SETUP(vehReplayCar) ELSE END_REPLAY_SETUP() ENDIF ELSE WAIT_FOR_WORLD_TO_LOAD(vecReplayPlayerLocation) ENDIF // Rolling start if needed IF bReplayInVehicle IF IS_ENTITY_ALIVE(vehReplayCar) SET_VEHICLE_ENGINE_ON(vehReplayCar, TRUE, TRUE) SET_VEHICLE_FORWARD_SPEED(vehReplayCar, 10.0) ENDIF WAIT(0) ENDIF ENDPROC /// PURPOSE: /// DEBUG SKIP: Warp to stalker appearance point and create him in his "primary" location /// THIS IS ALSO A CHECKPOINT SKIP PROC SKIP_TO_STALKER_APPEARS(BOOL bCheckpoint = FALSE) CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: Skipping to STALKER_APPEARS") SAFE_REMOVE_BLIP(biBlip) SKIP_REMOVE_STALKER() IF bCheckpoint START_REPLAY_SETUP(dpLocates[NUM_DESTINATIONS-1].location, 71.4) SKIP_RESPAWN_TRACEY(dpLocates[NUM_DESTINATIONS-1].location, 71.4, TRUE) ELSE // Set player in right area, get him into Tracey's car IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) SET_ENTITY_COORDS(PLAYER_PED_ID(), << dpLocates[NUM_DESTINATIONS-1].location.x, dpLocates[NUM_DESTINATIONS-1].location.y, dpLocates[NUM_DESTINATIONS-1].location.z+8 >>) // Respawn Tracey SKIP_RESPAWN_TRACEY(dpLocates[NUM_DESTINATIONS-1].location, 71.4, TRUE) SAFE_SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), viTraceyCar) ENDIF // Clear any cars from behind player - previous bug about ambient cars driving into them IF IS_ENTITY_ALIVE(viTraceyCar) CLEAR_AREA_OF_VEHICLES(GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(viTraceyCar, << 0.0, -8.0, 0.0>>), 6) ENDIF ENDIF // Set the points mvStalkerCar.location = vecStalkerSpawnPoint[1] mvStalkerCar.heading = fStalkerSpawnHead[1] CLEAR_AREA_OF_VEHICLES(mvStalkerCar.location, 5) MISSION_OBJECTIVE_EXPIRE(MO_MET1INITDRV)// Drive towards Vinewood. MISSION_OBJECTIVE_EXPIRE(MO_MET1TCAR) // Get into Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1WANT) // Lose the cops. MISSION_OBJECTIVE_RESET(MO_MET1CHASE) // Chase off the stalker. MISSION_OBJECTIVE_RESET(MO_MET1HOME) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1HOTEL) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1GETBKT) // Get back in Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1DLT) // Return to Tracey's car. UPDATE_AUDIO_SCENE(AUDIOSCENE_DRIVE_TO_STALKER) msTrack = MST_TRIGGER_STALKER sProgress = SP_SETUP IF bCheckpoint WHILE NOT HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT) WAIT(0) ENDWHILE END_REPLAY_SETUP(viTraceyCar, VS_DRIVER, FALSE) ELSE WAIT_FOR_WORLD_TO_LOAD(dpLocates[NUM_DESTINATIONS-1].location) SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_STALKER_APPEARS, "Stalker appears (CP2)") ENDIF ENDPROC #IF IS_DEBUG_BUILD /// PURPOSE: /// DEBUG SKIP: Stalker wreck skip /// If the player is in the stalker chase, all this will do is pop the stalker's tyres /// Otherwise, it will warp to a known 'good' location and create stalker there in knackered car PROC SKIP_TO_STALKER_WRECK() CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: Skipping to chase stage, wrecking stalker's car") SAFE_REMOVE_BLIP(biBlip) // If the stage isn't CHASE, we have more to do IF msTrack != MST_CHASE IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) // Warp player first SET_ENTITY_COORDS(PLAYER_PED_ID(), << -382.0171, 2.5451, 45.9866 >>) // Respawn Tracey SKIP_RESPAWN_TRACEY(<< -382.0171, 2.5451, 45.9866 >>, 63.13, TRUE) SAFE_SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), viTraceyCar) ENDIF // Respawn stalker SKIP_RESPAWN_STALKER(<< -409.6612, 14.4959, 45.4712 >>, 59.6) bStalkerDead = FALSE ENDIF // Pop the stalker's tyres IF IS_ENTITY_ALIVE(mvStalkerCar.vehicle) SET_VEHICLE_ENGINE_HEALTH(mvStalkerCar.vehicle, 20) SET_VEHICLE_TYRE_BURST(mvStalkerCar.vehicle, SC_WHEEL_CAR_FRONT_LEFT) SET_VEHICLE_TYRE_BURST(mvStalkerCar.vehicle, SC_WHEEL_CAR_FRONT_RIGHT) ENDIF MISSION_OBJECTIVE_EXPIRE(MO_MET1INITDRV)// Drive towards Vinewood. MISSION_OBJECTIVE_EXPIRE(MO_MET1TCAR) // Get into Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1WANT) // Lose the cops. MISSION_OBJECTIVE_EXPIRE(MO_MET1CHASE) // Chase off the stalker. MISSION_OBJECTIVE_RESET(MO_MET1HOME) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1HOTEL) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1GETBKT) // Get back in Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1DLT) // Return to Tracey's car. SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_MET_TRACEY, "Met Tracey (CP2)") IF msTrack != MST_CHASE WAIT_FOR_WORLD_TO_LOAD(<< -382.0171, 2.5451, 45.9866 >>) UPDATE_AUDIO_SCENE(AUDIOSCENE_CHASE) ENDIF msTrack = MST_CHASE sProgress = SP_RUNNING ENDPROC /// PURPOSE: /// Debug skip that places the stalker car wedged against a wall and the player car behind him so he can't move PROC SKIP_TO_STALKER_STUCK() CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: Skipping to chase stage, placing stalker in a stuck position") SAFE_REMOVE_BLIP(biBlip) IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) // Warp player SET_ENTITY_COORDS(PLAYER_PED_ID(), << -185.1866, -94.4907, 51.4701 >>) // Respawn Tracey SKIP_RESPAWN_TRACEY(<<-190.1716, -92.7500, 51.1335>>, 70.8, TRUE) SAFE_SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), viTraceyCar) ENDIF // Respawn stalker SKIP_RESPAWN_STALKER(<< -194.8900, -91.0374, 50.8075 >>, 250.18) bStalkerDead = FALSE MISSION_OBJECTIVE_EXPIRE(MO_MET1INITDRV)// Drive towards Vinewood. MISSION_OBJECTIVE_EXPIRE(MO_MET1TCAR) // Get into Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1WANT) // Lose the cops. MISSION_OBJECTIVE_EXPIRE(MO_MET1CHASE) // Chase off the stalker. MISSION_OBJECTIVE_RESET(MO_MET1HOME) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1HOTEL) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1GETBKT) // Get back in Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1DLT) // Return to Tracey's car. SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_MET_TRACEY, "Met Tracey (CP2)") IF IS_ENTITY_ALIVE(pedTracey) // Prevents skip-specific assert - workaround for a debug-only issue ENDIF UPDATE_AUDIO_SCENE(AUDIOSCENE_CHASE) msTrack = MST_CHASE sProgress = SP_RUNNING ENDPROC #ENDIF /// PURPOSE: /// Pick a sensible spawnpoint near to where the checkpoint coords got set /// PARAMS: /// vCoords - Current spawn vector, will be reset to one of the presets /// fHeading - Current spawn heading, will be reset to one of the presets PROC GET_NEAREST_PRESET_SPAWN_TO_CP(VECTOR vTestCoords, VECTOR &vCoords, FLOAT &fHeading) // Set up possible spawn coords/heading VECTOR vSpawnCoords[4] FLOAT fSpawnHead[4] vSpawnCoords[0] = << -170.3240, -52.5700, 51.6830 >> fSpawnHead[0] = 159.9 vSpawnCoords[1] = << 1196.1401, -1069.1301, 40.3586 >> fSpawnHead[1] = 107.2 vSpawnCoords[2] = << -1513.5652, -676.1716, 27.4587 >> fSpawnHead[2] = 53.2 vSpawnCoords[3] = << 55.9539, 342.8233, 111.6553 >> fSpawnHead[3] = 242.4 // Index for best match found so far INT iBestMatch = 0 iCount = 1 WHILE iCount < 4 // Compare distances for current 'best' and next in list (actually comparing the squares but amounts to the same thing) IF VDIST2(vSpawnCoords[iCount], vTestCoords) < VDIST2(vSpawnCoords[iBestMatch], vTestCoords) iBestMatch = iCount ENDIF iCount++ ENDWHILE // Set the passed in variables to be the best match found vCoords = vSpawnCoords[iBestMatch] fHeading = fSpawnHead[iBestMatch] ENDPROC /// PURPOSE: /// DEBUG SKIP: Set up as if player has just chased off stalker /// PARAMS: /// bCheckpoint - If true we're doing a checkpoint, otherwise just skipping /// bStalkerAlive - CHECKPOINT ONLY - whether the stalker should be considered alive or dead PROC SKIP_TO_DRIVE_HOME(BOOL bCheckpoint = FALSE, BOOL bStalkerAlive = TRUE) CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: Skipping to STAGE_DRIVE_HOME") SAFE_REMOVE_BLIP(biBlip) SKIP_REMOVE_STALKER() VECTOR vecTmpCarCoord[2] FLOAT fTmpCarHead IF NOT bStalkerAlive REQUEST_ANIM_DICT(sTraceyAnimDict) ENDIF IF bCheckpoint // CHECKPOINT vecTmpCarCoord[0] = GET_REPLAY_CHECKPOINT_PLAYER_POSITION() // See if we can get a safe road node near that - IF GET_CLOSEST_VEHICLE_NODE_WITH_HEADING(vecTmpCarCoord[0], vecTmpCarCoord[1], fTmpCarHead) CPRINTLN(DEBUG_MISSION, "SKIP_TO_DRIVE_HOME: Got a spawn location from GET_CLOSEST_VEHICLE_NODE_WITH_HEADING") ELSE CPRINTLN(DEBUG_MISSION, "SKIP_TO_DRIVE_HOME: Couldn't get a spawn location from GET_CLOSEST_VEHICLE_NODE_WITH_HEADING falling back to old safe points method") GET_NEAREST_PRESET_SPAWN_TO_CP(vecTmpCarCoord[0], vecTmpCarCoord[1], fTmpCarHead) ENDIF vecReplayPlayerLocation = vecTmpCarCoord[1] fReplayPlayerHeading = fTmpCarHead CLEAR_AREA_OF_VEHICLES(vecReplayPlayerLocation, 10) START_REPLAY_SETUP(vecReplayPlayerLocation, fReplayPlayerHeading) SKIP_RESPAWN_TRACEY(vecReplayPlayerLocation, fReplayPlayerHeading, TRUE) // Set whether stalker is alive IF bStalkerAlive bStalkerDead = FALSE ELSE bStalkerDead = TRUE ENDIF ELSE // NOT A CHECKPOINT // If we're rolling with Tracey just drive home from wherever we are now IF (msTrack = MST_DRIVE_TO_STALKER OR msTrack = MST_TRIGGER_STALKER OR msTrack = MST_CHASE) AND IS_ENTITY_ALIVE(viTraceyCar) AND IS_ENTITY_ALIVE(pedTracey) IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) SAFE_SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), viTraceyCar) vecReplayPlayerLocation = GET_ENTITY_COORDS(viTraceyCar) ENDIF ENDIF // If we're not with Tracey or already driving home, warp to stalker junction ELSE // Warp player vecReplayPlayerLocation = << -52.8746, -110.5227, 56.9431 >> SET_ENTITY_COORDS(PLAYER_PED_ID(), vecReplayPlayerLocation) SKIP_RESPAWN_TRACEY(vecReplayPlayerLocation, 71.4, TRUE) SAFE_SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), viTraceyCar) ENDIF ENDIF SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_DRIVE_HOME, "Drive home (CP3)") UPDATE_AUDIO_SCENE(AUDIOSCENE_DRIVE_HOME) msTrack = MST_DRIVE_HOME sProgress = SP_SETUP MISSION_OBJECTIVE_EXPIRE(MO_MET1INITDRV)// Drive towards Vinewood. MISSION_OBJECTIVE_EXPIRE(MO_MET1TCAR) // Get into Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1WANT) // Lose the cops. MISSION_OBJECTIVE_EXPIRE(MO_MET1CHASE) // Chase off the stalker. MISSION_OBJECTIVE_RESET(MO_MET1HOME) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1HOTEL) // Go home. MISSION_OBJECTIVE_RESET(MO_MET1GETBKT) // Get back in Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1DLT) // Return to Tracey's car. IF bCheckpoint WHILE NOT HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT) WAIT(0) ENDWHILE IF NOT bStalkerAlive WHILE NOT HAS_ANIM_DICT_LOADED(sTraceyAnimDict) WAIT(0) ENDWHILE ENDIF END_REPLAY_SETUP(viTraceyCar, VS_DRIVER, FALSE) ELSE WAIT_FOR_WORLD_TO_LOAD(vecReplayPlayerLocation) ENDIF ENDPROC #IF IS_DEBUG_BUILD /// PURPOSE: /// DEBUG SKIP: Set the player in Tracey's car to complete mission PROC SKIP_TO_ARRIVE_HOME() CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: Skipping to STALKER_KILLED") SAFE_REMOVE_BLIP(biBlip) SKIP_REMOVE_STALKER() IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) // Respot player SET_ENTITY_COORDS(PLAYER_PED_ID(), vecReturnLocation) // Respawn Tracey SKIP_RESPAWN_TRACEY(vecReturnLocation, 331.1, TRUE) SAFE_SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), viTraceyCar) ENDIF UPDATE_AUDIO_SCENE(AUDIOSCENE_DONE) msTrack = MST_AT_HOME sProgress = SP_SETUP MISSION_OBJECTIVE_EXPIRE(MO_MET1INITDRV)// Drive towards Vinewood. MISSION_OBJECTIVE_EXPIRE(MO_MET1TCAR) // Get into Tracey's car. MISSION_OBJECTIVE_RESET(MO_MET1WANT) // Lose the cops. MISSION_OBJECTIVE_EXPIRE(MO_MET1CHASE) // Chase off the stalker. MISSION_OBJECTIVE_EXPIRE(MO_MET1HOME) // Go home. MISSION_OBJECTIVE_EXPIRE(MO_MET1HOTEL) // Go home. MISSION_OBJECTIVE_EXPIRE(MO_MET1GETBKT) // Get back in Tracey's car. MISSION_OBJECTIVE_EXPIRE(MO_MET1DLT) // Return to Tracey's car. SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_MET_TRACEY, "Met Tracey (CP2)") ENDPROC /// PURPOSE: /// Evaluates Z-skip menu output and skips to appropriate point PROC DO_Z_SKIP(MISSION_SKIP_STAGE mssJumpTo) // Z-skip init RC_START_Z_SKIP() SKIP_CLEAR_WANTED() SKIP_KILL_CONVERSATION() SWITCH mssJumpTo CASE MSS_RESTART SKIP_TO_MS_INIT() BREAK CASE MSS_RESTART_CAR SKIP_TO_MS_INIT(TRUE) BREAK CASE MSS_MEET_TRACEY SKIP_TO_MEET_TRACEY() BREAK CASE MSS_STALKER_APPEARS SKIP_TO_STALKER_APPEARS() BREAK CASE MSS_STALKER_WRECK SKIP_TO_STALKER_WRECK() BREAK CASE MSS_STALKER_STUCK SKIP_TO_STALKER_STUCK() BREAK CASE MSS_DRIVE_HOME SKIP_TO_DRIVE_HOME() BREAK CASE MSS_DRIVE_HOME_DEAD SKIP_TO_DRIVE_HOME(FALSE, FALSE) BREAK CASE MSS_ARRIVE_HOME SKIP_TO_ARRIVE_HOME() BREAK ENDSWITCH // Z-skip complete RC_END_Z_SKIP() ENDPROC /// PURPOSE: /// Determines the correct stage to skip to in the mission's J-skips PROC SKIP_FORWARD() SWITCH msTrack CASE MST_DRIVE_TO_TRACEY CPRINTLN(DEBUG_MISSION, "J-skip : From MST_WAIT_TO_SPAWN_TRACEY") DO_Z_SKIP(MSS_MEET_TRACEY) BREAK CASE MST_WAIT_FOR_PLAYER CPRINTLN(DEBUG_MISSION, "J-skip : From MST_WAIT_FOR_PLAYER") DO_Z_SKIP(MSS_STALKER_APPEARS) BREAK CASE MST_DRIVE_TO_STALKER CPRINTLN(DEBUG_MISSION, "J-skip : From MST_TRACEY_START_DRIVING|MST_LINEAR_ROUTE") DO_Z_SKIP(MSS_STALKER_APPEARS) BREAK CASE MST_TRIGGER_STALKER CASE MST_CHASE CPRINTLN(DEBUG_MISSION, "J-skip : From MST_TRIGGER_STALKER|MST_CHASE") DO_Z_SKIP(MSS_STALKER_WRECK) BREAK CASE MST_STALKER_WRECKED CPRINTLN(DEBUG_MISSION, "J-skip : From MST_STALKER_WRECKED") DO_Z_SKIP(MSS_DRIVE_HOME) BREAK CASE MST_DRIVE_HOME CPRINTLN(DEBUG_MISSION, "J-skip : From MST_DRIVE_HOME") DO_Z_SKIP(MSS_ARRIVE_HOME) BREAK CASE MST_LOSE_WANTED CPRINTLN(DEBUG_MISSION, "J-skip : From MST_LOSE_WANTED") SKIP_CLEAR_WANTED() BREAK // CASE MST_FAIL_TRACEY_DRIVE_OFF // CASE MST_PASSED // // Do nothing, nowhere to go forward to // CPRINTLN(DEBUG_MISSION, "J-skip was requested but script is already awaiting a pass/fail exit.") // BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Determines the correct stage to skip to in the mission's P-skips PROC SKIP_BACKWARD() SWITCH msTrack CASE MST_INIT // Do nothing CPRINTLN(DEBUG_MISSION, "P-skip was requested but script is already at beginning.") BREAK CASE MST_DRIVE_TO_TRACEY CASE MST_WAIT_FOR_PLAYER CPRINTLN(DEBUG_MISSION, "P-skip : From MST_WAIT_TO_SPAWN_TRACEY|MST_WAIT_FOR_PLAYER") DO_Z_SKIP(MSS_RESTART) BREAK CASE MST_DRIVE_TO_STALKER CASE MST_TRIGGER_STALKER // CASE MST_FAIL_TRACEY_DRIVE_OFF CPRINTLN(DEBUG_MISSION, "P-skip : From MST_TRACEY_START_DRIVING|MST_LINEAR_ROUTE|MST_TRIGGER_STALKER") DO_Z_SKIP(MSS_MEET_TRACEY) BREAK CASE MST_CHASE CASE MST_STALKER_WRECKED CPRINTLN(DEBUG_MISSION, "P-skip : From MST_CHASE|MST_STALKER_WRECKED") DO_Z_SKIP(MSS_STALKER_APPEARS) BREAK CASE MST_DRIVE_HOME CPRINTLN(DEBUG_MISSION, "P-skip : From MST_DRIVE_HOME") DO_Z_SKIP(MSS_STALKER_WRECK) BREAK CASE MST_AT_HOME CPRINTLN(DEBUG_MISSION, "P-skip : From MST_AT_HOME") DO_Z_SKIP(MSS_DRIVE_HOME) BREAK CASE MST_FAIL_CALL CPRINTLN(DEBUG_MISSION, "P-skip : From MST_SUCCESS_CALL|MST_FAIL_CALL") DO_Z_SKIP(MSS_STALKER_WRECK) BREAK CASE MST_LOSE_WANTED CPRINTLN(DEBUG_MISSION, "P-skip : From MST_LOSE_WANTED") SKIP_CLEAR_WANTED() BREAK // CASE MST_PASSED // // Script is exiting now - do nothing // CPRINTLN(DEBUG_MISSION, "P-skip was requested but ignoring as the script is in a fail/pass state so it's too late!") // BREAK ENDSWITCH ENDPROC #ENDIF // =========================================================================================================== // Termination // =========================================================================================================== /// ----------------------------------------------------------------------------------------------------------- /// Mission Cleanup /// ----------------------------------------------------------------------------------------------------------- /// PARAMS: /// bDelete - Delete everything (for debug cleanups) /// bTraceyRelToFamily - If Tracey has already been released to the family controller, don't try releasing her again PROC Mission_Cleanup(BOOL bDelete = FALSE, BOOL bTraceyRelToFamily = FALSE) CPRINTLN(DEBUG_MISSION, "Mission_Cleanup") #IF IS_DEBUG_BUILD IF DOES_WIDGET_GROUP_EXIST(widgetGroup) DELETE_WIDGET_GROUP(widgetGroup) ENDIF #ENDIF SAFE_REMOVE_BLIP(biBlip) // Stalker cleanup IF DOES_ENTITY_EXIST(mvStalkerCar.vehicle) IF bStalkerStuckCheckActive REMOVE_VEHICLE_UPSIDEDOWN_CHECK(mvStalkerCar.vehicle) bStalkerStuckCheckActive = FALSE ENDIF REMOVE_ENTITY_FROM_AUDIO_MIX_GROUP(mvStalkerCar.vehicle) ENDIF IF bStalkerModelRequested SET_MODEL_AS_NO_LONGER_NEEDED(mnStalkerModel) SET_MODEL_AS_NO_LONGER_NEEDED(mvStalkerCar.model) ENDIF IF bDelete SAFE_DELETE_PED(pedStalker) SAFE_DELETE_VEHICLE(mvStalkerCar.vehicle) ELSE SAFE_RELEASE_PED(pedStalker) SAFE_RELEASE_VEHICLE(mvStalkerCar.vehicle) ENDIF KILL_CHASE_HINT_CAM(localChaseHintCamStruct) // Tracey cleanup IF bRelGroupExists REMOVE_RELATIONSHIP_GROUP(relGroupFriendly) ENDIF IF IS_ENTITY_ALIVE(viTraceyCar) AND bStuckCheckActive REMOVE_VEHICLE_STUCK_CHECK(viTraceyCar) bStuckCheckActive = FALSE ENDIF IF bDelete SAFE_DELETE_PED(pedTracey) SAFE_DELETE_VEHICLE(viTraceyCar) ELSE IF NOT bTraceyRelToFamily IF DOES_ENTITY_EXIST(pedTracey) IF NOT IS_ENTITY_DEAD(pedTracey) CLEAR_PED_TASKS(pedTracey) SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(pedTracey, FALSE) SAFE_RELEASE_PED(pedTracey) ELSE // This case shouldn't really happen as a dead tracey is a fail condition SAFE_RELEASE_PED(pedTracey) ENDIF ENDIF ENDIF SAFE_RELEASE_VEHICLE(viTraceyCar) ENDIF SET_ROADS_BACK_TO_ORIGINAL_IN_ANGLED_AREA(naaCarPark.vEnds[0], naaCarPark.vEnds[1], naaCarPark.fWidth) REMOVE_SCENARIO_BLOCKING_AREA(sbiCarpark) SET_INSTANCE_PRIORITY_HINT(INSTANCE_HINT_NONE) // Clear vehicle suppression SET_VEHICLE_MODEL_IS_SUPPRESSED(mvStalkerCar.model, FALSE) SET_VEHICLE_MODEL_IS_SUPPRESSED(ISSI2, FALSE) TOGGLE_VEHICLE_SUPPRESSION(FALSE) CLEAR_WEATHER_TYPE_PERSIST() // Normalise wanted stuff SET_WANTED_LEVEL_MULTIPLIER(1.0) SET_CREATE_RANDOM_COPS(TRUE) TERMINATE_THIS_THREAD() ENDPROC // ----------------------------------------------------------------------------------------------------------- // Mission Pass // ----------------------------------------------------------------------------------------------------------- PROC Mission_Passed(BOOL bDebugPass = FALSE) CPRINTLN(DEBUG_MISSION, "Mission_Passed") Mission_Flow_Mission_Passed() IF bDebugPass Mission_Cleanup(FALSE, FALSE) ELSE // Tracey will have been released to the family controller Mission_Cleanup(FALSE, TRUE) ENDIF ENDPROC //************************************************************************************************************************************************* // // Data init proc // //************************************************************************************************************************************************* // Initialise general data PROC DATA_INIT() CPRINTLN(DEBUG_MISSION, "DATA INIT") // Should we be going to the hotel? IF GetMichaelScheduleStage() = MSS_M4_WithoutFamily CPRINTLN(DEBUG_MISSION, "MICHAEL EVENTS: Family at the hotel") bGoingToHotel = TRUE ELSE CPRINTLN(DEBUG_MISSION, "MICHAEL EVENTS: Family at home, not going to hotel") bGoingToHotel = FALSE ENDIF // Stalker look at timer limits iStalkerRamLookDelay = 1000 iStalkerProxLookDelay = 1500 iStalkerLookAtTime = 3500 //600 #IF IS_DEBUG_BUILD mSkipMenu[0].sTxtLabel = "Restart" mSkipMenu[1].sTxtLabel = "Restart and give car" mSkipMenu[2].sTxtLabel = "Meet Tracey (CP1)" mSkipMenu[3].sTxtLabel = "Stalker appears (CP2)" mSkipMenu[4].sTxtLabel = "Stalker wrecked" mSkipMenu[5].sTxtLabel = "Stalker stuck" mSkipMenu[6].sTxtLabel = "Drive home/hotel - Stalker escaped (CP3)" mSkipMenu[7].sTxtLabel = "Drive home/hotel - Stalker dead (CP4)" mSkipMenu[8].sTxtLabel = "Arrive home/hotel (end)" IF NOT DOES_WIDGET_GROUP_EXIST(widgetGroup) CPRINTLN(DEBUG_MISSION, "Creating widget group - look for Michael Event Tracey widgets") widgetGroup = START_WIDGET_GROUP("Michael Event Tracey widgets") ADD_WIDGET_BOOL("TTY Toggle - Tracey Debug Info", bDebugTraceyTTY) ADD_WIDGET_BOOL("TTY Toggle - Stalker Debug Info", bDebugStalkerTTY) ADD_WIDGET_BOOL("Display call monitoring info on screen", bDebugCallTimeDisplay) ADD_WIDGET_BOOL("Flip stalker car on roof (auto-unchecks)", bDebugFlipStalkerCar) ADD_WIDGET_BOOL("Toggle the -is player driving weird- tracking bool ", bBonkersDriving) ADD_WIDGET_INT_SLIDER("Time to wait at the destinations (milliseconds)", iLookAroundDelay, 0, 5000, 100) ADD_WIDGET_INT_SLIDER("Delay before stalker can do a ram triggered look", iStalkerRamLookDelay, 1000, 15000, 50) ADD_WIDGET_INT_SLIDER("Delay before stalker can do a proximity triggered look", iStalkerProxLookDelay, 1000, 15000, 50) ADD_WIDGET_INT_SLIDER("How long each look task should run for", iStalkerLookAtTime, 100, 15000, 50) ADD_WIDGET_BOOL("Going to hotel instead of house if checked", bGoingToHotel) STOP_WIDGET_GROUP() ENDIF #ENDIF REQUEST_ADDITIONAL_TEXT("MET1", MISSION_TEXT_SLOT) STORE_AUDIOSCENES() STORE_MISSION_OBJECTIVE_DATA() SETUP_ENROUTE_CHAT() SETUP_NPC_CARS() STORE_DESTINATION_POINTS() STORE_STALKER_TRIGGERS() SETUP_NAA_VOLUME(naaCarPark, << 200.34, -30.73, 60.91 >>, << 244.07, -45.73, 77.22 >>, 30.0) // Suppress car model for stalker SET_VEHICLE_MODEL_IS_SUPPRESSED(mvStalkerCar.model, TRUE) // Suppress Issi2 (Tracey's car) SET_VEHICLE_MODEL_IS_SUPPRESSED(ISSI2, TRUE) // Suppress awkward vehicle models TOGGLE_VEHICLE_SUPPRESSION(TRUE) // Have we activated the stalker car's stuck check bStalkerStuckCheckActive = FALSE // Does stalker know that player is now after him bStalkerFleeing = FALSE // Tracey won't be spawned yet bTraceyIsCurrentlySpawned = FALSE // Prep player ped for phone calls etc. ADD_PED_FOR_DIALOGUE(mConversationStruct, 0, PLAYER_PED_ID(), "MICHAEL") // No fail reason yet sFailReason = "DEFAULT" // Get the current in-game time for triggering Tracey warning/fail calls INIT_DRIVE_TIMERS() wfcProgress = WFC_SETUP bWFCOnHold = FALSE // Set audioscene track so initial state will be correctly set iCurrentAudioScene = -1 // Fix possible bad weather - we're driving with the top down IF Is_Replay_In_Progress() // On replay - set weather now SET_WEATHER_TYPE_PERSIST("EXTRASUNNY") ELSE // Change to sunny quickly SET_WEATHER_TYPE_OVERTIME_PERSIST("EXTRASUNNY", 20) ENDIF SET_INSTANCE_PRIORITY_HINT(INSTANCE_HINT_DRIVING) // Wanted level multiplier - B*650203 SET_WANTED_LEVEL_MULTIPLIER(0.2) ENDPROC //************************************************************************************************************************************************* // // Mission stage procs // //************************************************************************************************************************************************* /// PURPOSE: /// Mission stage proc /// Initial stage - mainly a wait for the text to load. PROC STAGE_INIT() CPRINTLN(DEBUG_MISSION, "STAGE_INIT: Waiting for mission text to load...") IF HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT) CPRINTLN(DEBUG_MISSION, "STAGE_INIT: Progressing to STAGE_DRIVE_TO_TRACEY.") UPDATE_AUDIO_SCENE(AUDIOSCENE_NONE) SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN(<<0,0,0>>, 0, TRUE, CHAR_MICHAEL) IF IS_REPEAT_PLAY_ACTIVE() SAFE_FADE_SCREEN_IN_FROM_BLACK() ENDIF msTrack = MST_DRIVE_TO_TRACEY sProgress = SP_SETUP ENDIF ENDPROC /// PURPOSE: /// Mission stage proc /// Player drives to meet up with Tracey in Vinewood. /// Check the player is within reasonable range before we spawn Tracey, spawning her too far away won't work. PROC STAGE_DRIVE_TO_TRACEY() SWITCH sProgress CASE SP_SETUP CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_TRACEY : SP_SETUP") // Do drive to plaza blip and objective DISPLAY_MISSION_OBJECTIVE(MO_MET1INITDRV) // Go to Vinewood Plaza IF NOT DOES_BLIP_EXIST(biBlip) biBlip = CREATE_FAKE_TRACEY_PED_BLIP(vecTraceyPedStart, TRUE) SET_TAXI_DROPOFF_LOCATION_FOR_BLIP(biBlip, <<237.2897, -60.5704, 68.4345>>, 70.9753) ENDIF // Initially check the audio scene state IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) bPlayerOnFoot = FALSE UPDATE_AUDIO_SCENE(AUDIOSCENE_GO_TO_TRACEY) ELSE bPlayerOnFoot = TRUE ENDIF sProgress = SP_RUNNING BREAK CASE SP_RUNNING // Check whether player is taking too long IF NOT CHECK_WARNING_CALL() // Update audio scene if player was on foot and gets in car IF bPlayerOnFoot AND IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) bPlayerOnFoot = FALSE UPDATE_AUDIO_SCENE(AUDIOSCENE_GO_TO_TRACEY) // NOTE: Currently we don't flip-flop this because it wasn't requested but could do easily enough ENDIF // Check if Michael is wanted IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 // Wanted - lose cops before meeting Tracey msTrack = MST_LOSE_WANTED sProgress = SP_SETUP ELSE // Is player in range yet IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecTraceyStartPoint, SAFE_TRIGGER_DISTANCE) // Player near to Tracey rendezvous, progress to next stage sProgress = SP_CLEANUP ENDIF ENDIF ENDIF BREAK CASE SP_CLEANUP CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_TRACEY : SP_CLEANUP") // Check whether player is taking too long IF NOT CHECK_WARNING_CALL() REQUEST_ANIM_DICT(sTraceyAnimDict) // Stop ambient cars' crazy car park shenanigans SET_ROADS_IN_ANGLED_AREA(naaCarPark.vEnds[0], naaCarPark.vEnds[1], naaCarPark.fWidth, FALSE, FALSE) sbiCarpark = ADD_SCENARIO_BLOCKING_AREA(<< 227.4, -66.5, 67.5 >>, << 249.0, -30.8, 72.5 >>) CLEAR_AREA(vecTraceyStartPoint, 30, FALSE) CLEAR_AREA_OF_VEHICLES(vecTraceyStartPoint, 30, FALSE, FALSE, FALSE, FALSE) // This shouldn't be necessary but was added for B*1021065 sProgress = SP_SETUP msTrack = MST_WAIT_FOR_PLAYER ENDIF BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// Create Tracey in her car, then wait for the player to reach Tracey's location and get in the car. PROC STAGE_WAIT_FOR_PLAYER() SWITCH sProgress CASE SP_SETUP CPRINTLN(DEBUG_MISSION, "STAGE_WAIT_FOR_PLAYER : SP_SETUP") // Request anim dict again in case we're coming from a checkpoint REQUEST_ANIM_DICT(sTraceyAnimDict) // Check player isn't wanted IF NOT CHECK_WANTED_FAIL() // Check if player's taking too long to reach Tracey IF NOT CHECK_WARNING_CALL() // Spawn Tracey and car, go to running and wait for player to get closer once set up IF CREATE_TRACEY(pedTracey, vecTraceyPedStart, fTraceyPedStartHead) AND CREATE_NPC_VEHICLE(viTraceyCar, CHAR_TRACEY, vecTraceyStartPoint, fTraceyStartHeading) AND HAS_ANIM_DICT_LOADED(sTraceyAnimDict) AND IS_ENTITY_ALIVE(viTraceyCar) // Assert B*2233567: Possible that we'll drop through a few frames after CREATE_NPC_VEHICLE returns true CPRINTLN(DEBUG_MISSION, "Tracey now spawned! Going on to SP_RUNNING") bTraceyIsCurrentlySpawned = TRUE SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(pedTracey, TRUE) // Add Tracey to conversation struct REMOVE_PED_FOR_DIALOGUE(mConversationStruct, 3) ADD_PED_FOR_DIALOGUE(mConversationStruct, 3, pedTracey, "TRACEY") // Tracey can't fly through windscreen or be jacked SET_PED_CONFIG_FLAG(pedTracey, PCF_WillFlyThroughWindscreen, FALSE) SET_PED_CONFIG_FLAG(pedTracey, PCF_DontAllowToBeDraggedOutOfVehicle, TRUE) // Tracey is in friendly group with player DO_FRIENDLY_GROUP_SETUP() // Give Tracey some stuff to do TASK_PLAY_ANIM(pedTracey, sTraceyAnimDict, "nervous_loop", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING) SET_PED_KEEP_TASK(pedTracey, TRUE) // Configure Tracey's car SET_ENTITY_LOAD_COLLISION_FLAG(viTraceyCar, TRUE) SET_VEHICLE_STRONG(viTraceyCar, TRUE) LOWER_CONVERTIBLE_ROOF(viTraceyCar, TRUE) ADD_VEHICLE_UPSIDEDOWN_CHECK(viTraceyCar) SET_VEHICLE_HAS_STRONG_AXLES(viTraceyCar, TRUE) SET_VEHICLE_AS_RESTRICTED(viTraceyCar, RESTRICTION_TRACEY) bStuckCheckActive = TRUE // Don't allow random cops to spawn from now on SET_CREATE_RANDOM_COPS(FALSE) // Progress checkers iTraceyWaitingChatTimer = GET_GAME_TIMER() iTraceyWaitingConversationCount = 0 cptTraceyWaitingComments = CPT_WAIT_TO_TRIGGER traceyCarEntry = TCE_WAIT_FOR_PLAYER_RANGE bMichaelCommentPlayed = FALSE sProgress = SP_RUNNING ENDIF ENDIF ENDIF BREAK CASE SP_RUNNING // Check for warning call availability toggling on/off IF bWFCOnHold = FALSE // Warning calls are currently available - see if they should be toggled off IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecTraceyStartPoint, SAFE_TRIGGER_DISTANCE) CPRINTLN(DEBUG_MISSION, "STAGE_WAIT_FOR_PLAYER: SP_RUNNING: Player is within ", SAFE_TRIGGER_DISTANCE, "m of Tracey, warning/fail calls toggled OFF") bWFCOnHold = TRUE ENDIF ELSE // Warning calls are not currently available - see if they should be toggled on IF NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecTraceyStartPoint, TRIGGER_OFF_DISTANCE) CPRINTLN(DEBUG_MISSION, "STAGE_WAIT_FOR_PLAYER: SP_RUNNING: Player is over ", TRIGGER_OFF_DISTANCE, "m from Tracey, warning/fail calls toggled ON") bWFCOnHold = FALSE ENDIF ENDIF // Check whether player's taking too long IF NOT CHECK_WARNING_CALL() // Check player isn't wanted IF NOT CHECK_WANTED_FAIL() SWITCH traceyCarEntry CASE TCE_WAIT_FOR_PLAYER_RANGE // Wait for player to be close to Tracey // IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, TRACEY_MET_DIST) IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<246.147903,-39.210854,67.896645>>, <<202.663467,-23.777254,72.904160>>, 22.0, FALSE) // B*930057 - simple distance check allows triggering from roof - B*978708 added locate chevrons OR IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<233.789108,-45.515152,67.573883>>, <<229.991577,-55.962749,72.289795>>, 12.5, FALSE) // B*1028273 - adjusted trigger area so Tracey's reaction looks better // OR IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<238.792450,-32.855148,68.715935>>, <<237.636749,-36.150738,69.726151>>, 1.0, TRUE) // redundant check makes a chevron show at yellow blip location - REMOVED due to B*1135720 IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ENDIF // Tracey now gets in right away SEQUENCE_INDEX siTmpTC OPEN_SEQUENCE_TASK(siTmpTC) TASK_PLAY_ANIM(NULL, sTraceyAnimDict, "breakout", NORMAL_BLEND_IN, SLOW_BLEND_OUT, -1) TASK_ENTER_VEHICLE(NULL, viTraceyCar, DEFAULT_TIME_BEFORE_WARP*3, VS_FRONT_RIGHT, PEDMOVEBLENDRATIO_RUN) // TASK_LOOK_AT_ENTITY(NULL, PLAYER_PED_ID(), -1, SLF_WHILE_NOT_IN_FOV) // head track Michael - B*984650 - removed from task sequence due to B*1306732 CLOSE_SEQUENCE_TASK(siTmpTC) CLEAR_PED_TASKS(pedTracey) TASK_LOOK_AT_ENTITY(pedTracey, PLAYER_PED_ID(), 4000, SLF_DEFAULT, SLF_LOOKAT_HIGH) TASK_PERFORM_SEQUENCE(pedTracey, siTmpTC) CLEAR_SEQUENCE_TASK(siTmpTC) // Make player go straight to driver door SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_ForceDirectEntry, TRUE) // Record getting in REPLAY_START_EVENT() iMeetTimer = GET_GAME_TIMER() + 10000 bMeetReplayIsGoing = TRUE traceyCarEntry = TCE_WAIT_FOR_CONVERSATION_START ELSE // Audio scene update triggers within this proc TRACEY_WAITING_DIALOGUE() ENDIF BREAK CASE TCE_WAIT_FOR_CONVERSATION_START // Start the conversation IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_SEES", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES) OR IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar, FALSE) // Allow progression when audio doesn't play CPRINTLN(DEBUG_MISSION, "STAGE_WAIT_FOR_PLAYER: SP_RUNNING: Michael met up with Tracey. Setting checkpoint.") // Close enough to say they reached the checkpoint SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_MET_TRACEY, "Met Tracey (CP2)") // Disabling dawdle fail for now, may need revision // Set Tracey's wait mode to car-park wfcProgress = WFC_ARRIVED_WAIT iFootDawdleTimer = GET_GAME_TIMER() // Update blips and change objective SAFE_REMOVE_BLIP(biBlip) biBlip = CREATE_VEHICLE_BLIP(viTraceyCar, TRUE) DISPLAY_MISSION_OBJECTIVE(MO_MET1TCAR) traceyCarEntry = TCE_WAIT_FOR_PLAYER_IN_CAR ENDIF // Stop recording IF bMeetReplayIsGoing = TRUE AND GET_GAME_TIMER() > iMeetTimer REPLAY_STOP_EVENT() bMeetReplayIsGoing = FALSE ENDIF // Revised brute force head track - B*1306732 TASK_LOOK_AT_ENTITY(pedTracey, PLAYER_PED_ID(), 2000, SLF_WHILE_NOT_IN_FOV, SLF_LOOKAT_VERY_HIGH) BREAK CASE TCE_WAIT_FOR_PLAYER_IN_CAR IF NOT bMichaelCommentPlayed AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() AND NOT IS_THIS_PRINT_BEING_DISPLAYED("MET1TCAR") AND NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) // IF IS_THIS_PRINT_BEING_DISPLAYED("MET1TCAR") // IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_GETIN", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES) // bMichaelCommentPlayed = TRUE // ENDIF // ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_GETIN", CONV_PRIORITY_MEDIUM) bMichaelCommentPlayed = TRUE ENDIF // ENDIF ENDIF // Wait for player and Tracey to both be in car IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar, FALSE) SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_ForceDirectEntry, FALSE) IF IS_PED_IN_VEHICLE(pedTracey, viTraceyCar, FALSE) CPRINTLN(DEBUG_MISSION, "STAGE_WAIT_FOR_PLAYER: SP_RUNNING: Tracey and Michael both in car.") CLEAR_PRINTS() CLEAR_PED_TASKS(pedTracey) // Stop looking at Michael once he's in the car UPDATE_AUDIO_SCENE(AUDIOSCENE_DRIVE_TO_STALKER) sProgress = SP_CLEANUP ELIF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1WAIT) SAFE_REMOVE_BLIP(biBlip) biBlip = CREATE_PED_BLIP(pedTracey, TRUE, TRUE) SET_BLIP_NAME_FROM_TEXT_FILE(biBlip, "MET1LBTRAC") DISPLAY_MISSION_OBJECTIVE(MO_MET1WAIT) ENDIF ENDIF // Revised brute force head track - B*1306732 TASK_LOOK_AT_ENTITY(pedTracey, PLAYER_PED_ID(), 2000, SLF_WHILE_NOT_IN_FOV, SLF_LOOKAT_VERY_HIGH) // Stop recording IF bMeetReplayIsGoing = TRUE AND GET_GAME_TIMER() > iMeetTimer REPLAY_STOP_EVENT() bMeetReplayIsGoing = FALSE ENDIF BREAK ENDSWITCH // Check that the player hasn't run off, once Tracey is properly blipped IF (traceyCarEntry <> TCE_WAIT_FOR_PLAYER_RANGE) // Abandon check IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, 100.0) // FAIL - abandoned Tracey sFailReason = "MET1ABANDON" // You abandoned Tracey msTrack = MST_FAIL_FADE sProgress = SP_SETUP // Warn player not to run off, once Tracey is properly blipped ELIF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, 50.0) // Warn player DISPLAY_MISSION_OBJECTIVE(MO_MET1DLT) // Return to Tracey. ENDIF ENDIF // Check for player threatening Tracey IF HAS_PLAYER_THREATENED_PED(pedTracey, DEFAULT, DEFAULT, DEFAULT, TRUE) CLEAR_PED_TASKS(pedTracey) TASK_SMART_FLEE_PED(pedTracey, PLAYER_PED_ID(), 200, -1) IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() IF GET_SPEAKER_INT_FOR_CURRENT_STANDARD_CONVERSATION_LINE() = 3 KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ELSE KILL_FACE_TO_FACE_CONVERSATION() ENDIF ENDIF sFailReason = "MET1TRASCARE" msTrack = MST_FAIL_FADE sProgress = SP_SETUP ENDIF ENDIF ENDIF BREAK CASE SP_CLEANUP // Check player's not wanted IF NOT CHECK_WANTED_FAIL() CPRINTLN(DEBUG_MISSION, "STAGE_WAIT_FOR_PLAYER: SP_CLEANUP") SAFE_REMOVE_BLIP(biBlip) sProgress = SP_SETUP msTrack = MST_DRIVE_TO_STALKER INIT_BONKERS_DRIVING_CHECK() ENDIF // Stop recording IF bMeetReplayIsGoing = TRUE AND GET_GAME_TIMER() > iMeetTimer REPLAY_STOP_EVENT() bMeetReplayIsGoing = FALSE ENDIF BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// Drive around until the stalker appears PROC STAGE_DRIVE_TO_STALKER() // Stop recording IF bMeetReplayIsGoing = TRUE AND GET_GAME_TIMER() > iMeetTimer REPLAY_STOP_EVENT() bMeetReplayIsGoing = FALSE ENDIF SWITCH sProgress CASE SP_SETUP CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_SETUP") IF IS_ENTITY_ALIVE(viTraceyCar) // Initialise Tracey driving monitor variables IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar, TRUE) bPlayerOnFoot = FALSE ELSE bPlayerOnFoot = TRUE ENDIF IF IS_PED_IN_VEHICLE(pedTracey, viTraceyCar, TRUE) bTraceyonFoot = FALSE ELSE bTraceyonFoot = TRUE ENDIF iCurrentDestination = 0 traceyDestinationState = TDS_START_CHAT vecTraceyPositionTrack[0] = vecTraceyStartPoint vecTraceyPositionTrack[1] = vecTraceyPositionTrack[0] vecTraceyPositionTrack[2] = vecTraceyPositionTrack[1] iTraceyPositionTimer = GET_GAME_TIMER() iComplainTimer = GET_GAME_TIMER() sProgress = SP_RUNNING PLAYER_BONKERS_DRIVING_CHECK() ENDIF BREAK CASE SP_RUNNING // Check for wanted fail IF NOT CHECK_WANTED_FAIL() UPDATE_TRACEYCAR_SAVED_COORDS() PLAYER_BONKERS_DRIVING_CHECK() // Checks for if player has got out of the car IF bPlayerOnFoot IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = FALSE SAFE_REMOVE_BLIP(biBlip) // Car will be blipped CLEAR_PRINTS() // Check whether Tracey is still in car IF IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) bTraceyonFoot = FALSE // If we should have a blip, recreate it IF traceyDestinationState = TDS_DRIVING_TO_POINT AND NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), dpLocates[iCurrentDestination].location, dpLocates[iCurrentDestination].range) biBlip = CREATE_COORD_BLIP(dpLocates[iCurrentDestination].location) // If handler was waiting for chat to start, it will need a nudge because it's waiting on a killed conversation ELIF traceyDestinationState = TDS_WAITING_FOR_CHAT_TO_START traceyDestinationState = TDS_WAITING_FOR_BLIP_LINE ENDIF ELSE bTraceyonFoot = TRUE bTraceyAttemptingReentry = FALSE ENDIF ELIF HAS_PLAYER_THREATENED_PED(pedTracey) CLEAR_PED_TASKS(pedTracey) TASK_SMART_FLEE_PED(pedTracey, PLAYER_PED_ID(), 200, -1) IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() IF GET_SPEAKER_INT_FOR_CURRENT_STANDARD_CONVERSATION_LINE() = 3 KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ELSE KILL_FACE_TO_FACE_CONVERSATION() ENDIF ENDIF sFailReason = "MET1TRASCARE" msTrack = MST_FAIL_FADE sProgress = SP_SETUP ELIF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1DLT) // Don't leave Tracey behind IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, WARN_DIS_TOO_FAR) DISPLAY_MISSION_OBJECTIVE(MO_MET1DLT) ENDIF ELIF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, ABANDON_TRACEY_DIST) sFailReason = "MET1ABANDON" // You abandoned Tracey sProgress = SP_SETUP msTrack = MST_FAIL_FADE ELSE // Head track IF IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) HANDLE_BUDDY_HEAD_TRACK_WHILE_ENTERING_VEHICLE() ENDIF ENDIF // Check for player getting out of car ELIF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = TRUE SAFE_REMOVE_BLIP(biBlip) biBlip = CREATE_VEHICLE_BLIP(viTraceyCar, TRUE) #IF IS_DEBUG_BUILD IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1GETBKT) CPRINTLN(DEBUG_MISSION, "Displaying get back in obective in STAGE_DRIVE_TO_STALKER: SP_RUNNING") ENDIF #ENDIF DISPLAY_MISSION_OBJECTIVE(MO_MET1GETBKT) IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION() ENDIF // Checks for when Tracey is not in car. (Player is in car) ELIF bTraceyonFoot // Should Tracey be trying to get back in IF NOT bTraceyAttemptingReentry AND NOT CAR_CURRENTLY_ON_ROOF() bTraceyAttemptingReentry = TRUE TASK_ENTER_VEHICLE(pedTracey, viTraceyCar, DEFAULT, VS_FRONT_RIGHT, PEDMOVEBLENDRATIO_RUN) ENDIF IF IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) bTraceyonFoot = FALSE SAFE_REMOVE_BLIP(biBlip) // Tracey will be blipped // Already checked that player is in car when we get here so see if conversation/objective handling needs to progress IF iCurrentDestination < NUM_DESTINATIONS // If handler was waiting for chat to start, it will need a nudge because it's waiting on a killed conversation IF traceyDestinationState = TDS_WAITING_FOR_CHAT_TO_START CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_RUNNING: Player has just got back in car, TDS_WAITING_FOR_CHAT_TO_START bumped to TDS_WAITING_FOR_BLIP_LINE") traceyDestinationState = TDS_WAITING_FOR_BLIP_LINE ELIF traceyDestinationState = TDS_DO_DELAY CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_RUNNING: Player has just got back in car, TDS_WAITING_FOR_CHAT_TO_START bumped to TDS_WAITING_FOR_BLIP_LINE") traceyDestinationState = TDS_LOOK_AROUND ENDIF ENDIF ELIF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1DLT) // Don't leave Tracey behind IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, WARN_DIS_TOO_FAR) DISPLAY_MISSION_OBJECTIVE(MO_MET1DLT) ENDIF ELIF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, ABANDON_TRACEY_DIST) sFailReason = "MET1ABANDON" // You abandoned Tracey sProgress = SP_SETUP msTrack = MST_FAIL_FADE ENDIF // Check for whether Tracey has got out of car. (Player will be in car) ELIF NOT IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) bTraceyonFoot = TRUE bTraceyAttemptingReentry = FALSE SAFE_REMOVE_BLIP(biBlip) // A destination may be blipped biBlip = CREATE_PED_BLIP(pedTracey, TRUE, TRUE) DISPLAY_MISSION_OBJECTIVE(MO_MET1WAIT) IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ENDIF // Check for arriving at destinations. (Player and Tracey both in car) ELSE // Destination check varies by step SWITCH traceyDestinationState CASE TDS_START_CHAT // Don't update the chat etc. if the car is on its roof IF NOT CAR_CURRENTLY_ON_ROOF() IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", dpLocates[iCurrentDestination].chatLabel, CONV_PRIORITY_HIGH) CPRINTLN(DEBUG_MISSION, "Destination conversation ", iCurrentDestination, " starting...") traceyDestinationState = TDS_WAITING_FOR_CHAT_TO_START ENDIF ENDIF BREAK CASE TDS_WAITING_FOR_CHAT_TO_START // Wait until we're sure the conversation has started IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() CPRINTLN(DEBUG_MISSION, "Destination conversation ", iCurrentDestination, " now running.") traceyDestinationState = TDS_WAITING_FOR_BLIP_LINE ENDIF BREAK CASE TDS_WAITING_FOR_BLIP_LINE // Wait for the lines to reach the point where the blip should be displayed IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() IF GET_CURRENT_SCRIPTED_CONVERSATION_LINE() >= dpLocates[iCurrentDestination].blipUpdateLine CPRINTLN(DEBUG_MISSION, "TDS_WAITING_FOR_BLIP_LINE: Blip for destination ", iCurrentDestination, " added on line-count trigger.") biBlip = CREATE_COORD_BLIP(dpLocates[iCurrentDestination].location) traceyDestinationState = TDS_WAITING_TO_DELAY_QUEUING_EXTRA_CHAT ENDIF ELSE // Something went awry - blip now CPRINTLN(DEBUG_MISSION, "TDS_WAITING_FOR_BLIP_LINE: Blip for destination ", iCurrentDestination, " added on no-conversation trigger.") biBlip = CREATE_COORD_BLIP(dpLocates[iCurrentDestination].location) traceyDestinationState = TDS_WAITING_TO_DELAY_QUEUING_EXTRA_CHAT ENDIF BREAK CASE TDS_WAITING_TO_DELAY_QUEUING_EXTRA_CHAT // May need to recreate blip if player has been out of car - B*1135892 IF NOT DOES_BLIP_EXIST(biBlip) biBlip = CREATE_COORD_BLIP(dpLocates[iCurrentDestination].location) ENDIF // Skip out on this if the player's got ahead of where we expect IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), dpLocates[iCurrentDestination].location, dpLocates[iCurrentDestination].range) CPRINTLN(DEBUG_MISSION, "TDS_WAITING_TO_DELAY_QUEUING_EXTRA_CHAT: Skipping adding extra chat, destination ", iCurrentDestination, " already in range.") traceyDestinationState = TDS_DRIVING_TO_POINT // Wait of current conversation to be done ELIF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() CPRINTLN(DEBUG_MISSION, "Starting wait to queue extra conversation ", iCurrentDestination) iLookAroundTimer = GET_GAME_TIMER() + 2000 traceyDestinationState = TDS_WAITING_TO_QUEUE_EXTRA_CHAT ENDIF BREAK // ADDED ANOTHER DELAY HERE: B*996715 reopen 26/04 CASE TDS_WAITING_TO_QUEUE_EXTRA_CHAT // May need to recreate blip if player has been out of car - B*1135892 IF NOT DOES_BLIP_EXIST(biBlip) biBlip = CREATE_COORD_BLIP(dpLocates[iCurrentDestination].location) ENDIF // Skip out on this if the player's got ahead of where we expect IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), dpLocates[iCurrentDestination].location, dpLocates[iCurrentDestination].range) CPRINTLN(DEBUG_MISSION, "TDS_WAITING_TO_DELAY_QUEUING_EXTRA_CHAT: Skipping adding extra chat, destination ", iCurrentDestination, " already in range.") traceyDestinationState = TDS_DRIVING_TO_POINT // Wait of any active conversation to be done and delay timeout ELIF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() AND GET_GAME_TIMER() > iLookAroundTimer // Don't update the chat etc. if the car is on its roof IF NOT CAR_CURRENTLY_ON_ROOF() // See if we need to play bad driving complaint IF bBonkersDriving AND NOT ARE_STRINGS_EQUAL(dpLocates[iCurrentDestination].bonkersChatLabel, "NULL") // bad driving chat IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", dpLocates[iCurrentDestination].bonkersChatLabel, CONV_PRIORITY_HIGH) CPRINTLN(DEBUG_MISSION, "Destination extra conversation ", iCurrentDestination, " starting...") traceyDestinationState = TDS_DRIVING_TO_POINT ENDIF ELSE // Regular banter IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", dpLocates[iCurrentDestination].extraChatLabel, CONV_PRIORITY_HIGH) CPRINTLN(DEBUG_MISSION, "Destination extra conversation ", iCurrentDestination, " starting...") traceyDestinationState = TDS_DRIVING_TO_POINT ENDIF ENDIF ENDIF ENDIF BREAK CASE TDS_DRIVING_TO_POINT // Wait for player to be in range of next point IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), dpLocates[iCurrentDestination].location, dpLocates[iCurrentDestination].range) // Update coordinate iCurrentDestination++ SAFE_REMOVE_BLIP(biBlip) CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_RUNNING: Updating destination point to ", iCurrentDestination) LOOK_AROUND_FOR_STALKER() // REMOVED DELAY HERE: B*1135739/1135745 // REINSTATED DELAY HERE: B*996715 reopen 17/04 // Set wait timer unless it's the final point IF iCurrentDestination < NUM_DESTINATIONS AND IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() // Don't delay the next destination dialogue if banter has already finished CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_RUNNING: TDS_DRIVING_TO_POINT: Setting to do a delay after killed conversation") KILL_FACE_TO_FACE_CONVERSATION() traceyDestinationState = TDS_DO_DELAY ELSE CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_RUNNING: TDS_DRIVING_TO_POINT: Setting to not do a delay") // Kill conversation if stalker time IF iCurrentDestination = NUM_DESTINATIONS AND IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION() ENDIF bDoingDelay = FALSE traceyDestinationState = TDS_LOOK_AROUND ENDIF // May need to recreate blip if player has been out of car - B*1135892 ELIF NOT DOES_BLIP_EXIST(biBlip) biBlip = CREATE_COORD_BLIP(dpLocates[iCurrentDestination].location) ELSE // Do complaint conversations BANTER_CONTROLLER() ENDIF BREAK CASE TDS_DO_DELAY IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_RUNNING: TDS_DO_DELAY: Conversation finished, setting the look around delay now") bDoingDelay = TRUE iLookAroundTimer = GET_GAME_TIMER() + iLookAroundDelay traceyDestinationState = TDS_LOOK_AROUND ENDIF BREAK CASE TDS_LOOK_AROUND IF bDoingDelay // Wait for delay time at location until ready to continue IF GET_GAME_TIMER() > iLookAroundTimer bDoingDelay = FALSE ENDIF ELSE // If we have any destintions left, trigger the next destination conversation IF iCurrentDestination < NUM_DESTINATIONS CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_RUNNING: TDS_LOOK_AROUND: Updating destination point to ", iCurrentDestination) iLookAroundTimer = GET_GAME_TIMER() traceyDestinationState = TDS_START_CHAT // At final destination - trigger stalker ELSE CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_RUNNING: TDS_LOOK_AROUND: Reached last destination, going on to SP_CLEANUP") bMichaelArrivalLinePlayed = FALSE REQUEST_ANIM_DICT("missmichael_event@tracy") sProgress = SP_CLEANUP ENDIF ENDIF BREAK ENDSWITCH ENDIF ENDIF // If we're heading to last destination, reduce traffic density // SET_VEHICLE_DENSITY_MULTIPLIER has been replaced with SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME IF iCurrentDestination >= NUM_DESTINATIONS-2 SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0.5) ENDIF BREAK CASE SP_CLEANUP // Get ready to spawn stalker IF NOT CHECK_WANTED_FAIL() CPRINTLN(DEBUG_MISSION, "STAGE_DRIVE_TO_STALKER: SP_CLEANUP: Player reached destination") SAFE_REMOVE_BLIP(biBlip) // Checks for if player has got out of the car IF bPlayerOnFoot IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = FALSE SAFE_REMOVE_BLIP(biTraceyBlip) // Car will be blipped CLEAR_PRINTS() ENDIF ELIF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = TRUE biTraceyBlip = CREATE_VEHICLE_BLIP(viTraceyCar) #IF IS_DEBUG_BUILD IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1GETBKT) CPRINTLN(DEBUG_MISSION, "Displaying get back in obective in STAGE_DRIVE_TO_STALKER: SP_CLEANUP") ENDIF #ENDIF DISPLAY_MISSION_OBJECTIVE(MO_MET1GETBKT) ENDIF // Start requesting the models SPAWN_STALKER(<<0,0,0>>, 0, TRUE) // Comment on arrival IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_LOCX", CONV_PRIORITY_MEDIUM) bMichaelArrivalLinePlayed = TRUE ENDIF // Prep for stalker CHECK_STALKER_SPAWN_OCCLUSION() msTrack = MST_TRIGGER_STALKER sProgress = SP_SETUP ENDIF SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0.5) BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// Trigger stalker and get him onto the road to follow Tracey. /// Tracey IDs stalker so player can chase him. PROC STAGE_TRIGGER_STALKER() SWITCH sProgress CASE SP_SETUP IF NOT CHECK_WANTED_FAIL() CHECK_STALKER_SPAWN_OCCLUSION() // Request anim dict again in case at a checkpoint REQUEST_ANIM_DICT("missmichael_event@tracy") // Request Tracey's dead reaction anim - can potentially kill stalker right away REQUEST_ANIM_DICT(sTraceyAnimDict) // Checks for if player has got out of the car IF bPlayerOnFoot IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = FALSE SAFE_REMOVE_BLIP(biTraceyBlip) // Car will be blipped CLEAR_PRINTS() ENDIF ELIF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = TRUE biTraceyBlip = CREATE_VEHICLE_BLIP(viTraceyCar) #IF IS_DEBUG_BUILD IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1GETBKT) CPRINTLN(DEBUG_MISSION, "Displaying get back in obective in STAGE_TRIGGER_STALKER: SP_SETUP") ENDIF #ENDIF DISPLAY_MISSION_OBJECTIVE(MO_MET1GETBKT) ENDIF IF NOT bMichaelArrivalLinePlayed AND CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_LOCX", CONV_PRIORITY_MEDIUM) bMichaelArrivalLinePlayed = TRUE ENDIF IF SPAWN_STALKER(mvStalkerCar.location, mvStalkerCar.heading) CPRINTLN(DEBUG_MISSION, "STAGE_TRIGGER_STALKER: SP_SETUP: Stalker starting sequence") // Set stalker initial tracking variables and behaviour bPlayerWiseToStalker = FALSE bStalkerFleeing = FALSE bStalkerSpotChatStarted = FALSE SET_VEHICLE_FORWARD_SPEED(mvStalkerCar.vehicle, mvStalkerCar.initialSpeed) SEQUENCE_INDEX siTmp OPEN_SEQUENCE_TASK(siTmp) TASK_VEHICLE_MISSION_COORS_TARGET(NULL, mvStalkerCar.vehicle, GET_ENTITY_COORDS(viTraceyCar), MISSION_GOTO, 35.0, DRIVINGMODE_AVOIDCARS|DF_ChangeLanesAroundObstructions|DF_UseSwitchedOffNodes, 10, 12, TRUE) TASK_VEHICLE_ESCORT(NULL, mvStalkerCar.vehicle, viTraceyCar, VEHICLE_ESCORT_REAR, 25.0, DRIVINGMODE_AVOIDCARS|DF_ChangeLanesAroundObstructions|DF_UseSwitchedOffNodes) CLOSE_SEQUENCE_TASK(siTmp) TASK_PERFORM_SEQUENCE(pedStalker, siTmp) CLEAR_SEQUENCE_TASK(siTmp) SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_STALKER_APPEARS, "Stalker appears (CP2)") bStalkerDead = FALSE // Start tracking whether Tracey can see the stalker TICK_TRACEY_OUTCOME_TESTS() sProgress = SP_RUNNING #IF IS_DEBUG_BUILD ELIF bDebugStalkerTTY CPRINTLN(DEBUG_MISSION, "STAGE_TRIGGER_STALKER: SP_SETUP: Waiting for stalker to spawn...") #ENDIF ENDIF ENDIF // SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0.5) BREAK CASE SP_RUNNING // Checks for if player has got out of the car IF bPlayerOnFoot IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = FALSE SAFE_REMOVE_BLIP(biTraceyBlip) // Car will be blipped CLEAR_PRINTS() ENDIF ELIF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = TRUE biTraceyBlip = CREATE_VEHICLE_BLIP(viTraceyCar) #IF IS_DEBUG_BUILD IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1GETBKT) CPRINTLN(DEBUG_MISSION, "Displaying get back in obective in STAGE_TRIGGER_STALKER: SP_RUNNING") ENDIF #ENDIF DISPLAY_MISSION_OBJECTIVE(MO_MET1GETBKT) ENDIF // Checks for player damaging stalker IF IS_ENTITY_ALIVE(pedStalker) IF IS_ENTITY_ALIVE(mvStalkerCar.vehicle) // See if we're in range for Tracey to notice the stalker IF NOT bStalkerSpotChatStarted // IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, 35.0) // OR GET_GAME_TIMER() - iStalkerBlipTimer > STALKER_SPOT_TIMER IF HAS_ANIM_DICT_LOADED("missmichael_event@tracy") AND CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_TENDb", CONV_PRIORITY_MEDIUM) TASK_PLAY_ANIM(pedTracey, "missmichael_event@tracy", "base") REMOVE_ANIM_DICT("missmichael_event@tracy") IF NOT DOES_BLIP_EXIST(biBlip) biBlip = CREATE_VEHICLE_BLIP(mvStalkerCar.vehicle, FALSE) SET_BLIP_NAME_FROM_TEXT_FILE(biBlip, "MET1LBSTALK") UPDATE_AUDIO_SCENE(AUDIOSCENE_CHASE) ENDIF bStalkerSpotChatStarted = TRUE ENDIF // ENDIF ELSE // See if we can display the objective yet IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1CHASE) AND (GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()) CPRINTLN(DEBUG_MISSION, "Displaying MO_MET1CHASE in STAGE_TRIGGER_STALKER:SP_RUNNING after bStalkerSpotChatStarted set to TRUE") DISPLAY_MISSION_OBJECTIVE(MO_MET1CHASE) ENDIF // Check whether stalker should be reacting to player proximity/damage IF NOT bPlayerWiseToStalker // Check if player has damaged stalker IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(mvStalkerCar.vehicle, PLAYER_PED_ID()) OR HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(pedStalker, PLAYER_PED_ID()) CPRINTLN(DEBUG_MISSION, "STAGE_TRIGGER_STALKER: SP_RUNNING: player damaged stalker") CLEAR_ENTITY_LAST_DAMAGE_ENTITY(pedStalker) CLEAR_ENTITY_LAST_DAMAGE_ENTITY(mvStalkerCar.vehicle) bPlayerWiseToStalker = TRUE ELIF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, 15.0) CPRINTLN(DEBUG_MISSION, "STAGE_TRIGGER_STALKER: SP_RUNNING: player in spot range of stalker") bPlayerWiseToStalker = TRUE ENDIF // Once stalker knows player is wise to him ELSE CPRINTLN(DEBUG_MISSION, "STAGE_TRIGGER_STALKER: SP_RUNNING: Set stalker to flee player after spot") TASK_VEHICLE_MISSION_PED_TARGET(pedStalker, mvStalkerCar.vehicle, PLAYER_PED_ID(), MISSION_FLEE, 25.0, DRIVINGMODE_AVOIDCARS|DF_ChangeLanesAroundObstructions|DF_SteerAroundStationaryCars, 100.0, 1.0, TRUE) bStalkerFleeing = TRUE sProgress = SP_CLEANUP ENDIF // Check for player running away from stalker before spotting has occured IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_ESCAPE_DIST) CPRINTLN(DEBUG_MISSION, "Player drove away from stalker in STAGE_TRIGGER_STALKER!") SAFE_REMOVE_BLIP(biBlip) SAFE_REMOVE_BLIP(biTraceyBlip) sFailReason = "MET1ESCAPE" // The stalker escaped. msTrack = MST_FAIL_FADE sProgress = SP_SETUP ENDIF CONTROL_PED_CHASE_HINT_CAM_IN_VEHICLE(localChaseHintCamStruct, pedStalker) IF DOES_BLIP_EXIST(biBlip) UPDATE_CHASE_BLIP(biBlip, pedStalker, STALKER_ESCAPE_DIST, CHASE_FLASH_DIST) ENDIF ENDIF ELSE // Player has managed to trash stalker's car already msTrack = MST_STALKER_WRECKED sProgress = SP_SETUP ENDIF TICK_TRACEY_OUTCOME_TESTS() ELSE // Player has managed to kill stalker already CPRINTLN(DEBUG_MISSION, "STAGE_TRIGGER_STALKER: SP_RUNNING: Stalker killed!") SAFE_REMOVE_BLIP(biBlip) bStalkerDead = TRUE bTraceySawOutcome = DID_TRACEY_SEE_OUTCOME() START_STALKER_SNUFF_MOVIE() sProgress = SP_SETUP msTrack = MST_DRIVE_HOME CLEAR_PRINTS() ENDIF // SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME(0.5) BREAK CASE SP_CLEANUP CPRINTLN(DEBUG_MISSION, "STAGE_TRIGGER_STALKER: SP_CLEANUP: Going to STAGE_CHASE") // Allow cops again SET_CREATE_RANDOM_COPS(TRUE) // See if we can display the objective yet IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1CHASE) AND (GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()) CPRINTLN(DEBUG_MISSION, "Displaying MO_MET1CHASE in STAGE_TRIGGER_STALKER:SP_CLEANUP") DISPLAY_MISSION_OBJECTIVE(MO_MET1CHASE) ENDIF // Checks for if player has got out of the car IF bPlayerOnFoot IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = FALSE SAFE_REMOVE_BLIP(biTraceyBlip) // Car will be blipped CLEAR_PRINTS() ENDIF ELIF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = TRUE biTraceyBlip = CREATE_VEHICLE_BLIP(viTraceyCar) #IF IS_DEBUG_BUILD IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1GETBKT) CPRINTLN(DEBUG_MISSION, "Displaying get back in obective in STAGE_TRIGGER_STALKER: SP_CLEANUP") ENDIF #ENDIF DISPLAY_MISSION_OBJECTIVE(MO_MET1GETBKT) ENDIF // Track whether Tracey can see the stalker TICK_TRACEY_OUTCOME_TESTS() sProgress = SP_SETUP msTrack = MST_CHASE BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// Player pursues the stalker's car PROC STAGE_CHASE() SWITCH sProgress CASE SP_SETUP // Stalker will now spot Michael almost straight away IF IS_ENTITY_ALIVE(pedStalker) CONTROL_PED_CHASE_HINT_CAM_IN_VEHICLE(localChaseHintCamStruct, pedStalker) // Check for distance fail in case player is sat doing nothing IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_ESCAPE_DIST) SAFE_REMOVE_BLIP(biBlip) sFailReason = "MET1ESCAPE" msTrack = MST_FAIL_FADE sProgress = SP_SETUP ELSE // See if we can display the objective yet IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1CHASE) AND (GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()) CPRINTLN(DEBUG_MISSION, "Displaying MO_MET1CHASE in STAGE_CHASE:SP_SETUP") DISPLAY_MISSION_OBJECTIVE(MO_MET1CHASE) ENDIF CPRINTLN(DEBUG_MISSION, "STAGE_CHASE: SP_SETUP: Initialising stalker chase stuff, going to SP_RUNNING") // Initialise the conversation tracker iChaseChatTimer = GET_GAME_TIMER()// - CHASE_COMMENT_DELAY + 1000 // Make the first comment almost immediate iShootingComplaintGap = GET_GAME_TIMER() iShootingTimer = GET_GAME_TIMER() - RECENT_SHOOTING_TIMEOUT cptChaseTrack = CPT_WAIT_TO_TRIGGER iChaseStalkerChatCount = 0 iChaseTraceyChatCount = 0 bStalkerChatting = FALSE bTraceyChatting = FALSE bQuickRamComment = FALSE bShootingComment = FALSE iLastCollisionTime = GET_GAME_TIMER() - 1000 // Reinitialise the position tracking (stalker spawning stage can take a few seconds with no updates, or we may be restarting from a checkpoint) vecTraceyPositionTrack[0] = vecTraceyStartPoint vecTraceyPositionTrack[1] = vecTraceyPositionTrack[0] vecTraceyPositionTrack[2] = vecTraceyPositionTrack[1] iTraceyPositionTimer = GET_GAME_TIMER() iComplainTimer = GET_GAME_TIMER() // Start Stalker fleeing if they aren't already IF NOT bStalkerFleeing bStalkerFleeing = TRUE CLEAR_PED_TASKS(pedStalker) TASK_VEHICLE_MISSION_PED_TARGET(pedStalker, mvStalkerCar.vehicle, PLAYER_PED_ID(), MISSION_FLEE, 25.0, DRIVINGMODE_AVOIDCARS|DF_ChangeLanesAroundObstructions|DF_SteerAroundStationaryCars, 100.0, 1.0, TRUE) ENDIF // Initialise stalker position tracking and progress to main chase tracking iStalkerPositionTimer = GET_GAME_TIMER() IF IS_ENTITY_ALIVE(mvStalkerCar.vehicle) vecStalkerPositionTrack[0] = GET_ENTITY_COORDS(mvStalkerCar.vehicle) vecStalkerPositionTrack[1] = vecStalkerPositionTrack[0] vecStalkerPositionTrack[2] = vecStalkerPositionTrack[1] ENDIF INIT_HAS_PLAYER_RAMMED_ENEMY_ENOUGH(bStalkerRammedLastFrame, iStalkerRamTimer, iStalkerRamCount, fRamClosingSpeedLastFrame) // Init lookat behaviour delay //SET_PED_CAN_HEAD_IK(pedStalker, FALSE) iStalkerLookTimer = GET_GAME_TIMER() IF DOES_BLIP_EXIST(biBlip) UPDATE_CHASE_BLIP(biBlip, pedStalker, STALKER_ESCAPE_DIST, CHASE_FLASH_DIST) ENDIF sProgress = SP_RUNNING ENDIF // Checks for if player has got out of the car IF bPlayerOnFoot IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = FALSE SAFE_REMOVE_BLIP(biTraceyBlip) // Car will be blipped CLEAR_PRINTS() ENDIF ELIF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = TRUE biTraceyBlip = CREATE_VEHICLE_BLIP(viTraceyCar) #IF IS_DEBUG_BUILD IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1GETBKT) CPRINTLN(DEBUG_MISSION, "Displaying get back in obective in STAGE_CHASE: SP_SETUP") ENDIF #ENDIF DISPLAY_MISSION_OBJECTIVE(MO_MET1GETBKT) ENDIF TICK_TRACEY_OUTCOME_TESTS() // Stalker was killed inside vehicle ELSE CPRINTLN(DEBUG_MISSION, "STAGE_CHASE: SP_SETUP: Stalker killed!") KILL_CHASE_HINT_CAM(localChaseHintCamStruct) SAFE_REMOVE_BLIP(biBlip) bStalkerDead = TRUE bTraceySawOutcome = DID_TRACEY_SEE_OUTCOME() START_STALKER_SNUFF_MOVIE() sProgress = SP_SETUP msTrack = MST_DRIVE_HOME CLEAR_PRINTS() ENDIF BREAK CASE SP_RUNNING IF IS_ENTITY_ALIVE(pedStalker) // If stalker is alive, check whether his car has become undriveable IF STALKER_CAR_IS_TRASHED() CPRINTLN(DEBUG_MISSION, "STAGE_CHASE: SP_RUNNING: Stalker's car trashed") SAFE_REMOVE_BLIP(biBlip) sProgress = SP_SETUP msTrack = MST_STALKER_WRECKED // Handle unexpected cases where stalker exits their vehicle - e.g. player drags them out ELIF NOT IS_PED_IN_ANY_VEHICLE(pedStalker) CPRINTLN(DEBUG_MISSION, "STAGE_CHASE: SP_RUNNING: Stalker not in car") sProgress = SP_SETUP msTrack = MST_STALKER_WRECKED // Check for stalker escaping ELIF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedStalker, STALKER_ESCAPE_DIST) CPRINTLN(DEBUG_MISSION, "STAGE_CHASE: SP_RUNNING: Stalker escaped") SAFE_REMOVE_BLIP(biBlip) sFailReason = "MET1ESCAPE" // The stalker escaped. msTrack = MST_FAIL_FADE sProgress = SP_SETUP // Stalker and his car OK, update driving check ELSE // See if we can display the objective yet IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1CHASE) AND (GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()) CPRINTLN(DEBUG_MISSION, "Displaying MO_MET1CHASE in STAGE_CHASE:SP_RUNNING") DISPLAY_MISSION_OBJECTIVE(MO_MET1CHASE) ENDIF // Tick stalker's lookat responses now that we've updated the ram check STALKER_HEAD_TRACK_CONTROLLER() // Monitor the stalker's driving STALKER_DRIVE_CHECK() // Checks for if player has got out of the car IF bPlayerOnFoot IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = FALSE SAFE_REMOVE_BLIP(biTraceyBlip) // Car will be blipped CLEAR_PRINTS() // Check whether Tracey is still in car IF IS_PED_IN_VEHICLE(pedTracey, viTraceyCar, FALSE) // Tracey is in car - get back after stalker bTraceyonFoot = FALSE ELSE // Tracey is on foot - need her back in bTraceyonFoot = TRUE bTraceyAttemptingReentry = FALSE biTraceyBlip = CREATE_PED_BLIP(pedTracey, TRUE, TRUE) DISPLAY_MISSION_OBJECTIVE(MO_MET1WAIT) ENDIF ELIF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1DLT) // Don't leave Tracey behind IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, WARN_DIS_TOO_FAR) DISPLAY_MISSION_OBJECTIVE(MO_MET1DLT) ENDIF ELIF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, ABANDON_TRACEY_DIST) sFailReason = "MET1ABANDON" // You abandoned Tracey sProgress = SP_SETUP msTrack = MST_FAIL_FADE ELSE // Head track IF IS_PED_IN_VEHICLE(pedTracey, viTraceyCar, FALSE) HANDLE_BUDDY_HEAD_TRACK_WHILE_ENTERING_VEHICLE() ENDIF ENDIF // Check for player getting out of car ELIF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = TRUE biTraceyBlip = CREATE_VEHICLE_BLIP(viTraceyCar, TRUE) // Don't show get back in objective if stalker on roof B*1307970 IF NOT STALKER_CAR_UPSIDE_DOWN() #IF IS_DEBUG_BUILD IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1GETBKT) CPRINTLN(DEBUG_MISSION, "Displaying get back in obective in STAGE_CHASE: SP_RUNNING") ENDIF #ENDIF DISPLAY_MISSION_OBJECTIVE(MO_MET1GETBKT) // Get back in Tracey's car. ENDIF IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION() ENDIF // Checks for when Tracey is not in car. (Player is in car) ELIF bTraceyonFoot // Should Tracey be trying to get back in IF NOT bTraceyAttemptingReentry AND NOT CAR_CURRENTLY_ON_ROOF() bTraceyAttemptingReentry = TRUE TASK_ENTER_VEHICLE(pedTracey, viTraceyCar, DEFAULT, VS_FRONT_RIGHT, PEDMOVEBLENDRATIO_RUN) ENDIF // Is Tracey back in? IF IS_PED_IN_VEHICLE(pedTracey, viTraceyCar, FALSE) bTraceyonFoot = FALSE SAFE_REMOVE_BLIP(biTraceyBlip) // Tracey will be blipped // Already checked that player is in car when we get here so reblip stalker //biBlip = CREATE_VEHICLE_BLIP(mvStalkerCar.vehicle, FALSE) ELIF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1DLT) // Don't leave Tracey behind IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, WARN_DIS_TOO_FAR) DISPLAY_MISSION_OBJECTIVE(MO_MET1DLT) ENDIF ELIF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, ABANDON_TRACEY_DIST) sFailReason = "MET1ABANDON" // You abandoned Tracey sProgress = SP_SETUP msTrack = MST_FAIL_FADE ENDIF // Check for whether Tracey has got out of car. (Player will be in car) ELIF NOT IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) bTraceyonFoot = TRUE bTraceyAttemptingReentry = FALSE biTraceyBlip = CREATE_PED_BLIP(pedTracey, TRUE, TRUE) DISPLAY_MISSION_OBJECTIVE(MO_MET1WAIT) IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ENDIF ENDIF ENDIF // Flash chase blip if escaping IF DOES_BLIP_EXIST(biBlip) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) AND IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) UPDATE_CHASE_BLIP(biBlip, pedStalker, STALKER_ESCAPE_DIST, CHASE_FLASH_DIST) ENDIF // Chase hint cam and associated audio scene control CONTROL_PED_CHASE_HINT_CAM_IN_VEHICLE(localChaseHintCamStruct, pedStalker) IF IS_GAMEPLAY_HINT_ACTIVE() TOGGLE_FOCUS_AUDIO_SCENE(TRUE) ELSE TOGGLE_FOCUS_AUDIO_SCENE(FALSE) ENDIF TICK_TRACEY_OUTCOME_TESTS() ELSE // Stalker was killed CPRINTLN(DEBUG_MISSION, "STAGE_CHASE: SP_RUNNING: Stalker killed") SAFE_REMOVE_BLIP(biBlip) KILL_CHASE_HINT_CAM(localChaseHintCamStruct) bStalkerDead = TRUE START_STALKER_SNUFF_MOVIE() bTraceySawOutcome = DID_TRACEY_SEE_OUTCOME() sProgress = SP_SETUP msTrack = MST_DRIVE_HOME ENDIF // Update vehicle coords UPDATE_TRACEYCAR_SAVED_COORDS() // Update chase conversations tracker STALKER_CHASE_CHAT() BREAK CASE SP_CLEANUP SCRIPT_ASSERT("MET_TRACEY1::: Chase stage is trying to exit in non-standard way. Please bug this with as much information as possible.") Mission_Passed(TRUE) BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// Stalker gets out of car and flees on foot when his car is wrecked PROC STAGE_STALKER_WRECKED() SWITCH sProgress CASE SP_SETUP // Request dead reaction anim dictionary again in case we're at a checkpoint REQUEST_ANIM_DICT(sTraceyAnimDict) // Get stalker out of vehicle, set him to flee player on foot IF IS_ENTITY_ALIVE(pedStalker) CLEAR_PED_TASKS(pedStalker) SET_PED_FLEE_ATTRIBUTES(pedStalker, FA_USE_VEHICLE, FALSE) // Stalker may already be out of vehicle or not, handle either case IF IS_PED_IN_ANY_VEHICLE(pedStalker) CPRINTLN(DEBUG_MISSION, "STAGE_STALKER_WRECKED : Giving stalker flee task sequence") SEQUENCE_INDEX seqStalk OPEN_SEQUENCE_TASK(seqStalk) TASK_LEAVE_ANY_VEHICLE(NULL, 0, ECF_DONT_CLOSE_DOOR|ECF_RESUME_IF_INTERRUPTED) //TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 200.0, -1) TASK_SMART_FLEE_COORD(NULL, GET_ENTITY_COORDS(PLAYER_PED_ID()), 2000.0, -1) // TASK_SMART_FLEE_PED causes him to go back and forth - B*985005 CLOSE_SEQUENCE_TASK(seqStalk) TASK_PERFORM_SEQUENCE(pedStalker, seqStalk) CLEAR_SEQUENCE_TASK(seqStalk) ELSE CPRINTLN(DEBUG_MISSION, "STAGE_STALKER_WRECKED : Giving stalker flee task") //TASK_SMART_FLEE_PED(pedStalker, PLAYER_PED_ID(), 200.0, -1) TASK_SMART_FLEE_COORD(pedStalker, GET_ENTITY_COORDS(PLAYER_PED_ID()), 2000.0, -1) // TASK_SMART_FLEE_PED causes him to go back and forth - B*985005 ENDIF // Initialise stalker dialogue stuff bTraceyOnFootAlertDone = FALSE bTraceyEscapeCommentDone = FALSE iFootChaseStalkerChat = 0 iFootChaseTraceyChat = 0 bTraceyChatting = FALSE bStalkerChatting = FALSE iChaseChatTimer = GET_GAME_TIMER() cptFootChaseTrack = CPT_WAIT_TO_TRIGGER // Kill any conversation that might prevent Tracey's alert firing immediately - B*1135838 IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ENDIF // Initialise stalker on-foot chase monitoring bStalkerCowering = FALSE bStalkerOnPedFleeTask = FALSE FORCE_INIT_STALKER_FOOT_TRACKING() iChaseTaskTimer[0] = GET_GAME_TIMER() + CHASE_PROX_CHECK_TIME iChaseTaskTimer[1] = GET_GAME_TIMER() + CHASE_PROX_CHECK_TIME // Initialise to task time in case player already close to ped // Remove stalker vehicle blip, blip on foot, init blip as a flasher SAFE_REMOVE_BLIP(biBlip) biBlip = CREATE_PED_BLIP(pedStalker) INIT_FLASH_BLIP_AND_TEXT(biBlip, "MET1KSTKRED", "MET1KSTKBLU", iFlashTick, iFlashTimeout) SET_ENTITY_IS_TARGET_PRIORITY(pedStalker, TRUE) // Hint cam override CONTROL_PED_CHASE_HINT_CAM_IN_VEHICLE(localChaseHintCamStruct, pedStalker) // Getting back in Tracey's car not important at this point SAFE_REMOVE_BLIP(biTraceyBlip) // Update audio scene UPDATE_AUDIO_SCENE(AUDIOSCENE_CHASE_FOOT) TICK_TRACEY_OUTCOME_TESTS() sProgress = SP_RUNNING ELSE // Stalker dead CPRINTLN(DEBUG_MISSION, "STAGE_STALKER_WRECKED : Stalker killed during SP_SETUP!") SAFE_REMOVE_BLIP(biBlip) bStalkerDead = TRUE START_STALKER_SNUFF_MOVIE() bTraceySawOutcome = DID_TRACEY_SEE_OUTCOME() sProgress = SP_CLEANUP ENDIF BREAK CASE SP_RUNNING // Wait for player to kill stalker or stalker to escape // Flash blip FLASH_BLIP_AND_TEXT(biBlip, "MET1KSTKRED", "MET1KSTKBLU", iFlashTick, iFlashTimeout) // Check for stalker running off IF IS_ENTITY_ALIVE(pedStalker) IF NOT IS_ENTITY_IN_RANGE_ENTITY(pedStalker, PLAYER_PED_ID(), STALKER_FOOT_ESCAPE_DIST) AND NOT IS_ENTITY_ON_SCREEN(pedStalker) CPRINTLN(DEBUG_MISSION, "STAGE_STALKER_WRECKED : Stalker escaped on foot!") SAFE_DELETE_PED(pedStalker) bTraceySawOutcome = DID_TRACEY_SEE_OUTCOME() sProgress = SP_CLEANUP ELSE // Foot chase banter IF bTraceyOnFootAlertDone STALKER_ON_FOOT_CHAT() ELIF IS_PED_ON_FOOT(pedStalker) AND NOT IS_PED_RAGDOLL(pedStalker) AND NOT IS_PED_GETTING_UP(pedStalker) AND NOT IS_ENTITY_ON_FIRE(pedStalker) AND NOT IS_ENTITY_IN_AIR(pedStalker) // Tracey does one of her "making a run for it" lines IF IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKRED") OR IS_THIS_PRINT_BEING_DISPLAYED("MET1KSTKBLU") IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_THERUN", CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES) bTraceyOnFootAlertDone = TRUE ENDIF ELSE IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_THERUN", CONV_PRIORITY_MEDIUM, DISPLAY_SUBTITLES) bTraceyOnFootAlertDone = TRUE ENDIF ENDIF ENDIF // Head track IF IS_PED_ON_FOOT(PLAYER_PED_ID()) HANDLE_BUDDY_HEAD_TRACK_WHILE_ENTERING_VEHICLE() ENDIF // Hint cam override CONTROL_PED_CHASE_HINT_CAM_IN_VEHICLE(localChaseHintCamStruct, pedStalker) // Check for stalker being trapped STALKER_FLEE_CHECK() // Nobble stalker's running speed SET_PED_MAX_MOVE_BLEND_RATIO(pedStalker, 2.2) // Keep inside the in-range checks or may cause issues such as B*1119023 TICK_TRACEY_OUTCOME_TESTS() ENDIF ELSE // Stalker is dead CPRINTLN(DEBUG_MISSION, "STAGE_STALKER_WRECKED : Stalker killed!") SAFE_REMOVE_BLIP(biBlip) bStalkerDead = TRUE bTraceySawOutcome = DID_TRACEY_SEE_OUTCOME() START_STALKER_SNUFF_MOVIE() sProgress = SP_CLEANUP ENDIF BREAK CASE SP_CLEANUP // Stalker dead or fled, clear blip SAFE_REMOVE_BLIP(biBlip) IF MISSION_OBJECTIVES_CURRENTLY_DISPLAYED() CLEAR_PRINTS() ENDIF KILL_CHASE_HINT_CAM(localChaseHintCamStruct) UPDATE_AUDIO_SCENE(AUDIOSCENE_DRIVE_HOME) sProgress = SP_SETUP msTrack = MST_DRIVE_HOME BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// An eerily true-to-life "Dad's taxi" section /// Michael drives Tracey home PROC STAGE_DRIVE_HOME() SWITCH sProgress CASE SP_SETUP IF bGoingToHotel = TRUE vecReturnLocation = vecHotelLocation ELSE vecReturnLocation = vecHouseLocation ENDIF // Check whether player is still in Tracey's car IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 0 biBlip = CREATE_COORD_BLIP(vecReturnLocation) bPlayerWanted = FALSE bWantedObjectiveNeeded = FALSE ELSE bPlayerWanted = TRUE bWantedObjectiveNeeded = TRUE ENDIF IF bStalkerDead SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_DRIVE_HOME_DEAD, "Drive home - stalker dead (CP4)") CPRINTLN(DEBUG_MISSION, "Set CP_DRIVE_HOME_DEAD") ELSE SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_DRIVE_HOME, "Drive home - stalker chased off (CP3)") CPRINTLN(DEBUG_MISSION, "Set CP_DRIVE_HOME") ENDIF // Initialise home chat iDriveHomeChatStep = 0 // Tracey will be blipped if we started this section on foot SAFE_REMOVE_BLIP(biTraceyBlip) INIT_BONKERS_DRIVING_CHECK() bPlayerOnFoot = FALSE bNearlyHomeCommentDone = FALSE bConversationKilled = FALSE sProgress = SP_RUNNING // Player is on foot - ELSE // Player has to have a chance to get back to Tracey, otherwise we may get unfair distance fails IF NOT DOES_BLIP_EXIST(biTraceyBlip) biTraceyBlip = CREATE_VEHICLE_BLIP(viTraceyCar) ENDIF #IF IS_DEBUG_BUILD IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1GETBKT) CPRINTLN(DEBUG_MISSION, "Displaying get back in obective in STAGE_DRIVE_HOME: SP_SETUP") ENDIF #ENDIF DISPLAY_MISSION_OBJECTIVE(MO_MET1GETBKT) bPlayerOnFoot = TRUE // Keep outside check or blip may get created again in SP_RUNNING ENDIF BREAK CASE SP_RUNNING IF NOT bBonkersDriving // Check we only trigger complaint conv once PLAYER_BONKERS_DRIVING_CHECK() IF bBonkersDriving // Queue crazy complaint bNeedCrazyDrivingComment = TRUE ENDIF ENDIF // Checks for when player is not in car IF bPlayerOnFoot // Do we need the objective IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1GETBKT) IF GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() CPRINTLN(DEBUG_MISSION, "Displaying get back in obective in STAGE_DRIVE_HOME: SP_RUNNING") DISPLAY_MISSION_OBJECTIVE(MO_MET1GETBKT) ENDIF ENDIF // Has player got back in? IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = FALSE SAFE_REMOVE_BLIP(biBlip) SAFE_REMOVE_BLIP(biTraceyBlip) CLEAR_PRINTS() // Check whether Tracey is still in car IF NOT IS_PED_IN_VEHICLE(pedTracey, viTraceyCar, FALSE) // Tracey is on foot - need her back in as priority bTraceyOnFoot = TRUE bTraceyAttemptingReentry = FALSE biTraceyBlip = CREATE_PED_BLIP(pedTracey, TRUE, TRUE) ELSE // Tracey is in car bTraceyOnFoot = FALSE bTraceyAttemptingReentry = FALSE // Head track HANDLE_BUDDY_HEAD_TRACK_WHILE_ENTERING_VEHICLE() // See if player has become wanted while on foot IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 1 bPlayerWanted = FALSE biBlip = CREATE_COORD_BLIP(vecReturnLocation) ELSE bPlayerWanted = TRUE bWantedObjectiveNeeded = TRUE ENDIF ENDIF // See if they've abandoned the vehicle ELIF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, ABANDON_TRACEY_DIST) sFailReason = "MET1ABANDON" // You abandoned Tracey. msTrack = MST_FAIL_FADE sProgress = SP_SETUP // See if we need to display an abandon warning ELIF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, WARN_DIS_TOO_FAR) DISPLAY_MISSION_OBJECTIVE(MO_MET1DLT) // Return to Tracey's car ENDIF // Check whether player just got out of car ELIF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = TRUE CLEAR_PRINTS() SAFE_REMOVE_BLIP(biBlip) biTraceyBlip = CREATE_VEHICLE_BLIP(viTraceyCar) IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION() ENDIF // Checks for case where Tracey is on foot ELIF bTraceyonFoot // Do we need the objective IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1WAIT) AND (GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()) DISPLAY_MISSION_OBJECTIVE(MO_MET1WAIT) ENDIF // Should Tracey be trying to get back in IF NOT bTraceyAttemptingReentry AND NOT CAR_CURRENTLY_ON_ROOF() bTraceyAttemptingReentry = TRUE TASK_ENTER_VEHICLE(pedTracey, viTraceyCar, DEFAULT, VS_FRONT_RIGHT, PEDMOVEBLENDRATIO_RUN) ENDIF // Is Tracey back in? IF IS_PED_IN_VEHICLE(pedTracey, viTraceyCar, FALSE) bTraceyonFoot = FALSE SAFE_REMOVE_BLIP(biTraceyBlip) // Tracey currently will be blipped // Tracey is in car bTraceyOnFoot = FALSE bTraceyAttemptingReentry = FALSE // See if player has become wanted while Tracey was on foot IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 1 bPlayerWanted = FALSE biBlip = CREATE_COORD_BLIP(vecReturnLocation) ELSE bPlayerWanted = TRUE bWantedObjectiveNeeded = TRUE ENDIF ELIF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1DLT) // Don't leave Tracey behind IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, WARN_DIS_TOO_FAR) DISPLAY_MISSION_OBJECTIVE(MO_MET1DLT) ENDIF ELIF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), pedTracey, ABANDON_TRACEY_DIST) sFailReason = "MET1ABANDON" // You abandoned Tracey sProgress = SP_SETUP msTrack = MST_FAIL_FADE ENDIF // Check for whether Tracey has got out of car. (Player will be in car) ELIF NOT IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) bTraceyonFoot = TRUE bTraceyAttemptingReentry = FALSE CLEAR_PRINTS() SAFE_REMOVE_BLIP(biBlip) // A destination may be blipped SAFE_REMOVE_BLIP(biTraceyBlip) biTraceyBlip = CREATE_PED_BLIP(pedTracey, TRUE, TRUE) IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ENDIF // Checks for when player is wanted ELIF bPlayerWanted // Objective - waits until we're clear of subtitles IF bWantedObjectiveNeeded IF GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR (iDriveHomeChatStep >= 4 AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()) DISPLAY_MISSION_OBJECTIVE(MO_MET1WANT) bWantedObjectiveNeeded = FALSE ENDIF ENDIF // Check that player is still in car IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), viTraceyCar) bPlayerOnFoot = TRUE CLEAR_PRINTS() SAFE_REMOVE_BLIP(biBlip) SAFE_REMOVE_BLIP(biTraceyBlip) biTraceyBlip = CREATE_VEHICLE_BLIP(viTraceyCar) // Check for whether Tracey has got out of car. (Player will be in car) ELIF NOT IS_PED_IN_VEHICLE(pedTracey, viTraceyCar) bTraceyonFoot = TRUE bTraceyAttemptingReentry = FALSE biTraceyBlip = CREATE_PED_BLIP(pedTracey, TRUE, TRUE) DISPLAY_MISSION_OBJECTIVE(MO_MET1WAIT) // See if player is no longer wanted ELIF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 1 bPlayerWanted = FALSE bNeedWantedRemark = FALSE CLEAR_PRINTS() SAFE_REMOVE_BLIP(biBlip) biBlip = CREATE_COORD_BLIP(vecReturnLocation) ENDIF // Trigger chat in case we need to progress the initial conversation or need wanted dialogue DRIVING_HOME_CHAT() // Check whether player has become wanted ELIF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 // Player has become wanted bPlayerWanted = TRUE bWantedObjectiveNeeded = TRUE bNeedWantedRemark = TRUE CLEAR_PRINTS() SAFE_REMOVE_BLIP(biBlip) // Checks for when everything seems to be going swimmingly ELSE // Check if we're actually there now IF REACHED_DESTINATION_CHECK() sProgress = SP_CLEANUP // Trigger nearly home comment ELIF DESTINATION_COMMENT_TRIGGER() AND NOT bNearlyHomeCommentDone IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_NRHOME", CONV_PRIORITY_MEDIUM) bNearlyHomeCommentDone = TRUE ENDIF // Trigger banter ELSE DRIVING_HOME_CHAT() ENDIF // Drive home objective IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1HOME) AND MISSION_OBJECTIVE_WILL_DISPLAY(MO_MET1HOTEL) IF GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() IF bGoingToHotel DISPLAY_MISSION_OBJECTIVE(MO_MET1HOTEL) ELSE DISPLAY_MISSION_OBJECTIVE(MO_MET1HOME) ENDIF ENDIF ENDIF ENDIF BREAK CASE SP_CLEANUP SAFE_REMOVE_BLIP(biBlip) UPDATE_AUDIO_SCENE(AUDIOSCENE_DONE) IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION() ENDIF msTrack = MST_AT_HOME sProgress = SP_SETUP BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// Tracey disembarks car at house/hotel PROC STAGE_AT_HOME() SWITCH sProgress CASE SP_SETUP // Set health before vehicle has stopped for maximum leniency! IF GET_VEHICLE_PETROL_TANK_HEALTH(viTraceyCar) < 1 SET_VEHICLE_PETROL_TANK_HEALTH(viTraceyCar, 10.0) ENDIF IF GET_VEHICLE_ENGINE_HEALTH(viTraceyCar) < 1 SET_VEHICLE_ENGINE_HEALTH(viTraceyCar, 10.0) ENDIF // Stop the vehicle ready for delivery event IF BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(viTraceyCar, 5.0, 5) // Get Tracey out of car SEQUENCE_INDEX siTmp IF bGoingToHotel vecTraceyDest = <<-1321.4403, 379.9881, 67.8596>> OPEN_SEQUENCE_TASK(siTmp) TASK_PAUSE(NULL, 650) TASK_LEAVE_VEHICLE(NULL, viTraceyCar) TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, vecTraceyDest, 1) // TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, <<-813.7761, 179.4943, 71.1592>>, 1) CLOSE_SEQUENCE_TASK(siTmp) ELSE vecTraceyDest = <<-813.7761, 179.4943, 71.1592>> OPEN_SEQUENCE_TASK(siTmp) TASK_PAUSE(NULL, 650) TASK_LEAVE_VEHICLE(NULL, viTraceyCar) TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, <<-820.1358, 176.9053, 70.6086>>, 1) TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, vecTraceyDest, 1) CLOSE_SEQUENCE_TASK(siTmp) ENDIF CLEAR_PED_TASKS(pedTracey) TASK_PERFORM_SEQUENCE(pedTracey, siTmp) CLEAR_SEQUENCE_TASK(siTmp) SET_PED_CONFIG_FLAG(pedTracey, PCF_OpenDoorArmIK, TRUE) bAtHomeCommentDone = FALSE // Do we need the first person flash? IF IS_PLAYER_IN_FIRST_PERSON_CAMERA() bFPFlashNeeded = TRUE bFPFlashTimerStarted = FALSE SET_FIRST_PERSON_FLASH_EFFECT_VEHICLE_MODEL_NAME("ISSI2") ELSE bFPFlashNeeded = FALSE bFPFlashTimerStarted = FALSE ENDIF // Disable phone etc. RC_START_CUTSCENE_MODE(<<0.0,0.0,0.0>>) // Clear area of vehicles - note we can't use the standard resolves because they will move the player vehicle CLEAR_AREA_OF_VEHICLES(vecReturnLocation, 8.0, TRUE) // Clear locate area IF NOT bGoingToHotel CLEAR_AREA_OF_VEHICLES(<<-820.2315, 176.7027, 70.6122>>, 8.0, TRUE) // Don't block up the front door ENDIF IF bGoingToHotel iCutTimer = GET_GAME_TIMER() + 10000 ciHomeCam = CREATE_CAM_WITH_PARAMS("DEFAULT_SCRIPTED_CAMERA", <<-1315.6117, 402.8979, 76.0077>>, <<-26.8270, -0.0000, 175.0236>>, 48.4) ELSE iCutTimer = GET_GAME_TIMER() + 5000 ciHomeCam = CREATE_CAM_WITH_PARAMS("DEFAULT_SCRIPTED_CAMERA", << -840.7, 185.3, 78.4 >>, << -14.0, 0.0, -110.4 >>, 48.4) ENDIF SET_CAM_ACTIVE(ciHomeCam, TRUE) RENDER_SCRIPT_CAMS(TRUE, FALSE) bOutroWasSkipped = FALSE sProgress = SP_RUNNING ENDIF BREAK CASE SP_RUNNING IF IS_CUTSCENE_SKIP_BUTTON_JUST_PRESSED_WITH_DELAY() bOutroWasSkipped = TRUE bAtHomeCommentDone = TRUE ENDIF IF NOT bAtHomeCommentDone IF CREATE_CONVERSATION(mConversationStruct, "MET1AUD", "MET1_ATHOME", CONV_PRIORITY_MEDIUM) OR GET_GAME_TIMER() > iCutTimer bAtHomeCommentDone = TRUE ENDIF ELIF bFPFlashTimerStarted IF GET_GAME_TIMER() >= iFPFlashTimer sProgress = SP_CLEANUP ENDIF ELIF IS_ENTITY_IN_RANGE_COORDS(pedTracey, vecTraceyDest, 2.0) OR GET_GAME_TIMER() - iCutTimer > 5000 // 10s get-out clause OR bOutroWasSkipped IF bFPFlashNeeded CPRINTLN(DEBUG_MISSION, "REQUESTED FPS FLASH") ANIMPOSTFX_PLAY("CamPushInNeutral", 0, FALSE) PLAY_SOUND_FRONTEND(-1, "1st_Person_Transition", "PLAYER_SWITCH_CUSTOM_SOUNDSET") bFPFlashTimerStarted = TRUE iFPFlashTimer = GET_GAME_TIMER() + 300 ELSE sProgress = SP_CLEANUP ENDIF ENDIF IF NOT bGoingToHotel SET_PED_RESET_FLAG(pedTracey, PRF_UseProbeSlopeStairsDetection, TRUE) ENDIF BREAK CASE SP_CLEANUP // Sort Tracey out if cutscene was skipped IF bGoingToHotel SAFE_DELETE_PED(pedTracey) ELSE IF bOutroWasSkipped CLEAR_PED_TASKS_IMMEDIATELY(pedTracey) SET_ENTITY_COORDS(pedTracey, <<-813.7761, 179.4943, 71.1592>>, FALSE) FORCE_PED_AI_AND_ANIMATION_UPDATE(pedTracey) ENDIF IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() ENDIF SET_VEHICLE_DOOR_SHUT(viTraceyCar, SC_DOOR_FRONT_RIGHT, TRUE) RELEASE_PED_TO_FAMILY_SCENE(pedTracey) ENDIF // Restore hud etc. + Enable phone etc. RENDER_SCRIPT_CAMS(FALSE, FALSE) RC_END_CUTSCENE_MODE() SET_GAMEPLAY_CAM_RELATIVE_HEADING() DESTROY_CAM(ciHomeCam) Mission_Passed() BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// Player has taken too long to get to Tracey. Phone call of Tracey giving Michael shit. PROC STAGE_FAIL_CALL() SWITCH sProgress CASE SP_SETUP bTraceyIsCurrentlySpawned = FALSE SAFE_REMOVE_BLIP(biBlip) SAFE_DELETE_PED(pedTracey) SAFE_DELETE_VEHICLE(viTraceyCar) REMOVE_PED_FOR_DIALOGUE(mConversationStruct, 3) ADD_PED_FOR_DIALOGUE(mConversationStruct, 3, NULL, "TRACEY") IF CHAR_CALL_PLAYER_CELLPHONE_FORCE_ANSWER(mConversationStruct, CHAR_TRACEY, "MET1AUD", "MET1_FAIL", CONV_PRIORITY_MEDIUM) sProgress = SP_RUNNING ENDIF BREAK CASE SP_RUNNING IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() sProgress = SP_CLEANUP ENDIF BREAK CASE SP_CLEANUP sFailReason = "MET1TOOLATE" msTrack = MST_FAIL_FADE sProgress = SP_SETUP BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// Handle player becoming wanted en route to Tracey PROC STAGE_LOSE_WANTED() SWITCH sProgress CASE SP_SETUP // Check we're supposed to be in here then progress IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0 DISPLAY_MISSION_OBJECTIVE(MO_MET1WANT) SAFE_REMOVE_BLIP(biBlip) sProgress = SP_RUNNING ELSE msTrack = MST_DRIVE_TO_TRACEY sProgress = SP_SETUP ENDIF BREAK CASE SP_RUNNING // Check player is still wanted IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 1 CLEAR_MISSION_OBJECTIVE(MO_MET1WANT) sProgress = SP_CLEANUP ENDIF ENDIF // Check for Tracey timeout calls CHECK_WARNING_CALL() BREAK CASE SP_CLEANUP sProgress = SP_SETUP msTrack = MST_DRIVE_TO_TRACEY BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Mission stage proc /// Handles a fade-out/clean-up step for mission fail replay cleanliness PROC STAGE_FAIL_FADE() SWITCH sProgress CASE SP_SETUP CPRINTLN(DEBUG_MISSION, "Mission_Failed") SAFE_REMOVE_BLIP(biBlip) IF IS_STRING_NULL_OR_EMPTY(sFailReason) // Guard against null string case SCRIPT_ASSERT("Reached STAGE_FAIL_FADE with NULL/empty fail reason string - Please add detailed repro steps when bugging this.") sFailReason = "DEFAULT" ENDIF IF ARE_STRINGS_EQUAL(sFailReason, "DEFAULT") Mission_Flow_Mission_Failed() ELSE MISSION_FLOW_MISSION_FAILED_WITH_REASON(sFailReason) ENDIF sProgress = SP_RUNNING BREAK CASE SP_RUNNING IF GET_MISSION_FLOW_SAFE_TO_CLEANUP() // finished fading out // must only take 1 frame and terminate the thread // check if we need to respawn the player in a different position, // if so call MISSION_FLOW_SET_FAIL_WARP_LOCATION() + SET_REPLAY_DECLINED_VEHICLE_WARP_LOCATION here Mission_Cleanup(TRUE) // Deletes everything ELSE KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() // B*1118621 // not finished fading out // you may want to handle dialogue etc here. ENDIF BREAK ENDSWITCH ENDPROC // =========================================================================================================== // DEBUG FUNCTIONS // =========================================================================================================== /// PURPOSE: /// Handles debug keys PROC DO_DEBUG_CHECKS() #IF IS_DEBUG_BUILD INT iNewStage // Check for Pass IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_S)) SKIP_KILL_CONVERSATION() CLEAR_PRINTS() Mission_Passed(TRUE) ELIF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_F)) SKIP_KILL_CONVERSATION() CLEAR_PRINTS() SET_MISSION_FAILED("DEFAULT") ELIF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_J)) SKIP_FORWARD() ELIF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_P)) SKIP_BACKWARD() ELIF LAUNCH_MISSION_STAGE_MENU(mSkipMenu, iNewStage) eTargetStage = INT_TO_ENUM(MISSION_SKIP_STAGE, iNewStage) DO_Z_SKIP(eTargetStage) ENDIF // Stalker debug flip widget IF bDebugFlipStalkerCar bDebugFlipStalkerCar = FALSE IF IS_ENTITY_ALIVE(mvStalkerCar.vehicle) CPRINTLN(DEBUG_MISSION, "DEBUG FLIP STALKER CAR") VECTOR vecStalkCoord = GET_ENTITY_COORDS(mvStalkerCar.vehicle) VECTOR vecStalkRot = GET_ENTITY_ROTATION(mvStalkerCar.vehicle) vecStalkCoord.z += 1.0 vecStalkRot.y = WRAP(vecStalkRot.y+180, 0, 360) SET_ENTITY_COORDS(mvStalkerCar.vehicle, vecStalkCoord) SET_ENTITY_ROTATION(mvStalkerCar.vehicle, vecStalkRot) SET_ENTITY_VELOCITY(mvStalkerCar.vehicle, <<0,0,0>>) ENDIF ENDIF #ENDIF ENDPROC // =========================================================================================================== // Script Loop // =========================================================================================================== SCRIPT CPRINTLN(DEBUG_MISSION, "...ME_Tracey1 Launched") IF (HAS_FORCE_CLEANUP_OCCURRED()) CPRINTLN(DEBUG_MISSION, "...ME_Tracey1 Force Cleanup") Mission_Flow_Mission_Force_Cleanup() Mission_Cleanup() ENDIF SET_MISSION_FLAG(TRUE) DATA_INIT() // Check whether this is a replay IF Is_Replay_In_Progress() SWITCH GET_REPLAY_MID_MISSION_STAGE() CASE 0 // Create a car near Michael, B* 993260 VEHICLE_INDEX viTemp CREATE_VEHICLE_FOR_PHONECALL_TRIGGER_REPLAY(viTemp, TRUE, TRUE, TRUE, TRUE, TAILGATER) SAFE_RELEASE_VEHICLE(viTemp) RC_END_Z_SKIP() BREAK CASE CP_MET_TRACEY RC_START_Z_SKIP() SKIP_TO_MEET_TRACEY(TRUE) RC_END_Z_SKIP() BREAK CASE CP_STALKER_APPEARS RC_START_Z_SKIP() SKIP_TO_STALKER_APPEARS(TRUE) RC_END_Z_SKIP() BREAK CASE CP_DRIVE_HOME RC_START_Z_SKIP() SKIP_TO_DRIVE_HOME(TRUE, TRUE) RC_END_Z_SKIP() BREAK CASE CP_DRIVE_HOME_DEAD RC_START_Z_SKIP() SKIP_TO_DRIVE_HOME(TRUE, FALSE) RC_END_Z_SKIP() BREAK DEFAULT RC_END_Z_SKIP() SCRIPT_ASSERT("Replay in progress: Unknown checkpoint selected") BREAK ENDSWITCH ENDIF // Loop within here until the mission passes or fails WHILE(TRUE) REPLAY_CHECK_FOR_EVENT_THIS_FRAME("M_DD") IF iDisableReplayCameraTimer > GET_GAME_TIMER() REPLAY_DISABLE_CAMERA_MOVEMENT_THIS_FRAME() //Fix for bug 2227778 ENDIF IF msTrack = MST_FAIL_FADE STAGE_FAIL_FADE() ELSE IF NOT MISSION_FAIL_CHECKS() DO_DEBUG_CHECKS() MONITOR_STALKER_SNUFF_MOVIE() SWITCH msTrack CASE MST_INIT STAGE_INIT() BREAK CASE MST_DRIVE_TO_TRACEY STAGE_DRIVE_TO_TRACEY() BREAK CASE MST_WAIT_FOR_PLAYER STAGE_WAIT_FOR_PLAYER() BREAK CASE MST_DRIVE_TO_STALKER STAGE_DRIVE_TO_STALKER() BREAK CASE MST_TRIGGER_STALKER STAGE_TRIGGER_STALKER() BREAK CASE MST_CHASE STAGE_CHASE() BREAK CASE MST_STALKER_WRECKED STAGE_STALKER_WRECKED() BREAK CASE MST_DRIVE_HOME STAGE_DRIVE_HOME() BREAK CASE MST_AT_HOME STAGE_AT_HOME() BREAK CASE MST_FAIL_CALL STAGE_FAIL_CALL() BREAK // CASE MST_FAIL_TRACEY_DRIVE_OFF // STAGE_FAIL_TRACEY_DRIVE_OFF() // BREAK CASE MST_LOSE_WANTED STAGE_LOSE_WANTED() BREAK ENDSWITCH ENDIF ENDIF WAIT(0) ENDWHILE ENDSCRIPT