6582 lines
231 KiB
Python
Executable File
6582 lines
231 KiB
Python
Executable File
|
|
//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
|