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

372 lines
11 KiB
Scheme
Executable File

// *****************************************************************************************
// *****************************************************************************************
//
// FILE NAME : rc_leadin_public.sch
// AUTHOR : Aaron Gandaa
// DESCRIPTION : Helper Stuff for leadins
//
// *****************************************************************************************
// *****************************************************************************************
//----------------------
// INCLUDES
//----------------------
USING "rgeneral_include.sch"
USING "RC_Helper_Functions.sch"
//----------------------
// STRUCTS
//----------------------
STRUCT LEADIN_HANDLER
VECTOR vSyncScenePos
VECTOR vSyncSceneRot
STRING sLeadInDictionary
STRING sLeadInAnims[4]
STRING sIdleAnim
INT iCurrentLeadIn
INT iMaxLeadIn // total # of lead in lines
INT iAnimsPlayed // number of lines played
INT iLeadsInPlayedFlag // bit set telling us which ones have been chosen
INT iWaitTimer
INT iMinWaitTime = 0
INT iMaxWaitTime = 0
INT iState
INT iSyncSceneID = -1
FLOAT fCloseBreakOutDist = 0.0
ENDSTRUCT
//----------------------
// FUNCTIONS
//----------------------
PROC RESET_LEADIN_HANDLER(LEADIN_HANDLER &lead)
INT i
REPEAT COUNT_OF(lead.sLeadInAnims) i
lead.sLeadInAnims[i] = NULL
ENDREPEAT
lead.iMaxLeadIn = 0
lead.iCurrentLeadIn = -1
lead.sLeadInDictionary = NULL
lead.iAnimsPlayed = 0
lead.iLeadsInPlayedFlag = 0
lead.vSyncScenePos = <<0, 0, 0>>
lead.vSyncSceneRot = <<0, 0, 0>>
ENDPROC
/// PURPOSE:
/// Add Lead in Anim to list
/// PARAMS:
/// lead - lead in handler
/// str - anim name
PROC ADD_LEADIN_ANIM(LEADIN_HANDLER &lead, STRING str)
IF (lead.iMaxLeadIn >= COUNT_OF(lead.sLeadInAnims))
SCRIPT_ASSERT("YOU NEED TO INCREASE sLeadInAnims in LEADIN_HANDLER")
ENDIF
IF IS_STRING_NULL_OR_EMPTY(str)
EXIT
ENDIF
lead.sLeadInAnims[lead.iMaxLeadIn] = str
lead.iMaxLeadIn ++
ENDPROC
/// PURPOSE:
/// Restarts the lead in
/// PARAMS:
/// lead - lead in handler
PROC RESTART_LEAD_IN(LEADIN_HANDLER &lead)
lead.iCurrentLeadIn = -1
lead.iAnimsPlayed = 0
lead.iLeadsInPlayedFlag = 0
lead.iState = 0
lead.iSyncSceneID = -1
IF NOT IS_VECTOR_ZERO(lead.vSyncScenePos)
lead.iSyncSceneID = CREATE_SYNCHRONIZED_SCENE(lead.vSyncScenePos, lead.vSyncSceneRot)
CPRINTLN(DEBUG_MISSION, "LEADIN - SYNCHRONIZED SCENE CREATED")
ENDIF
ENDPROC
/// PURPOSE:
/// Sets Anim Idle Of Lead In
/// PARAMS:
/// lead - lead in handler
/// str - anim name
/// idleMinWait - min time to do idle
/// idleMaxWait - max time to do idle
PROC SET_LEADIN_IDLE_ANIM(LEADIN_HANDLER &lead, STRING str, INT idleMinWait = 0, INT idleMaxWait = 0)
IF IS_STRING_NULL_OR_EMPTY(str)
EXIT
ENDIF
lead.sIdleAnim = str
lead.iMinWaitTime = idleMinWait
lead.iMaxWaitTime = idleMaxWait
ENDPROC
/// PURPOSE:
/// Sets position and rotation of lead in sync scene
/// PARAMS:
/// lead - lead in handler
/// vp - position of scene
/// vs - rotation of scene
PROC SET_LEADIN_SYNC_SCENE_COORDS(LEADIN_HANDLER &lead, VECTOR vp, VECTOR vs)
lead.vSyncScenePos = vp
lead.vSyncSceneRot = vs
ENDPROC
/// PURPOSE:
/// Loads the lead anim dict
/// PARAMS:
/// lead - lead in handler
/// str - anim dictionaru
/// RETURNS:
/// returns false if it timesout or str is null
FUNC BOOL LOAD_LEADIN_ANIMDICT(LEADIN_HANDLER &lead, STRING str)
INT iTimer = GET_GAME_TIMER() + 10000
IF IS_STRING_NULL_OR_EMPTY(str)
RETURN FALSE
ENDIF
REQUEST_ANIM_DICT(str)
WHILE NOT HAS_ANIM_DICT_LOADED(str)
IF (GET_GAME_TIMER() > iTimer)
CPRINTLN(DEBUG_MISSION, "LEADIN ANIMDICT LOAD FAILED:", str, " TIME OUT")
RETURN FALSE
ENDIF
WAIT(0)
ENDWHILE
lead.sLeadInDictionary = str
CPRINTLN(DEBUG_MISSION, "LEADIN ANIMDICT LOAD SUCCESS:", str)
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Unloads the current lead in anim
/// PARAMS:
/// lead - lead in handler
PROC UNLOAD_LEADIN_ANIMDICT(LEADIN_HANDLER &lead)
IF IS_STRING_NULL_OR_EMPTY(lead.sLeadInDictionary)
EXIT
ENDIF
IF HAS_ANIM_DICT_LOADED(lead.sLeadInDictionary)
CPRINTLN(DEBUG_MISSION, "LEADIN ANIMDICT UNLOADED:", lead.sLeadInDictionary)
REMOVE_ANIM_DICT(lead.sLeadInDictionary)
ENDIF
ENDPROC
/// PURPOSE:
/// Checks to see if a ped can play the leadin
/// PARAMS:
/// ped - ped playing the leading
/// lead - lead in handler
/// dist - distance from player before leadin kicks in
/// angle - angle that player has to be to ped before leadin kicks in
/// RETURNS:
///
FUNC BOOL CAN_PED_PLAY_LEADIN(PED_INDEX ped, LEADIN_HANDLER &lead, FLOAT dist = 30.0, FLOAT angle = 0.0)
IF NOT DOES_ENTITY_EXIST(ped)
RETURN FALSE
ENDIF
IF IS_ENTITY_DEAD(ped)
RETURN FALSE
ENDIF
IF IS_STRING_NULL_OR_EMPTY(lead.sLeadInDictionary)
RETURN FALSE
ENDIF
IF (dist > 0.0)
IF (GET_DISTANCE_BETWEEN_ENTITIES(ped, PLAYER_PED_ID()) > dist)
RETURN FALSE
ENDIF
ENDIF
IF (angle > 0.0)
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Starts plays the next lead idle
/// PARAMS:
/// lead - lead in handler
/// ped - ped playing the leading
PROC PLAY_LEAD_IN_IDLE(LEADIN_HANDLER &lead, PED_INDEX ped)
IF IS_STRING_NULL_OR_EMPTY(lead.sIdleAnim)
EXIT
ENDIF
IF (lead.iSyncSceneID <> -1)
IF NOT IS_SYNCHRONIZED_SCENE_RUNNING(lead.iSyncSceneID)
lead.iSyncSceneID = CREATE_SYNCHRONIZED_SCENE(lead.vSyncScenePos, lead.vSyncSceneRot)
ENDIF
TASK_SYNCHRONIZED_SCENE(ped, lead.iSyncSceneID, lead.sLeadInDictionary, lead.sIdleAnim, NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
SET_SYNCHRONIZED_SCENE_LOOPED(lead.iSyncSceneID, TRUE)
SET_SYNCHRONIZED_SCENE_HOLD_LAST_FRAME(lead.iSyncSceneID, FALSE)
CPRINTLN(DEBUG_MISSION, "PLAYING SYNCHED LEAD IN IDLE:", lead.sIdleAnim, " GAME TIME:", GET_GAME_TIMER())
ELSE
TASK_PLAY_ANIM(ped, lead.sLeadInDictionary, lead.sIdleAnim, NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING)
CPRINTLN(DEBUG_MISSION, "PLAYING LEAD IN IDLE:", lead.sIdleAnim, " GAME TIME:", GET_GAME_TIMER())
ENDIF
ENDPROC
/// PURPOSE:
/// Starts playing the next lead in
/// PARAMS:
/// lead - lead in handler
/// ped - ped playing the leading
PROC PLAY_NEXT_LEAD_IN(LEADIN_HANDLER &lead, PED_INDEX ped)
// currently only handles sequential lead ins at the moment
lead.iCurrentLeadIn ++
IF (lead.iCurrentLeadIn >= lead.iMaxLeadIn)
lead.ICurrentLeadIn = 0
ENDIF
SET_BIT(lead.iLeadsInPlayedFlag, lead.iCurrentLeadIn)
lead.iAnimsPlayed ++
IF NOT IS_STRING_NULL_OR_EMPTY(lead.sLeadInAnims[lead.iCurrentLeadIn])
IF (lead.iSyncSceneID <> -1)
IF NOT IS_SYNCHRONIZED_SCENE_RUNNING(lead.iSyncSceneID)
lead.iSyncSceneID = CREATE_SYNCHRONIZED_SCENE(lead.vSyncScenePos, lead.vSyncSceneRot)
ENDIF
TASK_SYNCHRONIZED_SCENE(ped, lead.iSyncSceneID, lead.sLeadInDictionary, lead.sLeadInAnims[lead.iCurrentLeadIn], NORMAL_BLEND_IN, NORMAL_BLEND_OUT)
SET_SYNCHRONIZED_SCENE_LOOPED(lead.iSyncSceneID, FALSE)
SET_SYNCHRONIZED_SCENE_HOLD_LAST_FRAME(lead.iSyncSceneID, TRUE)
CPRINTLN(DEBUG_MISSION, "PLAYING SYNCHED LEADIN:", lead.sLeadInAnims[lead.iCurrentLeadIn], " GAME TIME:", GET_GAME_TIMER())
EXIT
ELSE
TASK_PLAY_ANIM(ped, lead.sLeadInDictionary, lead.sLeadInAnims[lead.iCurrentLeadIn], NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_HOLD_LAST_FRAME)
CPRINTLN(DEBUG_MISSION, "PLAYING LEADIN:", lead.sLeadInAnims[lead.iCurrentLeadIn], " GAME TIME:", GET_GAME_TIMER())
EXIT
ENDIF
ENDIF
CPRINTLN(DEBUG_MISSION, "LEADIN PLAYING:", lead.sLeadInAnims[lead.iCurrentLeadIn], " GAME TIME:", GET_GAME_TIMER())
ENDPROC
/// PURPOSE:
/// Checks if the current anim is finished
/// PARAMS:
/// lead - lead in handler
/// ped - ped playing the leading
/// RETURNS:
/// Returns true if so
FUNC BOOL IS_CURRENT_LEADIN_ANIM_FINISHED(LEADIN_HANDLER &lead, PED_INDEX ped)
IF IS_STRING_NULL_OR_EMPTY(lead.sLeadInAnims[lead.ICurrentLeadIn])
RETURN TRUE
ENDIF
IF NOT IS_ENTITY_PLAYING_ANIM(ped, lead.sLeadInDictionary, lead.sLeadInAnims[lead.ICurrentLeadIn])
RETURN TRUE
ENDIF
IF HAS_ENTITY_ANIM_FINISHED(ped, lead.sLeadInDictionary, lead.sLeadInAnims[lead.ICurrentLeadIn])
RETURN TRUE
ENDIF
IF (lead.iSyncSceneID = -1)
IF (GET_ENTITY_ANIM_CURRENT_TIME(ped, lead.sLeadInDictionary, lead.sLeadInAnims[lead.ICurrentLeadIn]) >= 1.0)
RETURN TRUE
ENDIF
ELSE
IF (GET_SYNCHRONIZED_SCENE_PHASE(lead.iSyncSceneID) >= 0.999)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Updates the Lead In
/// PARAMS:
/// lead - lead in handler
/// ped - ped playing the leading
/// dist - distance before leadin kicks in
/// angle - angle that player has to be to ped before leadin kicks in
/// bLockPlayer - if this is set use trigger lock in
/// RETURNS:
/// Returns true if the lead in is finished or it has been aborted
FUNC BOOL UPDATE_LEAD_IN(LEADIN_HANDLER &lead, PED_INDEX ped, FLOAT dist = 0.0, FLOAT angle = 0.0, BOOL bLockPlayer = TRUE)
IF (bLockPlayer = TRUE)
RC_PLAYER_TRIGGER_SCENE_LOCK_IN()
ENDIF
IF NOT IS_ENTITY_OK(ped)
CPRINTLN(DEBUG_MISSION, "ABORT - PED IS DEAD!!")
RETURN TRUE
ENDIF
IF (GET_DISTANCE_BETWEEN_ENTITIES(ped, PLAYER_PED_ID()) < lead.fCloseBreakOutDist) AND (lead.fCloseBreakOutDist > 0.0)
CPRINTLN(DEBUG_MISSION, "ABORT - EMERGENCY BREAK OUT - WE'RE TOO CLOSE")
RETURN TRUE
ENDIF
//CPRINTLN(DEBUG_MISSION, " PHASE:", GET_SYNCHRONIZED_SCENE_PHASE(lead.iSyncSceneID))
SWITCH (lead.iState)
CASE 0
PLAY_LEAD_IN_IDLE(lead, ped)
lead.iState ++
BREAK
CASE 1
IF CAN_PED_PLAY_LEADIN(ped, lead, dist, angle)
CPRINTLN(DEBUG_MISSION, "WE CAN START THE LEAD IN")
lead.iState ++
ENDIF
BREAK
CASE 2 // selecting a line
PLAY_NEXT_LEAD_IN(lead, ped)
lead.iState ++
BREAK
CASE 3 // wait till line has finished
IF NOT IS_CURRENT_LEADIN_ANIM_FINISHED(lead, ped)
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_MISSION, "LEADIN FINISHED:", lead.sLeadInAnims[lead.ICurrentLeadIn])
IF (lead.iCurrentLeadIn = (lead.iMaxLeadIn - 1))
CPRINTLN(DEBUG_MISSION, "ALL LEADINS FINISHED")
lead.iState = 5
RETURN TRUE
ENDIF
IF (lead.iMinWaitTime > 0) AND (lead.iMaxWaitTime > 0)
PLAY_LEAD_IN_IDLE(lead, ped)
lead.iWaitTimer = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(lead.iMinWaitTime, lead.iMaxWaitTime)
lead.iState ++
ELSE
lead.iState = 1
ENDIF
BREAK
CASE 4 // wait delay before playing the next line
IF (GET_GAME_TIMER() > lead.iWaitTimer)
lead.iState = 1
ENDIF
BREAK
CASE 5 // null state
RETURN TRUE
ENDSWITCH
RETURN FALSE
ENDFUNC