Files
gtav-src/script/dev_ng/singleplayer/scripts/Drunk/drunk.sc
T
2025-09-29 00:52:08 +02:00

2883 lines
93 KiB
Python
Executable File

USING "rage_builtins.sch"
USING "globals.sch"
USING "commands_streaming.sch"
USING "commands_pad.sch"
USING "commands_script.sch"
USING "drunkNoticeboard_private.sch"
USING "drunk_public.sch"
//KGMTAXI USING "taxi_functions.sch"
USING "respawnCutscene_private.sch"
USING "player_scene_schedule.sch"
#IF IS_DEBUG_BUILD
USING "drunk_debug.sch"
#ENDIF
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// MISSION NAME : drunk.sc
// AUTHOR : Keith / Alwyn
// DESCRIPTION : Controls one drunken ped or player.
//
// NOTES : Peds need to return to SWITCH_ON_RAGDOLL state rather than IDLE.
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
CONST_FLOAT WALKING_LEAN_VALUE 0.49
CONST_FLOAT MAX_DISTANCE_FROM_VEHICLE_m 7.0
CONST_FLOAT SPEED_CLASSED_AS_STOPPED 0.04
CONST_INT FAILSAFE_SHUFFLE_TIMEOUT_msec 1000
CONST_INT FAILSAFE_WARP_TIMEOUT_msec 500
CONST_INT STEERING_BIAS_PED_TIMEOUT_msec 2000
CONST_INT STEERING_BIAS_TIMEOUT_msec 1000
CONST_INT NO_AVAILABLE_SEAT -1
STRUCT m_sTimers
INT ragdolling // Length of time (in msec) that the ped should ragdoll
INT overall // Overall length of time (in msec) that any drunk effects should last
INT activity // Temporary timer for any short-term activities
INT failsafe // Temporary timer for any activity that needs a failsafe timer
INT steeringTime // Time until Steering Bias needs to change again
ENDSTRUCT
// Used to control the drunk ped. The Overall status could be 'walk to car' but this could be interrupted
// by an Immediate status like 'get up off the floor'.
STRUCT m_sStatus
g_eDrunkStatus shortTerm // The immediate (short-term) objective status
g_eDrunkStatus longTerm // The overall (long-term) objective status
STRING moveClip //
ENDSTRUCT
g_sDrunkRequests m_rawDetails
INT m_myUniqueID = NO_UNIQUE_DRUNK_PED_ID
INT m_leaderUniqueID = NO_UNIQUE_DRUNK_PED_ID
BOOL m_thisIsPlayer = FALSE
BOOL m_ragdollOn = FALSE
FLOAT m_lastKnownHeadHeight = 1.7 // Set Get_Head_Coordinates() for explanation
FLOAT m_steeringBias = 0.0
STRING m_transitionClip = ""
m_sTimers m_timing
m_sStatus m_status
INT m_wantedLevel = -1
INT m_myPedsArrayIndex = 0
BOOL m_bPlayerDrinkingInMP = FALSE
#IF IS_DEBUG_BUILD
// -----------------------------------------------------------------------------------------
// Debug
// -----------------------------------------------------------------------------------------
// PURPOSE: Convert an MSEC value to seconds
//
// INPUT PARAMS: paramMsec Number of milliseconds
// RETURN VALUE: INT Number of seconds, with a floor of 0
FUNC INT MSEC_TO_SEC(INT paramMsec)
IF (paramMsec <= 0)
RETURN 0
ENDIF
RETURN ((paramMsec / 1000) + 1)
ENDFUNC
// PURPOSE: Ensure that the value has a floor of 0
//
// INPUT PARAMS: paramValue Value to have negative values returned as 0
// RETURN VALUE: INT The value returned as-is except negative values are returned as 0
FUNC INT FLOOR_0(INT paramValue)
IF (paramValue <= 0)
RETURN 0
ENDIF
RETURN paramValue
ENDFUNC
// PURPOSE: Update 'drunk' debug widgets
PROC Update_Drunk_Debug_Variables()
IF (m_myPedsArrayIndex = UNKNOWN_DRUNK_ARRAY_INDEX)
EXIT
ENDIF
g_widgetLongTermStatusAsInt[m_myPedsArrayIndex] = ENUM_TO_INT(m_status.longTerm)
g_widgetShortTermStatusAsInt[m_myPedsArrayIndex] = ENUM_TO_INT(m_status.shortTerm)
g_widgetDrunkLevelAsInt[m_myPedsArrayIndex] = ENUM_TO_INT(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel)
g_widgetTimerA[m_myPedsArrayIndex] = MSEC_TO_SEC(TIMERA())
g_widgetRagdolling[m_myPedsArrayIndex] = MSEC_TO_SEC(m_timing.ragdolling - TIMERA())
g_widgetOverall[m_myPedsArrayIndex] = MSEC_TO_SEC(m_timing.overall - TIMERA())
g_widgetActivity[m_myPedsArrayIndex] = FLOOR_0(m_timing.activity - TIMERA())
g_widgetFailsafe[m_myPedsArrayIndex] = FLOOR_0(m_timing.failsafe - TIMERA())
g_widgetSteering[m_myPedsArrayIndex] = FLOOR_0(m_timing.steeringTime - TIMERA())
g_widgetAlcoholHitCount[m_myPedsArrayIndex] = g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit
g_widgetWeedHitCount[m_myPedsArrayIndex] = g_drunkPeds[m_myPedsArrayIndex].iWeedHit
ENDPROC
PROC Draw_Debug_Drink_Info()
TEXT_LABEL_63 str
VECTOR xyzDraw = GET_ENTITY_COORDS(m_rawDetails.ped)
IF IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped)
VEHICLE_INDEX vehIndex = GET_VEHICLE_PED_IS_IN(m_rawDetails.ped)
IF GET_PED_IN_VEHICLE_SEAT(vehIndex, VS_DRIVER) = m_rawDetails.ped
xyzDraw = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(vehIndex, <<-0.5, 0.5, 0.0>>)
ELIF GET_PED_IN_VEHICLE_SEAT(vehIndex, VS_FRONT_RIGHT) = m_rawDetails.ped
xyzDraw = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(vehIndex, << 0.5, 0.5, 0.0>>)
ELIF GET_PED_IN_VEHICLE_SEAT(vehIndex, VS_BACK_LEFT) = m_rawDetails.ped
xyzDraw = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(vehIndex, <<-0.5,-0.5, 0.0>>)
ELIF GET_PED_IN_VEHICLE_SEAT(vehIndex, VS_BACK_RIGHT) = m_rawDetails.ped
xyzDraw = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(vehIndex, << 0.5,-0.5, 0.0>>)
ENDIF
ENDIF
CONST_INT iTestXY 10
CONST_INT iTestOff -1
str = "longTerm: "
str += Get_String_From_DrunkStatus(m_status.longTerm)
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+-1), 0, 0, 0, 255)
str = "shortTerm: "
str += Get_String_From_DrunkStatus(m_status.shortTerm)
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+0), 0, 0, 255, 255)
str = "level: "
str += Get_String_From_DrunkLevel(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel)
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+1), 0, 0, 255, 255)
str = "TimerA: "
str += g_widgetTimerA[m_myPedsArrayIndex]
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+2), 0, 255, 0, 255)
str = "Ragdolling: "
str += g_widgetRagdolling[m_myPedsArrayIndex]
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+3), 0, 255, 255, 255)
str = "Overall: "
str += g_widgetOverall[m_myPedsArrayIndex]
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+4), 255, 0, 0, 255)
str = "Activity: "
str += g_widgetActivity[m_myPedsArrayIndex]
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+5), 255, 0, 255, 255)
str = "Failsafe: "
str += g_widgetFailsafe[m_myPedsArrayIndex]
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+6), 255, 255, 0, 255)
str = "Steering: "
str += g_widgetSteering[m_myPedsArrayIndex]
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+7), 255, 255, 255, 255)
str = "moveClip: \""
str += m_status.moveClip
str += "\""
IF NOT IS_STRING_NULL_OR_EMPTY(m_status.moveClip)
IF NOT HAS_CLIP_SET_LOADED(m_status.moveClip)
str += " - NOT LOADED"
ENDIF
ENDIF
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+8), 0, 0, 0, 255)
str = "HitCount: "
str += g_widgetAlcoholHitCount[m_myPedsArrayIndex]
str += ", "
str += g_widgetWeedHitCount[m_myPedsArrayIndex]
DrawDebugDrunkTextWithOffset(str, xyzDraw, 0, iTestXY*(iTestOff+1+9), 0, 0, 255, 255)
ENDPROC
#ENDIF
// -----------------------------------------------------------------------------------------
// Status Changes
// -----------------------------------------------------------------------------------------
// PURPOSE: Update the short-term status to be 'In Vehicle' and inform all followers
PROC Change_ShortTerm_Status_To_In_Vehicle()
IF (m_status.shortTerm = DSST_IN_VEHICLE)
EXIT
ENDIF
m_status.shortTerm = DSST_IN_VEHICLE
IF (m_myUniqueID = NO_UNIQUE_DRUNK_PED_ID)
EXIT
ENDIF
// Send a message to all followers
Post_Drunk_Notice(m_myUniqueID, UNIQUE_ID_ALL_FOLLOWERS, DNID_IN_VEHICLE)
// Set up the initial Steering Bias timeout
m_timing.steeringTime = TIMERA()
m_steeringBias = 0.0
ENDPROC
// -----------------------------------------------------------------------------------------
// Clipset "drunk"
// -----------------------------------------------------------------------------------------
FUNC BOOL Is_Ped_At_This_Drunk_Level(PED_INDEX PedIndex) //, g_eDrunkLevel thisDrunkLevel)
g_eDrunkLevel eDrunkLevel = Get_Peds_Drunk_Level(PedIndex)
STRING sDrunkLevelMoveClip = Get_Drunk_Level_Moveclip(eDrunkLevel)
IF IS_STRING_NULL_OR_EMPTY(m_status.moveClip)
IF IS_STRING_NULL_OR_EMPTY(sDrunkLevelMoveClip)
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDIF
RETURN ARE_STRINGS_EQUAL(m_status.moveClip, sDrunkLevelMoveClip)
ENDFUNC
// -----------------------------------------------------------------------------------------
// Ragdolling
// -----------------------------------------------------------------------------------------
// PURPOSE: Work out how long the ped should ragdoll for.
// NM can only handle ragdolling in 65535 msec chunks.
//
// RETURN VALUE: INT Number of msec to setup the ragdoll to activate for
FUNC INT Generate_Number_Of_MSec_Of_Active_Ragdolling()
IF (m_timing.ragdolling = INACTIVE_DRUNK_TIMER)
RETURN INACTIVE_DRUNK_TIMER
ENDIF
IF (m_timing.ragdolling = DRUNK_LEVEL_CONSTANT)
RETURN DRUNK_LEVEL_CONSTANT
ENDIF
INT remainingMsec = m_timing.ragdolling - TIMERA()
IF (remainingMsec < 0)
RETURN INACTIVE_DRUNK_TIMER
ENDIF
// Ensure it returns a maximum number of msec less than the maximum accepted by NM
CONST_INT MAX_RAGDOLLING_ACTIVATION_msec 65534
IF (remainingMsec > MAX_RAGDOLLING_ACTIVATION_msec)
remainingMsec = MAX_RAGDOLLING_ACTIVATION_msec
ENDIF
RETURN remainingMsec
ENDFUNC
// PURPOSE: Stop the ped ragdolling.
// This does not affect any timers, etc. It can be used to pause the ragdolling and restart again later.
PROC Stop_Ragdolling()
IF NOT (DOES_ENTITY_EXIST(m_rawDetails.ped)) //#381369
EXIT
ENDIF
// //#652851 & #733764
// IF (IS_PED_INJURED(m_rawDetails.ped)) //#515995
// EXIT
// ENDIF
// IF NOT (IS_PED_INJURED(m_rawDetails.ped)) //#515995
// IF NOT (Is_Ped_At_This_Drunk_Level(m_rawDetails.ped, g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
//
//
//
// #IF IS_DEBUG_BUILD
// CPRINTLN(DEBUG_DRUNK, "<DRUNK> This Unique Drunk Ped ID failed the Is_Ped_At_This_Drunk_Level check: ", m_myUniqueID)
// PRINTNL()
// #ENDIF
//
//
// EXIT
// ENDIF
// ENDIF
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "<DRUNK> This Unique Drunk Ped ID has been told to stop ragdolling: ", m_myUniqueID)
#ENDIF
IF NOT (IS_PED_INJURED(m_rawDetails.ped))
RESET_PED_MOVEMENT_CLIPSET(m_rawDetails.ped)
RESET_PED_STRAFE_CLIPSET(m_rawDetails.ped)
CLEAR_PED_ALTERNATE_MOVEMENT_ANIM(m_rawDetails.ped, AAT_IDLE)
m_status.moveClip = ""
CLEAR_FACIAL_IDLE_ANIM_OVERRIDE(m_rawDetails.ped)
SET_PED_RESET_FLAG(m_rawDetails.ped, PRF_DisableActionMode, FALSE)
SET_PED_RESET_FLAG(m_rawDetails.ped, PRF_DisablePlayerJumping, FALSE)
SET_PED_CAN_PLAY_AMBIENT_ANIMS(m_rawDetails.ped, TRUE)
SET_PED_FLEE_ATTRIBUTES(m_rawDetails.ped, FA_DISABLE_AMBIENT_CLIPS, FALSE)
SET_PED_IS_DRUNK(m_rawDetails.ped, FALSE)
ENDIF
IF NOT (m_ragdollOn)
EXIT
ENDIF
m_ragdollOn = FALSE
ENDPROC
//
FUNC BOOL Safe_To_Play_Transition_Animation(PED_INDEX thePed)
IF IS_PED_IN_ANY_VEHICLE(thePed, TRUE)
OR IS_PED_GETTING_INTO_A_VEHICLE(thePed)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: in a vehicle")
RETURN FALSE
ENDIF
IF (GET_SCRIPT_TASK_STATUS(thePed, SCRIPT_TASK_PLAY_ANIM) <> FINISHED_TASK)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: playing an animation")
RETURN FALSE
ENDIF
IF (GET_SCRIPT_TASK_STATUS(thePed, SCRIPT_TASK_SYNCHRONIZED_SCENE) <> FINISHED_TASK)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: playing a synch scene")
RETURN FALSE
ENDIF
IF IS_PED_SHOOTING(thePed)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: ped is shooting")
RETURN FALSE
ENDIF
IF IS_ENTITY_IN_AIR(thePed)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: ped is in air")
RETURN FALSE
ENDIF
IF IS_PED_RAGDOLL(thePed)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: ped is ragdoll")
RETURN FALSE
ENDIF
IF IS_PED_CLIMBING(thePed)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: ped is climbing")
RETURN FALSE
ENDIF
IF g_bBrowserVisible
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: browser visible")
RETURN FALSE
ENDIF
IF IS_CUSTOM_MENU_ON_SCREEN()
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: menu on screen")
RETURN FALSE
ENDIF
IF (thePed = PLAYER_PED_ID())
IF NOT IS_PLAYER_FREE_FOR_AMBIENT_TASK(PLAYER_ID())
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: not free of ambient tasks")
RETURN FALSE
ENDIF
IF NOT IS_PLAYER_CONTROL_ON(PLAYER_ID())
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: controll off")
RETURN FALSE
ENDIF
IF IS_PLAYER_FREE_AIMING(PLAYER_ID())
OR IS_PLAYER_TARGETTING_ANYTHING(PLAYER_ID())
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: player is aiming")
RETURN FALSE
ENDIF
IF IS_PLAYER_BROWSING_ITEMS_IN_ANY_SHOP()
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: player is browsing")
RETURN FALSE
ENDIF
ENDIF
VECTOR vClosestPedVelocity
vClosestPedVelocity = GET_ENTITY_VELOCITY(thePed)
IF (VMAG2(vClosestPedVelocity) >= (1.0*1.0))
CPRINTLN(DEBUG_DRUNK, "<DRUNK> don't play transition: velocity too high")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> play transition animation!!!")
RETURN TRUE
ENDFUNC
// PURPOSE: Start the ped ragdolling.
//
// RETURN VALUE: BOOL TRUE if the ped successfully started ragdolling, otherwise FALSE
FUNC BOOL Start_Ragdolling(g_eDrunkLevel thisDrunkLevel)
INT ragdollingActivationTime = Generate_Number_Of_MSec_Of_Active_Ragdolling()
IF (ragdollingActivationTime = INACTIVE_DRUNK_TIMER)
RETURN FALSE
ENDIF
IF (IS_PED_INJURED(m_rawDetails.ped)) //#652851 & #733764
IF (IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped))
OR (IS_PED_GETTING_INTO_A_VEHICLE(m_rawDetails.ped))
RETURN FALSE
ENDIF
IF (IS_ENTITY_WAITING_FOR_WORLD_COLLISION(m_rawDetails.ped))
RETURN FALSE
ENDIF
// Extra test, just in case - this can happen on odd occasions
IF (Is_Ped_At_This_Drunk_Level(m_rawDetails.ped)) //, thisDrunkLevel))
RETURN FALSE
ENDIF
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit < 3)
AND (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit <> 0)
AND (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit > g_drunkPeds[m_myPedsArrayIndex].iWeedHit)
// ...failed to activate walking - not drunk enough
#IF IS_DEBUG_BUILD
CDEBUG3LN(DEBUG_DRUNK, "<DRUNK> failed to activate walking - not drunk enough! iAlcoholHit: ", g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit, ", iWeedHit: ", g_drunkPeds[m_myPedsArrayIndex].iWeedHit, ", thisDrunkLevel: ", Get_String_From_DrunkLevel(thisDrunkLevel))
#ENDIF
RETURN FALSE
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit < 9)
AND (g_drunkPeds[m_myPedsArrayIndex].iWeedHit <> 0)
AND (g_drunkPeds[m_myPedsArrayIndex].iWeedHit > g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit)
// ...failed to activate walking
#IF IS_DEBUG_BUILD
CDEBUG3LN(DEBUG_DRUNK, "<DRUNK> failed to activate walking - not stoned enough! iWeedHit: ", g_drunkPeds[m_myPedsArrayIndex].iWeedHit, ", iAlcoholHit: ", g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit, ", thisDrunkLevel: ", Get_String_From_DrunkLevel(thisDrunkLevel))
#ENDIF
RETURN FALSE
ENDIF
#IF IS_DEBUG_BUILD
CDEBUG1LN(DEBUG_DRUNK, "<DRUNK> iAlcoholHit: ", g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit, ", iWeedHit: ", g_drunkPeds[m_myPedsArrayIndex].iWeedHit, ", thisDrunkLevel: ", Get_String_From_DrunkLevel(thisDrunkLevel))
#ENDIF
STRING m_movementClip = Get_Drunk_Level_Moveclip(thisDrunkLevel)
IF IS_STRING_NULL_OR_EMPTY(m_movementClip)
#IF IS_DEBUG_BUILD
// // // // // // // // // // // // // // //
// Ignore duplicate requests
INT drunkPedUniqueID = Get_Peds_Unique_Drunk_Ped_ID(m_rawDetails.ped)
INT arrayIndex = Get_Peds_Drunk_Ped_Array_Index(drunkPedUniqueID)
IF (arrayIndex = UNKNOWN_DRUNK_ARRAY_INDEX)
CPRINTLN(DEBUG_DRUNK, "IS_STRING_NULL_OR_EMPTY \"", m_movementClip, "\" // ", Get_String_From_DrunkLevel(thisDrunkLevel), " DL_NO_LEVEL")
ELSE
CPRINTLN(DEBUG_DRUNK, "IS_STRING_NULL_OR_EMPTY \"", m_movementClip, "\" // ", Get_String_From_DrunkLevel(thisDrunkLevel), " g_drunkPeds[", arrayIndex, "].eDrunkLevel: ", Get_String_From_DrunkLevel(g_drunkPeds[arrayIndex].eDrunkLevel))
ENDIF
// // // // // // // // // // // // // // //
PRINTNL()
#ENDIF
RETURN FALSE
ENDIF
IF Is_Ped_At_This_Drunk_Level(m_rawDetails.ped)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "Is_Ped_At_This_Drunk_Level \"", m_movementClip, "\" // ", Get_String_From_DrunkLevel(thisDrunkLevel))
#ENDIF
RETURN FALSE
ENDIF
REQUEST_CLIP_SET(m_movementClip)
// // // // // // // // // // // // // // // // //
IF Safe_To_Play_Transition_Animation(m_rawDetails.ped)
STRING sTransitionDict = "MOVE_M@DRUNK@TRANSITIONS"
STRING sTransitionClip = ""
SWITCH thisDrunkLevel
CASE DL_verydrunk
sTransitionClip = ""
BREAK
CASE DL_moderatedrunk
sTransitionClip = "VERY_TO_MODERATE"
BREAK
CASE DL_slightlydrunk
sTransitionClip = "MODERATE_TO_SLIGHTLY" // "SLIGHTLY_TO_IDLE"
BREAK
DEFAULT
SCRIPT_ASSERT(Get_String_From_DrunkLevel(thisDrunkLevel))
BREAK
ENDSWITCH
IF NOT IS_STRING_NULL_OR_EMPTY(sTransitionDict)
AND NOT IS_STRING_NULL_OR_EMPTY(sTransitionClip)
REQUEST_ANIM_DICT(sTransitionDict)
WHILE NOT HAS_ANIM_DICT_LOADED(sTransitionDict) //
WAIT(0)
ENDWHILE //
IF NOT (IS_PED_INJURED(m_rawDetails.ped))
TASK_PLAY_ANIM(m_rawDetails.ped, sTransitionDict, sTransitionClip,
WALK_BLEND_IN, WALK_BLEND_OUT, -1,
AF_SECONDARY|AF_UPPERBODY)
m_transitionClip = sTransitionClip
ENDIF
ENDIF
ENDIF
// // // // // // // // // // // // // // // // //
IF NOT HAS_CLIP_SET_LOADED(m_movementClip)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "NOT HAS_CLIP_SET_LOADED \"", m_movementClip, "\" // ", Get_String_From_DrunkLevel(thisDrunkLevel))
#ENDIF
RETURN FALSE
ENDIF
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "<DRUNK> This Unique Drunk Ped ID has been told to start ragdolling: ", m_myUniqueID, " \"", m_movementClip, "\"")
DEBUG_PRINTCALLSTACK()
#ENDIF
CONST_FLOAT blendDelta 2.0 //8.0 //#1351462
IF (IS_PED_INJURED(m_rawDetails.ped))
RETURN FALSE
ENDIF
SET_PED_MOVEMENT_CLIPSET(m_rawDetails.ped, m_movementClip, 0.75)
IF (GET_FOLLOW_PED_CAM_VIEW_MODE() = CAM_VIEW_MODE_FIRST_PERSON)
SET_PED_STRAFE_CLIPSET(m_rawDetails.ped, "move_ped_strafing_firstperson@drunk")
ENDIF
SET_PED_ALTERNATE_MOVEMENT_ANIM(m_rawDetails.ped, AAT_IDLE, m_movementClip, "idle", blendDelta)
m_status.moveClip = m_movementClip
m_ragdollOn = TRUE
STRING pOverrideIdleClipName = NULL
SWITCH GET_PLAYER_PED_ENUM(m_rawDetails.ped)
CASE CHAR_MICHAEL
pOverrideIdleClipName = "FACIALS@P_M_ZERO@BASE"
BREAK
CASE CHAR_FRANKLIN
pOverrideIdleClipName = "FACIALS@P_M_ONE@BASE"
BREAK
CASE CHAR_TREVOR
pOverrideIdleClipName = "FACIALS@P_M_TWO@BASE"
BREAK
DEFAULT
IF IS_PED_A_PLAYER(m_rawDetails.ped)
IF !IS_PLAYER_FEMALE()
pOverrideIdleClipName = "FACIALS@GEN_MALE@BASE"
ELSE
pOverrideIdleClipName = "FACIALS@GEN_FEMALE@BASE"
ENDIF
ELSE
IF IS_PED_MALE(m_rawDetails.ped)
pOverrideIdleClipName = "FACIALS@GEN_MALE@BASE"
ELSE
pOverrideIdleClipName = "FACIALS@GEN_FEMALE@BASE"
ENDIF
ENDIF
BREAK
ENDSWITCH
SET_FACIAL_IDLE_ANIM_OVERRIDE(m_rawDetails.ped, "mood_drunk_1", pOverrideIdleClipName)
SET_PED_RESET_FLAG(m_rawDetails.ped, PRF_DisableActionMode, TRUE)
SET_PED_RESET_FLAG(m_rawDetails.ped, PRF_DisablePlayerJumping, TRUE)
SET_PED_CAN_PLAY_AMBIENT_ANIMS(m_rawDetails.ped, FALSE)
SET_PED_FLEE_ATTRIBUTES(m_rawDetails.ped, FA_DISABLE_AMBIENT_CLIPS, TRUE)
SET_PED_IS_DRUNK(m_rawDetails.ped, TRUE)
RETURN TRUE
ENDFUNC
// -----------------------------------------------------------------------------------------
// Walking
// -----------------------------------------------------------------------------------------
FUNC BOOL Stop_Walking()
IF NOT (Is_Ped_At_This_Drunk_Level(m_rawDetails.ped)) //, g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
RETURN FALSE
ENDIF
IF NOT (m_ragdollOn)
RETURN FALSE
ENDIF
Force_Cleanup_Drunk_Ped(m_rawDetails.ped)
m_status.moveClip = ""
MPGlobalsAmbience.bUpdatePlayerWalk = TRUE
RETURN TRUE
ENDFUNC
PROC Set_Entity_Steer_Bias(ENTITY_INDEX EntityIndex, FLOAT steerBias)
IF NETWORK_IS_GAME_IN_PROGRESS()
AND NOT NETWORK_HAS_CONTROL_OF_ENTITY(EntityIndex)
CASSERTLN(DEBUG_DRUNK, "Set_Entity_Steer_Bias called when network doesn't have control of entity")
EXIT
ENDIF
IF (IS_ENTITY_A_PED(EntityIndex))
SET_PED_STEER_BIAS(GET_PED_INDEX_FROM_ENTITY_INDEX(EntityIndex), steerBias)
ELIF (IS_ENTITY_A_VEHICLE(EntityIndex))
SET_VEHICLE_STEER_BIAS(GET_VEHICLE_INDEX_FROM_ENTITY_INDEX(EntityIndex), steerBias)
ENDIF
ENDPROC
// -----------------------------------------------------------------------------------------
// Cleanup
// -----------------------------------------------------------------------------------------
// PURPOSE: Cancel a steering bias
PROC Cancel_Steering_Bias()
IF (IS_ENTITY_DEAD(m_rawDetails.ped))
EXIT
ENDIF
ENTITY_INDEX theEntity = m_rawDetails.ped
IF (IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped))
VEHICLE_INDEX theCar = GET_VEHICLE_PED_IS_IN(m_rawDetails.ped)
PED_INDEX theDriver = GET_PED_IN_VEHICLE_SEAT(theCar, VS_DRIVER)
IF NOT (m_rawDetails.ped = theDriver)
EXIT
ENDIF
theEntity = theCar
ELIF NOT (GET_FOLLOW_PED_CAM_VIEW_MODE() = CAM_VIEW_MODE_FIRST_PERSON) OR NOT (PLAYER_PED_ID() = m_rawDetails.ped)
EXIT
ENDIF
m_steeringBias = 0.0
Set_Entity_Steer_Bias(theEntity, 0.0)
ENDPROC
// PURPOSE: Cleanup any parts of the script that need it and terminate
PROC Drunk_Cleanup()
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "<DRUNK> This Unique Drunk Ped ID has been told to stop being drunk: ", m_myUniqueID)
#ENDIF
IF NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY)
AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_FRIENDS)
IF NOT (IS_ENTITY_DEAD(m_rawDetails.ped))
enumCharacterList ePed = GET_PLAYER_PED_ENUM(m_rawDetails.ped)
IF g_drunkPeds[m_myPedsArrayIndex].iWeedHit > 0
SWITCH ePed //#1532953
CASE CHAR_MICHAEL PLAY_PED_AMBIENT_SPEECH(m_rawDetails.ped, "POST_STONED") BREAK
CASE CHAR_FRANKLIN PLAY_PED_AMBIENT_SPEECH(m_rawDetails.ped, "POST_STONED") BREAK
CASE CHAR_TREVOR PLAY_PED_AMBIENT_SPEECH(m_rawDetails.ped, "POST_STONED") BREAK
ENDSWITCH
ENDIF
SWITCH ePed
CASE CHAR_AMANDA SET_AMBIENT_VOICE_NAME(m_rawDetails.ped, "AMANDA_NORMAL") BREAK
CASE CHAR_LAMAR SET_AMBIENT_VOICE_NAME(m_rawDetails.ped, "LAMAR_NORMAL") BREAK
ENDSWITCH
ENDIF
ENDIF
Stop_Ragdolling()
IF (m_thisIsPlayer)
g_playerIsDrunk = FALSE
ENDIF
Cancel_Steering_Bias()
#IF IS_DEBUG_BUILD
m_status.longTerm = DS_NO_STATUS
m_status.shortTerm = DS_NO_STATUS
Update_Drunk_Debug_Variables()
#ENDIF
REMOVE_ANIM_DICT(Get_Drunk_Level_Moveclip(DL_verydrunk))
REMOVE_ANIM_DICT(Get_Drunk_Level_Moveclip(DL_moderatedrunk))
REMOVE_ANIM_DICT(Get_Drunk_Level_Moveclip(DL_slightlydrunk))
g_bMPPlayerPassingOutDrunk = FALSE
IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("appEmail")) > 0
HANG_UP_AND_PUT_AWAY_PHONE()
ENDIF
TERMINATE_THIS_THREAD()
ENDPROC
// -----------------------------------------------------------------------------------------
// General Data
// -----------------------------------------------------------------------------------------
// PURPOSE: Checks to see if the Unique Drunk Ped ID for the drunk ped has been generated and stores it locally.
PROC Store_My_UniqueID()
IF NOT (m_myUniqueID = NO_UNIQUE_DRUNK_PED_ID)
EXIT
ENDIF
m_myUniqueID = Get_Peds_Unique_Drunk_Ped_ID(m_rawDetails.ped)
IF (m_myUniqueID = NO_UNIQUE_DRUNK_PED_ID)
EXIT
ENDIF
m_myPedsArrayIndex = Get_Peds_Drunk_Ped_Array_Index(m_myUniqueID)
ENDPROC
// NOTES: A ped skeleton only updates when on-screen so GET_PED_BONE_POSITION only reports correct values
// when on-screen and now asserts if called when off-screen. Before the assert was added the skeleton
// didn't move so always reported the last on-screen position of the skeleton. If off-screen I'm now
// going to do this by storing the height of the last known head position and all calculations will
// be based on the ped coordinates based on this stored height.
//
// PURPOSE: Return the head coordinates - this will be accurate if the ped is on-screen and
// estimated if off-screen [more...]
//
// RETURN VALUE: VECTOR The head coordinates
FUNC VECTOR Get_Head_Coordinates()
FLOAT groundZ = 0.0
FLOAT holdZ = 0.0
VECTOR xyzHead
IF (WAS_PED_SKELETON_UPDATED(m_rawDetails.ped))
// ...ped skeleton is on-screen so head coordinates are accurate
xyzHead = GET_PED_BONE_COORDS(m_rawDetails.ped, BONETAG_HEAD , <<0.0, 0.0, 0.0>>)
holdZ = xyzHead.z
xyzHead.z += 1.0
GET_GROUND_Z_FOR_3D_COORD(xyzHead, groundZ)
xyzHead.z = holdZ
// Update the last known head height above ground Z
m_lastKnownHeadHeight = xyzHead.z - groundZ
ELSE
// ...ped skeleton is off-screen so approximate the head position based on last known values
xyzHead = GET_ENTITY_COORDS(m_rawDetails.ped)
xyzHead.z += 2.0
GET_GROUND_Z_FOR_3D_COORD(xyzHead, groundZ)
// Store the z coordinates of the head as the last known head height above the ground Z
// NOTE: this is so that if the ped is on a slope the coords remains the same relative height above ground
xyzHead.z = groundZ + m_lastKnownHeadHeight
ENDIF
RETURN xyzHead
ENDFUNC
// PURPOSE: Checks whether or not this is the player or an AI
PROC Store_Player_Or_AI()
m_thisIsPlayer = FALSE
IF (m_rawDetails.ped = PLAYER_PED_ID())
m_thisIsPlayer = TRUE
g_playerIsDrunk = TRUE
g_iPlayerDrunkCount++
ENDIF
IF NOT (IS_ENTITY_DEAD(m_rawDetails.ped))
enumCharacterList ePed = GET_PLAYER_PED_ENUM(m_rawDetails.ped)
SWITCH ePed
CASE CHAR_AMANDA SET_AMBIENT_VOICE_NAME(m_rawDetails.ped, "AMANDA_DRUNK") BREAK
CASE CHAR_LAMAR SET_AMBIENT_VOICE_NAME(m_rawDetails.ped, "LAMAR_DRUNK") BREAK
ENDSWITCH
ENDIF
ENDPROC
// -----------------------------------------------------------------------------------------
// Notices
// -----------------------------------------------------------------------------------------
// PURPOSE: Act on a 'Extended Time' drunk notice
//
// INPUT PARAMS: paramTime_msec INT containint the milliseconds extended time
PROC Read_Drunk_Notice_Extended_Time(INT paramTime_msec)
m_rawDetails.overall_msec += paramTime_msec
m_rawDetails.ragdoll_msec += paramTime_msec
m_timing.overall += paramTime_msec
m_timing.ragdolling += paramTime_msec
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "<DRUNK> This Unique Drunk Ped ID has been told to extend it's time: ", m_myUniqueID, " by ", paramTime_msec)
#ENDIF
ENDPROC
PROC Read_Drunk_Notice_Hit_Alcohol(INT iHitCount)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit += iHitCount
// SCRIPT_ASSERT("g_drunkPeds[arrayIndex].iAlcoholHit 444")
IF (m_timing.ragdolling = DRUNK_LEVEL_CONSTANT)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
ELSE
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit < 3 AND g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit <> 0)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_NO_LEVEL
ELSE
INT remainingMsec = (m_timing.ragdolling - TIMERA())
IF (remainingMsec <= 0)
remainingMsec = 0
ENDIF
remainingMsec = ((remainingMsec / 1000) + 1)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
IF (remainingMsec < 30)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_moderatedrunk
ENDIF
IF (remainingMsec < 10)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_slightlydrunk
ENDIF
IF NOT Is_Ped_At_This_Drunk_Level(m_rawDetails.ped)
Start_Ragdolling(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel)
CPRINTLN(DEBUG_DRUNK, " not at level", Get_String_From_DrunkLevel(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
ELSE
CPRINTLN(DEBUG_DRUNK, " at level", Get_String_From_DrunkLevel(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
ENDIF
ENDIF
ENDIF
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "<DRUNK> This Unique Drunk Ped ID taken another Alcohol hit: ", m_myUniqueID, " to ", Get_String_From_DrunkLevel(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
#ENDIF
ENDPROC
PROC Read_Drunk_Notice_Hit_Weed()
g_drunkPeds[m_myPedsArrayIndex].iWeedHit++
// SCRIPT_ASSERT("g_drunkPeds[arrayIndex].iAlcoholHit 444")
IF (m_timing.ragdolling = DRUNK_LEVEL_CONSTANT)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
ELSE
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit < 9 AND g_drunkPeds[m_myPedsArrayIndex].iWeedHit <> 0)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_NO_LEVEL
ELSE
INT remainingMsec = (m_timing.ragdolling - TIMERA())
IF (remainingMsec <= 0)
remainingMsec = 0
ENDIF
remainingMsec = ((remainingMsec / 1000) + 1)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
IF (remainingMsec < 30)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_moderatedrunk
ENDIF
IF (remainingMsec < 10)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_slightlydrunk
ENDIF
IF NOT Is_Ped_At_This_Drunk_Level(m_rawDetails.ped)
Start_Ragdolling(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel)
CPRINTLN(DEBUG_DRUNK, " not at level ", Get_String_From_DrunkLevel(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
ELSE
CPRINTLN(DEBUG_DRUNK, " at level ", Get_String_From_DrunkLevel(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
ENDIF
ENDIF
ENDIF
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "<DRUNK> This Unique Drunk Ped ID taken another Weed hit: ", m_myUniqueID, " to ", Get_String_From_DrunkLevel(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
#ENDIF
ENDPROC
// PURPOSE: Act on a 'In Vehicle' drunk notice
PROC Read_Drunk_Notice_In_Vehicle()
// Change the long-term status to be 'Get Into Vehicle'
m_status.longTerm = DSLT_GET_INTO_VEHICLE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "<DRUNK> This Unique Drunk Ped ID has been told his leader is in a vehicle: ", m_myUniqueID)
#ENDIF
ENDPROC
// PURPOSE: Act on this Drunk Notice directed at this drunk ped
//
// INPUT PARAMS: paramArrayIndex Array Index into the Drunk Notices array
PROC Read_This_Drunk_Notice(INT paramArrayIndex)
g_eDrunkNoticeIDs thisNoticeID = g_drunkNotices[paramArrayIndex].notice
SWITCH (thisNoticeID)
CASE DNID_BECOME_SOBER
Drunk_Cleanup()
BREAK
CASE DNID_EXTENDED_TIME
Read_Drunk_Notice_Extended_Time(g_drunkNotices[paramArrayIndex].intval)
BREAK
CASE DNID_HIT_ALCOHOL
Read_Drunk_Notice_Hit_Alcohol(g_drunkNotices[paramArrayIndex].inthit)
BREAK
CASE DNID_HIT_WEED
Read_Drunk_Notice_Hit_Weed()
BREAK
CASE DNID_IN_VEHICLE
Read_Drunk_Notice_In_Vehicle()
BREAK
// Ignore notices aimed at the control script only
CASE DNID_STILL_DRUNK
BREAK
// Ignore this
CASE DNID_NO_DRUNK_NOTICE
BREAK
DEFAULT
SCRIPT_ASSERT("drunk: Read_This_Drunk_Notice - Unknown Drunk Notice ID. Tell Alwyn.")
BREAK
ENDSWITCH
ENDPROC
// PURPOSE: Check to see if any drunk notices are directed at this drunk ped and deal with them.
// Delete any that are specifically directed at this ped.
PROC Read_All_Drunk_Notices_Directed_At_Me()
g_eDrunkNoticeIDs thisNoticeID = DNID_NO_DRUNK_NOTICE
INT thisLoop = 0
REPEAT MAX_NUMBER_OF_DRUNK_NOTICES thisLoop
thisNoticeID = g_drunkNotices[thisLoop].notice
IF NOT (thisNoticeID = DNID_NO_DRUNK_NOTICE)
// Is this notice directed specifically at me?
IF (g_drunkNotices[thisLoop].reader = m_myUniqueID)
Read_This_Drunk_Notice(thisLoop)
Clear_One_Drunk_Notice(thisLoop)
// Is this notice directed at followers of my leader?
ELIF (g_drunkNotices[thisLoop].reader = UNIQUE_ID_ALL_FOLLOWERS)
IF NOT (m_leaderUniqueID = NO_UNIQUE_DRUNK_PED_ID)
IF (m_leaderUniqueID = g_drunkNotices[thisLoop].poster)
Read_This_Drunk_Notice(thisLoop)
ENDIF
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
// -----------------------------------------------------------------------------------------
// Timings
// -----------------------------------------------------------------------------------------
// PURPOSE: Based on the drunkLevel, calculate how long the various components of being drunk should last
PROC Store_Drunk_Timings()
// Clear out the timings struct
m_timing.ragdolling = m_rawDetails.ragdoll_msec
m_timing.overall = m_rawDetails.overall_msec
m_timing.activity = INACTIVE_DRUNK_TIMER
m_timing.failsafe = INACTIVE_DRUNK_TIMER
// Ensure the maximum drunk time is greater than the other drunk timings
#IF IS_DEBUG_BUILD
IF (m_timing.overall < m_timing.ragdolling)
SCRIPT_ASSERT("drunk: Store_Drunk_Timings(): maximum drunk time is less than ragdolling time")
ENDIF
#ENDIF
ENDPROC
// PURPOSE: Check the various drunk control timers to see if any have timed out
PROC Maintain_Drunk_Timers()
IF NOT (m_timing.ragdolling = DRUNK_LEVEL_CONSTANT)
// Has the ragdolling timer expired?
IF NOT (m_timing.ragdolling = INACTIVE_DRUNK_TIMER)
IF (TIMERA() >= m_timing.ragdolling)
Stop_Ragdolling()
m_timing.ragdolling = INACTIVE_DRUNK_TIMER
m_status.shortTerm = DS_IDLE
ENDIF
ENDIF
// Has the overall timer expired?
IF (TIMERA() > m_timing.overall)
Drunk_Cleanup()
ENDIF
ENDIF
ENDPROC
// -----------------------------------------------------------------------------------------
// Modifiers
// -----------------------------------------------------------------------------------------
// PURPOSE: Check the various drunk crime checks to see if a BAWSAQ modifier needs incimenting
PROC Maintain_Drunk_Crime_Modifiers()
// Only needed for the player
IF NOT (m_thisIsPlayer)
m_wantedLevel = -1
EXIT
ENDIF
// m_wantedLevel is -1, get the players wanted level to initialise
IF m_wantedLevel < 0
m_wantedLevel = GET_PLAYER_WANTED_LEVEL(PLAYER_ID())
EXIT
ENDIF
INT iCurrentWantedLevel = GET_PLAYER_WANTED_LEVEL(PLAYER_ID())
// Wanted level has increased since last incremented DRNKCRIME
IF iCurrentWantedLevel <> m_wantedLevel
IF iCurrentWantedLevel > m_wantedLevel
BawsaqIncrementDrunkModifier_DRNKCRIME()
ENDIF
m_wantedLevel = iCurrentWantedLevel
EXIT
ENDIF
ENDPROC
//// PURPOSE: Check the various drunk hangover checks to see if a BAWSAQ modifier needs incimenting
//PROC Maintain_Drunk_Hangover_Modifiers()
//
// // Maintain the BAWSAQ drunk modifier stat for number of drunk crimes
//// BawsaqIncrementDrunkModifier_DRNKCRIME()
//
//ENDPROC
// -----------------------------------------------------------------------------------------
// Status
// -----------------------------------------------------------------------------------------
// PURPOSE: Store the initial status for this drunk ped
PROC Store_Initial_Status()
// If the char is sitting in a vehicle then make the status 'In Vehicle' otherwise switch on ragdoll
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
IF NOT (IS_ENTITY_DEAD(m_rawDetails.ped))
IF (IS_PED_SITTING_IN_ANY_VEHICLE(m_rawDetails.ped))
// ...started in a vehicle
m_status.shortTerm = DSST_IN_VEHICLE
ENDIF
ENDIF
IF (m_thisIsPlayer)
BawsaqIncrementDrunkModifier_TIMESDRUNK()
BAWSAQ_INCREMENT_MODIFIER(BSMF_SM_TDRNK) //stockmarket #1514495
IF NETWORK_IS_GAME_IN_PROGRESS()
INT iDrunkCount = GET_MP_INT_CHARACTER_STAT(MP_STAT_NUM_TIMES_DRUNK)
CONST_INT iCONST_THRESHOLD 10
INT iDrunkTarget = ((iDrunkCount/iCONST_THRESHOLD)+1) * iCONST_THRESHOLD
CPRINTLN(DEBUG_SHOPS, "Store_Initial_Status: request drunk (", iDrunkCount ," + ", 1, ") >= ", iDrunkTarget, " times")
IF (iDrunkCount+1) >= iDrunkTarget
REQUEST_SYSTEM_ACTIVITY_TYPE_DRUNK(iDrunkTarget)
ENDIF
SET_MP_INT_CHARACTER_STAT(MP_STAT_NUM_TIMES_DRUNK, iDrunkCount+1)
m_bPlayerDrinkingInMP = TRUE
ELSE
INT iDrunkCountSP0 = 0, iDrunkCountSP1 = 0, iDrunkCountSP2 = 0
STAT_GET_INT(SP0_SP_NUM_TIMES_DRUNK, iDrunkCountSP0)
STAT_GET_INT(SP1_SP_NUM_TIMES_DRUNK, iDrunkCountSP1)
STAT_GET_INT(SP2_SP_NUM_TIMES_DRUNK, iDrunkCountSP2)
INT iDrunkCount = iDrunkCountSP0+iDrunkCountSP1+iDrunkCountSP2
CONST_INT iCONST_THRESHOLD 10
INT iDrunkTarget = ((iDrunkCount/iCONST_THRESHOLD)+1) * iCONST_THRESHOLD
CPRINTLN(DEBUG_SHOPS, "Store_Initial_Status: request drunk (", iDrunkCount ," + ", 1, ") >= ", iDrunkTarget, " times")
IF (iDrunkCount+1) >= iDrunkTarget
REQUEST_SYSTEM_ACTIVITY_TYPE_DRUNK(iDrunkTarget)
ENDIF
SWITCH GET_CURRENT_PLAYER_PED_ENUM()
CASE CHAR_MICHAEL STAT_SET_INT(SP0_SP_NUM_TIMES_DRUNK, iDrunkCountSP0+1) BREAK
CASE CHAR_FRANKLIN STAT_SET_INT(SP1_SP_NUM_TIMES_DRUNK, iDrunkCountSP1+1) BREAK
CASE CHAR_TREVOR STAT_SET_INT(SP2_SP_NUM_TIMES_DRUNK, iDrunkCountSP2+1) BREAK
ENDSWITCH
ENDIF
m_status.longTerm = DSLT_PLAYER_CONTROLLED
EXIT
ENDIF
// A leaderless AI
m_status.longTerm = DS_IDLE
// g_drunkpeds[m_mypedsarrayindex].iAlcoholHit++
// SCRIPT_ASSERT("g_drunkPeds[arrayIndex].iAlcoholHit 555")
IF (m_timing.ragdolling = DRUNK_LEVEL_CONSTANT)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
// m_status.moveClip = Get_Drunk_Level_Moveclip(DL_verydrunk)
ELSE
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit < 3 AND g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit <> 0)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_NO_LEVEL
ELSE
INT remainingMsec = (m_timing.ragdolling - TIMERA())
IF (remainingMsec <= 0)
remainingMsec = 0
ENDIF
remainingMsec = ((remainingMsec / 1000) + 1)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
IF (remainingMsec < 30)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_moderatedrunk
// m_status.moveClip = Get_Drunk_Level_Moveclip(DL_moderatedrunk)
ENDIF
IF (remainingMsec < 10)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_slightlydrunk
// m_status.moveClip = Get_Drunk_Level_Moveclip(DL_slightlydrunk)
ENDIF
ENDIF
ENDIF
ENDPROC
// -----------------------------------------------------------------------------------------
// Maintenance
// -----------------------------------------------------------------------------------------
// PURPOSE: Check if the ped is still close to his vehicle
//
// RETURN VALUE: BOOL TRUE if the ped is still close to the target vehicle, otherwise FALSE
FUNC BOOL Is_Ped_Close_To_Vehicle()
IF (m_rawDetails.vehicle = NULL)
RETURN FALSE
ENDIF
IF (IS_ENTITY_DEAD(m_rawDetails.vehicle))
RETURN FALSE
ENDIF
VECTOR xyzP = GET_ENTITY_COORDS(m_rawDetails.ped)
VECTOR xyzV = GET_ENTITY_COORDS(m_rawDetails.vehicle)
FLOAT theDist = GET_DISTANCE_BETWEEN_COORDS(xyzP, xyzV)
RETURN (theDist < MAX_DISTANCE_FROM_VEHICLE_m)
ENDFUNC
// PURPOSE: Check for any changes in the ped status that forces a short-term status change
PROC Check_For_Enforced_Short_Term_Status_Changes()
// IF (Check_If_Falling())
// EXIT
// ENDIF
ENDPROC
// PURPOSE: Make sure the ped continues to ragdoll for the required duration - NM can quit early under some circumstances
PROC Maintain_Ragdolling_For_Required_Duration()
IF (m_rawDetails.ped = PLAYER_PED_ID())
// DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_JUMP)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_DUCK)
IF GET_PED_STEALTH_MOVEMENT(m_rawDetails.ped)
IF (g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk)
OR (g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_moderatedrunk)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> turn off stealth movement for this drunken ped [", Get_String_From_DrunkLevel(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel), "]")
SET_PED_STEALTH_MOVEMENT(m_rawDetails.ped, FALSE)
ELSE
CDEBUG1LN(DEBUG_DRUNK, "<DRUNK> allow stealth movement for this drunken ped [", Get_String_From_DrunkLevel(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel), "]")
ENDIF
ENDIF
IF IS_PED_DUCKING(m_rawDetails.ped)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> turn off ducking for this drunken ped")
SET_PED_DUCKING(m_rawDetails.ped, FALSE)
ENDIF
ENDIF
IF (m_timing.ragdolling <> INACTIVE_DRUNK_TIMER)
IF (m_timing.ragdolling = DRUNK_LEVEL_CONSTANT)
IF (g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel <> DL_verydrunk)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
// m_status.moveClip = Get_Drunk_Level_Moveclip(DL_verydrunk)
ENDIF
ELSE
INT remainingMsec = (m_timing.ragdolling - TIMERA())
IF (remainingMsec <= 0)
remainingMsec = 0
ENDIF
remainingMsec = ((remainingMsec / 1000) + 1)
IF (g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk)
IF (remainingMsec < 30)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_moderatedrunk
IF NOT Start_Ragdolling(DL_moderatedrunk)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
EXIT
ENDIF
ENDIF
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_moderatedrunk)
IF (remainingMsec < 10)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_slightlydrunk
IF NOT Start_Ragdolling(DL_moderatedrunk)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_moderatedrunk
EXIT
ENDIF
ENDIF
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_slightlydrunk)
ENDIF
ENDIF
ELSE
EXIT
ENDIF
IF NOT IS_STRING_NULL_OR_EMPTY(m_transitionClip)
IF NOT Safe_To_Play_Transition_Animation(m_rawDetails.ped)
STRING sTransitionDict = "MOVE_M@DRUNK@TRANSITIONS"
IF IS_ENTITY_PLAYING_ANIM(m_rawDetails.ped, sTransitionDict, m_transitionClip)
STOP_ANIM_TASK(m_rawDetails.ped, sTransitionDict, m_transitionClip, SLOW_BLEND_OUT)
ENDIF
m_transitionClip = ""
EXIT
ENDIF
ENDIF
// 1/12/2015: AM_MP_PROPERTY_INT.sc references these hardcoded threshold values for being drunk/stoned a lot
// so if they every get updated here they should also be updated there
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
OR (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
OR IS_BIT_SET(g_iArcadeFortuneBS, ARCADE_FORTUNE_GLOBAL_BS_DRANK_PEYOTE)
IF (GET_SCRIPT_TASK_STATUS(m_rawDetails.ped, SCRIPT_TASK_SYNCHRONIZED_SCENE) = PERFORMING_TASK)
AND NOT IS_BIT_SET(g_SimpleInteriorData.iForthBS, BS4_SIMPLE_INTERIOR_GLOBAL_BS_PREVENT_DRUNK_RAGDOLL)
EXIT
ENDIF
IF IS_ANY_SPEECH_PLAYING(m_rawDetails.ped)
EXIT
ENDIF
IF IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped, TRUE)
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is in a vehicle, not passing out.")
EXIT
ENDIF
// no passout for g_sMPTunables.bBB_NIGHTCLUB_DISABLE_NIGHTCLUB_PASS_OUT_DISABLE if ped is in nightclub
IF NETWORK_IS_GAME_IN_PROGRESS()
AND m_rawDetails.ped = PLAYER_PED_ID()
AND IS_PLAYER_IN_NIGHTCLUB(PLAYER_ID())
AND g_sMPTunables.bBB_NIGHTCLUB_DISABLE_NIGHTCLUB_PASS_OUT_DISABLE
// reset the limit, so they don't pass out as soon as they walk out the door.
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is in nightclub and g_sMPTunables.bBB_NIGHTCLUB_DISABLE_NIGHTCLUB_PASS_OUT_DISABLE is set, not passing out.")
EXIT
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
AND m_rawDetails.ped = PLAYER_PED_ID()
AND IS_LOCAL_PLAYER_IN_ARENA_SPECTATOR_BOX()
// reset the limit, so they don't pass out as soon as they walk out the door.
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is in Arena Spectator Box, not passing out.")
EXIT
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
AND NETWORK_IS_ACTIVITY_SESSION()
AND CASINO_HEIST_FLOW_IS_CURRENT_MISSION_CASINO_HEIST_FINALE()
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is in Casino Heist, not passing out.")
EXIT
ENDIF
#IF FEATURE_HEIST_ISLAND
IF NETWORK_IS_GAME_IN_PROGRESS()
AND NETWORK_IS_ACTIVITY_SESSION()
AND HEIST_ISLAND_FLOW_IS_CURRENT_MISSION_HEIST_ISLAND_FINALE()
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is in Island Heist, not passing out.")
EXIT
ENDIF
IF GB_IS_PLAYER_ON_ISLAND_HEIST_SCOPING_MISSION(PLAYER_ID())
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is on Island Heist scoping mission, not passing out.")
EXIT
ENDIF
#ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
AND m_rawDetails.ped = PLAYER_PED_ID()
AND IS_PLAYER_IN_CASINO(PLAYER_ID())
AND g_sMPTunables.bVC_CASINO_DISABLE_PASSOUT
// reset the limit, so they don't pass out as soon as they walk out the door.
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is in Arena Spectator Box, not passing out.")
EXIT
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
AND m_rawDetails.ped = PLAYER_PED_ID()
AND IS_PLAYER_IN_CASINO_APARTMENT(PLAYER_ID())
AND g_sMPTunables.bVC_PENTHOUSE_DISABLE_PASSOUT
// reset the limit, so they don't pass out as soon as they walk out the door.
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is in Arena Spectator Box, not passing out.")
EXIT
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
AND m_rawDetails.ped = PLAYER_PED_ID()
AND GB_GET_GB_CASINO_VARIATION_PLAYER_IS_ON(PLAYER_ID()) = CSV_UNDER_THE_INFLUENCE
// reset the limit, so they don't pass out as soon as they walk out the door.
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is playing Under the Influence casino mission, not passing out.")
EXIT
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
AND m_rawDetails.ped = PLAYER_PED_ID()
AND g_bBrowserVisible
AND !g_bHANGOVER_WAKEUP_BROWSER_OPEN_KILLSWITCH
// reset the limit, so they don't pass out as soon as they walk out the door.
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player browser open, not passing out.")
EXIT
ENDIF
#IF FEATURE_GEN9_EXCLUSIVE
IF NETWORK_IS_GAME_IN_PROGRESS()
AND IS_PLAYER_IN_OFFICE_PROPERTY(PLAYER_ID())
AND NOT HAS_PLAYER_COMPLETED_MP_INTRO()
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
ENDIF
CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is in Executive Office, not passing out.")
EXIT
ENDIF
#ENDIF
// stop network player from passing out inside appartments.
// IF NETWORK_IS_GAME_IN_PROGRESS()
// IF (m_rawDetails.ped = PLAYER_PED_ID())
// IF (NATIVE_TO_INT(PLAYER_ID()) > -1)
// IF (GlobalplayerBD_FM[NATIVE_TO_INT(PLAYER_ID())].propertyDetails.iCurrentlyInsideProperty > 0)
//
// CPRINTLN(DEBUG_DRUNK, "<DRUNK> network player is in appartment, not passing out.")
//
// // reset the limit, so they don't pass out as soon as they walk out the door.
// IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
// g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
// ENDIF
//
// IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
// g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
// ENDIF
//
// EXIT
// ENDIF
// ENDIF
// ENDIF
// ENDIF
m_status.longTerm = DSLT_HANGOVER_WAKEUP
EXIT
ENDIF
IF NOT (m_ragdollOn)
EXIT
ENDIF
IF NOT (Is_Ped_At_This_Drunk_Level(m_rawDetails.ped)) //, g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
EXIT
ENDIF
ENDPROC
// PURPOSE: If the ped is already ragdolling then the Short-Term status will become Idle,
// otherwise ragdolling will activate.
PROC Maintain_ShortTerm_Status_Switch_On_Ragdoll()
IF (m_timing.ragdolling = DRUNK_LEVEL_CONSTANT)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
// m_status.moveClip = Get_Drunk_Level_Moveclip(DL_verydrunk)
ELSE
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit < 3 AND g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit <> 0)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_NO_LEVEL
ELSE
INT remainingMsec = (m_timing.ragdolling - TIMERA())
IF (remainingMsec <= 0)
remainingMsec = 0
ENDIF
remainingMsec = ((remainingMsec / 1000) + 1)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_verydrunk
IF (remainingMsec < 30)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_moderatedrunk
// m_status.moveClip = Get_Drunk_Level_Moveclip(DL_moderatedrunk)
ENDIF
IF (remainingMsec < 10)
g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel = DL_slightlydrunk
// m_status.moveClip = Get_Drunk_Level_Moveclip(DL_slightlydrunk)
ENDIF
ENDIF
ENDIF
// Don't ragdoll if in a car
IF (IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped))
m_status.shortTerm = DSST_IN_VEHICLE
EXIT
ENDIF
// Don't ragdoll if already ragdolling
IF (Is_Ped_At_This_Drunk_Level(m_rawDetails.ped)) //, g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
m_status.shortTerm = DS_IDLE
EXIT
ENDIF
// Don't ragdoll if the ragdoll timer has expired
IF (m_timing.ragdolling = INACTIVE_DRUNK_TIMER)
CPRINTLN(DEBUG_DRUNK, "(m_timing.ragdolling = INACTIVE_DRUNK_TIMER)")
EXIT
ENDIF
IF NOT (Start_Ragdolling(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
EXIT
ENDIF
// Update the short-term status to Idle
m_status.shortTerm = DS_IDLE
ENDPROC
// PURPOSE: Check to see if the ped should continue with the walking task.
PROC Maintain_ShortTerm_Status_Walk()
// Check if the activity timer has expired
IF (TIMERA() < m_timing.activity)
// ...it hasn't expired, so make sure the ped hasn't quit ragdolling when it should still be active
Maintain_Ragdolling_For_Required_Duration()
EXIT
ENDIF
// It has expired
Stop_Walking()
m_timing.activity = INACTIVE_DRUNK_TIMER
m_status.shortTerm = DS_IDLE
ENDPROC
// PURPOSE: Maintains a ped that is close to a vehicle trying to get close enough to enter the vehicle
// Assumes that peds are always passengers, that the player is always the driver
// Should not be used for the player
PROC Maintain_ShortTerm_Status_Enter_Vehicle()
CPRINTLN(DEBUG_DRUNK, "<DRUNK> Maintain_ShortTerm_Status_Enter_Vehicle")
// This shouldn't be the player
IF (m_thisIsPlayer)
SCRIPT_ASSERT("drunk: Maintain_ShortTerm_Status_Enter_Vehicle(): ped should not be player")
EXIT
ENDIF
// Does the ped have a vehicle?
IF (m_rawDetails.vehicle = NULL)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> vehicle is NULL")
// ...no, so switch Ragdoll back on
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
EXIT
ENDIF
// Make sure the vehicle is still driveable
IF NOT (IS_VEHICLE_DRIVEABLE(m_rawDetails.vehicle))
CPRINTLN(DEBUG_DRUNK, "<DRUNK> vehicle is not driveable")
// ...no, so switch ragdoll back on
m_rawDetails.vehicle = NULL
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
EXIT
ENDIF
// Check if the ped is close enough to start the 'Enter Vehicle' task
CONST_FLOAT PASSENGER_THRESHOLD_m 3.0
VECTOR xyzMe = GET_ENTITY_COORDS(m_rawDetails.ped)
VECTOR xyzV = GET_ENTITY_COORDS(m_rawDetails.vehicle)
FLOAT theDist = GET_DISTANCE_BETWEEN_COORDS(xyzMe, xyzV)
IF (theDist > PASSENGER_THRESHOLD_m)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> still a bit far away")
// Make the ped walk a bit closer
IF NOT (Start_Ragdolling(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
// ...failed to activate walking
m_status.shortTerm = DS_IDLE
EXIT
ENDIF
CONST_INT WALK_TIME_msec 2000
// Set the action and activity timer
m_status.shortTerm = DSST_WALK
m_timing.activity = TIMERA() + WALK_TIME_msec
EXIT
ENDIF
// Choose an empty passenger seat
INT maxPassengersAllowed = GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(m_rawDetails.vehicle)
INT thisSeat = 0
BOOL keepChecking = TRUE
// If the leader is in the back of a taxi, then only check the back two seats
//KGMTAXI IF (IS_CHAR_IN_BACK_OF_TAXI(m_rawDetails.leader))
thisSeat = 1
//KGMTAXI ENDIF
WHILE (keepChecking)
IF (thisSeat < maxPassengersAllowed)
// ...check if this car seat is free
IF (IS_VEHICLE_SEAT_FREE(m_rawDetails.vehicle, INT_TO_ENUM(VEHICLE_SEAT, thisSeat)))
CPRINTLN(DEBUG_DRUNK, "<DRUNK> found an empty car seat")
keepChecking = FALSE
ELSE
thisSeat++
ENDIF
ELSE
// ...ran out of car seats
keepChecking = FALSE
thisSeat = NO_AVAILABLE_SEAT
ENDIF
ENDWHILE
// If there is no available seat, switch on ragdoll again (except, for a taxi, try the front passenger seat)
IF (thisSeat = NO_AVAILABLE_SEAT)
//KGMTAXI IF NOT (IS_CHAR_IN_BACK_OF_TAXI(m_rawDetails.leader))
//KGMTAXI // ...try front passenger seat
//KGMTAXI IF (IS_CAR_PASSENGER_SEAT_FREE(m_rawDetails.vehicle, SEAT_FRONT_PASSENGER))
//KGMTAXI thisSeat = SEAT_FRONT_PASSENGER
//KGMTAXI CPRINTLN(DEBUG_DRUNK, "<DRUNK> using front seat of the taxi")
//KGMTAXI ENDIF
//KGMTAXI ENDIF
// May now have found a seat, so do another check
IF (thisSeat = NO_AVAILABLE_SEAT)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> failed to find an empty car seat")
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
EXIT
ENDIF
ENDIF
// Found a seat
// Stop Natural Motion and get ped into car
Stop_Ragdolling()
//SET_NEXT_DESIRED_MOVE_BLEND_RATIO(PEDMOVE_WALK) //- deprecated
// Enter player's car as a passenger
CPRINTLN(DEBUG_DRUNK, "<DRUNK> enter car as passenger [thisSeat:", thisSeat, "]")
TASK_ENTER_VEHICLE(m_rawDetails.ped, m_rawDetails.vehicle, -1, INT_TO_ENUM(VEHICLE_SEAT, thisSeat))
m_status.shortTerm = DSST_ENTERING_VEHICLE
ENDPROC
// PURPOSE: Maintain the process of getting a ped into a vehicle
// Assumes that peds are always passengers, that the player is always the driver
PROC Maintain_ShortTerm_Status_Entering_Vehicle()
IF NOT (m_thisIsPlayer)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> Maintain_ShortTerm_Status_Entering_Vehicle")
ENDIF
VEHICLE_INDEX thisVehicle = NULL
// Is the ped sitting in the back of a taxi?
BOOL inBackOfTaxi = FALSE
//KGMTAXI IF (IS_CHAR_IN_BACK_OF_TAXI(m_rawDetails.ped))
//KGMTAXI inBackOfTaxi = TRUE
//KGMTAXI
//KGMTAXI IF NOT (m_thisIsPlayer)
//KGMTAXI CPRINTLN(DEBUG_DRUNK, "<DRUNK> in back of taxi")
//KGMTAXI ENDIF
//KGMTAXI ENDIF
// Is the ped sitting in a car or in the back of a taxi?
IF (inBackOfTaxi)
OR (IS_PED_SITTING_IN_ANY_VEHICLE(m_rawDetails.ped))
IF NOT (m_thisIsPlayer)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> in a vehicle")
ENDIF
// ...ped is in the back of a taxi or is sitting in any car
// Is the taxi the vehicle the ped is supposed to be in?
thisVehicle = GET_VEHICLE_PED_IS_IN(m_rawDetails.ped)
IF NOT (thisVehicle = m_rawDetails.vehicle)
IF NOT (m_thisIsPlayer)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> wrong vehicle")
ENDIF
// ...this is the wrong vehicle, so exit the vehicle again if this ped is not the player
IF NOT (m_thisIsPlayer)
IF NOT (m_thisIsPlayer)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> leave vehicle")
ENDIF
// ...this is not the player
// Ped's can only be in the wrong vehicle if they are following another ped and they don't have
// their own vehicle, so eject them
TASK_LEAVE_ANY_VEHICLE(m_rawDetails.ped)
m_status.shortTerm = DSST_LEAVE_VEHICLE
EXIT
ENDIF
// This is the player, so this has to be the 'correct' vehicle, so update the vehicle
// to be the current vehicle
m_rawDetails.vehicle = thisVehicle
ENDIF
// If the ped is in a taxi and the taxi is the correct car then there is nothing else to do,
// so update the status to be 'in vehicle'
IF (inBackOfTaxi)
IF NOT (m_thisIsPlayer)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> status now In Vehicle (back of taxi)")
ENDIF
Change_ShortTerm_Status_To_In_Vehicle()
EXIT
ENDIF
// If this is not the player then there is nothing else to do
IF NOT (m_thisIsPlayer)
IF NOT (m_thisIsPlayer)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> status now In Vehicle")
ENDIF
Change_ShortTerm_Status_To_In_Vehicle()
EXIT
ENDIF
IF NOT (m_thisIsPlayer)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> NON-PLAYER'S SHOULDN'T REACH HERE")
ENDIF
// This is the player
// Is the player driving the vehicle?
PED_INDEX driverOfVehicle = GET_PED_IN_VEHICLE_SEAT(m_rawDetails.vehicle, VS_DRIVER)
IF (driverOfVehicle = m_rawDetails.ped)
// ...player is the driver, so nothing else to do
Change_ShortTerm_Status_To_In_Vehicle()
EXIT
ENDIF
// Player is not the driver, so the player needs to shuffle over to the driver's seat
TASK_SHUFFLE_TO_NEXT_VEHICLE_SEAT(m_rawDetails.ped, thisVehicle)
// Change the status and create a failsafe timeout
m_status.shortTerm = DSST_SHUFFLE_CARSEATS
m_timing.failsafe = TIMERA() + FAILSAFE_SHUFFLE_TIMEOUT_msec
EXIT
ENDIF
// Ped is not in a vehicle, so check if the vehicle has moved away
IF NOT (Is_Ped_Close_To_Vehicle())
CLEAR_PED_TASKS(m_rawDetails.ped)
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
EXIT
ENDIF
// AI may get locked out of a taxi while the player is choosing destinations, etc
IF NOT (m_thisIsPlayer)
SCRIPTTASKSTATUS thisStatus = GET_SCRIPT_TASK_STATUS(m_rawDetails.ped, SCRIPT_TASK_ENTER_VEHICLE)
IF (thisStatus = FINISHED_TASK)
// ...The 'enter car' task has ended but it looks like the AI is still not in the car
// If the leader is in the back of a taxi then warp this drunk ped into a free taxi seat
// NOTE: The taxi script locks the player inside while choosing destinations
//KGMTAXI IF (IS_CHAR_IN_BACK_OF_TAXI(m_rawDetails.leader))
//KGMTAXI // ...leader is in back of taxi
//KGMTAXI // Is this AI sitting in a car?
//KGMTAXI IF NOT (IS_CHAR_SITTING_IN_ANY_CAR(m_rawDetails.ped))
//KGMTAXI Warp_Into_Leaders_Taxi()
//KGMTAXI EXIT
//KGMTAXI ENDIF
//KGMTAXI ELSE
// IF the task is finished and the ped is not in any car then it may be that the car seat he
// was heading for has been filled, so switch on ragdolling again
IF NOT (IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped))
CLEAR_PED_TASKS(m_rawDetails.ped)
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
EXIT
ENDIF
//KGMTAXI ENDIF
ENDIF
ENDIF
ENDPROC
// PURPOSE: Makes sure that the ped successfully warps into the taxi
PROC Maintain_ShortTerm_Status_Warp_Into_Taxi()
// Is the ped sitting in a car?
IF (IS_PED_SITTING_IN_ANY_VEHICLE(m_rawDetails.ped))
// Change status to 'in vehicle'
m_status.shortTerm = DSST_IN_VEHICLE
EXIT
ENDIF
// Not yet in the car - check for failsafe timeout
IF (TIMERA() < m_timing.failsafe)
EXIT
ENDIF
// Timed Out so switch back to ragdoll
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
m_timing.failsafe = INACTIVE_DRUNK_TIMER
ENDPROC
// PURPOSE: Make sure that the ped manages to complete the 'shuffle carseats' task.
PROC Maintain_ShortTerm_Status_Shuffle_Carseats()
// Check for failsafe timeout
IF (TIMERA() <= m_timing.failsafe)
EXIT
ENDIF
// Timeout has occurred
SCRIPTTASKSTATUS thisStatus = GET_SCRIPT_TASK_STATUS(PLAYER_PED_ID(), SCRIPT_TASK_SHUFFLE_TO_NEXT_VEHICLE_SEAT)
IF NOT (thisStatus = FINISHED_TASK)
// Extend the failsafe timer then test again later
m_timing.failsafe = TIMERA() + FAILSAFE_SHUFFLE_TIMEOUT_msec
EXIT
ENDIF
// The task is finished.
// If the ped is no longer in any car then swap back to ragdoll
IF NOT (IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped))
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
m_timing.failsafe = INACTIVE_DRUNK_TIMER
EXIT
ENDIF
// Check if the ped is now successfully the driver of the vehicle
VEHICLE_INDEX thisVehicle = GET_VEHICLE_PED_IS_IN(m_rawDetails.ped)
PED_INDEX driverOfVehicle = GET_PED_IN_VEHICLE_SEAT(thisVehicle, VS_DRIVER)
IF (driverOfVehicle = m_rawDetails.ped)
// ...this ped is the driver, so task complete
Change_ShortTerm_Status_To_In_Vehicle()
m_timing.failsafe = INACTIVE_DRUNK_TIMER
EXIT
ENDIF
// This ped is not the driver, so give the shuffle task again
TASK_SHUFFLE_TO_NEXT_VEHICLE_SEAT(m_rawDetails.ped, thisVehicle)
// Change the status and create a failsafe timeout
m_status.shortTerm = DSST_SHUFFLE_CARSEATS
m_timing.failsafe = TIMERA() + FAILSAFE_SHUFFLE_TIMEOUT_msec
ENDPROC
// PURPOSE: Maintain the 'In Vehicle' task
// For the player, this checks if the player has left the vehicle.
PROC Maintain_ShortTerm_Status_In_Vehicle()
// Nothing to do if the ped is no longer in the vehicle
IF NOT (IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped))
// ...ped is no longer in any vehicle, so switch on ragdoll again
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
EXIT
ENDIF
// if player drinks too much in vehicle
IF NETWORK_IS_GAME_IN_PROGRESS()
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
OR (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
// limit how drunk / stoned they get in vehicle so they never pass out.
IF (g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit >= 10)
g_drunkPeds[m_myPedsArrayIndex].iAlcoholHit = 9
CPRINTLN(DEBUG_DRUNK, "Maintain_ShortTerm_Status_In_Vehicle - limiting how drunk ped can get in vehicle.")
ENDIF
IF (g_drunkPeds[m_myPedsArrayIndex].iWeedHit >= 15)
g_drunkPeds[m_myPedsArrayIndex].iWeedHit = 14
CPRINTLN(DEBUG_DRUNK, "Maintain_ShortTerm_Status_In_Vehicle - limiting how stoned ped can get in vehicle.")
ENDIF
// CPRINTLN(DEBUG_DRUNK, "Maintain_ShortTerm_Status_In_Vehicle - too drunk in vehicle mp, fading out.")
//
// IF NOT (GET_SCRIPT_TASK_STATUS(m_rawDetails.ped, SCRIPT_TASK_SYNCHRONIZED_SCENE) = PERFORMING_TASK)
// AND NOT (IS_ANY_SPEECH_PLAYING(m_rawDetails.ped))
//
// IF NOT IS_SCREEN_FADED_OUT()
// DO_SCREEN_FADE_OUT(DEFAULT_FADE_TIME_LONG)
// WHILE IS_SCREEN_FADING_OUT()
// WAIT(0)
// ENDWHILE
// ENDIF
//
// IF NOT IS_PED_INJURED(m_rawDetails.ped)
// IF IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped)
// TASK_LEAVE_ANY_VEHICLE(m_rawDetails.ped)
// ENDIF
// ENDIF
//
// // if in network game just cleanup and set flag for neil
// IF NETWORK_IS_GAME_IN_PROGRESS()
//
// NET_SET_PLAYER_CONTROL(PLAYER_ID(), FALSE, NSPC_SET_INVISIBLE | NSPC_NO_COLLISION | NSPC_FREEZE_POSITION)
// g_SpawnData.bPassedOutDrunk = TRUE
// IF IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0 )
// g_SpawnData.bPassedOutDrunkWithWantedLevel = TRUE
// ELSE
// g_SpawnData.bPassedOutDrunkWithWantedLevel = FALSE
// ENDIF
//
// Quit_Drunk_Camera_Immediately()
// Drunk_Cleanup()
// ENDIF
//
//
// EXIT
// ENDIF
ENDIF
ENDIF
// Ped is still in the vehicle
// If this is the player then nothing more to do
IF (m_thisIsPlayer)
EXIT
ENDIF
// This is an AI
VEHICLE_INDEX thisVehicle = GET_VEHICLE_PED_IS_IN(m_rawDetails.ped)
// If the vehicle is no longer driveable then exit
IF NOT (IS_VEHICLE_DRIVEABLE(thisVehicle))
TASK_LEAVE_ANY_VEHICLE(m_rawDetails.ped)
m_status.shortTerm = DSST_LEAVE_VEHICLE
EXIT
ENDIF
// Seems fine to leave the ped in this state
ENDPROC
// PURPOSE: Calculate and return a steering bias
FUNC FLOAT Friend_Drink_Calculate_Steering_Bias(ENTITY_INDEX EntityIndex, FLOAT paramRange, FLOAT paramOffset)
// INPUT PARAMS: paramRange // The max distance from 0.0 (+ or -)
// paramOffset // An offset to add on to the distance
// RETURN VALUE: FLOAT // The calculated bias (between -1.0 and 1.0)
FLOAT thisValue = GET_RANDOM_FLOAT_IN_RANGE(-paramRange, paramRange)
FLOAT thisOffset = GET_RANDOM_FLOAT_IN_RANGE(0.0, paramOffset)
IF (thisValue < 0.0)
thisValue -= thisOffset
ELSE
thisValue += thisOffset
ENDIF
IF IS_ENTITY_A_PED(EntityIndex)
IF IS_PED_SPRINTING(GET_PED_INDEX_FROM_ENTITY_INDEX(EntityIndex))
CONST_FLOAT fCONST_DRUNK_STERRRING_BIAS_PED_SPRINT_MULTIPLIER 4.5
thisValue *= fCONST_DRUNK_STERRRING_BIAS_PED_SPRINT_MULTIPLIER
ELSE
CONST_FLOAT fCONST_DRUNK_STERRRING_BIAS_PED_MULTIPLIER 3.0
thisValue *= fCONST_DRUNK_STERRRING_BIAS_PED_MULTIPLIER
ENDIF
ELSE
MODEL_NAMES EntityModelHashKey = GET_ENTITY_MODEL(EntityIndex)
IF IS_THIS_MODEL_A_BIKE(EntityModelHashKey)
CONST_FLOAT fCONST_DRUNK_STERRRING_BIAS_BIKE_MULTIPLIER 1.5
thisValue *= fCONST_DRUNK_STERRRING_BIAS_BIKE_MULTIPLIER
ELSE
CONST_FLOAT fCONST_DRUNK_STERRRING_BIAS_MULTIPLIER 0.5
thisValue *= fCONST_DRUNK_STERRRING_BIAS_MULTIPLIER
ENDIF
ENDIF
thisValue = CLAMP(thisValue, -1.0000, 1.0000)
RETURN thisValue
ENDFUNC
// PURPOSE: Update the Steering Bias if the ped is the driver of a car
PROC Maintain_Steering_Bias()
ENTITY_INDEX theEntity = m_rawDetails.ped
// Is the Char still in a car?
IF (IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped))
// Is the char the driver of the car?
VEHICLE_INDEX theCar = GET_VEHICLE_PED_IS_IN(m_rawDetails.ped)
PED_INDEX theDriver = GET_PED_IN_VEHICLE_SEAT(theCar, VS_DRIVER)
IF NOT (theDriver = m_rawDetails.ped)
EXIT
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
AND NOT NETWORK_HAS_CONTROL_OF_ENTITY(theCar)
CDEBUG1LN(DEBUG_DRUNK, "Maintain_Steering_Bias called when network doesn't have control of entity")
EXIT
ENDIF
theEntity = theCar
ELIF NOT (PLAYER_PED_ID() = m_rawDetails.ped)
EXIT
ELIF NOT (GET_FOLLOW_PED_CAM_VIEW_MODE() = CAM_VIEW_MODE_FIRST_PERSON)
m_steeringBias = 0.0
Set_Entity_Steer_Bias(theEntity, 0.0)
EXIT
ENDIF
// Has the Steering Bias timer expired?
IF (TIMERA() < m_timing.steeringTime)
Set_Entity_Steer_Bias(theEntity, m_steeringBias)
EXIT
ENDIF
// Set up a new timer
IF (IS_ENTITY_A_PED(theEntity))
m_timing.steeringTime = TIMERA() + STEERING_BIAS_PED_TIMEOUT_msec
ELSE
m_timing.steeringTime = TIMERA() + STEERING_BIAS_TIMEOUT_msec
ENDIF
// Is the car still moving?
FLOAT thisSpeed = GET_ENTITY_SPEED(theEntity)
IF (thisSpeed < SPEED_CLASSED_AS_STOPPED)
m_steeringBias = 0.0
Set_Entity_Steer_Bias(theEntity, 0.0)
EXIT
ENDIF
// Give the car a new steering bias - this should be based on the overall time remaining
IF (m_timing.overall = DRUNK_LEVEL_CONSTANT)
m_steeringBias = Friend_Drink_Calculate_Steering_Bias(theEntity, 0.13, 0.06)
CDEBUG1LN(DEBUG_DRUNK, "<DRUNK> m_steeringBias: ", "drunk level constant, so extreme //", m_steeringBias)
ELSE
INT timeRemaining = m_timing.overall - TIMERA()
IF (timeRemaining < 05000)
m_steeringBias = 0.0
CDEBUG1LN(DEBUG_DRUNK, "<DRUNK> m_steeringBias: ", TO_FLOAT(timeRemaining) / 1000.0, " less than 10 secs, so none //", m_steeringBias)
ELIF (timeRemaining < 15000)
m_steeringBias = Friend_Drink_Calculate_Steering_Bias(theEntity, 0.05, 0.02)
CDEBUG1LN(DEBUG_DRUNK, "<DRUNK> m_steeringBias: ", TO_FLOAT(timeRemaining) / 1000.0, " less than 30 secs, so mild //", m_steeringBias)
ELIF (timeRemaining < 30000)
m_steeringBias = Friend_Drink_Calculate_Steering_Bias(theEntity, 0.07, 0.03)
CDEBUG1LN(DEBUG_DRUNK, "<DRUNK> m_steeringBias: ", TO_FLOAT(timeRemaining) / 1000.0, " less than 60 secs, so medium //", m_steeringBias)
ELIF (timeRemaining < 45000)
m_steeringBias = Friend_Drink_Calculate_Steering_Bias(theEntity, 0.09, 0.04)
CDEBUG1LN(DEBUG_DRUNK, "<DRUNK> m_steeringBias: ", TO_FLOAT(timeRemaining) / 1000.0, " less than 90 secs, so heavy //", m_steeringBias)
ELIF (timeRemaining < 600000)
m_steeringBias = Friend_Drink_Calculate_Steering_Bias(theEntity, 0.1, 0.05)
CDEBUG1LN(DEBUG_DRUNK, "<DRUNK> m_steeringBias: ", TO_FLOAT(timeRemaining) / 1000.0, " less than 120 secs, so very heavy //", m_steeringBias)
ELSE
m_steeringBias = Friend_Drink_Calculate_Steering_Bias(theEntity, 0.13, 0.06)
CDEBUG1LN(DEBUG_DRUNK, "<DRUNK> m_steeringBias: ", TO_FLOAT(timeRemaining) / 1000.0, " greater than 120 secs, so extreme //", m_steeringBias)
ENDIF
ENDIF
Set_Entity_Steer_Bias(theEntity, m_steeringBias)
ENDPROC
// PURPOSE: Check if the player should get a wanted level for driving drunk past a police car
PROC Maintain_Wanted_Level()
IF NOT (m_thisIsPlayer)
EXIT
ENDIF
IF NOT (IS_PLAYER_PLAYING(PLAYER_ID()))
EXIT
ENDIF
//KGMTAXI IF (IS_CHAR_IN_BACK_OF_TAXI(PLAYER_PED_ID()))
//KGMTAXI EXIT
//KGMTAXI ENDIF
IF NOT (IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()))
EXIT
ENDIF
IF (IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0))
EXIT
ENDIF
// Ignore if the steering bias has stopped
// ...TO DO
// Ignore if the the car is moving slowly
VEHICLE_INDEX theCar = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
FLOAT thisSpeed = GET_ENTITY_SPEED(theCar)
CONST_FLOAT MINIMUM_CAR_SPEED 5.0
IF (thisSpeed < MINIMUM_CAR_SPEED)
EXIT
ENDIF
// Is there a police car nearby?
CONST_FLOAT NEARBY_POLICE_CAR_RANGE_m 30.0
CONST_FLOAT NEARBY_POLICE_CAR_HEIGHT_m 3.0
VECTOR xyzPlayer = GET_ENTITY_COORDS(PLAYER_PED_ID())
VECTOR xyzMin = xyzPlayer - <<NEARBY_POLICE_CAR_RANGE_m, NEARBY_POLICE_CAR_RANGE_m, NEARBY_POLICE_CAR_HEIGHT_m>>
VECTOR xyzMax = xyzPlayer + <<NEARBY_POLICE_CAR_RANGE_m, NEARBY_POLICE_CAR_RANGE_m, NEARBY_POLICE_CAR_HEIGHT_m>>
IF NOT (IS_COP_VEHICLE_IN_AREA_3D(xyzMin, xyzMax))
AND NOT (IS_COP_PED_IN_AREA_3D(xyzMin, xyzMax))
EXIT
ENDIF
SET_PLAYER_WANTED_LEVEL_NO_DROP(PLAYER_ID(), 1)
SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID())
BAWSAQ_INCREMENT_MODIFIER(BSMF_SM_DRNKCRM) //stockmarket #1514495
CPRINTLN(DEBUG_DRUNK, "Maintain_Wanted_Level")
ENDPROC
// PURPOSE: Switch on ragdoll again when a ped has left his vehicle
PROC Maintain_ShortTerm_Status_Leave_Vehicle()
IF NOT (IS_PED_IN_ANY_VEHICLE(m_rawDetails.ped))
// ...ped is no longer in any vehicle, so switch on ragdoll again
m_status.shortTerm = DSST_SWITCH_ON_RAGDOLL
EXIT
ENDIF
ENDPROC
// PURPOSE: Generate a new short-term task when the long-term task is 'Get Into Vehicle'
PROC Maintain_LongTerm_Status_Get_Into_Vehicle()
CPRINTLN(DEBUG_DRUNK, "<DRUNK> Maintain_LongTerm_Status_Get_Into_Vehicle")
// This shouldn't be the player
IF (m_thisIsPlayer)
SCRIPT_ASSERT("drunk: Maintain_LongTerm_Status_Get_Into_Vehicle(): ped should not be player")
EXIT
ENDIF
IF NOT (Is_Ped_Close_To_Vehicle())
CONST_INT WALK_TIME_msec 5000
// Set the action and activity timer
m_status.shortTerm = DSST_WALK
m_timing.activity = TIMERA() + WALK_TIME_msec
EXIT
ENDIF
// Ped is now close to the leader's vehicle, so enter the vehicle
m_status.shortTerm = DSST_ENTER_VEHICLE
ENDPROC
// PURPOSE: Generate a new short-term task when the long-term task is 'Idle'
PROC Maintain_LongTerm_Status_Idle()
// This shouldn't be the player
IF (m_thisIsPlayer)
SCRIPT_ASSERT("drunk: Maintain_LongTerm_Status_Idle(): ped should not be player")
EXIT
ENDIF
// Remove the ped's vehicle - for Idle there can't be a leader so no vehicle
m_rawDetails.vehicle = NULL
// Ped has no leader so make this ped lean randomly (and perhaps therefore walk)
// VECTOR xyzMe = GET_ENTITY_COORDS(m_rawDetails.ped)
//
// FLOAT leanValue = GET_RANDOM_FLOAT_IN_RANGE(0.05, WALKING_LEAN_VALUE)
// Activate a short-term walking task
IF NOT (Start_Ragdolling(g_drunkPeds[m_myPedsArrayIndex].eDrunkLevel))
// ...failed to activate walking
EXIT
ENDIF
CONST_INT LEAN_TIME_MIN_msec 500
CONST_INT LEAN_TIME_MAX_msec 3000
INT theTime = GET_RANDOM_INT_IN_RANGE(LEAN_TIME_MIN_msec, LEAN_TIME_MAX_msec)
// Set the action and activity timer
m_status.shortTerm = DSST_WALK
m_timing.activity = TIMERA() + theTime
ENDPROC
PROC Maintain_LongTerm_Status_Hangover_Wakeup()
IF NOT IS_BIT_SET(g_SimpleInteriorData.iForthBS, BS4_SIMPLE_INTERIOR_GLOBAL_BS_PREVENT_DRUNK_RAGDOLL)
SET_PED_TO_RAGDOLL(m_rawDetails.ped, DEFAULT_FADE_TIME_LONG+0500, DEFAULT_FADE_TIME_LONG+1000, TASK_RELAX)
ENDIF
g_bMPPlayerPassingOutDrunk = TRUE
IF NOT IS_SCREEN_FADED_OUT()
DO_SCREEN_FADE_OUT(DEFAULT_FADE_TIME_LONG)
WHILE IS_SCREEN_FADING_OUT()
WAIT(0)
ENDWHILE
ENDIF
// if in network game just cleanup and set flag for neil
IF NETWORK_IS_GAME_IN_PROGRESS()
//NETWORK_LEAVE_PED_BEHIND_BEFORE_WARP(PLAYER_ID(), GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), TRUE, TRUE)
SCRIPT_TIMER stPlayerFade
START_NET_TIMER(stPlayerFade)
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
NETWORK_FADE_OUT_ENTITY(PLAYER_PED_ID(), FALSE, TRUE)
ENDIF
WHILE DOES_ENTITY_EXIST(PLAYER_PED_ID())
AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
AND NETWORK_GET_ENTITY_IS_NETWORKED(PLAYER_PED_ID()) // url:bugstar:7854566 - Caused by player getting dunk in MP and switching sessions while passing out
AND NETWORK_IS_ENTITY_FADING(PLAYER_PED_ID())
WAIT(0)
ENDWHILE
IF NOT NETWORK_GET_ENTITY_IS_NETWORKED(PLAYER_PED_ID()) // url:bugstar:7854566 - Caused by player getting dunk in MP and switching sessions while passing out
PRINTLN("Maintain_LongTerm_Status_Hangover_Wakeup - Stopping drunk.sc because player ped is not networked while drunk in MP")
Drunk_Cleanup()
ENDIF
CLEAR_BIT(g_SimpleInteriorData.iForthBS, BS4_SIMPLE_INTERIOR_GLOBAL_BS_PREVENT_DRUNK_RAGDOLL)
NET_SET_PLAYER_CONTROL(PLAYER_ID(), FALSE, NSPC_SET_INVISIBLE | NSPC_NO_COLLISION | NSPC_FREEZE_POSITION)
g_SpawnData.bPassedOutDrunk = TRUE
IF IS_BIT_SET(g_SimpleInteriorData.iBS ,BS_SIMPLE_INTERIOR_GLOBAL_DATA_ALL_EXIT_BUNKER_FROM_TRUCK_TRIGGERED)
CLEAR_BIT(g_SimpleInteriorData.iBS ,BS_SIMPLE_INTERIOR_GLOBAL_DATA_ALL_EXIT_BUNKER_FROM_TRUCK_TRIGGERED)
PRINTLN("Maintain_LongTerm_Status_Hangover_Wakeup - BS_SIMPLE_INTERIOR_GLOBAL_DATA_ALL_EXIT_BUNKER_FROM_TRUCK_TRIGGERED FALSE")
ENDIF
IF IS_BIT_SET(g_SimpleInteriorData.iThirdBS, BS3_SIMPLE_INTERIOR_GLOBAL_DATA_ALL_EXIT_BASE_FROM_AIRCRAFT_TRIGGERED)
CLEAR_BIT(g_SimpleInteriorData.iThirdBS, BS3_SIMPLE_INTERIOR_GLOBAL_DATA_ALL_EXIT_BASE_FROM_AIRCRAFT_TRIGGERED)
PRINTLN("Maintain_LongTerm_Status_Hangover_Wakeup - BS3_SIMPLE_INTERIOR_GLOBAL_DATA_ALL_EXIT_BASE_FROM_AIRCRAFT_TRIGGERED FALSE")
ENDIF
IF IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0 )
g_SpawnData.bPassedOutDrunkWithWantedLevel = TRUE
ELSE
g_SpawnData.bPassedOutDrunkWithWantedLevel = FALSE
ENDIF
IF IS_SCRIPT_GLOBAL_SHAKING()
CPRINTLN(DEBUG_DRUNK, "Maintain_LongTerm_Status_Hangover_Wakeup: someone started a global script cam shake, nuke it on drunk wakeup!!")
STOP_SCRIPT_GLOBAL_SHAKING()
ENDIF
IF GB_IS_LOCAL_PLAYER_MEMBER_OF_A_BIKER_GANG()
BIK_ADD_POINTS_FOR_THIS(BIK_ADD_POINTS_DRUNK)
ENDIF
Quit_Drunk_Camera_Immediately()
Drunk_Cleanup()
ENDIF
// Should not reach SP part below if player got wasted in MP
IF m_bPlayerDrinkingInMP // url:bugstar:7854566 - Caused by player getting dunk in MP and switching sessions while passing out
PRINTLN("Maintain_LongTerm_Status_Hangover_Wakeup - Stopping drunk.sc because player is no longer in MP session while started to pass out drunk in MP")
Drunk_Cleanup()
ENDIF
STRING pDrunkDebugName = ""
RESPAWN_CUTSCENE_STRUCT sRespawnCutscene
g_eDrunkWakeupCutscene eDrunkWakeupScene = DWC_NO_DRUNK_WAKEUP_CUTSCENE
SWITCH GET_CURRENT_PLAYER_PED_ENUM()
CASE CHAR_MICHAEL
IF (GetMichaelScheduleStage() <> MSS_M6_Exiled)
eDrunkWakeupScene = DWC_MICHAEL_mansion
ELSE
eDrunkWakeupScene = DWC_MICHAEL_trailer
ENDIF
BREAK
CASE CHAR_FRANKLIN
IF NOT Get_Mission_Flow_Flag_State(FLOWFLAG_FRANKLIN_MOVED_TO_HILLS_APARTMENT)
eDrunkWakeupScene = DWC_FRANKLIN_city
ELSE
eDrunkWakeupScene = DWC_FRANKLIN_hills
ENDIF
BREAK
CASE CHAR_TREVOR
IF NOT Is_Savehouse_Respawn_Available(SAVEHOUSE_TREVOR_SC)
IF Get_Mission_Flow_Flag_State(FLOWFLAG_TREVOR_RESTRICTED_TO_COUNTRY)
eDrunkWakeupScene = DWC_TREVOR_trailer
ENDIF
IF Get_Mission_Flow_Flag_State(FLOWFLAG_TREVOR_RESTRICTED_TO_CITY)
eDrunkWakeupScene = DWC_TREVOR_beach
ENDIF
IF (eDrunkWakeupScene = DWC_NO_DRUNK_WAKEUP_CUTSCENE)
IF NOT GET_RANDOM_BOOL()
eDrunkWakeupScene = DWC_TREVOR_trailer
ELSE
eDrunkWakeupScene = DWC_TREVOR_beach
ENDIF
ENDIF
ELSE
eDrunkWakeupScene = DWC_TREVOR_stripclub
ENDIF
BREAK
ENDSWITCH
SWITCH eDrunkWakeupScene
CASE DWC_MICHAEL_mansion
pDrunkDebugName = "DWC_MICHAEL_mansion"
sRespawnCutscene.pAnimDictName = "SAVEM_Default@"
sRespawnCutscene.pAnimClipName = "M_GetOut_R"
sRespawnCutscene.pAnimCamName = "M_GetOut_R_CAM"
sRespawnCutscene.vAnimPos = <<-814.181, 181.100, 75.740 >>
sRespawnCutscene.vAnimRot = <<0.0000, 0.0000, 21.1994 >>
sRespawnCutscene.ePedMotionState = MS_ON_FOOT_IDLE
BREAK
CASE DWC_MICHAEL_trailer
pDrunkDebugName = "DWC_MICHAEL_trailer"
sRespawnCutscene.pAnimDictName = "SAVECountryside@"
sRespawnCutscene.pAnimClipName = "M_GetOut_countryside"
sRespawnCutscene.pAnimCamName = "M_GetOut_countryside_CAM"
sRespawnCutscene.vAnimPos = <<1968.14, 3816.79, 32.4287>>
sRespawnCutscene.vAnimRot = <<0.0000, 0.0000, 29.7938 >>
sRespawnCutscene.ePedMotionState = MS_ON_FOOT_IDLE
BREAK
CASE DWC_FRANKLIN_city
pDrunkDebugName = "DWC_FRANKLIN_city"
sRespawnCutscene.pAnimDictName = "SWITCH@FRANKLIN@BED"
sRespawnCutscene.pAnimClipName = "Sleep_GetUp_RubEyes"
sRespawnCutscene.pAnimCamName = "Sleep_GetUp_RubEyes_CAM"
sRespawnCutscene.vAnimPos = <<-17.2168, -1441.2240, 30.1015>>
sRespawnCutscene.vAnimRot = <<0.0000, 0.0000, -179.6530>>
sRespawnCutscene.ePedMotionState = MS_ON_FOOT_IDLE
BREAK
CASE DWC_FRANKLIN_hills
pDrunkDebugName = "DWC_FRANKLIN_hills"
sRespawnCutscene.pAnimDictName = "SAVEBighouse@"
sRespawnCutscene.pAnimClipName = "F_GetOut_r_bighouse"
sRespawnCutscene.pAnimCamName = "F_GetOut_r_bighouse_CAM"
sRespawnCutscene.vAnimPos = <<-1.049, 524.283, 170.064 >>
sRespawnCutscene.vAnimRot = <<0.0000, 0.0000, 24.000 >>
sRespawnCutscene.ePedMotionState = MS_ON_FOOT_IDLE
BREAK
CASE DWC_TREVOR_trailer
pDrunkDebugName = "DWC_TREVOR_trailer"
sRespawnCutscene.pAnimDictName = "SAVECountryside@"
sRespawnCutscene.pAnimClipName = "T_GetOut_countryside"
sRespawnCutscene.pAnimCamName = "T_GetOut_countryside_CAM"
sRespawnCutscene.vAnimPos = <<1968.14, 3816.79, 32.4287>>
sRespawnCutscene.vAnimRot = <<0.0000, 0.0000, 29.7938 >>
sRespawnCutscene.ePedMotionState = MS_ON_FOOT_IDLE
BREAK
CASE DWC_TREVOR_beach
pDrunkDebugName = "DWC_TREVOR_beach"
sRespawnCutscene.pAnimDictName = "SAVEVeniceB@"
sRespawnCutscene.pAnimClipName = "T_GetOut_r_veniceB"
sRespawnCutscene.pAnimCamName = "T_GetOut_r_veniceB_CAM"
sRespawnCutscene.vAnimPos = <<-1148.438, -1512.246, 9.689 >>
sRespawnCutscene.vAnimRot = <<0.0000, 0.0000, 36.250 >>
sRespawnCutscene.ePedMotionState = MS_ON_FOOT_IDLE
BREAK
CASE DWC_TREVOR_stripclub
pDrunkDebugName = "DWC_TREVOR_stripclub"
sRespawnCutscene.pAnimDictName = "SAVECouch@"
sRespawnCutscene.pAnimClipName = "T_GetOut_couch"
sRespawnCutscene.pAnimCamName = "T_GetOut_couch_CAM"
sRespawnCutscene.vAnimPos = << 94.53, -1289.86, 28.27 >>
sRespawnCutscene.vAnimRot = <<0.0000, 0.0000, 29.7938 >>
sRespawnCutscene.ePedMotionState = MS_ON_FOOT_IDLE
BREAK
ENDSWITCH
IF NOT IS_ENTITY_DEAD(m_rawDetails.ped)
SET_ENTITY_COORDS(m_rawDetails.ped, sRespawnCutscene.vAnimPos)
ENDIF
WAIT(0500)
sRespawnCutscene.DialogueTextLabel = ""
sRespawnCutscene.fDialoguePhase = -1
#IF IS_DEBUG_BUILD
sRespawnCutscene.respawn_widgetId = g_wDrawDebugDrunkInfo
#ENDIF
RUN_RESPAWN_CUTSCENE(pDrunkDebugName, sRespawnCutscene, "")
BAWSAQ_INCREMENT_MODIFIER(BSMF_SM_HANGOVR) //stockmarket #1514495
Drunk_Cleanup()
ENDPROC
/*
// PURPOSE: Check to see if a player is trying to enter a car
//
// RETURN VALUE: BOOL TRUE if the player tried to enter a vehicle, otherwise FALSE
FUNC BOOL Maintain_Player_Trying_To_Enter_Vehicle()
// Has the player has tried to enter a vehicle?
IF NOT (IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_ENTER))
RETURN FALSE
ENDIF
// Make sure the player is in control
// This is to fix GTA E1 PS3 bug 754
IF NOT (IS_PLAYER_CONTROL_ON(PLAYER_ID()))
RETURN FALSE
ENDIF
// Player has tried to enter a car
// Check if there is a car nearby that the player can enter
VEHICLE_INDEX closestCar = NULL
VECTOR xyzP = GET_ENTITY_COORDS(m_rawDetails.ped)
INT searchFlags = (VEHICLE_SEARCH_FLAG_RETURN_RANDOM_VEHICLES | VEHICLE_SEARCH_FLAG_RETURN_MISSION_VEHICLES | VEHICLE_SEARCH_FLAG_RETURN_VEHICLES_WITH_PEDS_ENTERING_OR_EXITING)
closestCar = GET_CLOSEST_VEHICLE(xyzP, MAX_DISTANCE_FROM_VEHICLE_m, DUMMY_MODEL_FOR_SCRIPT, searchFlags)
IF (closestCar = NULL)
RETURN FALSE
ENDIF
// There is a nearby car
// Ensure it is driveable
IF NOT (IS_VEHICLE_DRIVEABLE(closestCar))
RETURN FALSE
ENDIF
// Check if the player is close enough to either the driver's door or the passenger door (to prevent running around the whole car)
CONST_FLOAT OFFSET_ON_DRIVERS_SIDE_m -1.0
CONST_FLOAT OFFSET_ON_PASSENGER_SIDE_m 1.0
CONST_FLOAT OFFSET_ON_DRIVERS_SIDE_TAXI_m 0.0
CONST_FLOAT VALID_PLAYER_RANGE_m 2.0
CONST_FLOAT VALID_PLAYER_TAXI_RANGE_m 4.0
FLOAT thisOffset = OFFSET_ON_DRIVERS_SIDE_m
FLOAT thisRange = VALID_PLAYER_RANGE_m
BOOL onDriverSide = TRUE
BOOL isCloseToCar = FALSE
BOOL useCentreOfCar = FALSE
// Taxi?
//KGMTAXI IF (IS_VEHICLE_MODEL(closestCar, TAXI))
//KGMTAXI OR (IS_VEHICLE_MODEL(closestCar, CABBY))
//KGMTAXI OR (IS_VEHICLE_MODEL(closestCar, TAXI2))
//KGMTAXI thisRange = VALID_PLAYER_TAXI_RANGE_m
//KGMTAXI thisOffset = OFFSET_ON_DRIVERS_SIDE_TAXI_m
//KGMTAXI useCentreOfCar = TRUE
//KGMTAXI ENDIF
// Player on driver's side or in taxi?
VECTOR theOffsetVector = << thisOffset, 0.0, 0.0 >>
VECTOR xyzCar = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(closestCar, theOffsetVector)
VECTOR theRangeVector = << thisRange, thisRange, thisRange >>
IF (IS_ENTITY_AT_COORD(m_rawDetails.ped, xyzCar, theRangeVector, FALSE))
isCloseToCar = TRUE
onDriverSide = TRUE
ENDIF
// Only test passenger side offset if not using the centre of the car for the driver's side offset
IF NOT (isCloseToCar)
AND NOT (useCentreOfCar)
theOffsetVector = << OFFSET_ON_PASSENGER_SIDE_m, 0.0, 0.0 >>
xyzCar = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(closestCar, theOffsetVector)
theRangeVector = << VALID_PLAYER_RANGE_m, VALID_PLAYER_RANGE_m, VALID_PLAYER_RANGE_m >>
IF (IS_ENTITY_AT_COORD(m_rawDetails.ped, xyzCar, theRangeVector, FALSE))
isCloseToCar = TRUE
onDriverSide = FALSE
ENDIF
ENDIF
IF NOT (isCloseToCar)
RETURN FALSE
ENDIF
// Close enough to the car to jack
// Stop Natural Motion and get player into car
Stop_Ragdolling()
// SET_NEXT_DESIRED_MOVE_BLEND_RATIO(PEDMOVE_WALK)
// Check if a bike
MODEL_NAMES thisModel = GET_ENTITY_MODEL(closestCar)
BOOL isBike = IS_THIS_MODEL_A_BIKE(thisModel)
IF (onDriverSide)
OR (isBike)
CPRINTLN(DEBUG_DRUNK, "<DRUNK> enter car as DRIVER")
TASK_ENTER_VEHICLE(m_rawDetails.ped, closestCar, DEFAULT_TIME_BEFORE_WARP, VS_DRIVER)
ELSE
CPRINTLN(DEBUG_DRUNK, "<DRUNK> enter car as FRONT_RIGHT")
TASK_ENTER_VEHICLE(m_rawDetails.ped, closestCar, DEFAULT_TIME_BEFORE_WARP, VS_FRONT_RIGHT)
ENDIF
m_rawDetails.vehicle = closestCar
m_status.shortTerm = DSST_ENTERING_VEHICLE
RETURN TRUE
ENDFUNC
*/
// PURPOSE: Check to see if a player is driving a car
//
// RETURN VALUE: BOOL TRUE if the player is driving a vehicle, otherwise FALSE
FUNC BOOL Maintain_Player_Is_Driving_Vehicle()
//
IF NOT (IS_PED_SITTING_IN_ANY_VEHICLE(m_rawDetails.ped))
RETURN FALSE
ENDIF
VEHICLE_INDEX drivenCar = NULL
drivenCar = GET_VEHICLE_PED_IS_IN(m_rawDetails.ped)
// Ensure it is driveable
IF NOT (IS_VEHICLE_DRIVEABLE(drivenCar))
RETURN FALSE
ENDIF
IF NOT (GET_PED_IN_VEHICLE_SEAT(drivenCar, VS_DRIVER) = m_rawDetails.ped)
RETURN FALSE
ENDIF
m_rawDetails.vehicle = drivenCar
m_status.shortTerm = DSST_ENTERING_VEHICLE
RETURN TRUE
ENDFUNC
// PURPOSE: Maintain the components associated with being drunk
// A ped should always have an Immediate task. If Idle then the Overall task is used to
// generate a new Immediate task.
PROC Maintain_Being_Drunk()
// Ensure the ped is still alive
IF (IS_ENTITY_DEAD(m_rawDetails.ped))
Drunk_Cleanup()
ENDIF
// If this is the player, ensure the player is playing
IF (m_thisIsPlayer)
IF NOT (IS_PLAYER_PLAYING(PLAYER_ID()))
Drunk_Cleanup()
ENDIF
ENDIF
// Need to see if a new short-term status should interrupt any current task - eg: Get Up From Floor
Check_For_Enforced_Short_Term_Status_Changes()
// Every ped should have an immediate status. This flag will be used to highlight problems.
BOOL foundShortTermStatus = TRUE
// Deal with the Immediate task
SWITCH (m_status.shortTerm)
CASE DSST_SWITCH_ON_RAGDOLL
Maintain_ShortTerm_Status_Switch_On_Ragdoll()
EXIT
CASE DSST_WALK
Maintain_ShortTerm_Status_Walk()
EXIT
CASE DSST_ENTER_VEHICLE
Maintain_ShortTerm_Status_Enter_Vehicle()
EXIT
CASE DSST_ENTERING_VEHICLE
Maintain_ShortTerm_Status_Entering_Vehicle()
EXIT
CASE DSST_WARP_INTO_TAXI
Maintain_ShortTerm_Status_Warp_Into_Taxi()
EXIT
CASE DSST_SHUFFLE_CARSEATS
Maintain_ShortTerm_Status_Shuffle_Carseats()
EXIT
CASE DSST_IN_VEHICLE
Maintain_ShortTerm_Status_In_Vehicle()
Maintain_Steering_Bias()
Maintain_Wanted_Level()
EXIT
CASE DSST_LEAVE_VEHICLE
Maintain_ShortTerm_Status_Leave_Vehicle()
EXIT
// When Idle, look to the long-term objective for something to do
CASE DS_IDLE
BREAK
DEFAULT
foundShortTermStatus = FALSE
BREAK
ENDSWITCH
// Error Checking
IF NOT (foundShortTermStatus)
SCRIPT_ASSERT("drunk: Maintain_Being_Drunk(): Found a ped with an illegal Short-Term Status")
EXIT
ENDIF
IF NOT (m_status.shortTerm = DS_IDLE)
SCRIPT_ASSERT("drunk: Maintain_Being_Drunk(): Long-term status for a ped is being checked but their Short-term Status is not Idle")
EXIT
ENDIF
// Deal with the long-term objectives - a ped should only reach here if the long-term status is Idle
SWITCH (m_status.longTerm)
// Player Controlled drunk ped's need to do a few checks
CASE DSLT_PLAYER_CONTROLLED
IF NOT /*(Maintain_Player_Trying_To_Enter_Vehicle())
AND NOT*/ (Maintain_Player_Is_Driving_Vehicle())
Maintain_Ragdolling_For_Required_Duration()
Maintain_Steering_Bias()
ENDIF
BREAK
CASE DSLT_GET_INTO_VEHICLE
Maintain_LongTerm_Status_Get_Into_Vehicle()
BREAK
// Peds with no long-term objective
CASE DS_IDLE
Maintain_LongTerm_Status_Idle()
BREAK
// Peds with no long-term objective
CASE DSLT_HANGOVER_WAKEUP
Maintain_LongTerm_Status_Hangover_Wakeup()
BREAK
DEFAULT
SCRIPT_ASSERT("drunk: Maintain_Being_Drunk(): Found a ped with an illegal long-term Status")
BREAK
ENDSWITCH
ENDPROC
SCRIPT (g_sDrunkRequests scriptArgs)
// This script needs to cleanup only when the game moves from SP to MP
IF (HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_SP_TO_MP))
CPRINTLN(DEBUG_DRUNK, "...drunk.sc has been forced to cleanup (SP to MP)")
Drunk_Cleanup()
ENDIF
// Store details passed as args
m_rawDetails = scriptArgs
Store_My_UniqueID()
Store_Player_Or_AI()
// Still need to tell controller on first frame that this ped is still drunk
Post_Drunk_Notice(m_myUniqueID, UNIQUE_ID_CONTROL_SCRIPT, DNID_STILL_DRUNK)
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_DRUNK, "--------------------------------------------------------------")
IF (m_myUniqueID = NO_UNIQUE_DRUNK_PED_ID)
IF (m_leaderUniqueID = NO_UNIQUE_DRUNK_PED_ID)
CPRINTLN(DEBUG_DRUNK, "Started new drunk ped with unique ID: currently unknown and with a leader with unique ID: currently unknown")
ELSE
CPRINTLN(DEBUG_DRUNK, "Started new drunk ped with unique ID: currently unknown and with a leader with unique ID: ", m_leaderUniqueID)
ENDIF
ELSE
IF (m_leaderUniqueID = NO_UNIQUE_DRUNK_PED_ID)
CPRINTLN(DEBUG_DRUNK, "Started new drunk ped with unique ID: ", m_myUniqueID, " and with a leader with unique ID: currently unknown")
ELSE
CPRINTLN(DEBUG_DRUNK, "Started new drunk ped with unique ID: ", m_myUniqueID, " and with a leader with unique ID: ", m_leaderUniqueID)
ENDIF
ENDIF
CPRINTLN(DEBUG_DRUNK, "--------------------------------------------------------------")
#ENDIF
// Use TimerA as the control timer
SETTIMERA(0)
// Store length of time that the various components of being drunk should last
Store_Drunk_Timings()
// Store the initial statuses
Store_Initial_Status()
WHILE (TRUE)
WAIT(0)
// Clear out any previously sent notices by me
Clear_All_Notices_From_This_Unique_Drunk_Ped_ID(m_myUniqueID)
// Does the drunk effects need to continue?
Maintain_Drunk_Timers()
// Maintain the BAWSAQ modifiers for drunken events
Maintain_Drunk_Crime_Modifiers()
// Maintain_Drunk_Hangover_Modifiers()
// Read and act on any notices directed at this drunk ped
Read_All_Drunk_Notices_Directed_At_Me()
// Post a notice each frame telling the controller that this ped is still drunk
Post_Drunk_Notice(m_myUniqueID, UNIQUE_ID_CONTROL_SCRIPT, DNID_STILL_DRUNK)
// Grab any data that may not have been available when the script launched
Store_My_UniqueID()
// Maintain the components of being drunk
Maintain_Being_Drunk()
// Ensure multiplayer "on call" missions not triggered while drunk
IF NETWORK_IS_GAME_IN_PROGRESS()
AND NOT NETWORK_IS_ACTIVITY_SESSION()
AND NOT IS_TRANSITION_SESSION_RANKED_QUICKMATCH_READY_TO_LAUNCH()
SET_TRANSITION_SESSIONS_CLEAN_UP_ON_CALL_NOW_IF_NEEDED()
ENDIF
#IF IS_DEBUG_BUILD
Update_Drunk_Debug_Variables()
// Draw useful info (state, time etc) on this drunk ped
Draw_Debug_Drink_Info()
IF IS_KEYBOARD_KEY_JUST_PRESSED(KEY_K)
EXPLODE_PED_HEAD(m_rawDetails.ped)
ENDIF
#ENDIF
ENDWHILE
ENDSCRIPT