Files
2025-09-29 00:52:08 +02:00

4326 lines
143 KiB
Scheme
Executable File

// *****************************************************************************************
// *****************************************************************************************
//
// MISSION NAME : carwash_shared.sch
// AUTHOR : Aaron Gandaa
// DESCRIPTION : Car Wash Shared Structs and Functions
//
// *****************************************************************************************
// *****************************************************************************************
//----------------------
// INCLUDES
//----------------------
USING "rgeneral_include.sch"
USING "RC_Helper_Functions.sch"
USING "RC_Asset_Public.sch"
USING "RC_Camera_Public.sch"
USING "cost_halo.sch"
USING "net_ambience.sch"
USING "net_cash_transactions.sch"
USING "commands_volume.sch"
#IF IS_DEBUG_BUILD
USING "shared_debug.sch"
#ENDIF
//----------------------
// ENUM
//----------------------
ENUM eCarwashAreaState
ECA_NULL,
ECA_ENTERED_AREA,
ECA_INAREA,
ECA_EXITED_AREA
ENDENUM
ENUM CARWASH_PARTSTATE
CPS_NULL,
CPS_STARTUP,
CPS_WARMUP,
CPS_ACTIVE,
CPS_WARMDOWN,
CPS_SHUTDOWN,
CPS_FINISHED
ENDENUM
ENUM CARWASH_LOCATIONID
CARWASH_LOCID_LONG = 1,
CARWASH_LOCID_SHORT = 2
ENDENUM
//----------------------
// CONSTANTS
//---------------------
CONST_FLOAT CAR_WASH_ACTIVE_RANGE 90.0
CONST_FLOAT ROLLER_RADIUS 0.55
CONST_FLOAT ROLLER_SPINRATE 360.0
CONST_FLOAT VROLLER_CHECKDIFF 0.95
CONST_FLOAT VROLLER_ZSHIFT 1.5
CONST_FLOAT VROLLER_CHECKZSHIFT 0.5
CONST_FLOAT DEFAULT_DUALVROLL_SEP 3.75 // 4.0
CONST_INT COST_CARWASH 15
CONST_FLOAT VROLLER_SEP 1.75 //0.825
CONST_FLOAT AUTODRIVE_TOLERANCE 30.0
CONST_FLOAT JET_TRIGGER_DIST 0.6
CONST_FLOAT ROLLER_TRIGGER_DIST 1.25
CONST_INT CAMERASTATE_LASTCAMERA 98
CONST_INT CAMERASTATE_ALLDONE 99
CONST_INT CARWASH_AXIS_X 0
CONST_INT CARWASH_AXIS_Y 0
INT ROLLER_CHECK_INTERVAL = 125
INT SHAPE_CHECK_INTERVAL = 128
CONST_INT BLOCKED_SHAPE_CHECK_INTERVAL 250
FLOAT ROLLER_SHIFT_FACTOR = 0.625
//----------------------
// STRUCT
//----------------------
STRUCT CARWASH_CAMERA
BOOL bSetup = FALSE
VECTOR vPosition[2]
VECTOR vRotation[2]
INT iInterpTime = 0
FLOAT fFov
CAMERA_INDEX cameraID
ENDSTRUCT
STRUCT CARWASH_VROLLER2
BOOL bSetup = FALSE
OBJECT_INDEX pivotID
CARWASH_PARTSTATE state
OBJECT_INDEX rollerID[2]
PTFX_ID fxBrushID[2]
FLOAT fOffset[2]
FLOAT fTgtOffset[2]
FLOAT fRollerSpinAngle = 0.0
FLOAT fSpinRate = 0.0
FLOAT fMoveRate = 1.0 // rate the brush moves in meters per second
FLOAT fSensorOffset[2] // this is how far away from the center the sensors are
FLOAT fSensorRadius[2]
VECTOR vBasePosition
INT iSpinSoundID = -1
INT iMoveSoundID = -1
INT iHitSoundID = -1
FLOAT fOriginalSep
BOOL bCollisionOn = TRUE
BOOL bOldCollision
BOOL bSensorOn[2]
SHAPETEST_INDEX shapeTestID
VEHICLE_INDEX activeVehicle
SHAPETEST_INDEX brushShapeTestID[2]
INT iNextBrushShapeTestTime[2]
INT iNextShapeTestTime
FLOAT fShutDownMoveRate = 0.3
BOOL bHitCheck[2]
BOOL bOldHitCheck[2]
ENDSTRUCT
STRUCT CARWASH_JETS
BOOL bSetup = FALSE
BOOL bSteam = FALSE
CARWASH_PARTSTATE state
OBJECT_INDEX pivotID
INT iNextCheckTime
INT iSoundID = -1
INT iSplashSoundID = -1
FLOAT fTriggerDist
FLOAT fSeperation = 0.0
FLOAT fHeight = 0.0
VECTOR vBasePos
STRING sJetName
PTFX_ID fxJets[4]
SHAPETEST_INDEX shapeTestID
INT iNextShapeTestTime
ENDSTRUCT
STRUCT CARWASH_HROLLER
CARWASH_PARTSTATE state
BOOL bSetup = FALSE
VECTOR vPosition // this is the position of the roller when it starts
VECTOR vContactPoint // this is the contact point for the line test, the brush should be ROLLER_RADIUS m above this
VECTOR vOldRollerPos
FLOAT fRollerPivotAngle = 0.0
FLOAT fRollerSpinAngle = 0.0
FLOAT fSpinRate = 0.0
FLOAT fMoveRate = 2.5 // rate the brush moves in meters per second
FLOAT fTriggerDist
INT iSpinSoundID = -1
INT iMoveSoundID = -1
INT iHitSoundID = -1
OBJECT_INDEX rollerID
SHAPETEST_INDEX shapeTestID
PTFX_ID fxBrushID
FLOAT fGroundZero = 0.0 // this is the z height of floor when the carwash is empty
FLOAT fTargetZ = 0.0
FLOAT fOriginalZ = 0.0
INT iNextCheckTime
INT iNextShapeTestTime
ENDSTRUCT
STRUCT CARWASH_TRACK
VECTOR vTrackPoint[2]
VECTOR vBlockMinMax[2]
VECTOR vBlockPoint[2]
VECTOR vVehicleSnapPoint
FLOAT fTrackHeading
FLOAT fTrackInterpolate = 0.0
VECTOR vDirection
INT iDominantBlockAxis
ENDSTRUCT
STRUCT CARWASH_HANDLER
CARWASH_TRACK cTrack
CARWASH_JETS soapJets
CARWASH_JETS waterJets
CARWASH_JETS steamJets
CARWASH_HROLLER horzRoller
CARWASH_VROLLER2 vertRoller
CAMERA_STRUCT carWashCamera[7]
BUILDING_NAME_ENUM iplSwap
STRING sWayPointRec
FLOAT fForwardSpeed = 1.5
FLOAT fBoostSpeed
FLOAT fFinalCameraInterpolate = 0.8 // when we get to here
INT iCurrentCameraState = 0
CAMERA_INDEX cameraID
BOOL bTimerStarted = FALSE
BOOL bTallVehicle
BOOL bThrottleBoosted
BOOL bSkipped = FALSE
BOOL bIsAllowedInMP = FALSE
INT iNextBlockCheckTime
INT iLastTimeUsed = 0
SHAPETEST_INDEX shapeTestID
INT iBlockCounts = 0
INT iTaskSequenceSize = 0 // NUMBER OF TASKS IN SEQUENCE
CARWASH_LOCATIONID iLocationID = CARWASH_LOCID_LONG
VECTOR vNoPedWalkMin
VECTOR vNoPedWalkMax
BOOL bCarwashAborted = FALSE
BOOL bBackInterruptCheck = FALSE
BOOL bOldUpdateCheck = FALSE
INT iAutoAbortTimer // if the time gets bigger than this automatically exit as something has gone wrong
TIME_DATATYPE iAutoAbortTimerMP //
ENDSTRUCT
//----------------------
// VARIABLES
//----------------------
VECTOR vRollerRadius = <<0, 0, ROLLER_RADIUS * 1.1>>
BOOL bDrawDebugCarwash = FALSE
VECTOR vRollerVertPosFX = <<0, 0, -1.125>>
VECTOR vRollerVertRotFX = <<0, 0, 0>>
VECTOR vRollerHorzRotFX = <<0, 90, 0>>
VECTOR vJetRotFX = <<90, 90, 0>>
VECTOR vSteamRotFX = <<0, 0, 0>>
VECTOR vSteamPosFX = <<0, 0.1, -0.76>>
FLOAT fRumbleFactor = 1.0
BOOL bUseOldVerticleBrushCheck = FALSE
BOOL bDebugForceClearPedTasks = FALSE
BOOL bDebugForceRestartTasks = FALSE
BOOL bIsDriverRunningCarwashSequence = FALSE
BOOL bIsDriverFinishedCarwashSequence = FALSE
INT iDriverCarwashSequenceProgress = -1
BOOL bUseNewMPVertRollers = TRUE
BOOL bUseNewSweptSphereTest = TRUE
FLOAT fSweepSphereRadius = 1.0
FLOAT fShapeTestXSeperation = 3.0
#IF IS_DEBUG_BUILD
FLOAT fCarDebugRatio
INT iDebugCarWashTimer
BOOL bCreateBlockCar
FLOAT fBlockCarPlaceT = 0.5
#ENDIF
//----------------------
// MISC FUNCTIONS
//----------------------
/*
PROC PROCESS_EVENT_CARWASH_NETWORK_SCRIPT_EVENT(CARWASH_HANDLER &ch, INT iCount)
SCRIPT_EVENT_DATA_CARWASH_EVENT sEvent
IF GET_EVENT_DATA(SCRIPT_EVENT_QUEUE_NETWORK, iCount, sEvent, SIZE_OF(sEvent))
CPRINTLN(DEBUG_MISSION, "[CARWASH] - NETWORK SCRIPT EVENT RECIEVED")
IF (ENUM_TO_INT(ch.iLocationID) = sEvent.iCarwashID)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - NETWORK SCRIPT EVENT PROCESSED BY CARWASH:", ENUM_TO_INT(ch.iLocationID))
ENDIF
ENDIF
ENDPROC
PROC PROCESS_CARWASH_NETWORK_SCRIPT_EVENT(CARWASH_HANDLER &ch, INT iEventID)
STRUCT_EVENT_COMMON_DETAILS Details
GET_EVENT_DATA(SCRIPT_EVENT_QUEUE_NETWORK, iEventID, Details, SIZE_OF(Details))
SWITCH Details.Type
CASE SCRIPT_EVENT_CARWASH_EVENT
PROCESS_EVENT_CARWASH_NETWORK_SCRIPT_EVENT(ch, iEventID)
BREAK
ENDSWITCH
ENDPROC
PROC PROCESS_CARWASH_NETWORK_EVENTS(CARWASH_HANDLER &ch)
INT iCount
EVENT_NAMES ThisScriptEvent
REPEAT GET_NUMBER_OF_EVENTS(SCRIPT_EVENT_QUEUE_NETWORK) iCount
ThisScriptEvent = GET_EVENT_AT_INDEX(SCRIPT_EVENT_QUEUE_NETWORK, iCount)
SWITCH ThisScriptEvent
CASE EVENT_NETWORK_SCRIPT_EVENT
PROCESS_CARWASH_NETWORK_SCRIPT_EVENT(ch, iCount)
BREAK
ENDSWITCH
ENDREPEAT
ENDPROC
*/
PROC UPDATE_VEHICLE_DOOR_DAMAGE_BIT_FIELD(VEHICLE_INDEX veh, INT &iBitField)
iBitField = 0
IF NOT IS_THIS_MODEL_A_CAR(GET_ENTITY_MODEL(veh))
EXIT
ENDIF
IF IS_VEHICLE_DOOR_DAMAGED(veh, SC_DOOR_FRONT_LEFT)
SET_BIT(iBitField, 0)
ENDIF
IF IS_VEHICLE_DOOR_DAMAGED(veh, SC_DOOR_FRONT_RIGHT)
SET_BIT(iBitField, 1)
ENDIF
IF IS_VEHICLE_DOOR_DAMAGED(veh, SC_DOOR_REAR_LEFT)
SET_BIT(iBitField, 2)
ENDIF
IF IS_VEHICLE_DOOR_DAMAGED(veh, SC_DOOR_REAR_RIGHT)
SET_BIT(iBitField, 3)
ENDIF
ENDPROC
FUNC BOOL IS_ANY_VEHICLE_MAIN_DOOR_BROKEN(VEHICLE_INDEX veh)
IF NOT IS_THIS_MODEL_A_CAR(GET_ENTITY_MODEL(veh))
RETURN TRUE
ENDIF
IF IS_VEHICLE_DOOR_DAMAGED(veh, SC_DOOR_FRONT_LEFT)
RETURN TRUE
ENDIF
IF IS_VEHICLE_DOOR_DAMAGED(veh, SC_DOOR_FRONT_RIGHT)
RETURN TRUE
ENDIF
IF IS_VEHICLE_DOOR_DAMAGED(veh, SC_DOOR_REAR_LEFT)
RETURN TRUE
ENDIF
IF IS_VEHICLE_DOOR_DAMAGED(veh, SC_DOOR_REAR_RIGHT)
RETURN TRUE
ENDIF
IF IS_VEHICLE_A_CONVERTIBLE(veh, TRUE)
IF GET_CONVERTIBLE_ROOF_STATE(veh) = CRS_ROOF_STUCK_LOWERED
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
PROC REMOVE_CARWASH_STUCK_CHECK(VEHICLE_INDEX veh)
IF NOT IS_ENTITY_ALIVE(veh)
EXIT
ENDIF
IF DOES_VEHICLE_HAVE_STUCK_VEHICLE_CHECK(veh)
REMOVE_VEHICLE_STUCK_CHECK(veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Removed stuck check")
ENDIF
IF DECOR_EXIST_ON(veh, "Carwash_Vehicle_Decorator")
DECOR_REMOVE(veh, "Carwash_Vehicle_Decorator")
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Vehicle Decorator Removed")
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
IF NETWORK_HAS_CONTROL_OF_ENTITY(veh)
SET_VEHICLE_DOORS_LOCKED_FOR_ALL_PLAYERS(veh, FALSE)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Carwash Network Door Lock Released")
ENDIF
ENDIF
ENDPROC
PROC UPDATE_COLLISIONS_FOR_CARWASH(CARWASH_HANDLER &ch, VEHICLE_INDEX veh)
IF DOES_ENTITY_EXIST(ch.horzRoller.rollerID)
SET_ENTITY_NO_COLLISION_ENTITY(veh, ch.horzRoller.rollerID, TRUE)
SET_ENTITY_NO_COLLISION_ENTITY(ch.horzRoller.rollerID, veh, TRUE)
ENDIF
IF DOES_ENTITY_EXIST(ch.vertRoller.rollerID[0])
SET_ENTITY_NO_COLLISION_ENTITY(veh, ch.vertRoller.rollerID[0], TRUE)
SET_ENTITY_NO_COLLISION_ENTITY(ch.vertRoller.rollerID[0], veh, TRUE)
ENDIF
IF DOES_ENTITY_EXIST(ch.vertRoller.rollerID[1])
SET_ENTITY_NO_COLLISION_ENTITY(veh, ch.vertRoller.rollerID[1], TRUE)
SET_ENTITY_NO_COLLISION_ENTITY(ch.vertRoller.rollerID[1], veh, TRUE)
ENDIF
ENDPROC
PROC RESET_COLLISIONS_FOR_CARWASH(CARWASH_HANDLER &ch, VEHICLE_INDEX veh = NULL)
IF DOES_ENTITY_EXIST(ch.horzRoller.rollerID)
SET_ENTITY_COLLISION(ch.horzRoller.rollerID, TRUE)
ENDIF
REMOVE_CARWASH_STUCK_CHECK(veh)
ENDPROC
PROC STOP_ALL_CARWASH_SOUNDS(CARWASH_HANDLER &ch)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.horzRoller.iSpinSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.horzRoller.iMoveSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.horzRoller.iHitSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.vertRoller.iSpinSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.vertRoller.iMoveSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.vertRoller.iHitSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.soapJets.iSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.soapJets.iSplashSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.waterJets.iSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.waterJets.iSplashSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.steamJets.iSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(ch.steamJets.iSplashSoundID)
ENDPROC
PROC SHUTDOWN_CARWASH_JETS_PARTICLES(CARWASH_JETS &roll)
INT i
REPEAT COUNT_OF (roll.fxJets) i
SAFE_REMOVE_PARTICLE_FX(roll.fxJets[i])
ENDREPEAT
ENDPROC
PROC STOP_ALL_CARWASH_PARTICLES(CARWASH_HANDLER &ch)
SHUTDOWN_CARWASH_JETS_PARTICLES(ch.waterJets)
SHUTDOWN_CARWASH_JETS_PARTICLES(ch.soapJets)
SHUTDOWN_CARWASH_JETS_PARTICLES(ch.steamJets)
SAFE_REMOVE_PARTICLE_FX(ch.vertRoller.fxBrushID[0])
SAFE_REMOVE_PARTICLE_FX(ch.vertRoller.fxBrushID[1])
SAFE_REMOVE_PARTICLE_FX(ch.horzRoller.fxBrushID)
ENDPROC
PROC CARWASH_NETWORK_WAIT(INT time = 60)
IF NOT NETWORK_IS_GAME_IN_PROGRESS()
EXIT
ENDIF
CPRINTLN(DEBUG_MISSION, "---------- CREATE WAIT FOR ", time, "MS ", GET_GAME_TIMER())
TIME_DATATYPE abortTime = GET_NETWORK_TIME()
WHILE (ABSI(GET_TIME_DIFFERENCE(GET_NETWORK_TIME(), abortTime)) < time)
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_MISSION, "---------- CREATE WAIT FOR ", time, "MS COMPLETE ", GET_GAME_TIMER())
ENDPROC
PROC PRINT_PLAYER_CAR_DIMENSIONS()
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
VECTOR vMin, vMax
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())), vMin, vMax)
CPRINTLN(DEBUG_MISSION, "----------CAR DUMP DATA -----------")
IF IS_ENTITY_ALIVE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
CPRINTLN(DEBUG_MISSION, "MODEL:", GET_MODEL_NAME_OF_VEHICLE_FOR_DEBUG_ONLY(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())))
ELSE
CPRINTLN(DEBUG_MISSION, "MODEL: dead vehicle")
ENDIF
CPRINTLN(DEBUG_MISSION, "MIN:", vMin, " MAX:", vMax)
CPRINTLN(DEBUG_MISSION, "L:", ABSF(vMax.y - vMin.y), " W:", ABSF(vMax.x - vMin.x), " H:", ABSF(vMax.z - vMin.z))
CPRINTLN(DEBUG_MISSION, "---------- CAR DUMP END -----------")
ENDIF
ENDPROC
PROC PRINT_ENTITY_MODEL_DIMENSIONS(MODEL_NAMES mdl, STRING str)
VECTOR vMin, vMax
GET_MODEL_DIMENSIONS(mdl, vMin, vMax)
CPRINTLN(DEBUG_MISSION, "----------MODEL DUMP DATA -----------")
CPRINTLN(DEBUG_MISSION, "MODEL:", str)
CPRINTLN(DEBUG_MISSION, "MIN:", vMin, " MAX:", vMax)
CPRINTLN(DEBUG_MISSION, "L:", ABSF(vMax.y - vMin.y), " W:", ABSF(vMax.x - vMin.x), " H:", ABSF(vMax.z - vMin.z))
CPRINTLN(DEBUG_MISSION, "---------- MODEL DUMP END -----------")
ENDPROC
FUNC BOOL IS_CARWASH_PED_OK(PED_INDEX ped)
IF NOT DOES_ENTITY_EXIST(ped)
RETURN FALSE
ENDIF
IF IS_ENTITY_DEAD(ped)
RETURN FALSE
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
IF NOT IS_PED_A_PLAYER(ped)
RETURN FALSE
ENDIF
ENDIF
RETURN NOT IS_PED_DEAD_OR_DYING(ped)
ENDFUNC
PROC APPLY_CARWASH_WASH_TO_VEHICLE(VEHICLE_INDEX veh, FLOAT washDecal, FLOAT dirtLevel)
IF NETWORK_HAS_CONTROL_OF_ENTITY(veh)
WASH_DECALS_FROM_VEHICLE(veh, washDecal)
SET_VEHICLE_DIRT_LEVEL(veh, dirtLevel)
ENDIF
ENDPROC
PROC SET_CARWASH_CAR_LOCK_STATE(VEHICLE_INDEX ind, LOCK_STATE lock)
IF NOT NETWORK_IS_GAME_IN_PROGRESS()
SET_VEHICLE_DOORS_LOCKED(ind, lock)
EXIT
ENDIF
IF NOT IS_VEHICLE_A_PERSONAL_VEHICLE(ind)
AND NOT IS_VEHICLE_A_TEST_DRIVE_VEHICLE(ind)
SET_VEHICLE_DOORS_LOCKED(ind, lock)
ENDIF
ENDPROC
PROC START_CARWASH_TIMER(CARWASH_HANDLER &ch)
ch.bTimerStarted = TRUE
IF g_bInMultiplayer
ch.iAutoAbortTimerMP = GET_NETWORK_TIME()
ELSE
ch.iAutoAbortTimer = GET_GAME_TIMER()
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS()
IF IS_COMMERCE_STORE_OPEN()
EXIT
ENDIF
ENDIF
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Carwash ", ENUM_TO_INT(ch.iLocationID), " Timer Started")
ENDPROC
FUNC INT GET_CARWASH_TIMER_ELAPSED(CARWASH_HANDLER &ch)
IF g_bInMultiplayer
RETURN GET_TIME_DIFFERENCE(GET_NETWORK_TIME(), ch.iAutoAbortTimerMP)
ELSE
RETURN GET_GAME_TIMER() - ch.iAutoAbortTimer
ENDIF
ENDFUNC
FUNC BOOL HAS_ABORT_TIME_EXPIRED(CARWASH_HANDLER &ch)
INT iAbortTime = PICK_INT((ch.iLocationID = CARWASH_LOCID_LONG), 20000, 15000)
IF g_bInMultiplayer
RETURN (GET_CARWASH_TIMER_ELAPSED(ch) > iAbortTime) AND (ch.bTimerStarted)
ENDIF
RETURN GET_GAME_TIMER() > (ch.iAutoAbortTimer + iAbortTime)
ENDFUNC
/// PURPOSE:
///
/// PARAMS:
/// carwashInd -
PROC CHARGE_PLAYER_FOR_CARWASH(CARWASH_LOCATIONID carwashInd = CARWASH_LOCID_LONG)
VEHICLE_INDEX veh
INT iScriptTransactionIndex
IF NOT g_bInMultiplayer
CHARGE_CURRENT_PLAYER_PED_ACCOUNT_BALANCE(COST_CARWASH)
ELSE
veh = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
IF IS_ENTITY_OK(veh)
IF GET_PED_IN_VEHICLE_SEAT(veh) = PLAYER_PED_ID()
//Just charge as much as possible up to the cost.
INT iCost = COST_CARWASH
INT iDifference
IF NOT NETWORK_CAN_SPEND_MONEY2(iCost, FALSE, FALSE, TRUE, iDifference)
iCost -= iDifference
IF iCost <= 0
EXIT
ENDIF
ENDIF
// B*1885699 - Changes to Cash Spent Priorities - Take money from cash then bank (This wasn't actually ever fixed properly until now!)
IF USE_SERVER_TRANSACTIONS()
TRIGGER_FIRE_AND_FORGET_SERVICE_TRANSACTION(SERVICE_SPEND_CARWASH, iCost, iScriptTransactionIndex, FALSE, FALSE, TRUE)
g_cashTransactionData[iScriptTransactionIndex].cashInfo.iItemHash = ENUM_TO_INT(GET_ENTITY_MODEL(veh))
g_cashTransactionData[iScriptTransactionIndex].cashInfo.iLocation = ENUM_TO_INT(carwashInd)
ELSE
NETWORK_SPENT_CARWASH(iCost, ENUM_TO_INT(GET_ENTITY_MODEL(veh)), ENUM_TO_INT(carwashInd), FALSE, TRUE)
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
FUNC BOOL IS_CARWASH_PART_RUNNING(CARWASH_PARTSTATE state)
RETURN NOT ((state = CPS_NULL) OR (state = CPS_SHUTDOWN))
ENDFUNC
FUNC BOOL IS_VEHICLE_USING_CARWASH(VEHICLE_INDEX veh)
IF NOT IS_ENTITY_OK(veh)
RETURN FALSE
ENDIF
RETURN DECOR_EXIST_ON(veh, "Carwash_Vehicle_Decorator")
ENDFUNC
FUNC BOOL IS_ENTITY_A_CARWASH_PART(ENTITY_INDEX obj)
IF GET_ENTITY_MODEL(obj) = PROP_CARWASH_ROLLER_HORZ
RETURN TRUE
ENDIF
IF GET_ENTITY_MODEL(obj) = PROP_CARWASH_ROLLER_VERT
RETURN TRUE
ENDIF
IF GET_ENTITY_MODEL(obj) = PROP_LD_TEST_01
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL IS_ENTITY_BIG_ENOUGH_TO_BLOCK_CARWASH(ENTITY_INDEX obj)
VECTOR vMin, vMax, vSize
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(obj), vMin, vMax)
vSize.x = ABSF(vMax.x - vMin.x)
vSize.y = ABSF(vMax.y - vMin.y)
vSize.z = ABSF(vMax.z - vMin.z)
RETURN (vSize.x >= 1.4) AND (vSize.y >= 1.4) AND (vSize.z >= 1.4)
ENDFUNC
FUNC BOOL IS_THIS_ENTITY_A_DUMPSTER(ENTITY_INDEX obj)
IF GET_ENTITY_MODEL(obj) = PROP_DUMPSTER_01A
RETURN TRUE
ENDIF
IF GET_ENTITY_MODEL(obj) = PROP_DUMPSTER_02A
RETURN TRUE
ENDIF
IF GET_ENTITY_MODEL(obj) = PROP_DUMPSTER_02B
RETURN TRUE
ENDIF
IF GET_ENTITY_MODEL(obj) = PROP_DUMPSTER_3A
RETURN TRUE
ENDIF
IF GET_ENTITY_MODEL(obj) = PROP_DUMPSTER_4A
RETURN TRUE
ENDIF
IF GET_ENTITY_MODEL(obj) = PROP_DUMPSTER_4B
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL CAN_THIS_ENTITY_BLOCK_THE_CARWASH(ENTITY_INDEX obj)
IF DOES_ENTITY_EXIST(obj)
IF IS_ENTITY_A_VEHICLE(obj)
RETURN TRUE
ENDIF
IF IS_ENTITY_A_PED(obj)
RETURN FALSE
ENDIF
IF IS_ENTITY_A_CARWASH_PART(obj)
RETURN FALSE
ENDIF
IF IS_THIS_ENTITY_A_DUMPSTER(obj)
RETURN TRUE
ENDIF
IF IS_ENTITY_BIG_ENOUGH_TO_BLOCK_CARWASH(obj)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Check if ped is network carwash driver
/// PARAMS:
/// ped - ped index
FUNC BOOL IS_PED_IN_CAR_WITH_CARWASH_DRIVER(PED_INDEX ped)
VEHICLE_INDEX veh
IF NOT IS_CARWASH_PED_OK(ped)
RETURN FALSE
ENDIF
IF NOT IS_PED_IN_ANY_VEHICLE(ped)
RETURN FALSE
ENDIF
veh = GET_VEHICLE_PED_IS_IN(ped)
IF NOT IS_ENTITY_OK(veh)
RETURN FALSE
ENDIF
PED_INDEX driveped = GET_PED_IN_VEHICLE_SEAT(veh)
IF NOT IS_CARWASH_PED_OK(driveped)
RETURN FALSE
ENDIF
IF (g_bInMultiplayer)
PLAYER_INDEX player = NETWORK_GET_PLAYER_INDEX_FROM_PED(driveped)
IF (player = INVALID_PLAYER_INDEX())
RETURN FALSE
ENDIF
IF NOT IS_NET_PLAYER_OK(player, TRUE, FALSE)
GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = FALSE
RETURN FALSE
ENDIF
RETURN GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash
//RETURN IS_NET_PLAYER_OK(player, TRUE, FALSE) AND GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash
ENDIF
RETURN TRUE
ENDFUNC
PROC DO_CARWASH_PAD_RUMBLE(INT iDuration, INT iFreq)
IF IS_PED_IN_CAR_WITH_CARWASH_DRIVER(PLAYER_PED_ID())
FLOAT fFinalFreq = (TO_FLOAT(iFreq) * fRumbleFactor)
fFinalFreq = CLAMP(fFinalFreq, 0, 256)
//SET_PAD_SHAKE(PAD1, iDuration, FLOOR(fFinalFreq))
// old function has been depreciated
SET_CONTROL_SHAKE(PLAYER_CONTROL, iDuration, FLOOR(fFinalFreq))
ENDIF
ENDPROC
FUNC BOOL IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
INT i
REPEAT NUM_NETWORK_PLAYERS i
IF GlobalPlayerBD[i].bDrivingThroughCarwash
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
FUNC BOOL CHECK_ENTITY_IS_VEHICLE_OK(ENTITY_INDEX hitEntity, BOOL bCheckDriver = TRUE)
VEHICLE_INDEX veh
IF IS_ENTITY_A_VEHICLE(hitEntity) AND IS_ENTITY_OK(hitEntity)
veh = GET_VEHICLE_INDEX_FROM_ENTITY_INDEX(hitEntity)
IF (bCheckDriver)
IF NOT IS_CARWASH_PED_OK(GET_PED_IN_VEHICLE_SEAT(veh))
RETURN FALSE
ENDIF
ENDIF
IF NOT IS_VEHICLE_USING_CARWASH(veh)
RETURN FALSE
ENDIF
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
PROC UPDATE_EMERGENCY_PLAYER_WARP_OUT_FOR_CARWASH()
IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<40.279442,-1398.855957,23.846724>>, <<-0.984962,-1398.240234,32.011398>>, 5.750000)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: UPDATE_EMERGENCY_PLAYER_WARP_OUT_FOR_CARWASH - PLAYER IS STUCK IN WALL BEHIND CARWASH 1")
SET_ENTITY_COORDS(PLAYER_PED_ID(), <<-3.4237, -1396.3101, 28.2554>>)
SET_ENTITY_HEADING(PLAYER_PED_ID(), 85.1922)
ENDIF
ENDPROC
/*
/// PURPOSE:
/// Handle push block - stops vehicles from driving in
/// PARAMS:
/// ct - carwash track
/// veh - vehicle
/// blockRadius - block radius
FUNC FLOAT UPDATE_VEHICLE_IN_CARWASH(CARWASH_TRACK &ct, VEHICLE_INDEX veh, FLOAT fwdSpeed, FLOAT startDirt)
// move car along and stop people dicking about with sun roof
VECTOR v
FLOAT r = GET_RATIO_OF_CLOSEST_POINT_ON_LINE(GET_ENTITY_COORDS(veh), ct.vTrackPoint[0], ct.vTrackPoint[1], FALSE)
IF (r <= 1)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ROOF)
v = GET_CLOSEST_POINT_ON_LINE(GET_ENTITY_COORDS(veh), ct.vTrackPoint[0], ct.vTrackPoint[1], FALSE)
IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(veh, v) < 4.0
SET_ENTITY_HEADING(veh, ct.fTrackHeading)
//SET_VEHICLE_ENGINE_ON(veh, TRUE, TRUE)
SET_VEHICLE_FORWARD_SPEED(veh, fwdSpeed)
IF (r > 0.0)
SET_VEHICLE_DIRT_LEVEL(veh, startDirt * (1.0 - r))
ENDIF
ENDIF
ENDIF
RETURN r
ENDFUNC
*/
PROC SNAP_VEHICLE_BACK_ON_TRACK(VEHICLE_INDEX veh, CARWASH_TRACK &ct)
VECTOR v = GET_CLOSEST_POINT_ON_LINE(GET_ENTITY_COORDS(veh), ct.vTrackPoint[0], ct.vTrackPoint[1], FALSE)
SET_ENTITY_COORDS_GROUNDED(veh, v)
SET_ENTITY_HEADING(veh, ct.fTrackHeading)
SET_VEHICLE_ON_GROUND_PROPERLY(veh)
ENDPROC
/// PURPOSE:
/// Handle push block - stops vehicles from driving in
/// PARAMS:
/// ct - carwash track
/// veh - vehicle
/// blockRadius - block radius
PROC UPDATE_VEHICLE_PUSH_BLOCK(CARWASH_TRACK &ct, VEHICLE_INDEX veh, FLOAT blockRadius = 2.0)
VECTOR v
IF NOT IS_VECTOR_ZERO(ct.vBlockPoint[0]) AND NOT IS_VECTOR_ZERO(ct.vBlockPoint[1])
IF IS_ENTITY_IN_RANGE_COORDS(veh, ct.vBlockPoint[0], blockRadius)
v = NORMALISE_VECTOR(GET_ENTITY_COORDS(veh) - ct.vBlockPoint[0])
SET_ENTITY_VELOCITY(veh, v * 2.0)
ELIF IS_ENTITY_IN_RANGE_COORDS(veh, ct.vBlockPoint[1], blockRadius)
v = NORMALISE_VECTOR(GET_ENTITY_COORDS(veh) - ct.vBlockPoint[1])
SET_ENTITY_VELOCITY(veh, v * 2.0)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Tells the Global BD That this ped is not driver in carwash
/// PARAMS:
/// ped - ped index
PROC FORCE_CLEAR_NET_PED_DRIVING_CARWASH_STATUS(PED_INDEX ped)
PLAYER_INDEX player = NETWORK_GET_PLAYER_INDEX_FROM_PED(ped)
IF (player = INVALID_PLAYER_INDEX())
EXIT
ENDIF
GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = FALSE
ENDPROC
/// PURPOSE:
/// Sets Global BD Net Ped Driving State
/// PARAMS:
/// ped - ped index
/// ok - state
PROC SET_NET_PED_DRIVING_CARWASH_STATUS(PED_INDEX ped, BOOL ok)
PLAYER_INDEX player = NETWORK_GET_PLAYER_INDEX_FROM_PED(ped)
IF (player = INVALID_PLAYER_INDEX())
EXIT
ENDIF
IF NOT IS_CARWASH_PED_OK(ped)
GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = FALSE
EXIT
ENDIF
GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = OK
ENDPROC
PROC DISABLE_CONTROL_ACTIONS_FOR_CARWASH()
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ROOF)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_HEADLIGHT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SCRIPT_RRIGHT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ATTACK)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ATTACK2)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_PASSENGER_AIM)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_PASSENGER_ATTACK)
RC_DISABLE_CONTROL_ACTIONS_FOR_LEAD_IN()
IF NOT (g_bInMultiplayer)
DISABLE_SELECTOR_THIS_FRAME()
ENDIF
ENDPROC
/// PURPOSE:
/// Loads the carwash models
PROC REQUEST_AND_LOAD_CARWASH_ASSETS_MP(ASSET_REQUESTER &as, STRING wayPointName = NULL)
ADD_ASSET_REQUEST_FOR_MODEL(as, 0, PROP_CARWASH_ROLLER_HORZ)
ADD_ASSET_REQUEST_FOR_MODEL(as, 1, PROP_CARWASH_ROLLER_VERT)
ADD_ASSET_REQUEST_FOR_MODEL(as, 2, PROP_LD_TEST_01)
IF HINT_SCRIPT_AUDIO_BANK("SCRIPT\\CARWASH")
PRINTLN("[CARWASH] Audio bank hinted")
ENDIF
ADD_ASSET_REQUEST_FOR_PTFX(as, 3)
IF NOT IS_STRING_NULL_OR_EMPTY(wayPointName)
ADD_ASSET_REQUEST_FROM_STRING(as, 4, ASSET_WAYREC, wayPointName)
ENDIF
WHILE NOT HAVE_ASSET_REQUESTS_LOADED(as)
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_CONTEXT)
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_VEH_EXIT)
DISABLE_CONTROL_ACTIONS_FOR_CARWASH()
WAIT(0)
ENDWHILE
ENDPROC
PROC REQUEST_AND_LOAD_CARWASH_ASSETS(ASSET_REQUESTER &as, STRING wayPointName = NULL)
ADD_ASSET_REQUEST_FOR_MODEL(as, 0, PROP_CARWASH_ROLLER_HORZ)
ADD_ASSET_REQUEST_FOR_MODEL(as, 1, PROP_CARWASH_ROLLER_VERT)
ADD_ASSET_REQUEST_FOR_MODEL(as, 2, PROP_LD_TEST_01)
ADD_ASSET_REQUEST_FROM_STRING(as, 3, ASSET_AUDIOBANK, "SCRIPT\\CARWASH")
ADD_ASSET_REQUEST_FOR_PTFX(as, 4)
IF NOT IS_STRING_NULL_OR_EMPTY(wayPointName)
ADD_ASSET_REQUEST_FROM_STRING(as, 5, ASSET_WAYREC, wayPointName)
ENDIF
WHILE NOT HAVE_ASSET_REQUESTS_LOADED(as)
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_CONTEXT)
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_VEH_EXIT)
DISABLE_CONTROL_ACTIONS_FOR_CARWASH()
WAIT(0)
ENDWHILE
ENDPROC
/// PURPOSE:
/// Loads the carwash models
PROC RELEASE_CARWASH_MODEL_ASSETS(ASSET_REQUESTER &as)
_UNLOAD_ASSET_FROM_REQUESTER(as, 0)
_UNLOAD_ASSET_FROM_REQUESTER(as, 1)
_UNLOAD_ASSET_FROM_REQUESTER(as, 2)
ENDPROC
FUNC BOOL IS_CARWASH_POSITION_OCCUPIED(VECTOR v, FLOAT rad, BOOL bVisibleCheck = TRUE)
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_ENTITY_IN_RANGE_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), v, rad)
RETURN TRUE
ENDIF
IF NOT IS_SPHERE_VISIBLE(v, rad) AND (bVisibleCheck = TRUE)
RETURN FALSE
ENDIF
RETURN IS_POSITION_OCCUPIED(v, rad, FALSE, TRUE, FALSE, FALSE, FALSE, NULL, TRUE)
ENDFUNC
/// PURPOSE:
/// Places vehicle along a two point track, gives it a speed and a go to order
/// PARAMS:
/// ind - vehicle index
/// v1 - position 1
/// v2 - position 2
/// fRatio - ratio along track - 0 is back, 1 is front
/// fSpeed - speed to move aong
PROC SET_VEHICLE_ALONG_LINE(VEHICLE_INDEX ind, VECTOR v1, VECTOR v2, FLOAT fRatio, FLOAT fSpeed = 0.0)
VECTOR v
FLOAT head
PED_INDEX ped
IF NOT IS_ENTITY_OK(ind)
EXIT
ENDIF
v = INTERPOLATE_VECTOR(v1, v2, fRatio, FALSE)
head = GET_HEADING_FROM_COORDS(v1, v2)
SET_ENTITY_COORDS(ind, v)
SET_ENTITY_HEADING(ind, head)
FREEZE_ENTITY_POSITION(ind, FALSE)
IF (fSpeed = 0.0)
EXIT
ENDIF
SET_VEHICLE_ENGINE_ON(ind, TRUE, TRUE)
SET_VEHICLE_FORWARD_SPEED(ind, fSpeed)
IF (fRatio > 1.0)
EXIT
ENDIF
ped = GET_PED_IN_VEHICLE_SEAT(ind)
IF NOT IS_CARWASH_PED_OK(ped)
EXIT
ENDIF
CPRINTLN(DEBUG_MISSION, "CAR RATIO:", fRatio, " SPEED:", fSpeed, " DEST:", v2)
TASK_VEHICLE_DRIVE_TO_COORD(ped, ind, v2, fSpeed, DRIVINGSTYLE_STRAIGHTLINE, GET_ENTITY_MODEL(ind), DRIVINGMODE_PLOUGHTHROUGH, 0.5, 1000.0)
ENDPROC
//----------------------
// TRACK FUNCTIONS
//----------------------
PROC SET_CARWASH_IPL(CARWASH_HANDLER &ch, BUILDING_NAME_ENUM ipl)
ch.iplSwap = ipl
SET_BUILDING_STATE(ch.iplSwap, BUILDINGSTATE_DESTROYED)
ENDPROC
PROC SET_CARWASH_WAYPOINT_REC(CARWASH_HANDLER &ch, STRING s)
ch.sWayPointRec = s
ENDPROC
/// PURPOSE:
/// Sets up a carwash track
/// PARAMS:
/// ct - carwash track reference
/// v1 - track point 1
/// v2 - track point 2
PROC SETUP_CARWASH_TRACK(CARWASH_TRACK &ct, VECTOR v1, VECTOR v2)
ct.vTrackPoint[0] = v1
ct.vTrackPoint[1] = v2
ct.vDirection = NORMALISE_VECTOR(v2 - v1)
ct.fTrackHeading = GET_HEADING_BETWEEN_VECTORS_2D(ct.vTrackPoint[0], ct.vTrackPoint[1])
CLEAR_CYLINDER_OF_ENTITIES(ct.vTrackPoint[0], ct.vTrackPoint[1], 3.0, FALSE, NOT g_bInMultiplayer, FALSE, TRUE, NOT g_bInMultiplayer)
ENDPROC
PROC SETUP_CARWASH_BLOCK_MIN_MAX(CARWASH_TRACK &ct, VECTOR v1, VECTOR v2)
ct.vBlockMinMax[0] = v1
ct.vBlockMinMax[1] = v2
IF ABSF(v2.x - v1.x) > ABSF(v2.y - v1.y)
ct.iDominantBlockAxis = CARWASH_AXIS_X
ELSE
ct.iDominantBlockAxis = CARWASH_AXIS_Y
ENDIF
ENDPROC
/// PURPOSE:
/// Setup block points - these stop other vehicles driving in MP
/// PARAMS:
/// ct - carwash track reference
/// v1 - point 1
/// v2 - point 2
PROC SETUP_CARWASH_BLOCK_POINTS(CARWASH_TRACK &ct, VECTOR v1, VECTOR v2)
ct.vBlockPoint[0] = v1
ct.vBlockPoint[1] = v2
ENDPROC
PROC DRAW_DEBUG_CARWASH_TRACK(CARWASH_TRACK &ct)
/*
DRAW_DEBUG_LINE(ct.vTrackPoint[0], ct.vTrackPoint[1])
DRAW_DEBUG_SPHERE(INTERPOLATE_VECTOR(ct.vTrackPoint[0], ct.vTrackPoint[1], fInter), 0.5)
DRAW_DEBUG_BOX(ct.vBlockMinMax[0], ct.vBlockMinMax[1])
DRAW_DEBUG_CIRCLE(ct.vTrackPoint[1], 1.0, 0, 255, 0, 255)
DRAW_DEBUG_CIRCLE(ct.vBlockPoint[0], 1.0, 255, 0, 0, 255)
DRAW_DEBUG_CIRCLE(ct.vBlockPoint[1], 1.0, 255, 0, 0, 255)
*/
DRAW_DEBUG_SPHERE(ct.vBlockMinMax[0], 0.0625)
DRAW_DEBUG_SPHERE(ct.vBlockMinMax[1], 0.0625)
DRAW_DEBUG_LINE(ct.vBlockMinMax[0], ct.vBlockMinMax[1])
ENDPROC
PROC DRAW_DEBUG_CARWASH(CARWASH_HANDLER &ct)
/*
DRAW_DEBUG_LINE(ct.vTrackPoint[0], ct.vTrackPoint[1])
DRAW_DEBUG_SPHERE(INTERPOLATE_VECTOR(ct.vTrackPoint[0], ct.vTrackPoint[1], fInter), 0.5)
DRAW_DEBUG_BOX(ct.vBlockMinMax[0], ct.vBlockMinMax[1])
DRAW_DEBUG_CIRCLE(ct.vTrackPoint[1], 1.0, 0, 255, 0, 255)
DRAW_DEBUG_CIRCLE(ct.vBlockPoint[0], 1.0, 255, 0, 0, 255)
DRAW_DEBUG_CIRCLE(ct.vBlockPoint[1], 1.0, 255, 0, 0, 255)
*/
DRAW_DEBUG_SPHERE(ct.cTrack.vBlockMinMax[0], 0.0625)
DRAW_DEBUG_SPHERE(ct.cTrack.vBlockMinMax[1], 0.0625)
DRAW_DEBUG_LINE(ct.cTrack.vBlockMinMax[0], ct.cTrack.vBlockMinMax[1])
ENDPROC
/// PURPOSE:
/// Places vehicle along a two point track, gives it a speed and a go to order
/// PARAMS:
/// ind - vehicle index
/// v1 - position 1
/// v2 - position 2
/// fRatio - ratio along track - 0 is back, 1 is front
/// fSpeed - speed to move aong
PROC SET_VEHICLE_ALONG_CARWASH_TRACK(VEHICLE_INDEX ind, CARWASH_TRACK &ct, FLOAT fRatio, FLOAT fSpeed = 0.0)
VECTOR v
FLOAT head
PED_INDEX ped
// work out point along the track we are
v = INTERPOLATE_VECTOR(ct.vTrackPoint[0], ct.vTrackPoint[1], fRatio, FALSE)
// get the closest point to this point on the groove track
head = GET_HEADING_FROM_COORDS(ct.vTrackPoint[0], ct.vTrackPoint[1])
SET_ENTITY_COORDS_GROUNDED(ind, v + <<0, 0, 0.1>>)
SET_ENTITY_HEADING(ind, head)
FREEZE_ENTITY_POSITION(ind, FALSE)
IF (fSpeed = 0.0)
EXIT
ENDIF
SET_VEHICLE_ENGINE_ON(ind, TRUE, TRUE)
IF (fRatio > 1.0)
EXIT
ENDIF
SET_VEHICLE_FORWARD_SPEED(ind, fSpeed)
ped = GET_PED_IN_VEHICLE_SEAT(ind)
IF NOT IS_CARWASH_PED_OK(ped)
EXIT
ENDIF
v = INTERPOLATE_VECTOR(ct.vTrackPoint[0], ct.vTrackPoint[1], 1.1, FALSE)
CPRINTLN(DEBUG_MISSION, "CAR RATIO:", fRatio, " SPEED:", fSpeed, " DEST:", v)
TASK_VEHICLE_DRIVE_TO_COORD(ped, ind, v, fSpeed, DRIVINGSTYLE_STRAIGHTLINE, GET_ENTITY_MODEL(ind), DRIVINGMODE_PLOUGHTHROUGH, 0.5, 1000.0)
ENDPROC
/// PURPOSE:
/// Get Ratio of Closest Point To Track
/// PARAMS:
/// v - point to test
/// c - cartrack reference
/// RETURNS:
/// Ratio - not clamped
FUNC FLOAT GET_RATIO_ALONG_CARWASH_TRACK(VECTOR v, CARWASH_TRACK &c, BOOL clmp = FALSE)
RETURN GET_RATIO_OF_CLOSEST_POINT_ON_LINE(v, c.vTrackPoint[0], c.vTrackPoint[1], clmp)
ENDFUNC
/// PURPOSE:
/// Get Ratio of Closest Point To Track
/// PARAMS:
/// v - point to test
/// c - cartrack reference
/// RETURNS:
/// Ratio - not clamped
FUNC FLOAT GET_HEADING_ALONG_CARWASH_TRACK(CARWASH_TRACK &c)
RETURN GET_HEADING_BETWEEN_VECTORS_2D(c.vTrackPoint[0], c.vTrackPoint[1])
ENDFUNC
//----------------------
// HROLLER FUNCTIONS
//----------------------
PROC SHUTDOWN_CARWASH_HROLLER(CARWASH_HROLLER &roll)
IF IS_CARWASH_PART_RUNNING(roll.state)
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iHitSoundID)
roll.state = CPS_NULL
ENDIF
ENDPROC
PROC SHARED_CLEANUP_DELETE_CARWASH_HROLLER(CARWASH_HROLLER &roll)
roll.state = CPS_ACTIVE
SHUTDOWN_CARWASH_HROLLER(roll)
ENDPROC
/// PURPOSE:
/// Cleanup the hroller
/// PARAMS:
/// roll - roller reference
PROC DELETE_CARWASH_HROLLER(CARWASH_HROLLER &roll)
SHARED_CLEANUP_DELETE_CARWASH_HROLLER(roll)
SAFE_DELETE_OBJECT(roll.rollerID)
ENDPROC
/// PURPOSE:
/// Cleanup the hroller
/// PARAMS:
/// roll - roller reference
PROC CLEANUP_CARWASH_HROLLER(CARWASH_HROLLER &roll)
SHARED_CLEANUP_DELETE_CARWASH_HROLLER(roll)
SAFE_RELEASE_OBJECT(roll.rollerID)
ENDPROC
PROC START_CARWASH_HROLLER_PARTICLES(CARWASH_HROLLER &roll)
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID)
IF IS_ENTITY_OK(roll.rollerID) //AND NOT (g_bInMultiplayer)
IF NOT DOES_PARTICLE_FX_LOOPED_EXIST(roll.fxBrushID)
roll.fxBrushID = START_PARTICLE_FX_LOOPED_ON_ENTITY("ent_amb_car_wash", roll.rollerID, <<0.0, 0.0, 0.0>>, vRollerHorzRotFX)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Update the carwash roller
/// PARAMS:
/// roll - roller reference
PROC _UPDATE_CARWASH_HROLLER_INTERNAL(CARWASH_HROLLER &roll)
INT iHits
VECTOR vec
VECTOR vHitPos, vHitNormal
SHAPETEST_STATUS shapeStatus
ENTITY_INDEX hitEntity
IF NOT roll.bSetup = TRUE
EXIT
ENDIF
// do shape test
IF (IS_CARWASH_PART_RUNNING(roll.state))
IF (roll.shapeTestID = NULL)
IF (GET_GAME_TIMER() > roll.iNextShapeTestTime)
roll.shapeTestID = START_SHAPE_TEST_LOS_PROBE(roll.vPosition, roll.vPosition - <<0, 0, 5.0>>, SCRIPT_INCLUDE_VEHICLE, roll.rollerID, SCRIPT_SHAPETEST_OPTION_IGNORE_NO_COLLISION)
IF (roll.shapeTestID = NULL)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: CAN'T GET SHAPETEST FOR HORIZONTAL BRUSH")
ENDIF
ENDIF
ELSE
shapeStatus = GET_SHAPE_TEST_RESULT(roll.shapeTestID, iHits, vHitPos, vHitNormal, hitEntity)
IF (shapeStatus = SHAPETEST_STATUS_RESULTS_READY)
IF (iHits > 0)
// set the ground zero point
IF (roll.fGroundZero = 0.0)
roll.fGroundZero = vHitPos.z + ROLLER_RADIUS
ENDIF
// work out contact point
roll.vContactPoint = vHitPos + vRollerRadius
// work out target point we should be moving towards
IF (roll.vContactPoint.z = roll.fGroundZero)
roll.fTargetZ = roll.vPosition.z - (ROLLER_RADIUS * 1.1)
ELSE
roll.fTargetZ = roll.vContactPoint.z + 0.1
IF CHECK_ENTITY_IS_VEHICLE_OK(hitEntity)
SET_ENTITY_NO_COLLISION_ENTITY(hitEntity, roll.rollerID, TRUE)
SET_ENTITY_NO_COLLISION_ENTITY(roll.rollerID, hitEntity, TRUE)
IF (roll.iHitSoundID = -1)
roll.iHitSoundID = GET_SOUND_ID()
PLAY_SOUND_FROM_ENTITY(roll.iHitSoundID, "BRUSHES_HIT_CAR", roll.rollerID, "CARWASH_SOUNDS")
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
roll.shapeTestID = NULL
roll.iNextShapeTestTime = GET_GAME_TIMER() + SHAPE_CHECK_INTERVAL
ENDIF
ELSE
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iHitSoundID)
roll.fTargetZ = roll.fOriginalZ
ENDIF
// move the roller to get to contact point
vec = GET_ENTITY_COORDS(roll.rollerID)
IF (vec.z < roll.fTargetZ)
vec.z += roll.fMoveRate * TIMESTEP()
IF (vec.z > roll.fTargetZ)
vec.z = roll.fTargetZ
ENDIF
ENDIF
IF (vec.z > roll.fTargetZ)
vec.z -= roll.fMoveRate * TIMESTEP()
IF (vec.z < roll.fTargetZ)
DO_CARWASH_PAD_RUMBLE(64, 64)
vec.z = roll.fTargetZ
ENDIF
ENDIF
IF (roll.fGroundZero <> 0.0)
vec.z = CLAMP(vec.z,roll.fGroundZero, roll.fOriginalZ)
ENDIF
// set position and rotation
IF NOT ARE_VECTORS_EQUAL(roll.vOldRollerPos, vec)
SET_ENTITY_COORDS(roll.rollerID, vec)
ENDIF
roll.vOldRollerPos = vec
// draw some debug crap
IF bDrawDebugCarwash = TRUE
DRAW_DEBUG_CIRCLE(<<roll.vPosition.x, roll.vPosition.y, roll.fGroundZero - ROLLER_RADIUS>>, roll.fTriggerDist)
DRAW_DEBUG_SPHERE(roll.vPosition, 0.0625)
DRAW_DEBUG_LINE(roll.vPosition, roll.vContactPoint - vRollerRadius)
DRAW_DEBUG_SPHERE(roll.vContactPoint - vRollerRadius, 0.03125)
ENDIF
ENDPROC
/// PURPOSE:
/// Update the dual roller
/// PARAMS:
/// roll - roller reference
PROC UPDATE_CARWASH_HROLLER(CARWASH_HROLLER &roll, BOOL bSomeOneIn = TRUE)
INT iHits
VECTOR vHitPos, vHitNormal
SHAPETEST_STATUS shapeStatus
ENTITY_INDEX hitEntity
VECTOR v = roll.vPosition
FLOAT tStep = ROLLER_SPINRATE * TIMESTEP()
v.z = roll.fGroundZero
IF IS_CARWASH_PART_RUNNING(roll.state)
IF (bSomeOneIn = FALSE)
CPRINTLN(DEBUG_MISSION, "Carwash HRoller - Shutdown No One is In Carwash")
roll.state = CPS_SHUTDOWN
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS() AND NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
CPRINTLN(DEBUG_MISSION, "Carwash HRoller - NET Shutdown No One is In Carwash")
roll.state = CPS_SHUTDOWN
ENDIF
ENDIF
SWITCH (roll.state)
CASE CPS_NULL
IF g_bInMultiplayer
IF NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
EXIT
ENDIF
ENDIF
IF IS_ANY_VEHICLE_NEAR_POINT(roll.vPosition, 4.0)
IF (roll.shapeTestID = NULL)
IF (GET_GAME_TIMER() > roll.iNextShapeTestTime)
roll.shapeTestID = START_SHAPE_TEST_CAPSULE(roll.vPosition, roll.vPosition - <<0, 0, 6.0>>, roll.fTriggerDist * 1.2, SCRIPT_INCLUDE_VEHICLE, roll.rollerID, SCRIPT_SHAPETEST_OPTION_IGNORE_NO_COLLISION)
ENDIF
ELSE
shapeStatus = GET_SHAPE_TEST_RESULT(roll.shapeTestID, iHits, vHitPos, vHitNormal, hitEntity)
IF (shapeStatus = SHAPETEST_STATUS_RESULTS_READY)
IF CHECK_ENTITY_IS_VEHICLE_OK(hitEntity)
roll.state = CPS_STARTUP
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
roll.iSpinSoundID = GET_SOUND_ID()
PLAY_SOUND_FROM_ENTITY(roll.iSpinSoundID, "BRUSHES_SPINNING", roll.rollerID, "CARWASH_SOUNDS")
CPRINTLN(DEBUG_MISSION, "[CARWASH]: HROLLER STARTUP")
ENDIF
ENDIF
roll.shapeTestID = NULL
roll.iNextShapeTestTime = GET_GAME_TIMER() + SHAPE_CHECK_INTERVAL
ENDIF
ENDIF
BREAK
CASE CPS_STARTUP
IF (bSomeOneIn = FALSE)
roll.state = CPS_SHUTDOWN
ELSE
roll.fSpinRate += tStep
IF (roll.fSpinRate >= ROLLER_SPINRATE)
roll.fSpinRate = ROLLER_SPINRATE
roll.state = CPS_ACTIVE
START_CARWASH_HROLLER_PARTICLES(roll)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
roll.iMoveSoundID = GET_SOUND_ID()
PLAY_SOUND_FROM_ENTITY(roll.iMoveSoundID, "BRUSHES_MOVE", roll.rollerID, "CARWASH_SOUNDS")
ENDIF
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS() AND NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
roll.state = CPS_SHUTDOWN
ENDIF
BREAK
CASE CPS_ACTIVE
IF (bSomeOneIn = FALSE)
roll.state = CPS_SHUTDOWN
ELIF (GET_GAME_TIMER() > roll.iNextCheckTime)
IF NOT IS_CARWASH_POSITION_OCCUPIED(v, roll.fTriggerDist)
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID)
roll.state = CPS_SHUTDOWN
ENDIF
roll.iNextCheckTime = GET_GAME_TIMER() + ROLLER_CHECK_INTERVAL
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS() AND NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
roll.state = CPS_SHUTDOWN
ENDIF
BREAK
CASE CPS_SHUTDOWN
roll.shapetestID = NULL
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iHitSoundID)
roll.fSpinRate -= tStep
//bDoShapeTest = TRUE
IF (roll.fSpinRate <= 0)
roll.fSpinRate = 0
roll.state = CPS_NULL
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
ENDIF
BREAK
ENDSWITCH
roll.fRollerSpinAngle += roll.fSpinRate * TIMESTEP()
IF (roll.fRollerSpinAngle > 360.0)
roll.fRollerSpinAngle -= 360.0
ENDIF
_UPDATE_CARWASH_HROLLER_INTERNAL(roll)
SET_ENTITY_HEADING(roll.rollerID, roll.fRollerPivotAngle)
SET_ENTITY_ROTATION(roll.rollerID, GET_ENTITY_ROTATION(roll.rollerID) + <<roll.fRollerSpinAngle, 0, 0>>)
ENDPROC
/// PURPOSE:
/// Create the carwash horizontal roller
/// PARAMS:
/// roll - roller reference
/// pos - position of the roller arm joint
/// head - heading
PROC CREATE_CARWASH_HROLLER(CARWASH_HROLLER &roll, VECTOR pos, FLOAT head = 0.0, FLOAT gz = 0.0)
FLOAT z
roll.vPosition = pos
roll.rollerID = CREATE_OBJECT(PROP_CARWASH_ROLLER_HORZ, pos, FALSE)
roll.vContactPoint = pos
roll.fTargetZ = pos.z
roll.fOriginalZ = pos.z
roll.fRollerPivotAngle = head
roll.bSetup = TRUE
roll.iNextCheckTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(1, ROLLER_CHECK_INTERVAL)
roll.iNextShapeTestTime = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(2, SHAPE_CHECK_INTERVAL)
roll.fTriggerDist = ROLLER_TRIGGER_DIST
IF (gz = 0.0)
IF GET_GROUND_Z_FOR_3D_COORD(pos, z)
IF (z <> 0) AND (z <> INVALID_WORLD_Z)
roll.fGroundZero = z + ROLLER_RADIUS
CPRINTLN(DEBUG_MISSION, "[CARWASH] - HRoller GroundZero:", roll.fGroundZero)
ENDIF
ENDIF
ELSE
roll.fGroundZero = gz
ENDIF
IF IS_ENTITY_OK(roll.rollerID)
SET_ENTITY_HEADING(roll.rollerID, head)
FREEZE_ENTITY_POSITION(roll.rollerID, TRUE)
SET_ENTITY_COLLISION(roll.rollerID, TRUE)
SET_ENTITY_INVINCIBLE(roll.rollerID, TRUE)
//SET_ENTITY_HAS_GRAVITY(roll.rollerID, FALSE)
ENDIF
// we need to do a forced update here so the roller can find the ground point
UPDATE_CARWASH_HROLLER(roll)
ENDPROC
//----------------------
// VERTROLLER FUNCTIONS
//----------------------
PROC START_CARWASH_VERTROLLER_PARTICLES(CARWASH_VROLLER2 &roll)
INT i
REPEAT COUNT_OF(roll.rollerID) i
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[i])
IF IS_ENTITY_OK(roll.rollerID[i]) //AND NOT (g_bInMultiplayer)
IF NOT DOES_PARTICLE_FX_LOOPED_EXIST(roll.fxBrushID[i])
roll.fxBrushID[i] = START_PARTICLE_FX_LOOPED_ON_ENTITY("ent_amb_car_wash", roll.rollerID[i], vRollerVertPosFX, vRollerVertRotFX)
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC SHUTDOWN_CARWASH_VERTROLLER(CARWASH_VROLLER2 &roll)
IF IS_CARWASH_PART_RUNNING(roll.state)
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[0])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[1])
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iHitSoundID)
roll.state = CPS_NULL
ENDIF
ENDPROC
PROC SHARED_CLEANUP_DELETE_CARWASH_VERTROLLER(CARWASH_VROLLER2 &roll)
roll.state = CPS_NULL
SHUTDOWN_CARWASH_VERTROLLER(roll)
SAFE_DELETE_OBJECT(roll.pivotID)
ENDPROC
/// PURPOSE:
/// Update the dual roller
/// PARAMS:
/// roll - roller reference
PROC CLEANUP_CARWASH_VERTROLLER(CARWASH_VROLLER2 &roll)
SHARED_CLEANUP_DELETE_CARWASH_VERTROLLER(roll)
SAFE_RELEASE_OBJECT(roll.rollerID[0])
SAFE_RELEASE_OBJECT(roll.rollerID[1])
ENDPROC
/// PURPOSE:
/// Update the dual roller
/// PARAMS:
/// roll - roller reference
PROC DELETE_CARWASH_VERTROLLER(CARWASH_VROLLER2 &roll)
SHARED_CLEANUP_DELETE_CARWASH_VERTROLLER(roll)
SAFE_DELETE_OBJECT(roll.rollerID[0])
SAFE_DELETE_OBJECT(roll.rollerID[1])
ENDPROC
PROC UPDATE_CARWASH_VERTROLLER_MOVEMENT(CARWASH_VROLLER2 &roll)
INT i
FLOAT fOldSpinAngle = roll.fRollerSpinAngle
FLOAT fOldOffset[2]
// handle and moving spinning
IF (roll.fSpinRate >= ROLLER_SPINRATE)
roll.fSpinRate = ROLLER_SPINRATE
ENDIF
IF (roll.fSpinRate <= 0)
roll.fSpinRate = 0
ENDIF
roll.fRollerSpinAngle += roll.fSpinRate * TIMESTEP()
IF (roll.fRollerSpinAngle < 0)
roll.fRollerSpinAngle += 360.0
ENDIF
IF (roll.fRollerSpinAngle > 360.0)
roll.fRollerSpinAngle -= 360.0
ENDIF
REPEAT COUNT_OF(roll.rollerID) i
fOldOffset[i] = roll.fOffset[i]
IF (roll.fOffset[i] < roll.fTgtOffset[i])
roll.fOffset[i] += roll.fMoveRate * TIMESTEP()
IF (roll.fOffset[i] > roll.fTgtOffset[i])
DO_CARWASH_PAD_RUMBLE(SHAPE_CHECK_INTERVAL, 64)
roll.fOffset[i] = roll.fTgtOffset[i]
ENDIF
ENDIF
IF (roll.fOffset[i] > roll.fTgtOffset[i])
roll.fOffset[i] -= roll.fMoveRate * TIMESTEP()
IF (roll.fOffset[i] < roll.fTgtOffset[i])
DO_CARWASH_PAD_RUMBLE(SHAPE_CHECK_INTERVAL, 64)
roll.fOffset[i] = roll.fTgtOffset[i]
ENDIF
ENDIF
IF (fOldOffset[i] <> roll.fOffset[i])
SET_ENTITY_COORDS(roll.rollerID[i], GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<roll.fOffset[i], 0, VROLLER_ZSHIFT>>))
ENDIF
IF (fOldSpinAngle <> roll.fRollerSpinAngle)
SET_ENTITY_HEADING(roll.rollerID[i], roll.fRollerSpinAngle)
ENDIF
ENDREPEAT
ENDPROC
PROC UPDATE_CARWASH_VERTROLLER_COLLISION(CARWASH_VROLLER2 &roll)
IF (roll.bCollisionOn <> roll.bOldCollision)
CPRINTLN(DEBUG_MISSION, "TURNING BRUSH ROL COLLISION:", roll.bCollisionOn)
SET_ENTITY_COLLISION(roll.rollerID[0], roll.bCollisionOn)
SET_ENTITY_COLLISION(roll.rollerID[1], roll.bCollisionOn)
ENDIF
roll.bOldCollision = roll.bCollisionOn
ENDPROC
/// PURPOSE:
/// Update the dual roller
/// PARAMS:
/// roll - roller reference
PROC UPDATE_CARWASH_VERTROLLER(CARWASH_VROLLER2 &roll, BOOL bSomeOneIn = TRUE, BOOL bAborted = FALSE)
VECTOR vec
FLOAT tStep = ROLLER_SPINRATE * TIMESTEP()
VECTOR v1, v2
ENTITY_INDEX hitEntity
SHAPETEST_STATUS shapeStatus
VECTOR vHitPos, vHitNormal
INT i, iHits
PLANE_SIDE psd
//FLOAT fDist
FLOAT vWidth
FLOAT vLength
VECTOR vvMin, vvMax
VEHICLE_INDEX vehicleIndex
INT iDriverSeatBoneIndex = -1
IF NOT roll.bSetup = TRUE
EXIT
ENDIF
UPDATE_CARWASH_VERTROLLER_MOVEMENT(roll)
IF IS_CARWASH_PART_RUNNING(roll.state)
IF (bSomeOneIn = FALSE)
CPRINTLN(DEBUG_MISSION, "Carwash VRoller - Shutdown No One is In Carwash")
roll.state = CPS_SHUTDOWN
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS() AND NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
CPRINTLN(DEBUG_MISSION, "Carwash VRoller - NET Shutdown No One is In Carwash")
bSomeOneIn = FALSE
roll.state = CPS_SHUTDOWN
ENDIF
IF (bSomeOneIn = FALSE)
roll.fSpinRate -= (tStep * 2.0)
IF (roll.fSpinRate <= 0)
roll.fSpinRate = 0
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
ENDIF
ENDIF
ELSE
roll.fSpinRate -= (tStep * 2.0)
IF (roll.fSpinRate <= 0)
roll.fSpinRate = 0
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
ENDIF
ENDIF
// check sensors
FLOAT fFirstCheckYShift = -1.5 // we shift the file in check by this abount
FLOAT fCheckYShift = -ROLLER_RADIUS
// BOOL bBrushesDone
IF NOT (bAborted) AND (roll.state <> CPS_SHUTDOWN)
IF (GET_GAME_TIMER() > roll.iNextShapeTestTime)
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[0], 0>>)
roll.bSensorOn[0] = IS_CARWASH_POSITION_OCCUPIED(vec, roll.fSensorRadius[0])
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[1], 0>>)
roll.bSensorOn[1] = IS_CARWASH_POSITION_OCCUPIED(vec, roll.fSensorRadius[1])
roll.iNextShapeTestTime = GET_GAME_TIMER() + SHAPE_CHECK_INTERVAL
ENDIF
IF (bDrawDebugCarwash = TRUE)
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[0], 0>>)
IF (roll.bSensorOn[0])
DRAW_DEBUG_CIRCLE(vec, roll.fSensorRadius[0], 0, 255, 0, 255)
ELSE
DRAW_DEBUG_CIRCLE(vec, roll.fSensorRadius[0], 255, 0, 0, 255)
ENDIF
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[1], 0>>)
IF (roll.bSensorOn[1])
DRAW_DEBUG_CIRCLE(vec, roll.fSensorRadius[1], 0, 255, 0, 255)
ELSE
DRAW_DEBUG_CIRCLE(vec, roll.fSensorRadius[1], 0, 0, 255, 255)
ENDIF
DRAW_DEBUG_LINE(GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<-2.5, fFirstCheckYShift, VROLLER_CHECKZSHIFT>>),
GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<2.5, fFirstCheckYShift, VROLLER_CHECKZSHIFT>>))
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, 0, VROLLER_CHECKZSHIFT>>)
DRAW_DEBUG_LINE(vec, vec + GET_ENTITY_FORWARD_VECTOR(roll.pivotID))
ENDIF
ENDIF
SWITCH (roll.state)
CASE CPS_NULL
IF NOT (bAborted)
IF (bSomeOneIn = TRUE) AND (roll.bSensorOn[0])
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
roll.iSpinSoundID = GET_SOUND_ID()
PLAY_SOUND_FROM_ENTITY(roll.iSpinSoundID, "BRUSHES_SPINNING", roll.pivotID, "CARWASH_SOUNDS")
roll.fTgtOffset[0] = -ROLLER_RADIUS
roll.fTgtOffset[1] = ROLLER_RADIUS
CPRINTLN(DEBUG_MISSION, "[CARWASH] - VERT BRUSHES ACTIVATED")
roll.bCollisionOn = FALSE
CPRINTLN(DEBUG_MISSION, "[CARWASH] - TURNING BRUSH COLLISION OFF ON STARTUP")
//SET_ENTITY_COLLISION(roll.rollerID[0], roll.bCollisionOn)
//SET_ENTITY_COLLISION(roll.rollerID[1], roll.bCollisionOn)
roll.state = CPS_STARTUP
roll.bHitCheck[0] = FALSE
roll.bHitCheck[1] = FALSE
roll.bOldHitCheck[0] = FALSE
roll.bOldHitCheck[1] = FALSE
ENDIF
ENDIF
BREAK
CASE CPS_STARTUP
roll.fSpinRate += tStep
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[0], 0>>)
vehicleIndex = GET_RANDOM_VEHICLE_IN_SPHERE(vec, 2.0, DUMMY_MODEL_FOR_SCRIPT, VEHICLE_SEARCH_FLAG_RETURN_VEHICLES_CONTAINING_A_PLAYER | VEHICLE_SEARCH_FLAG_ALLOW_VEHICLE_OCCUPANTS_TO_BE_PERFORMING_A_SCRIPTED_TASK)
IF CHECK_ENTITY_IS_VEHICLE_OK(vehicleIndex)
SET_ENTITY_NO_COLLISION_ENTITY(vehicleIndex, roll.rollerID[0], TRUE)
SET_ENTITY_NO_COLLISION_ENTITY(vehicleIndex, roll.rollerID[1], TRUE)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - COLLISION OFF BETWEEN BUMPERS")
ENDIF
IF (roll.fSpinRate >= ROLLER_SPINRATE)
roll.fSpinRate = ROLLER_SPINRATE
START_CARWASH_VERTROLLER_PARTICLES(roll)
roll.iMoveSoundID = GET_SOUND_ID()
PLAY_SOUND_FROM_ENTITY(roll.iMoveSoundID, "BRUSHES_MOVE", roll.pivotID, "CARWASH_SOUNDS")
CPRINTLN(DEBUG_MISSION, "[CARWASH] - VERT BRUSH SPIN UP COMPLETE")
roll.state = CPS_WARMUP
ENDIF
BREAK
CASE CPS_WARMUP
IF (roll.shapeTestID = NULL)
IF (bUseOldVerticleBrushCheck)
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, -1, 0>>)
roll.shapeTestID = START_SHAPE_TEST_CAPSULE(vec, vec + <<0, 0, 1>>, 2.5, SCRIPT_INCLUDE_VEHICLE)
ELSE
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<-3.0, fFirstCheckYShift, VROLLER_CHECKZSHIFT>>)
roll.shapeTestID = START_SHAPE_TEST_LOS_PROBE(vec, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, fFirstCheckYShift, VROLLER_CHECKZSHIFT>>), SCRIPT_INCLUDE_VEHICLE)
ENDIF
IF (roll.shapeTestID = NULL)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - UPDATE_CARWASH_VERTROLLER - CPS_WARMUP - CAN'T GET VALID SHAPE TEST")
ENDIF
ELSE
shapeStatus = GET_SHAPE_TEST_RESULT(roll.shapeTestID, iHits, vHitPos, vHitNormal, hitEntity)
IF (shapeStatus = SHAPETEST_STATUS_RESULTS_READY)
IF CHECK_ENTITY_IS_VEHICLE_OK(hitEntity)
roll.activeVehicle = GET_VEHICLE_INDEX_FROM_ENTITY_INDEX(hitEntity)
IF IS_ENTITY_ALIVE(roll.activeVehicle)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - ACTIVE VEHICLE XX GET:", GET_MODEL_NAME_OF_VEHICLE_FOR_DEBUG_ONLY(roll.activeVehicle))
ELSE
CPRINTLN(DEBUG_MISSION, "[CARWASH] - ACTIVE VEHICLE XX GET: dead vehicle")
ENDIF
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(roll.activeVehicle), vvMin, vvMax)
vWidth = ABSF(vvMax.x - vvMin.x)
IF (bUseOldVerticleBrushCheck)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - USING OLD STYLE BRUSH CHECK:")
roll.fTgtOffset[0] = -((ROLLER_RADIUS * 0.75) + (vWidth / 2.0))
roll.fTgtOffset[1] = (ROLLER_RADIUS * 0.75) + (vWidth / 2.0)
ELSE
vec = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(roll.pivotID, vHitPos + (GET_ENTITY_FORWARD_VECTOR(roll.pivotID) * -fFirstCheckYShift))
CPRINTLN(DEBUG_MISSION, "[CARWASH] - VROLLER MOVE RATE IS 1.5")
roll.fMoveRate = 1.5
//roll.fTgtOffset[0] = v.x - ROLLER_RADIUS
//roll.fTgtOffset[1] = (v.x * -1) + ROLLER_RADIUS
ENDIF
IF (iHits = 0)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - SOMETHING HAS COCKED UP HERE DEFAULTING TO DEFAULT WIDTH")
roll.fTgtOffset[0] = -((ROLLER_RADIUS) + (vWidth / 2.0))
roll.fTgtOffset[1] = (ROLLER_RADIUS) + (vWidth / 2.0)
ENDIF
roll.state = CPS_ACTIVE
roll.fMoveRate = 1.5
roll.bHitCheck[0] = FALSE
roll.bHitCheck[1] = FALSE
roll.bOldHitCheck[0] = FALSE
roll.bOldHitCheck[1] = FALSE
roll.iNextBrushShapeTestTime[0] = GET_GAME_TIMER() + 32
roll.iNextBrushShapeTestTime[1] = GET_GAME_TIMER() + 64
ENDIF
ENDIF
roll.shapeTestID = NULL
ENDIF
BREAK
CASE CPS_ACTIVE
// wait till car is in front of brushes before pulling them in.
IF IS_ENTITY_ALIVE(roll.activeVehicle)
SET_ENTITY_NO_COLLISION_ENTITY(roll.activeVehicle, roll.rollerID[0], TRUE)
SET_ENTITY_NO_COLLISION_ENTITY(roll.activeVehicle, roll.rollerID[1], TRUE)
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(roll.activeVehicle), vvMin, vvMax)
vLength = ABSF(vvMax.y - vvMin.y) / 2.0
vWidth = ABSF(vvMax.x - vvMin.x)
psd = GET_PLANE_SIDE(GET_ENTITY_FORWARD_VECTOR(roll.pivotID), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, vLength, 0>>), GET_ENTITY_COORDS(roll.activeVehicle))
IF (psd = INFRONT_PLANE)
roll.fTgtOffset[0] = -(ROLLER_RADIUS)
roll.fTgtOffset[1] = (ROLLER_RADIUS)
ELSE
IF (bUseOldVerticleBrushCheck)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - USING OLD STYLE BRUSH CHECK:")
roll.fTgtOffset[0] = -((ROLLER_RADIUS * ROLLER_SHIFT_FACTOR) + (vWidth / 2.0))
roll.fTgtOffset[1] = (ROLLER_RADIUS * ROLLER_SHIFT_FACTOR) + (vWidth / 2.0)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - VROLLER MOVE RATE IS 1.0")
roll.fMoveRate = 1.0
ELSE
REPEAT COUNT_OF(roll.rollerID) i
v1 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, fCheckYShift, VROLLER_CHECKZSHIFT>>)
IF (i = 0)
v2 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<-fShapeTestXSeperation, fCheckYShift, VROLLER_CHECKZSHIFT>>)
ELSE
v2 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<fShapeTestXSeperation, fCheckYShift, VROLLER_CHECKZSHIFT>>)
ENDIF
iDriverSeatBoneIndex = GET_ENTITY_BONE_INDEX_BY_NAME(roll.activeVehicle, "seat_dside_f")
IF (iDriverSeatBoneIndex <> -1)
vec = GET_WORLD_POSITION_OF_ENTITY_BONE(roll.activeVehicle, iDriverSeatBoneIndex)
v1.z = vec.z
v2.z = vec.z
ENDIF
IF bDrawDebugCarwash
DRAW_DEBUG_LINE(v1, v2)
ENDIF
IF (roll.brushShapeTestID[i] = NULL)
IF (GET_GAME_TIMER() > roll.iNextBrushShapeTestTime[i])
IF (bUseNewSweptSphereTest = TRUE) OR (GET_VEHICLE_MOD(roll.activeVehicle, MOD_SPOILER) != -1)
roll.brushShapeTestID[i] = START_SHAPE_TEST_SWEPT_SPHERE(v2, v1, fSweepSphereRadius, SCRIPT_INCLUDE_VEHICLE)
ELSE
roll.brushShapeTestID[i] = START_SHAPE_TEST_LOS_PROBE(v2, v1, SCRIPT_INCLUDE_VEHICLE)
ENDIF
IF (roll.brushShapeTestID[i] = NULL)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: CAN'T GET SHAPETEST FOR VERTICAL BRUSH ", i)
ENDIF
ENDIF
ELSE
shapeStatus = GET_SHAPE_TEST_RESULT(roll.brushShapeTestID[i], iHits, vHitPos, vHitNormal, hitEntity)
IF (shapeStatus = SHAPETEST_STATUS_RESULTS_READY)
roll.bOldHitCheck[i] = roll.bHitCheck[i]
roll.bHitCheck[i] = FALSE
IF (iHits > 0)
IF (bDrawDebugCarwash)
DRAW_DEBUG_SPHERE(vHitPos, 0.06625)
ENDIF
//CPRINTLN(DEBUG_MISSION, "HIT HIT HIT - BRUSH:", i)
roll.bHitCheck[i] = TRUE
ENDIF
IF CHECK_ENTITY_IS_VEHICLE_OK(hitEntity)
vec = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(roll.pivotID, vHitPos + (GET_ENTITY_FORWARD_VECTOR(roll.pivotID) * -fCheckYShift))
roll.bHitCheck[i] = TRUE
IF (i = 0)
roll.fTgtOffset[i] = vec.x - ROLLER_RADIUS
ELSE
roll.fTgtOffset[i] = vec.x + ROLLER_RADIUS
ENDIF
ENDIF
ENDIF
roll.brushShapeTestID[i] = NULL
roll.iNextBrushShapeTestTime[i] = GET_GAME_TIMER() + 120
ENDIF
IF (roll.bOldHitCheck[i] <> roll.bHitCheck[i])
IF (roll.bOldHitCheck[i] = TRUE) AND (roll.bHitCheck[i] = FALSE)
CPRINTLN(DEBUG_MISSION, "CARWASH BRUSH ", i, " ISN'T HITTING ANYTHING ANY MORE")
// bBrushesDone = true
ENDIF
IF (roll.bOldHitCheck[i] = FALSE) AND (roll.bHitCheck[i] = TRUE)
CPRINTLN(DEBUG_MISSION, "CARWASH BRUSH ", i, " HAS STARTED HITTING THINGS")
ENDIF
ENDIF
ENDREPEAT
// // STH: Removed bBrushesDone for b*2019238 - The hit test was briefly returning false in middle of cars pass through rollers, so the rollers came together and clipped through rest of the car
// IF (bBrushesDone = TRUE)
// CPRINTLN(DEBUG_MISSION, "CARWASH BRUSHED START WARM DOWN")
// roll.fTgtOffset[0] = -(ROLLER_RADIUS)
// roll.fTgtOffset[1] = (ROLLER_RADIUS)
// roll.fMoveRate = roll.fShutDownMoveRate
// CPRINTLN(DEBUG_MISSION, "[CARWASH] - VROLLER MOVE RATE IS ", roll.fShutDownMoveRate)
// SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[0])
// SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[1])
// roll.state = CPS_WARMDOWN
// EXIT
// ENDIF
ENDIF
ENDIF
// check to see if car is properly in front of point
psd = GET_PLANE_SIDE(GET_ENTITY_FORWARD_VECTOR(roll.pivotID), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, vLength * 1.25, 0>>), GET_ENTITY_COORDS(roll.activeVehicle))
IF (psd = INFRONT_PLANE)
roll.fSpinRate -= (tStep * 2)
IF (roll.fSpinRate < 0)
roll.fSpinRate = 0
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iHitSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[0])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[1])
CPRINTLN(DEBUG_MISSION, "[CARWASH] - BRUSHES ARE IN FRONT TURNING THEM OFF")
ENDIF
ENDIF
ENDIF
IF NOT (roll.bSensorOn[0] OR roll.bSensorOn[1])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[0])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[1])
CPRINTLN(DEBUG_MISSION, "[CARWASH] - SHUTDOWN SPIN RATE:", roll.fSpinRate)
roll.state = CPS_SHUTDOWN
ENDIF
BREAK
CASE CPS_WARMDOWN
IF IS_ENTITY_ALIVE(roll.activeVehicle)
SET_ENTITY_NO_COLLISION_ENTITY(roll.activeVehicle, roll.rollerID[0], TRUE)
SET_ENTITY_NO_COLLISION_ENTITY(roll.activeVehicle, roll.rollerID[1], TRUE)
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(roll.activeVehicle), vvMin, vvMax)
vLength = ABSF(vvMax.y - vvMin.y) / 2.0
vWidth = ABSF(vvMax.x - vvMin.x)
// check to see if car is properly in front of point
psd = GET_PLANE_SIDE(GET_ENTITY_FORWARD_VECTOR(roll.pivotID), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, vLength * 1.25, 0>>), GET_ENTITY_COORDS(roll.activeVehicle))
IF (psd = INFRONT_PLANE)
roll.fSpinRate -= (tStep * 2)
IF (roll.fSpinRate < 0)
roll.fSpinRate = 0
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iHitSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[0])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[1])
roll.state = CPS_SHUTDOWN
//CPRINTLN(DEBUG_MISSION, "[CARWASH] - BRUSHES ARE IN FRONT TURNING THEM OFF")
ENDIF
ENDIF
ENDIF
IF NOT (roll.bSensorOn[0] OR roll.bSensorOn[1])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[0])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[1])
CPRINTLN(DEBUG_MISSION, "[CARWASH] - SHUTDOWN SPIN RATE:", roll.fSpinRate)
roll.state = CPS_SHUTDOWN
ENDIF
BREAK
CASE CPS_SHUTDOWN
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iHitSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[0])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[1])
roll.fSpinRate -= tStep
roll.fTgtOffset[0] = -VROLLER_SEP //-ROLLER_RADIUS * 2.0
roll.fTgtOffset[1] = VROLLER_SEP //ROLLER_RADIUS * 2.0
roll.fMoveRate = 1.5
CPRINTLN(DEBUG_MISSION, "[CARWASH] - VROLLER MOVE RATE IS ", roll.fMoveRate)
roll.bHitCheck[0] = FALSE
roll.bHitCheck[1] = FALSE
roll.bOldHitCheck[0] = FALSE
roll.bOldHitCheck[1] = FALSE
IF (roll.fSpinRate <= 0)
roll.fSpinRate = 0
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
ENDIF
// if aborted wait till area is clear before allowing collsion to turn back on
IF (GET_GAME_TIMER() > roll.iNextShapeTestTime)
IF NOT IS_CARWASH_POSITION_OCCUPIED(roll.vBasePosition, 1.0)
roll.bCollisionOn = TRUE
CPRINTLN(DEBUG_MISSION, "[CARWASH] - TURNING BRUSH COLLISION ON AFTER SHUTDOWN")
SET_ENTITY_COLLISION(roll.rollerID[0], roll.bCollisionOn)
SET_ENTITY_COLLISION(roll.rollerID[1], roll.bCollisionOn)
roll.iNextShapeTestTime = 0
roll.state = CPS_NULL
ELSE
roll.iNextShapeTestTime = GET_GAME_TIMER() + SHAPE_CHECK_INTERVAL
ENDIF
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Update the dual roller
/// PARAMS:
/// roll - roller reference
PROC UPDATE_CARWASH_VERTROLLER_MP(CARWASH_VROLLER2 &roll, BOOL bSomeOneIn = TRUE, BOOL bAborted = FALSE)
VECTOR vec, v1, v2
VEHICLE_INDEX vehicleIndex
FLOAT fFirstCheckYShift = -1.5 // we shift the file in check by this abount
FLOAT fCheckYShift = -ROLLER_RADIUS
INT i, iHits
ENTITY_INDEX hitEntity
SHAPETEST_STATUS shapeStatus
VECTOR vHitPos, vHitNormal
FLOAT tStep = ROLLER_SPINRATE * TIMESTEP()
INT iDriverSeatBoneIndex = -1
PLANE_SIDE psd
FLOAT vLength
VECTOR vvMin, vvMax
IF NOT roll.bSetup = TRUE
EXIT
ENDIF
UPDATE_CARWASH_VERTROLLER_MOVEMENT(roll)
IF IS_CARWASH_PART_RUNNING(roll.state)
IF (bSomeOneIn = FALSE)
CPRINTLN(DEBUG_MISSION, "Carwash VRoller - Shutdown No One is In Carwash")
roll.state = CPS_SHUTDOWN
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS() AND NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
CPRINTLN(DEBUG_MISSION, "Carwash VRoller - NET Shutdown No One is In Carwash")
bSomeOneIn = FALSE
roll.state = CPS_SHUTDOWN
ENDIF
IF (bSomeOneIn = FALSE)
roll.fSpinRate -= (tStep * 2.0)
IF (roll.fSpinRate <= 0)
roll.fSpinRate = 0
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
ENDIF
ENDIF
ELSE
roll.fSpinRate -= (tStep * 2.0)
IF (roll.fSpinRate <= 0)
roll.fSpinRate = 0
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
ENDIF
ENDIF
// update sensors
IF NOT (bAborted) AND (roll.state <> CPS_SHUTDOWN)
IF (GET_GAME_TIMER() > roll.iNextShapeTestTime)
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[0], 0>>)
roll.bSensorOn[0] = IS_CARWASH_POSITION_OCCUPIED(vec, roll.fSensorRadius[0])
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[1], 0>>)
roll.bSensorOn[1] = IS_CARWASH_POSITION_OCCUPIED(vec, roll.fSensorRadius[1])
roll.iNextShapeTestTime = GET_GAME_TIMER() + SHAPE_CHECK_INTERVAL
ENDIF
ENDIF
// draw debug for sensors
IF (bDrawDebugCarwash = TRUE)
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[0], 0>>)
IF (roll.bSensorOn[0])
DRAW_DEBUG_CIRCLE(vec, roll.fSensorRadius[0], 0, 255, 0, 255)
ELSE
DRAW_DEBUG_CIRCLE(vec, roll.fSensorRadius[0], 255, 0, 0, 255)
ENDIF
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[1], 0>>)
IF (roll.bSensorOn[1])
DRAW_DEBUG_CIRCLE(vec, roll.fSensorRadius[1], 0, 255, 0, 255)
ELSE
DRAW_DEBUG_CIRCLE(vec, roll.fSensorRadius[1], 0, 0, 255, 255)
ENDIF
DRAW_DEBUG_LINE(GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<-2.5, fFirstCheckYShift, VROLLER_CHECKZSHIFT>>),
GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<2.5, fFirstCheckYShift, VROLLER_CHECKZSHIFT>>))
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, 0, VROLLER_CHECKZSHIFT>>)
DRAW_DEBUG_LINE(vec, vec + GET_ENTITY_FORWARD_VECTOR(roll.pivotID))
ENDIF
// update state
SWITCH (roll.state)
CASE CPS_NULL
// if the front sensor is on run shape test
IF NOT (roll.bSensorOn[0])
EXIT
ENDIF
IF (roll.shapeTestID = NULL)
vec = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, roll.fSensorOffset[0], 0>>)
roll.shapeTestID = START_SHAPE_TEST_CAPSULE(vec, vec + <<0, 0, 1>>, 2.25, SCRIPT_INCLUDE_VEHICLE)
ELSE
shapeStatus = GET_SHAPE_TEST_RESULT(roll.shapeTestID, iHits, vHitPos, vHitNormal, hitEntity)
IF (shapeStatus = SHAPETEST_STATUS_RESULTS_READY)
IF CHECK_ENTITY_IS_VEHICLE_OK(hitEntity)
vehicleIndex = GET_VEHICLE_INDEX_FROM_ENTITY_INDEX(hitEntity)
IF IS_DIRECTION_WITHIN_DEGRESS_OF_DESIRED_DIRECTION_SIGNED(GET_ENTITY_FORWARD_VECTOR(vehicleIndex), GET_ENTITY_FORWARD_VECTOR(roll.pivotID), 10.0)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - PLAYER IS POINTING THE RIGHT WAY")
vec = GET_ENTITY_SPEED_VECTOR(vehicleIndex, TRUE)
IF (vec.y <= 0)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - PLAYER IS POINTING THE RIGHT WAY BUT IS REVERSING OR STOPPED")
ELSE
roll.state = CPS_STARTUP
roll.activeVehicle = vehicleIndex
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
roll.iSpinSoundID = GET_SOUND_ID()
PLAY_SOUND_FROM_ENTITY(roll.iSpinSoundID, "BRUSHES_SPINNING", roll.pivotID, "CARWASH_SOUNDS")
CPRINTLN(DEBUG_MISSION, "[CARWASH] - PLAYER IS POINTING THE RIGHT WAY AND MOVING IN THE RIGHT WAY")
ENDIF
ENDIF
ENDIF
ENDIF
roll.shapeTestID = NULL
ENDIF
BREAK
CASE CPS_STARTUP
roll.fSpinRate += tStep
SET_ENTITY_NO_COLLISION_ENTITY(roll.activeVehicle, roll.rollerID[0], TRUE)
SET_ENTITY_NO_COLLISION_ENTITY(roll.activeVehicle, roll.rollerID[1], TRUE)
IF IS_ENTITY_ALIVE(roll.activeVehicle)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - COLLISION OFF BETWEEN BUMPERS AND ", GET_MODEL_NAME_OF_VEHICLE_FOR_DEBUG_ONLY(roll.activeVehicle))
ELSE
CPRINTLN(DEBUG_MISSION, "[CARWASH] - COLLISION OFF BETWEEN BUMPERS AND dead vehicle")
ENDIF
IF (roll.fSpinRate >= ROLLER_SPINRATE)
roll.fSpinRate = ROLLER_SPINRATE
START_CARWASH_VERTROLLER_PARTICLES(roll)
roll.iMoveSoundID = GET_SOUND_ID()
PLAY_SOUND_FROM_ENTITY(roll.iMoveSoundID, "BRUSHES_MOVE", roll.pivotID, "CARWASH_SOUNDS")
CPRINTLN(DEBUG_MISSION, "[CARWASH] - VERT BRUSH SPIN UP COMPLETE")
roll.state = CPS_WARMUP
ENDIF
BREAK
CASE CPS_WARMUP
CPRINTLN(DEBUG_MISSION, "[CARWASH] - SET VERTROLL STATE - CPS_ACTIVE")
roll.state = CPS_ACTIVE
BREAK
CASE CPS_ACTIVE
IF NOT CHECK_ENTITY_IS_VEHICLE_OK(roll.activeVehicle)
roll.state = CPS_WARMDOWN
EXIT
ENDIF
IF NOT IS_CARWASH_PED_OK(GET_PED_IN_VEHICLE_SEAT(roll.activeVehicle))
CPRINTLN(DEBUG_MISSION, "[CARWASH] - SET VERTROLL STATE - CPS_WARMDOWN - PED IN CAR IS NOT OKAY")
roll.state = CPS_WARMDOWN
EXIT
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS() AND NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
roll.state = CPS_WARMDOWN
EXIT
ENDIF
// wait for vehicle to leave
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(roll.activeVehicle), vvMin, vvMax)
vLength = ABSF(vvMax.y - vvMin.y) / 2.0
psd = GET_PLANE_SIDE(GET_ENTITY_FORWARD_VECTOR(roll.pivotID), GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<0, vLength, 0>>), GET_ENTITY_COORDS(roll.activeVehicle))
IF (psd = INFRONT_PLANE)
roll.fTgtOffset[0] = -(ROLLER_RADIUS)
roll.fTgtOffset[1] = (ROLLER_RADIUS)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - SET VERTROLL STATE - CPS_WARMDOWN - CAR HAS GONE PAST BRUSHES")
roll.state = CPS_WARMDOWN
EXIT
ENDIF
REPEAT COUNT_OF(roll.rollerID) i
IF (i = 0)
v1 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<1.0, fCheckYShift, VROLLER_CHECKZSHIFT>>)
v2 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<-fShapeTestXSeperation, fCheckYShift, VROLLER_CHECKZSHIFT>>)
ELSE
v1 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<-1.0, fCheckYShift, VROLLER_CHECKZSHIFT>>)
v2 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<fShapeTestXSeperation, fCheckYShift, VROLLER_CHECKZSHIFT>>)
ENDIF
iDriverSeatBoneIndex = GET_ENTITY_BONE_INDEX_BY_NAME(roll.activeVehicle, "seat_dside_f")
IF (iDriverSeatBoneIndex <> -1)
vec = GET_WORLD_POSITION_OF_ENTITY_BONE(roll.activeVehicle, iDriverSeatBoneIndex)
v1.z = vec.z
v2.z = vec.z
ENDIF
IF (roll.brushShapeTestID[i] = NULL)
IF (GET_GAME_TIMER() > roll.iNextBrushShapeTestTime[i])
IF (bUseNewSweptSphereTest = TRUE) OR (GET_VEHICLE_MOD(roll.activeVehicle, MOD_SPOILER) != -1)
roll.brushShapeTestID[i] = START_SHAPE_TEST_SWEPT_SPHERE(v2, v1, fSweepSphereRadius, SCRIPT_INCLUDE_VEHICLE)
ELSE
roll.brushShapeTestID[i] = START_SHAPE_TEST_LOS_PROBE(v2, v1, SCRIPT_INCLUDE_VEHICLE)
ENDIF
IF (roll.brushShapeTestID[i] = NULL)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: CAN'T GET SHAPETEST FOR VERTICAL BRUSH ", i)
ENDIF
ENDIF
ELSE
shapeStatus = GET_SHAPE_TEST_RESULT(roll.brushShapeTestID[i], iHits, vHitPos, vHitNormal, hitEntity)
IF (shapeStatus = SHAPETEST_STATUS_RESULTS_READY)
roll.bOldHitCheck[i] = roll.bHitCheck[i]
roll.bHitCheck[i] = FALSE
IF (iHits > 0)
//IF (bDrawDebugCarwash)
DRAW_DEBUG_SPHERE(vHitPos, 0.06625)
//ENDIF
roll.bHitCheck[i] = TRUE
ENDIF
IF CHECK_ENTITY_IS_VEHICLE_OK(hitEntity)
vec = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(roll.pivotID, vHitPos + (GET_ENTITY_FORWARD_VECTOR(roll.pivotID) * -fCheckYShift))
IF (i = 0)
roll.fTgtOffset[i] = vec.x - ROLLER_RADIUS
ELSE
roll.fTgtOffset[i] = vec.x + ROLLER_RADIUS
ENDIF
ENDIF
ENDIF
roll.brushShapeTestID[i] = NULL
roll.iNextBrushShapeTestTime[i] = GET_GAME_TIMER() + 120
ENDIF
IF (roll.bOldHitCheck[i] <> roll.bHitCheck[i])
IF (roll.bOldHitCheck[i] = TRUE) AND (roll.bHitCheck[i] = FALSE)
CPRINTLN(DEBUG_MISSION, "CARWASH BRUSH ", i, " ISN'T HITTING ANYTHING ANY MORE")
ENDIF
IF (roll.bOldHitCheck[i] = FALSE) AND (roll.bHitCheck[i] = TRUE)
CPRINTLN(DEBUG_MISSION, "CARWASH BRUSH ", i, " HAS STARTED HITTING THINGS")
ENDIF
ENDIF
ENDREPEAT
SET_ENTITY_NO_COLLISION_ENTITY(roll.activeVehicle, roll.rollerID[0], TRUE)
SET_ENTITY_NO_COLLISION_ENTITY(roll.activeVehicle, roll.rollerID[1], TRUE)
IF (bAborted)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - SET VERTROLL STATE - CPS_WARMDOWN - PED IN CAR IS NOT OKAY")
roll.state = CPS_WARMDOWN
EXIT
ENDIF
BREAK
CASE CPS_WARMDOWN
roll.activeVehicle = NULL
roll.fTgtOffset[0] = -roll.fOriginalSep / 2.0
roll.fTgtOffset[1] = roll.fOriginalSep / 2.0
roll.fSpinRate -= (tStep)
IF (roll.fSpinRate <= 0)
roll.fSpinRate = 0
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iHitSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[0])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[1])
ENDIF
IF (roll.fTgtOffset[0] = roll.fOffset[0]) AND (roll.fTgtOffset[1] = roll.fOffset[1]) AND (roll.fSpinRate = 0)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - SET VERTROLL STATE - CPS_SHUTDOWN")
roll.state = CPS_SHUTDOWN
ENDIF
BREAK
CASE CPS_SHUTDOWN
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iMoveSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iHitSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSpinSoundID)
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[0])
SAFE_REMOVE_PARTICLE_FX(roll.fxBrushID[1])
roll.fTgtOffset[0] = -roll.fOriginalSep / 2.0
roll.fTgtOffset[1] = roll.fOriginalSep / 2.0
roll.fMoveRate = 1.5
// if aborted wait till area is clear before allowing collsion to turn back on
IF (GET_GAME_TIMER() > roll.iNextShapeTestTime)
IF NOT IS_CARWASH_POSITION_OCCUPIED(roll.vBasePosition, 1.0)
roll.bCollisionOn = TRUE
roll.iNextShapeTestTime = 0
CPRINTLN(DEBUG_MISSION, "[CARWASH] - SET VERTROLL STATE - CPS_NULL")
roll.state = CPS_NULL
ELSE
roll.iNextShapeTestTime = GET_GAME_TIMER() + SHAPE_CHECK_INTERVAL
ENDIF
ENDIF
BREAK
ENDSWITCH
ENDPROC
PROC RESET_CARWASH_VERTROLLER_PROPS(CARWASH_VROLLER2 &roll)
VECTOR v
IF IS_ENTITY_ALIVE(roll.pivotID)
SET_ENTITY_COORDS_NO_OFFSET(roll.pivotID, roll.vBasePosition)
ENDIF
IF IS_ENTITY_ALIVE(roll.rollerID[0])
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<roll.fTgtOffset[0], 0, VROLLER_ZSHIFT>>)
SET_ENTITY_COORDS(roll.rollerID[0], v)
ENDIF
IF IS_ENTITY_ALIVE(roll.rollerID[1])
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<roll.fTgtOffset[1], 0, VROLLER_ZSHIFT>>)
SET_ENTITY_COORDS(roll.rollerID[1], v)
ENDIF
ENDPROC
PROC CREATE_CARWASH_VERTROLLER(CARWASH_VROLLER2 &roll, VECTOR pos, FLOAT head, float sep = DEFAULT_DUALVROLL_SEP, FLOAT zShift = 0.0)
FLOAT z
VECTOR v
IF GET_GROUND_Z_FOR_3D_COORD(pos + <<0, 0, 0.3>>, z)
//pos.z = z
ENDIF
roll.vBasePosition = pos
roll.fOriginalSep = sep
pos.z += zShift//
roll.vBasePosition = pos
roll.pivotID = CREATE_OBJECT(PROP_LD_TEST_01, pos, FALSE)
// setup pivot
IF IS_ENTITY_ALIVE(roll.pivotID)
FREEZE_ENTITY_POSITION(roll.pivotID, TRUE)
SET_ENTITY_COORDS_NO_OFFSET(roll.pivotID, pos)
SET_ENTITY_HEADING(roll.pivotID, head)
SET_ENTITY_COLLISION(roll.pivotID, FALSE)
ENDIF
CPRINTLN(DEBUG_MISSION, "[CARWASH] - VROLLER PIVOT BASE POSITION:", pos)
// create left brush
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<-sep / 2.0, 0, VROLLER_ZSHIFT>>)
roll.rollerID[0] = CREATE_OBJECT(PROP_CARWASH_ROLLER_VERT, v, FALSE)
roll.fTgtOffset[0] = -sep / 2.0
roll.fOffset[0] = -sep / 2.0
FREEZE_ENTITY_POSITION(roll.rollerID[0], TRUE)
SET_ENTITY_COLLISION(roll.rollerID[0], TRUE)
SET_ENTITY_INVINCIBLE(roll.rollerID[0], TRUE)
SET_ENTITY_HAS_GRAVITY(roll.rollerID[0], FALSE)
SET_ENTITY_COORDS(roll.rollerID[0], v)
// create left brush
v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<sep / 2.0, 0, VROLLER_ZSHIFT>>)
roll.rollerID[1] = CREATE_OBJECT(PROP_CARWASH_ROLLER_VERT, v, FALSE)
roll.fTgtOffset[1] = sep / 2.0
roll.fOffset[1] = sep / 2.0
FREEZE_ENTITY_POSITION(roll.rollerID[1], TRUE)
SET_ENTITY_COLLISION(roll.rollerID[1], TRUE)
SET_ENTITY_INVINCIBLE(roll.rollerID[1], TRUE)
SET_ENTITY_HAS_GRAVITY(roll.rollerID[1], FALSE)
SET_ENTITY_COORDS(roll.rollerID[1], v)
// finialize
roll.fRollerSpinAngle = 0.0
roll.state = CPS_NULL
roll.bSetup = TRUE
roll.fSensorOffset[0] = -1.275
roll.fSensorRadius[0] = 1.25
roll.fSensorOffset[1] = 0.0
roll.fSensorRadius[1] = 0.620
roll.fTgtOffset[0] = -VROLLER_SEP
roll.fTgtOffset[1] = VROLLER_SEP
roll.iNextShapeTestTime = 0
ENDPROC
//----------------------
// JETS FUNCTIONS
//----------------------
/// PURPOSE:
/// Create the carwash jets
/// PARAMS:
/// roll - roller reference
/// pos - the middle point between the two arms - ground based
/// head - heading
/// sep - the distance between the arm joints
/// steam - are these steam jets (their positioning is forced)
PROC CREATE_CARWASH_JETS(CARWASH_JETS &roll, VECTOR pos, FLOAT head = 0.0, FLOAT sep = DEFAULT_DUALVROLL_SEP, BOOL steam = FALSE, FLOAT jetTrig = JET_TRIGGER_DIST)
FLOAT z
IF IS_STRING_NULL_OR_EMPTY(roll.sJetName)
roll.sJetName = "ent_amb_car_wash_jet"
ENDIF
roll.bSetup = TRUE
roll.fSeperation = sep / 2.0
roll.pivotID = CREATE_OBJECT(PROP_LD_TEST_01, pos, FALSE)
roll.bSteam = steam
IF IS_ENTITY_OK(roll.pivotID)
SET_ENTITY_HEADING(roll.pivotID, head)
FREEZE_ENTITY_POSITION(roll.pivotID, TRUE)
ENDIF
IF GET_GROUND_Z_FOR_3D_COORD(pos, z)
roll.fHeight = ABSF(pos.z - z)
ENDIF
CPRINTLN(DEBUG_MISSION, "[CARWASH] - JETS BASE POS:", pos, " HEIGHT:", roll.fHeight)
roll.fTriggerDist = jetTrig
roll.vBasePos = pos
roll.vBasePos.z = z
ENDPROC
PROC SET_CARWASH_JETS_PARTICLES(CARWASH_JETS &roll, STRING str)
roll.sJetName = str
ENDPROC
PROC START_CARWASH_JETS_PARTICLES(CARWASH_JETS &roll, STRING str = NULL)
IF NOT IS_STRING_EMPTY_HUD(str)
roll.sJetName = str
ENDIF
SHUTDOWN_CARWASH_JETS_PARTICLES(roll)
IS_VECTOR_ZERO(vSteamRotFX)
IF (roll.bSteam = FALSE)
roll.fxJets[0] = START_PARTICLE_FX_LOOPED_ON_ENTITY(roll.sJetName, roll.pivotID, <<roll.fSeperation, 0, -roll.fHeight * 0.25>>, -vJetRotFX)
roll.fxJets[1] = START_PARTICLE_FX_LOOPED_ON_ENTITY(roll.sJetName, roll.pivotID, <<-roll.fSeperation, 0, -roll.fHeight * 0.25>>, vJetRotFX)
roll.fxJets[2] = START_PARTICLE_FX_LOOPED_ON_ENTITY(roll.sJetName, roll.pivotID, <<roll.fSeperation, 0, -roll.fHeight * 0.75>>, -vJetRotFX)
roll.fxJets[3] = START_PARTICLE_FX_LOOPED_ON_ENTITY(roll.sJetName, roll.pivotID, <<-roll.fSeperation, 0, -roll.fHeight * 0.75>>, vJetRotFX)
ELSE
roll.fxJets[0] = START_PARTICLE_FX_LOOPED_ON_ENTITY(roll.sJetName, roll.pivotID, vSteamPosFX, <<0, 90, 0>>)
roll.fxJets[1] = START_PARTICLE_FX_LOOPED_ON_ENTITY(roll.sJetName, roll.pivotID, <<-1.96, 0.1, -2.16>>, <<0, 35, 0>>)
roll.fxJets[2] = START_PARTICLE_FX_LOOPED_ON_ENTITY(roll.sJetName, roll.pivotID, <<1.96, 0.1, -2.16>>, <<0, 145, 0>>)
ENDIF
ENDPROC
PROC SHUTDOWN_CARWASH_JETS(CARWASH_JETS &roll)
IF IS_CARWASH_PART_RUNNING(roll.state)
SHUTDOWN_CARWASH_JETS_PARTICLES(roll)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSplashSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSoundID)
roll.state = CPS_NULL
ENDIF
ENDPROC
PROC SHARED_CLEANUP_DELETE_CARWASH_JETS(CARWASH_JETS &roll)
roll.state = CPS_ACTIVE
SHUTDOWN_CARWASH_JETS(roll)
SAFE_DELETE_OBJECT(roll.pivotID)
ENDPROC
/// PURPOSE:
/// Update the dual roller
/// PARAMS:
/// roll - roller reference
PROC CLEANUP_CARWASH_JETS(CARWASH_JETS &roll)
SHARED_CLEANUP_DELETE_CARWASH_JETS(roll)
ENDPROC
/// PURPOSE:
/// Update the dual roller
/// PARAMS:
/// roll - roller reference
PROC DELETE_CARWASH_JETS(CARWASH_JETS &roll)
SHARED_CLEANUP_DELETE_CARWASH_JETS(roll)
ENDPROC
/// PURPOSE:
/// Update the dual roller
/// PARAMS:
/// roll - roller reference
PROC UPDATE_CARWASH_JETS(CARWASH_JETS &roll, BOOL bSomeOneIn = TRUE)
INT iHits
VECTOR v1, v2
VECTOR vHitPos, vHitNormal
SHAPETEST_STATUS shapeStatus
ENTITY_INDEX hitEntity
IF NOT IS_ENTITY_OK(roll.pivotID) or (roll.bSetup = FALSE)
EXIT
ENDIF
#IF IS_DEBUG_BUILD
IF bDrawDebugCarwash = TRUE
DRAW_DEBUG_SPHERE(GET_ENTITY_COORDS(roll.pivotID), 0.03125)
VECTOR v = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, vSteamPosFX)
DRAW_DEBUG_SPHERE(v, 0.0625, 0, 255, 0, 255)
DRAW_DEBUG_CIRCLE(roll.vBasePos, roll.fTriggerDist)
ENDIF
#ENDIF
IF IS_CARWASH_PART_RUNNING(roll.state)
IF (bSomeOneIn = FALSE)
CPRINTLN(DEBUG_MISSION, "Carwash Water - Shutdown No One is In Carwash")
roll.state = CPS_SHUTDOWN
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS() AND NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
CPRINTLN(DEBUG_MISSION, "Carwash Water - NET Shutdown No One is In Carwash")
roll.state = CPS_SHUTDOWN
ENDIF
ENDIF
SWITCH (roll.state)
CASE CPS_NULL
IF (GET_GAME_TIMER() > roll.iNextShapeTestTime) AND (bSomeOneIn = TRUE)
IF (roll.bSteam = FALSE)
IF (roll.shapeTestID = NULL)
IF (GET_GAME_TIMER() > roll.iNextShapeTestTime)
v1 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<-roll.fSeperation * 0.8, 0, -roll.fHeight * 0.75>>)
v2 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<roll.fSeperation * 0.8, 0, -roll.fHeight * 0.75>>)
roll.shapeTestID = START_SHAPE_TEST_LOS_PROBE(v1, v2, SCRIPT_INCLUDE_VEHICLE, roll.pivotID, SCRIPT_SHAPETEST_OPTION_IGNORE_NO_COLLISION)
STOP_FIRE_IN_RANGE(roll.vBasePos, roll.fTriggerDist)
ENDIF
ELSE
shapeStatus = GET_SHAPE_TEST_RESULT(roll.shapeTestID, iHits, vHitPos, vHitNormal, hitEntity)
IF (shapeStatus = SHAPETEST_STATUS_RESULTS_READY)
IF CHECK_ENTITY_IS_VEHICLE_OK(hitEntity)
roll.state = CPS_STARTUP
CPRINTLN(DEBUG_MISSION, "[CARWASH]: PARTICLE STARTUP")
ENDIF
roll.iNextShapeTestTime = GET_GAME_TIMER() + SHAPE_CHECK_INTERVAL
ENDIF
roll.shapeTestID = NULL
ENDIF
ELSE
roll.iNextShapeTestTime = GET_GAME_TIMER() + SHAPE_CHECK_INTERVAL
IF IS_CARWASH_POSITION_OCCUPIED(roll.vBasePos, roll.fTriggerDist)
roll.state = CPS_STARTUP
roll.shapeTestID = NULL
ENDIF
ENDIF
ENDIF
BREAK
CASE CPS_STARTUP
roll.state = CPS_ACTIVE
START_CARWASH_JETS_PARTICLES(roll)
STOP_FIRE_IN_RANGE(roll.vBasePos, roll.fTriggerDist * 1.2)
roll.iSoundID = GET_SOUND_ID()
IF (roll.bSteam = FALSE)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: PARTICLE ACTIVE")
PLAY_SOUND_FROM_ENTITY(roll.iSoundID, "SPRAY", roll.pivotID, "CARWASH_SOUNDS")
ELSE
PLAY_SOUND_FROM_ENTITY(roll.iSoundID, "DRYER", roll.pivotID, "CARWASH_SOUNDS")
ENDIF
BREAK
CASE CPS_ACTIVE
IF (bSomeOneIn = FALSE)
CPRINTLN(DEBUG_MISSION, "Carwash Water - Splash Start")
roll.state = CPS_SHUTDOWN
EXIT
ENDIF
IF NETWORK_IS_GAME_IN_PROGRESS() AND NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
roll.state = CPS_SHUTDOWN
EXIT
ENDIF
IF (roll.bSteam = FALSE)
STOP_FIRE_IN_RANGE(roll.vBasePos, roll.fTriggerDist * 1.2)
IF (roll.shapeTestID = NULL)
IF (GET_GAME_TIMER() > roll.iNextShapeTestTime)
v1 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<-roll.fSeperation * 0.8, 0, -roll.fHeight * 0.75>>)
v2 = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(roll.pivotID, <<roll.fSeperation * 0.8, 0, -roll.fHeight * 0.75>>)
roll.shapeTestID = START_SHAPE_TEST_LOS_PROBE(v1, v2, SCRIPT_INCLUDE_VEHICLE, roll.pivotID, SCRIPT_SHAPETEST_OPTION_IGNORE_NO_COLLISION)
ENDIF
ELSE
shapeStatus = GET_SHAPE_TEST_RESULT(roll.shapeTestID, iHits, vHitPos, vHitNormal, hitEntity)
IF (shapeStatus = SHAPETEST_STATUS_RESULTS_READY)
IF NOT CHECK_ENTITY_IS_VEHICLE_OK(hitEntity)
roll.state = CPS_SHUTDOWN
ELSE
IF (roll.iSplashSoundID = -1)
roll.iSplashSoundID = GET_SOUND_ID()
PLAY_SOUND_FROM_ENTITY(roll.iSplashSoundID, "SPRAY_CAR", roll.pivotID, "CARWASH_SOUNDS")
CPRINTLN(DEBUG_MISSION, "Carwash Water - Splash Start")
ENDIF
IF IS_PED_IN_THIS_VEHICLE(PLAYER_PED_ID(), GET_VEHICLE_INDEX_FROM_ENTITY_INDEX(hitEntity))
//CPRINTLN(DEBUG_MISSION, "Carwash Water - Pad Rumble")
DO_CARWASH_PAD_RUMBLE(SHAPE_CHECK_INTERVAL, 64)
ENDIF
ENDIF
roll.iNextShapeTestTime = GET_GAME_TIMER() + SHAPE_CHECK_INTERVAL
ENDIF
roll.shapeTestID = NULL
ENDIF
IF (IS_PED_ON_ANY_BIKE(PLAYER_PED_ID()) OR IS_PED_ON_FOOT(PLAYER_PED_ID()))
OR (IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT ARE_ALL_VEHICLE_WINDOWS_INTACT(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())))
vHitPos = GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(roll.pivotID, GET_ENTITY_COORDS(PLAYER_PED_ID()))
IF (ABSF(vHitPos.x) < roll.fSeperation) AND (ABSF(vHitPos.y) < 1.2) AND (vHitPos.z < -roll.fHeight * 0.25)
//CPRINTLN(DEBUG_MISSION, "Carwash Water - Wet")
SET_PED_WETNESS_HEIGHT(PLAYER_PED_ID(), 3.0)
ENDIF
ENDIF
ELIF (GET_GAME_TIMER() > roll.iNextCheckTime)
DO_CARWASH_PAD_RUMBLE(ROLLER_CHECK_INTERVAL, 16)
IF NOT IS_CARWASH_POSITION_OCCUPIED(roll.vBasePos, roll.fTriggerDist * 1.25)
roll.state = CPS_SHUTDOWN
ENDIF
roll.iNextCheckTime = GET_GAME_TIMER() + ROLLER_CHECK_INTERVAL
ENDIF
BREAK
CASE CPS_SHUTDOWN
CPRINTLN(DEBUG_MISSION, "[CARWASH]: PARTICLE SHUTDOWN")
SHUTDOWN_CARWASH_JETS_PARTICLES(roll)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSplashSoundID)
SAFE_STOP_AND_RELEASE_SOUND_ID(roll.iSoundID)
roll.state = CPS_NULL
BREAK
ENDSWITCH
ENDPROC
//----------------------
// CAM FUNCTIONS
//----------------------
PROC SETUP_CARWASH_CAMERA(CARWASH_CAMERA &cam, VECTOR pos, VECTOR rot, FLOAT fov)
cam.bSetup = TRUE
cam.vPosition[0] = pos
cam.vRotation[0] = rot
cam.vPosition[1] = <<0, 0, 0>>
cam.vRotation[1] = <<0, 0, 0>>
cam.iInterpTime = 0
cam.fFov = fov
ENDPROC
PROC SETUP_CARWASH_CAMERA_INTERPOLATE(CARWASH_CAMERA &cam, VECTOR pos, VECTOR rot, VECTOR pos2, VECTOR rot2, FLOAT fov, INT itime)
cam.bSetup = TRUE
cam.vPosition[0] = pos
cam.vRotation[0] = rot
cam.vPosition[1] = pos2
cam.vRotation[1] = rot2
cam.iInterpTime = itime
cam.fFov = fov
ENDPROC
PROC DISABLE_CARWASH_CAMERA(CARWASH_CAMERA &cr)
IF DOES_CAM_EXIST(cr.cameraID)
SET_CAM_ACTIVE(cr.cameraID, FALSE)
RENDER_SCRIPT_CAMS(FALSE, FALSE)
ENDIF
ENDPROC
PROC DESTROY_CARWASH_CAMERA(CARWASH_CAMERA &cr)
IF DOES_CAM_EXIST(cr.cameraID)
DISABLE_CARWASH_CAMERA(cr)
DESTROY_CAM(cr.cameraID)
ENDIF
cr.cameraID = NULL
ENDPROC
FUNC BOOL ENABLE_CARWASH_CAMERA(CARWASH_CAMERA &cr)
IF NOT (cr.bSetup = TRUE)
RETURN FALSE
ENDIF
IF NOT DOES_CAM_EXIST(cr.cameraID)
cr.cameraID = CREATE_CAM_WITH_PARAMS("DEFAULT_SCRIPTED_CAMERA", <<0, 0, 0>>, <<0, 0, 0>>, 60.0, TRUE)
ENDIF
SET_CAM_PARAMS(cr.cameraID, cr.vPosition[0], cr.vRotation[0], cr.fFov, 0)
SET_CAM_ACTIVE(cr.cameraID, TRUE)
RENDER_SCRIPT_CAMS(TRUE, FALSE)
IF (cr.iInterpTime > 0) AND NOT IS_VECTOR_ZERO(cr.vPosition[1])
CPRINTLN(DEBUG_MISSION, "CAMERA INTERPOLATE")
SET_CAM_PARAMS(cr.cameraID, cr.vPosition[1], cr.vRotation[1], cr.fFov, cr.iInterpTime)
ENDIF
RETURN TRUE
ENDFUNC
//----------------------
// HANDLER FUNCTIONS
//----------------------
FUNC BOOL RESTART_CARWASH_VEHICLE_TASK(VEHICLE_INDEX veh, CARWASH_HANDLER &ch)
IF NOT IS_ENTITY_OK(veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Aborting as vehicle is broken")
RETURN FALSE
ENDIF
PED_INDEX ped = GET_PED_IN_VEHICLE_SEAT(veh)
IF NOT IS_ENTITY_OK(veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Aborting as vehicle has no driver")
RETURN FALSE
ENDIF
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED(ch.sWayPointRec)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Waypoint recording not loaded")
RETURN FALSE
ENDIF
SET_VEHICLE_DOORS_SHUT(veh, TRUE)
IF NETWORK_HAS_CONTROL_OF_ENTITY(veh)
SET_VEHICLE_DOORS_LOCKED_FOR_ALL_PLAYERS(veh, TRUE)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Carwash Network Door Lock Activated")
ENDIF
SEQUENCE_INDEX seqCarWash
OPEN_SEQUENCE_TASK(seqCarWash)
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(NULL, veh, ch.sWayPointRec, DRIVINGMODE_PLOUGHTHROUGH, 0,
EWAYPOINT_NAVMESH_TO_INITIAL_WAYPOINT | EWAYPOINT_USE_TIGHTER_TURN_SETTINGS | EWAYPOINT_DO_NOT_RESPOND_TO_COLLISION_EVENTS,
-1, ch.fForwardSpeed, FALSE, 1.25)
TASK_STAND_STILL(NULL, 3000)
CLOSE_SEQUENCE_TASK(seqCarWash)
TASK_PERFORM_SEQUENCE(ped, seqCarWash)
CLEAR_SEQUENCE_TASK(seqCarWash)
VEHICLE_WAYPOINT_PLAYBACK_OVERRIDE_SPEED(veh, ch.fForwardSpeed)
iDriverCarwashSequenceProgress = -1
ch.iTaskSequenceSize = 2
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Task Restarted")
RETURN TRUE
ENDFUNC
FUNC BOOL SET_VEHICLE_THROUGH_CARWASH(VEHICLE_INDEX veh, CARWASH_HANDLER &ch, INT iDelay = 0)
IF NOT IS_ENTITY_OK(veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Aborting as vehicle is broken")
RETURN FALSE
ENDIF
PED_INDEX ped = GET_PED_IN_VEHICLE_SEAT(veh)
IF NOT IS_ENTITY_OK(veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Aborting as vehicle has no driver")
RETURN FALSE
ENDIF
IF DOES_VEHICLE_HAVE_ROOF(veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Car has a roof that's good then")
ENDIF
IF IS_VEHICLE_A_CONVERTIBLE(veh, TRUE)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Car is a convertable - Convertable Roof State:", ENUM_TO_INT(GET_CONVERTIBLE_ROOF_STATE(veh)))
ENDIF
IF IS_STRING_NULL_OR_EMPTY(ch.sWayPointRec)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Waypoint not set up")
SET_VEHICLE_ALONG_CARWASH_TRACK(veh, ch.cTrack, 0.0, ch.fForwardSpeed)
RETURN FALSE
ENDIF
IF NOT GET_IS_WAYPOINT_RECORDING_LOADED(ch.sWayPointRec)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Waypoint recording not loaded")
ENDIF
// need to turn off player control when in carwash
IF (g_bInMultiplayer)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Dis-Enabling Player Controls")
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE, SPC_ALLOW_PLAYER_DAMAGE)
IF NETWORK_HAS_CONTROL_OF_ENTITY(veh)
SET_VEHICLE_DOORS_LOCKED_FOR_ALL_PLAYERS(veh, TRUE)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Carwash Network Door Lock Activated")
ENDIF
ENDIF
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Spoiler Mod:", GET_VEHICLE_MOD(veh, MOD_SPOILER))
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Shutting Doors")
SET_VEHICLE_DOORS_SHUT(veh, FALSE)
CLEAR_PED_TASKS(ped)
SET_ENTITY_VELOCITY(veh, <<0, 0, 0>>)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Clear Ped Tasks and Set Car Velocity to Zero")
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Number of Car Seats:", GET_VEHICLE_MAX_NUMBER_OF_PASSENGERS(veh))
SEQUENCE_INDEX seqCarWash
ch.iTaskSequenceSize = 2
OPEN_SEQUENCE_TASK(seqCarWash)
IF iDelay > 0
TASK_STAND_STILL(NULL, iDelay)
ch.iTaskSequenceSize ++
ENDIF
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(NULL, veh, ch.sWayPointRec, DRIVINGMODE_PLOUGHTHROUGH, 0,
EWAYPOINT_NAVMESH_TO_INITIAL_WAYPOINT | EWAYPOINT_USE_TIGHTER_TURN_SETTINGS | EWAYPOINT_DO_NOT_RESPOND_TO_COLLISION_EVENTS,
-1, ch.fForwardSpeed, FALSE, 1.25)
TASK_STAND_STILL(NULL, 3000)
CLOSE_SEQUENCE_TASK(seqCarWash)
TASK_PERFORM_SEQUENCE(ped, seqCarWash)
CLEAR_SEQUENCE_TASK(seqCarWash)
VEHICLE_WAYPOINT_PLAYBACK_OVERRIDE_SPEED(veh, ch.fForwardSpeed)
iDriverCarwashSequenceProgress = -1
ch.bCarwashAborted = FALSE
PRINT_PLAYER_CAR_DIMENSIONS()
ADD_VEHICLE_STUCK_CHECK_WITH_WARP(veh,0.2,1000,FALSE,FALSE,FALSE,-1)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Adding stuck check")
IF NOT DECOR_EXIST_ON(veh, "Carwash_Vehicle_Decorator")
DECOR_SET_BOOL(veh, "Carwash_Vehicle_Decorator", TRUE)
CPRINTLN(DEBUG_MISSION, "[CARWASH] - Adding vehicle decorator")
ENDIF
START_CARWASH_TIMER(ch)
RETURN TRUE
ENDFUNC
FUNC BOOL IS_CARWASH_VEHICLE_STUCK(VEHICLE_INDEX vehPlayerCar)
IF NOT DOES_VEHICLE_HAVE_STUCK_VEHICLE_CHECK(vehPlayerCar)
RETURN FALSE
ENDIF
IF IS_VEHICLE_STUCK_TIMER_UP(vehPlayerCar,VEH_STUCK_ON_ROOF,5000)
OR IS_VEHICLE_STUCK_TIMER_UP(vehPlayerCar,VEH_STUCK_ON_SIDE, 5000)
OR IS_VEHICLE_STUCK_TIMER_UP(vehPlayerCar,VEH_STUCK_HUNG_UP, 5000)
OR IS_VEHICLE_STUCK_TIMER_UP(vehPlayerCar,VEH_STUCK_JAMMED, 5000)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Handle push block - stops vehicles from driving in
/// PARAMS:
/// ct - carwash track
/// veh - vehicle
/// blockRadius - block radius
FUNC FLOAT UPDATE_VEHICLE_THROUGH_CARWASH(CARWASH_HANDLER &ch, VEHICLE_INDEX veh, FLOAT startDirt)
// move car along and stop people dicking about with sun roof
VECTOR v
FLOAT r = GET_RATIO_OF_CLOSEST_POINT_ON_LINE(GET_ENTITY_COORDS(veh), ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], FALSE)
IF (r <= 1)
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), veh)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ROOF)
//DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MAP)
ENDIF
IF GET_PED_IN_VEHICLE_SEAT(veh) = PLAYER_PED_ID()
DISABLE_CONTROL_ACTIONS_FOR_CARWASH()
//DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_MAP)
ENDIF
IF NETWORK_HAS_CONTROL_OF_ENTITY(veh)
v = GET_CLOSEST_POINT_ON_LINE(GET_ENTITY_COORDS(veh), ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], FALSE)
IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(veh, v) < 4.0
IF (r > 0.0)
APPLY_CARWASH_WASH_TO_VEHICLE(veh, 0.005, startDirt * (1.0 - r))
ENDIF
ENDIF
ENDIF
ENDIF
// force collsion on rollers to be off
IF (NETWORK_IS_GAME_IN_PROGRESS() = FALSE)
UPDATE_COLLISIONS_FOR_CARWASH(ch, veh)
ENDIF
IF NETWORK_HAS_CONTROL_OF_ENTITY(veh)
IF r > 0.85 AND (NOT ch.bThrottleBoosted) AND ch.fBoostSpeed > 0.0
CPRINTLN(DEBUG_MISSION, "Setting new override speed: ", ch.fBoostSpeed)
VEHICLE_WAYPOINT_PLAYBACK_OVERRIDE_SPEED(veh, ch.fBoostSpeed)
ch.bThrottleBoosted = TRUE
ENDIF
ENDIF
RETURN r
ENDFUNC
PROC UPDATE_CARWASH_PARTS(CARWASH_HANDLER &ch)
BOOL update = TRUE
IF (g_bInMultiplayer)
update = IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
IF (update)
ch.iLastTimeUsed = GET_GAME_TIMER()
ENDIF
IF (update = FALSE) AND (ch.bOldUpdateCheck = TRUE)
//SCRIPT_ASSERT("NO ONE IS USING CARWASH ANYMORE")
CPRINTLN(DEBUG_MISSION, "[CARWASH] NO ONE IS USING CARWASH ANYMORE")
ch.vertRoller.fSpinRate = 0.0
ch.bTimerStarted = FALSE
ENDIF
ENDIF
IF (NETWORK_IS_GAME_IN_PROGRESS() AND bUseNewMPVertRollers)
UPDATE_CARWASH_VERTROLLER_MP(ch.vertRoller, update, ch.bCarwashAborted)
ELSE
UPDATE_CARWASH_VERTROLLER(ch.vertRoller, update, ch.bCarwashAborted)
ENDIF
IF (g_bInMultiplayer)
ch.bOldUpdateCheck = update
// don't bother to update if no one has used it for 0.5 seconds
IF (GET_GAME_TIMER() > ch.iLastTimeUsed + 1500)
ch.shapeTestID = NULL
ch.iBlockCounts = 0
EXIT
ENDIF
ENDIF
UPDATE_CARWASH_HROLLER(ch.horzRoller, update)
UPDATE_CARWASH_JETS(ch.waterJets, update)
UPDATE_CARWASH_JETS(ch.soapJets, update)
UPDATE_CARWASH_JETS(ch.steamJets, update)
ENDPROC
PROC SNAP_VEHICLE_TO_CARWASH_START(VEHICLE_INDEX veh, CARWASH_HANDLER &ch, BOOL bForceSnap = FALSE)
VECTOR fwd
IF IS_ENTITY_OK(veh)
ENABLE_CAMERA_STRUCT(ch.carwashCamera[0], ch.cameraID, ch.bTallVehicle, TRUE)
// snap car if angle between forward and carwash track is less than 60 degrees (cos(60) = 0.5)
fwd = GET_ENTITY_FORWARD_VECTOR(veh)
IF NOT IS_DIRECTION_WITHIN_DEGRESS_OF_DESIRED_DIRECTION(ch.cTrack.vDirection, fwd, AUTODRIVE_TOLERANCE) OR (bForceSnap = TRUE)
//IF (DOT_PRODUCT_XY(ch.cTrack.vDirection, fwd) < COS(60.0)) OR (bForceSnap = TRUE)
SET_ENTITY_COORDS_GROUNDED(veh, GET_CLOSEST_POINT_ON_LINE(GET_ENTITY_COORDS(veh), ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], FALSE) + <<0, 0, 0.1>>)
SET_ENTITY_HEADING(veh, ch.cTrack.fTrackHeading)
SET_VEHICLE_ON_GROUND_PROPERLY(veh)
SET_VEHICLE_FORWARD_SPEED(veh, 0.0)
ENDIF
SET_VEHICLE_DOORS_SHUT(veh, FALSE)
ch.iCurrentCameraState = 0
ch.bIsAllowedInMP = FALSE
ch.shapeTestID = NULL
ch.iBlockCounts = 0
// B*1439838 - only the machine who owns this can call this
IF (g_bInMultiplayer)
IF NOT NETWORK_HAS_CONTROL_OF_ENTITY(veh)
EXIT
ENDIF
ENDIF
SET_CARWASH_CAR_LOCK_STATE(veh, VEHICLELOCK_LOCKED)
IF IS_VEHICLE_A_CONVERTIBLE(veh, FALSE)
RAISE_CONVERTIBLE_ROOF(veh, FALSE)
ENDIF
ENDIF
ENDPROC
PROC SHUTDOWN_CARWASH_CAMERA(CAMERA_INDEX cameraID, BOOL bForce = FALSE)
VEHICLE_INDEX ind
IF DOES_CAM_EXIST(cameraID)
SHUTDOWN_CAMERA(cameraID)
DUMMY_REFERENCE_BOOL(bForce)
SET_EVERYONE_IGNORE_PLAYER(PLAYER_ID(), FALSE)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Carwash Camera ShutDown - ", bForce)
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
ind = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
IF IS_ENTITY_OK(ind)
IF NOT IS_VEHICLE_A_PERSONAL_VEHICLE(ind)
IF GET_PED_IN_VEHICLE_SEAT(ind) = PLAYER_PED_ID()
SET_CARWASH_CAR_LOCK_STATE(ind, VEHICLELOCK_UNLOCKED)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Carwash car doors unlocked")
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
FUNC BOOL IS_THERE_A_VEHICLE_IN_FRONT(VEHICLE_INDEX veh)
VECTOR checkpoint
VECTOR dmin, dmax
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(veh), dmin, dmax)
checkPoint = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(veh, <<0, dmax.y + 0.325, 0>>)
//DRAW_DEBUG_SPHERE(checkPoint, 0.0625)
//DRAW_DEBUG_LINE(checkPoint, checkPoint + <<0, 0, 10>>)
RETURN IS_POSITION_OCCUPIED(checkPoint, 0.75, FALSE, TRUE, FALSE, FALSE, TRUE, veh)
ENDFUNC
FUNC BOOL IS_THERE_A_VEHICLE_IN_FRONT_SHAPETEST(CARWASH_HANDLER &ch, VEHICLE_INDEX veh)
IF (GET_GAME_TIMER() < ch.iNextBlockCheckTime)
RETURN FALSE
ENDIF
INT iHits
VECTOR checkpoint
VECTOR dmin, dmax
VECTOR vHitPos, vHitNormal
SHAPETEST_STATUS shapeStatus
ENTITY_INDEX hitEntity
IF (ch.shapeTestID = NULL)
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(veh), dmin, dmax)
IF (ch.bBackInterruptCheck = FALSE)
checkPoint = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(veh, <<0, dmax.y + 0.325, 0>>)
ELSE
checkPoint = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(veh, <<0, dmin.y - 0.325, 0>>)
ENDIF
/*
// flip this - not sure if i can do variable = ! variable in this
IF (ch.bBackInterruptCheck)
ch.bBackInterruptCheck = FALSE
ELSE
ch.bBackInterruptCheck = TRUE
ENDIF
*/
IF (g_bInMultiplayer)
ch.shapeTestID = START_SHAPE_TEST_CAPSULE(checkPoint - <<0, 0, 0.1>>, checkPoint + <<0, 0, 0.1>>, 0.75, SCRIPT_INCLUDE_VEHICLE | SCRIPT_INCLUDE_OBJECT, veh)
ELSE
ch.shapeTestID = START_SHAPE_TEST_CAPSULE(checkPoint - <<0, 0, 0.1>>, checkPoint + <<0, 0, 0.1>>, 0.75, SCRIPT_INCLUDE_VEHICLE, veh)
ENDIF
RETURN FALSE
ELSE
shapeStatus = GET_SHAPE_TEST_RESULT(ch.shapeTestID, iHits, vHitPos, vHitNormal, hitEntity)
IF (shapeStatus = SHAPETEST_STATUS_RESULTS_READY)
IF DOES_ENTITY_EXIST(hitEntity)
IF CAN_THIS_ENTITY_BLOCK_THE_CARWASH(hitEntity)
ch.iBlockCounts ++
RETURN TRUE
ELSE
ch.iBlockCounts = 0
ENDIF
ENDIF
ENDIF
ch.iNextBlockCheckTime = GET_GAME_TIMER() + 500
ch.shapeTestID = NULL
ENDIF
RETURN FALSE
ENDFUNC
FUNC FLOAT GET_CURRENT_RATIO_FOR_VEHICLE_IN_CARWASH(CARWASH_HANDLER &ch, VEHICLE_INDEX veh)
IF NOT IS_ENTITY_ALIVE(veh)
RETURN 0.0
ENDIF
RETURN GET_RATIO_OF_CLOSEST_POINT_ON_LINE(GET_ENTITY_COORDS(veh), ch.cTrack.vBlockPoint[0], ch.cTrack.vBlockPoint[1], FALSE)
ENDFUNC
PROC EMERGENCY_ABORT_CARWASH(CARWASH_HANDLER &ch, VEHICLE_INDEX veh = NULL)
//SCRIPT_ASSERT("EMERGENCY CARWASH ABORT!!")
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Emergency Carwash Terminate")
ch.iCurrentCameraState = CAMERASTATE_ALLDONE
RESET_COLLISIONS_FOR_CARWASH(ch)
STOP_ALL_CARWASH_SOUNDS(ch)
STOP_ALL_CARWASH_PARTICLES(ch)
SHUTDOWN_CARWASH_CAMERA(ch.cameraID, TRUE)
SET_NET_PED_DRIVING_CARWASH_STATUS(PLAYER_PED_ID(), FALSE)
DELETE_CARWASH_JETS(ch.waterJets)
DELETE_CARWASH_JETS(ch.soapJets)
DELETE_CARWASH_JETS(ch.steamJets)
SET_EVERYONE_IGNORE_PLAYER(PLAYER_ID(), FALSE)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Re-Enabling Player Controls")
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
IF (g_bInMultiplayer)
PLAYER_INDEX player = NETWORK_GET_PLAYER_INDEX_FROM_PED(PLAYER_PED_ID())
IF (player != INVALID_PLAYER_INDEX())
IF (GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = TRUE)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Setting player to net be in carwash")
GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = FALSE
ENDIF
ENDIF
ENDIF
IF DOES_ENTITY_EXIST(veh)
SET_CARWASH_CAR_LOCK_STATE(veh, VEHICLELOCK_UNLOCKED)
REMOVE_CARWASH_STUCK_CHECK(veh)
IF NETWORK_IS_GAME_IN_PROGRESS()
IF NETWORK_HAS_CONTROL_OF_ENTITY(veh)
SET_VEHICLE_DOORS_LOCKED_FOR_ALL_PLAYERS(veh, FALSE)
ENDIF
ENDIF
ENDIF
SET_PED_PATHS_BACK_TO_ORIGINAL(ch.vNoPedWalkMin, ch.vNoPedWalkMax)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Unblocking ped area:", ch.vNoPedWalkMin, " ", ch.vNoPedWalkMax)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Carwash car doors unlocked")
ch.shapeTestID = NULL
ch.iBlockCounts = 0
ch.bCarwashAborted = TRUE
ch.bTimerStarted = FALSE
//SET_VEHICLE_AND_OCCUPANTS_INVINCIBLE(veh, FALSE)
IF IS_AUDIO_SCENE_ACTIVE("CAR_WASH_SCENE")
CPRINTLN(DEBUG_MISSION, "Carwash Stop Audio Scene")
STOP_AUDIO_SCENE("CAR_WASH_SCENE")
ENDIF
ENDPROC
FUNC BOOL IS_PED_RUNNING_TASK_OR_HAS_FINISHED(PED_INDEX ped, SCRIPT_TASK_NAME task)
IF (GET_SCRIPT_TASK_STATUS(ped, task) = PERFORMING_TASK)
RETURN TRUE
ENDIF
IF (GET_SCRIPT_TASK_STATUS(ped, task) = WAITING_TO_START_TASK)
RETURN TRUE
ENDIF
RETURN (GET_SCRIPT_TASK_STATUS(ped, task) = FINISHED_TASK)
ENDFUNC
PROC SHUT_CARWASH_VEHICLE_DOORS(VEHICLE_INDEX veh)
IF NETWORK_IS_GAME_IN_PROGRESS()
IF NETWORK_HAS_CONTROL_OF_ENTITY(veh)
SET_VEHICLE_DOORS_SHUT(veh, TRUE)
ENDIF
EXIT
ENDIF
SET_VEHICLE_DOORS_SHUT(veh, TRUE)
ENDPROC
FUNC BOOL UPDATE_CARWASH_HANDLER_CAMERAS(CARWASH_HANDLER &ch, VEHICLE_INDEX veh)
PED_INDEX driver
FLOAT fRatio = GET_CURRENT_RATIO_FOR_VEHICLE_IN_CARWASH(ch, veh)
BOOL bAbort = FALSE
BOOL bAbortLastCamera = FALSE
#IF IS_DEBUG_BUILD
fCarDebugRatio = fRatio
iDebugCarWashTimer = GET_CARWASH_TIMER_ELAPSED(ch)
#ENDIF
IF NOT IS_ENTITY_OK(veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Emergency Carwash Terminate - Vehicle Is Not OK")
EMERGENCY_ABORT_CARWASH(ch, veh)
RETURN TRUE
ENDIF
// B*1926983 - Car Wash animation stops when player enters Xbox Store and then backing out
// Reset the timer if the player is in the xbox store or the game will bust out
IF NETWORK_IS_GAME_IN_PROGRESS()
IF IS_COMMERCE_STORE_OPEN()
START_CARWASH_TIMER(ch)
ENDIF
ENDIF
IF IS_PAUSE_MENU_ACTIVE()
START_CARWASH_TIMER(ch)
ENDIF
// update carwash tasks
driver = GET_PED_IN_VEHICLE_SEAT(veh)
IF IS_CARWASH_PED_OK(driver)
bIsDriverRunningCarwashSequence = ((GET_SCRIPT_TASK_STATUS(driver, SCRIPT_TASK_PERFORM_SEQUENCE) = PERFORMING_TASK) OR (GET_SCRIPT_TASK_STATUS(driver, SCRIPT_TASK_PERFORM_SEQUENCE) = WAITING_TO_START_TASK))
IF (bIsDriverRunningCarwashSequence)
iDriverCarwashSequenceProgress = GET_SEQUENCE_PROGRESS(driver)
bIsDriverFinishedCarwashSequence = (GET_SCRIPT_TASK_STATUS(driver, SCRIPT_TASK_PERFORM_SEQUENCE) = FINISHED_TASK) AND (iDriverCarwashSequenceProgress = (ch.iTaskSequenceSize - 1))
ENDIF
IF (bDebugForceClearPedTasks)
CPRINTLN(DEBUG_MISSION, "[CARWASH] DEBUG - FORCE CLEAR PED TASKS")
IF IS_PED_IN_ANY_VEHICLE(driver)
TASK_LEAVE_ANY_VEHICLE(driver)
ENDIF
//CLEAR_PED_TASKS(driver)
bDebugForceClearPedTasks = FALSE
ENDIF
IF (bDebugForceRestartTasks)
RESTART_CARWASH_VEHICLE_TASK(veh, ch)
CPRINTLN(DEBUG_MISSION, "[CARWASH] DEBUG - FORCE RESTART TASKS")
bDebugForceRestartTasks = FALSE
ENDIF
ENDIF
#IF IS_DEBUG_BUILD
IF bDrawDebugCarwash
DRAW_DEBUG_SPHERE(INTERPOLATE_VECTOR(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], fBlockCarPlaceT, FALSE), 0.0625)
ENDIF
IF (bCreateBlockCar)
CREATE_VEHICLE(GET_ENTITY_MODEL(veh), INTERPOLATE_VECTOR(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], fBlockCarPlaceT, FALSE), ch.cTrack.fTrackHeading, FALSE)
bCreateBlockCar = FALSE
ENDIF
#ENDIF
// abort if driver is killed
IF (g_bInMultiplayer)
IF IS_PLAYER_ON_MP_AMBIENT_SCRIPT(PLAYER_ID(), MPAM_TYPE_TIME_TRIAL)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Aborting as Driver is part of Time Trial")
bAbort = TRUE
ENDIF
IF IS_PLAYER_ON_MP_AMBIENT_SCRIPT(PLAYER_ID(), MPAM_TYPE_RC_TIME_TRIAL)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Aborting as Driver is part of RC Time Trial")
bAbort = TRUE
ENDIF
IF NOT IS_CARWASH_PED_OK(driver)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Aborting as Driver is dead")
bAbort = TRUE
ENDIF
IF IS_PED_IN_VEHICLE(driver, veh, FALSE)
IF NOT IS_PED_SITTING_IN_VEHICLE(driver, veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: ABORT! - Driver is has fallen out of car")
bAbort = TRUE
ENDIF
ENDIF
IF NOT IS_PED_IN_CAR_WITH_CARWASH_DRIVER(PLAYER_PED_ID())
CPRINTLN(DEBUG_MISSION, "[CARWASH]: As Ped isn't in carwash car")
bAbort = TRUE
ENDIF
/*
ELIF (NOT IS_STRING_NULL_OR_EMPTY(ch.sWayPointRec))
IF NOT IS_PED_RUNNING_TASK_OR_HAS_FINISHED(driver, SCRIPT_TASK_PERFORM_SEQUENCE) AND (ch.iCurrentCameraState >= 1)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: As Ped driving abandonded task")
bAbort = TRUE
ENDIF
*/
IF ARE_VEHICLE_TYRES_BURST(veh, 3)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: At least 3 tyres are burst - Car will probably not make it through - Emergency Exit")
bAbort = TRUE
ENDIF
IF NOT IS_ANY_NET_PLAYER_DRIVING_IN_CARWASH()
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Emergency Exit - No one at all are using carwash anymore")
bAbort = TRUE
ENDIF
IF IS_PED_BEING_JACKED(driver)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Aborting as Driver is being jacked")
bAbort = TRUE
ENDIF
IF IS_CARWASH_VEHICLE_STUCK(veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Emergency Exit - Carwash car is stuck")
bAbort = TRUE
ENDIF
IF HAS_ABORT_TIME_EXPIRED(ch)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Carwash has taken too long to finish something has gone wrong - Emergency Exit")
EMERGENCY_ABORT_CARWASH(ch, veh)
RETURN TRUE
ENDIF
IF (bAbort = TRUE)
EMERGENCY_ABORT_CARWASH(ch, veh)
RETURN TRUE
ENDIF
IF NOT NETWORK_HAS_CONTROL_OF_ENTITY(veh)
NETWORK_USE_LOGARITHMIC_BLENDING_THIS_FRAME(veh)
ENDIF
ELSE
IF HAS_ABORT_TIME_EXPIRED(ch) AND (ch.bSkipped = FALSE)
SAFE_FADE_SCREEN_OUT_TO_BLACK(500, TRUE)
APPLY_CARWASH_WASH_TO_VEHICLE(veh, 100.0, 0.0)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Carwash has taken too long - Emergency Exit SP - Fade to End")
ch.bSkipped = TRUE
RETURN TRUE
ENDIF
ENDIF
// check if task has been aborted
IF (driver = PLAYER_PED_ID())
IF (NOT bIsDriverRunningCarwashSequence) AND ((iDriverCarwashSequenceProgress > -1) AND (iDriverCarwashSequenceProgress < ch.iTaskSequenceSize))
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Emergency - task has aborted improperly")
RESTART_CARWASH_VEHICLE_TASK(veh, ch)
ENDIF
IF (bIsDriverFinishedCarwashSequence)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Sequence Finished")
ENDIF
ENDIF
IF IS_THERE_A_VEHICLE_IN_FRONT_SHAPETEST(ch, veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Someone has tried to drive in - abort")
EMERGENCY_ABORT_CARWASH(ch, veh)
RETURN TRUE
ENDIF
IF (ch.iCurrentCameraState <> CAMERASTATE_ALLDONE)
DISABLE_CELLPHONE_THIS_FRAME_ONLY()
SET_EVERYONE_IGNORE_PLAYER(PLAYER_ID(), TRUE)
IF (ch.iCurrentCameraState > 0)
HIDE_HUD_AND_RADAR_THIS_FRAME()
IF (GET_BUILDING_STATE(ch.iplSwap) != BUILDINGSTATE_DESTROYED)
SET_BUILDING_STATE(ch.iplSwap, BUILDINGSTATE_DESTROYED)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: The IPL hasn't been swapped for some reason - Swap it back")
ENDIF
ENDIF
ENDIF
SWITCH (ch.iCurrentCameraState)
CASE 0
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching To Camera 0 - Ratio", fRatio)
CLEAR_CYLINDER_OF_FIRE(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], 3.0, NOT g_bInMultiplayer)
SET_PED_PATHS_IN_AREA(ch.vNoPedWalkMin, ch.vNoPedWalkMax, FALSE)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Blocking ped area:", ch.vNoPedWalkMin, " ", ch.vNoPedWalkMax)
IF GET_BUILDING_STATE(ch.iplSwap) <> BUILDINGSTATE_DESTROYED
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Building Swap didn't happen properly?")
SET_BUILDING_STATE(ch.iplSwap, BUILDINGSTATE_DESTROYED)
ENDIF
ENABLE_CAMERA_STRUCT(ch.carwashCamera[0], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_CUBIC_EASE_IN_OUT, GRAPH_TYPE_CUBIC_EASE_IN_OUT)
START_CARWASH_TIMER(ch)
IF NOT g_bInMultiplayer
CLEAR_AREA_OF_PEDS(GET_PLAYER_COORDS(GET_PLAYER_INDEX()), 50.0)
ENDIF
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Carwash car doors locked")
//SET_VEHICLE_AND_OCCUPANTS_INVINCIBLE(veh)
ch.iCurrentCameraState ++
IF NOT IS_AUDIO_SCENE_ACTIVE("CAR_WASH_SCENE")
START_AUDIO_SCENE("CAR_WASH_SCENE")
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Carwash Start Audio Scene")
ENDIF
IF NOT g_bInMultiplayer
SET_ENTITY_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), ch.cTrack.vVehicleSnapPoint)
SET_ENTITY_HEADING(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), ch.cTrack.fTrackHeading)
IF IS_VEHICLE_A_CONVERTIBLE(veh, FALSE)
RAISE_CONVERTIBLE_ROOF(veh, TRUE)
ENDIF
SET_CARWASH_CAR_LOCK_STATE(veh, VEHICLELOCK_LOCKED)
//PRINT_HELP("CWASH_SKIPRIDE")
ELSE
// B*1439838 - only the machine who owns this can call this
IF NETWORK_HAS_CONTROL_OF_ENTITY(veh)
SET_CARWASH_CAR_LOCK_STATE(veh, VEHICLELOCK_CANNOT_ENTER)
IF IS_VEHICLE_A_CONVERTIBLE(veh, FALSE)
RAISE_CONVERTIBLE_ROOF(veh, FALSE)
ENDIF
ENDIF
ENDIF
BREAK
CASE 1
IF HAS_CAMERA_STRUCT_FINISHED_INTERPOLATING(ch.carwashCamera[0], fRatio)
CLEAR_CYLINDER_OF_FIRE(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], 3.0, NOT g_bInMultiplayer)
ENABLE_CAMERA_STRUCT(ch.carwashCamera[1], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_LINEAR)
SHUT_CARWASH_VEHICLE_DOORS(veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 1 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed:", GET_CARWASH_TIMER_ELAPSED(ch))
START_CARWASH_TIMER(ch)
ch.iCurrentCameraState ++
ENDIF
BREAK
CASE 2
IF HAS_CAMERA_STRUCT_FINISHED_INTERPOLATING(ch.carwashCamera[1], fRatio)
CLEAR_CYLINDER_OF_FIRE(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], 3.0, NOT g_bInMultiplayer)
IF (ch.carWashCamera[2].bSetup)
ENABLE_CAMERA_STRUCT(ch.carwashCamera[2], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_LINEAR)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 2 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed:", GET_CARWASH_TIMER_ELAPSED(ch))
ch.iCurrentCameraState ++
ELSE
ENABLE_CAMERA_STRUCT(ch.carwashCamera[6], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_LINEAR)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 6 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed;", GET_CARWASH_TIMER_ELAPSED(ch))
APPLY_CARWASH_WASH_TO_VEHICLE(veh, 50.0, 0.0)
ch.iCurrentCameraState = CAMERASTATE_LASTCAMERA
ENDIF
SHUT_CARWASH_VEHICLE_DOORS(veh)
START_CARWASH_TIMER(ch)
ENDIF
BREAK
CASE 3
IF HAS_CAMERA_STRUCT_FINISHED_INTERPOLATING(ch.carwashCamera[2], fRatio)
CLEAR_CYLINDER_OF_FIRE(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], 3.0, NOT g_bInMultiplayer)
IF (ch.carWashCamera[3].bSetup)
ENABLE_CAMERA_STRUCT(ch.carwashCamera[3], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_LINEAR)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 3 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed;", GET_CARWASH_TIMER_ELAPSED(ch))
ch.iCurrentCameraState ++
ELSE
ENABLE_CAMERA_STRUCT(ch.carwashCamera[6], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_LINEAR)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 6 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed;", GET_CARWASH_TIMER_ELAPSED(ch))
APPLY_CARWASH_WASH_TO_VEHICLE(veh, 50.0, 0.0)
ch.iCurrentCameraState = CAMERASTATE_LASTCAMERA
ENDIF
SHUT_CARWASH_VEHICLE_DOORS(veh)
START_CARWASH_TIMER(ch)
ENDIF
BREAK
CASE 4
IF HAS_CAMERA_STRUCT_FINISHED_INTERPOLATING(ch.carwashCamera[3], fRatio)
CLEAR_CYLINDER_OF_FIRE(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], 3.0, NOT g_bInMultiplayer)
IF (ch.carWashCamera[4].bSetup)
ENABLE_CAMERA_STRUCT(ch.carwashCamera[4], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_LINEAR)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 4 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed;", GET_CARWASH_TIMER_ELAPSED(ch))
ch.iCurrentCameraState ++
ELSE
ENABLE_CAMERA_STRUCT(ch.carwashCamera[6], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_LINEAR)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 6 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed:", GET_CARWASH_TIMER_ELAPSED(ch))
APPLY_CARWASH_WASH_TO_VEHICLE(veh, 50.0, 0.0)
ch.iCurrentCameraState = CAMERASTATE_LASTCAMERA
ENDIF
SHUT_CARWASH_VEHICLE_DOORS(veh)
START_CARWASH_TIMER(ch)
ENDIF
BREAK
CASE 5
IF HAS_CAMERA_STRUCT_FINISHED_INTERPOLATING(ch.carwashCamera[4], fRatio)
CLEAR_CYLINDER_OF_FIRE(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], 3.0, NOT g_bInMultiplayer)
IF (ch.carWashCamera[5].bSetup)
ENABLE_CAMERA_STRUCT(ch.carwashCamera[5], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_LINEAR)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 5 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed:", GET_CARWASH_TIMER_ELAPSED(ch))
ch.iCurrentCameraState ++
ELSE
ENABLE_CAMERA_STRUCT(ch.carwashCamera[6], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_LINEAR)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 6 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed:", GET_CARWASH_TIMER_ELAPSED(ch))
APPLY_CARWASH_WASH_TO_VEHICLE(veh, 50.0, 0.0)
ch.iCurrentCameraState = CAMERASTATE_LASTCAMERA
ENDIF
SHUT_CARWASH_VEHICLE_DOORS(veh)
START_CARWASH_TIMER(ch)
ENDIF
BREAK
CASE 6
IF HAS_CAMERA_STRUCT_FINISHED_INTERPOLATING(ch.carwashCamera[5], fRatio) AND (fRatio >= ch.fFinalCameraInterpolate)
CLEAR_CYLINDER_OF_FIRE(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], 3.0, NOT g_bInMultiplayer)
IF NOT IS_POSITION_OCCUPIED(ch.carwashCamera[6].vPosition[0], 2.0, FALSE, TRUE, FALSE, FALSE, FALSE, veh)
ENABLE_CAMERA_STRUCT(ch.carwashCamera[6], ch.cameraID, ch.bTallVehicle, FALSE, GRAPH_TYPE_DECEL)
ENDIF
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Switching to Camera 6 - Car Ratio:", fRatio)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed:", GET_CARWASH_TIMER_ELAPSED(ch))
APPLY_CARWASH_WASH_TO_VEHICLE(veh, 100.0, 0.0)
IF NOT g_bInMultiplayer
//REMOVE_DECALS_FROM_VEHICLE(veh)
ENDIF
ch.iCurrentCameraState = CAMERASTATE_LASTCAMERA
SHUT_CARWASH_VEHICLE_DOORS(veh)
START_CARWASH_TIMER(ch)
ENDIF
BREAK
CASE CAMERASTATE_LASTCAMERA
IF IS_POSITION_OCCUPIED(ch.carwashCamera[6].vPosition[0], 2.0, FALSE, TRUE, FALSE, FALSE, FALSE, veh)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Car in the way of last camera")
bAbortLastCamera = TRUE
ENDIF
IF HAS_CAMERA_STRUCT_FINISHED_INTERPOLATING(ch.carwashCamera[6], fRatio) OR (bAbortLastCamera)
CPRINTLN(DEBUG_MISSION, "Carwash Finished")
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Time Elapsed:", GET_CARWASH_TIMER_ELAPSED(ch))
CLEAR_CYLINDER_OF_FIRE(ch.cTrack.vTrackPoint[0], ch.cTrack.vTrackPoint[1], 3.0, NOT g_bInMultiplayer)
SHUTDOWN_CARWASH_CAMERA(ch.cameraID, FALSE)
IF IS_AUDIO_SCENE_ACTIVE("CAR_WASH_SCENE")
STOP_AUDIO_SCENE("CAR_WASH_SCENE")
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Carwash Stop Audio Scene")
ENDIF
IF IS_PED_IN_CAR_WITH_CARWASH_DRIVER(PLAYER_PED_ID())
CLEAR_PED_TASKS(PLAYER_PED_ID())
ENDIF
FORCE_CLEAR_NET_PED_DRIVING_CARWASH_STATUS(PLAYER_PED_ID())
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Re-Enabling Player Controls")
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
//SET_VEHICLE_AND_OCCUPANTS_INVINCIBLE(veh, FALSE)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Carwash is complete")
ch.iCurrentCameraState = CAMERASTATE_ALLDONE
ch.shapeTestID = NULL
ch.iBlockCounts = 0
bIsDriverFinishedCarwashSequence = FALSE
bIsDriverRunningCarwashSequence = FALSE
iDriverCarwashSequenceProgress = -1
SET_EVERYONE_IGNORE_PLAYER(PLAYER_ID(), FALSE)
APPLY_CARWASH_WASH_TO_VEHICLE(veh, 100.0, 0.0)
REMOVE_CARWASH_STUCK_CHECK(veh)
IF NOT g_bInMultiplayer
//REMOVE_DECALS_FROM_VEHICLE(veh)
ENDIF
SET_CARWASH_CAR_LOCK_STATE(veh, VEHICLELOCK_UNLOCKED)
SET_PED_PATHS_BACK_TO_ORIGINAL(ch.vNoPedWalkMin, ch.vNoPedWalkMax)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Unblocking ped area:", ch.vNoPedWalkMin, " ", ch.vNoPedWalkMax)
CPRINTLN(DEBUG_MISSION, "[CARWASH]:Carwash car doors unlocked")
REGISTER_SCRIPT_IN_COMPLETION_PERCENTAGE_TOTAL(CP_CARWSH)
RETURN TRUE
ELSE
HIDE_HUD_AND_RADAR_THIS_FRAME()
ENDIF
BREAK
CASE CAMERASTATE_ALLDONE
IF IS_AUDIO_SCENE_ACTIVE("CAR_WASH_SCENE")
CPRINTLN(DEBUG_MISSION, "Carwash Stop Audio Scene")
STOP_AUDIO_SCENE("CAR_WASH_SCENE")
ENDIF
SHUTDOWN_CARWASH_CAMERA(ch.cameraID, FALSE)
ch.shapeTestID = NULL
ch.iBlockCounts = 0
ch.bTimerStarted = FALSE
bIsDriverFinishedCarwashSequence = FALSE
bIsDriverRunningCarwashSequence = FALSE
iDriverCarwashSequenceProgress = -1
BREAK
ENDSWITCH
RETURN FALSE
ENDFUNC
PROC DELETE_CARWASH_HANDLER(CARWASH_HANDLER &ch)
VEHICLE_INDEX ind
IF NOT NETWORK_IS_GAME_IN_PROGRESS()
RC_END_CUTSCENE_MODE()
ENDIF
CPRINTLN(DEBUG_MISSION, "Delete Carwash")
FORCE_CLEAR_NET_PED_DRIVING_CARWASH_STATUS(PLAYER_PED_ID())
DISABLE_CELLPHONE(FALSE)
ch.shapeTestID = NULL
ch.iBlockCounts = 0
RESET_COLLISIONS_FOR_CARWASH(ch)
STOP_ALL_CARWASH_SOUNDS(ch)
STOP_ALL_CARWASH_PARTICLES(ch)
DELETE_CARWASH_VERTROLLER(ch.vertRoller)
DELETE_CARWASH_HROLLER(ch.horzRoller)
DELETE_CARWASH_JETS(ch.waterJets)
DELETE_CARWASH_JETS(ch.soapJets)
DELETE_CARWASH_JETS(ch.steamJets)
SET_BUILDING_STATE(ch.iplSwap, BUILDINGSTATE_NORMAL)
SHUTDOWN_CAMERA(ch.cameraID)
IF IS_AUDIO_SCENE_ACTIVE("CAR_WASH_SCENE")
CPRINTLN(DEBUG_MISSION, "Carwash Stop Audio Scene")
STOP_AUDIO_SCENE("CAR_WASH_SCENE")
ENDIF
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
IS_ENTITY_DEAD(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
ind = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
IF IS_ENTITY_OK(ind)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Unlocking Car")
SET_CARWASH_CAR_LOCK_STATE(ind, VEHICLELOCK_UNLOCKED)
REMOVE_CARWASH_STUCK_CHECK(ind)
ENDIF
ENDIF
ENDIF
IF (g_bInMultiplayer)
PLAYER_INDEX player = NETWORK_GET_PLAYER_INDEX_FROM_PED(PLAYER_PED_ID())
IF (player != INVALID_PLAYER_INDEX())
IF (GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = TRUE)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Setting player to net be in carwash")
GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = FALSE
ENDIF
ENDIF
ENDIF
ind = GET_PLAYERS_LAST_VEHICLE()
IF IS_ENTITY_OK(ind)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Unlocking Players Last Vehicle")
SET_CARWASH_CAR_LOCK_STATE(ind, VEHICLELOCK_UNLOCKED)
REMOVE_CARWASH_STUCK_CHECK(ind)
ENDIF
SET_PED_PATHS_BACK_TO_ORIGINAL(ch.vNoPedWalkMin, ch.vNoPedWalkMax)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Unblocking ped area:", ch.vNoPedWalkMin, " ", ch.vNoPedWalkMax)
// Enable car wash scenarios
SET_SCENARIO_TYPE_ENABLED("DRIVE", TRUE)
SET_SCENARIO_TYPE_ENABLED("WORLD_VEHICLE_DRIVE_SOLO", TRUE)
ENDPROC
PROC SHARED_CARWASH_SCRIPT_CLEANUP(CARWASH_HANDLER &ch, BOOL bSkip = FALSE)
VECTOR v
DELETE_CARWASH_HANDLER(ch)
IF (g_bInMultiplayer)
PLAYER_INDEX player = NETWORK_GET_PLAYER_INDEX_FROM_PED(PLAYER_PED_ID())
IF (player != INVALID_PLAYER_INDEX())
IF (GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = TRUE)
CPRINTLN(DEBUG_MISSION, "[CARWASH]: Setting player to net be in carwash")
GlobalPlayerBD[NATIVE_TO_INT(player)].bDrivingThroughCarwash = FALSE
ENDIF
ENDIF
ENDIF
// B*1331838 - Player wasn't being charged on skip
IF (bSkip = TRUE)
CLEAR_PED_TASKS(PLAYER_PED_ID())
SET_VEHICLE_ALONG_CARWASH_TRACK(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), ch.cTrack, 1.0, 0.0)
SET_VEHICLE_ON_GROUND_PROPERLY(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
SET_ENTITY_VELOCITY(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), <<0, 0, 0>>)
WAIT(0)
IS_CARWASH_PED_OK(PLAYER_PED_ID())
v = GET_ENTITY_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
v.z = INVALID_WORLD_Z
SET_ENTITY_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), v)
APPLY_CARWASH_WASH_TO_VEHICLE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), 500.0, 0.0)
SET_CARWASH_CAR_LOCK_STATE(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VEHICLELOCK_UNLOCKED)
WAIT(125)
DO_SCREEN_FADE_IN(500)
WAIT(1000)
REGISTER_SCRIPT_IN_COMPLETION_PERCENTAGE_TOTAL(CP_CARWSH)
CHARGE_PLAYER_FOR_CARWASH(ch.iLocationID)
ELIF NOT NETWORK_IS_GAME_IN_PROGRESS()
CLEAR_PED_TASKS(PLAYER_PED_ID())
ENDIF
IF NOT (g_bInMultiplayer)
REACTIVATE_NAMED_WORLD_BRAINS_WAITING_TILL_OUT_OF_RANGE("launcher_CarWash")
ENDIF
ENDPROC
/// PURPOSE:
/// Gets bank balance of current player
/// RETURNS:
///
FUNC INT GET_CARWASH_CURRENT_PLAYER_PED_ACCOUNT_BALANCE()
IF NETWORK_IS_GAME_IN_PROGRESS()
RETURN NETWORK_GET_VC_BALANCE()
ENDIF
RETURN GET_TOTAL_CASH(GET_CURRENT_PLAYER_PED_ENUM())
ENDFUNC
FUNC BOOL DO_WE_HAVE_ENOUGH_MONEY_FOR(INT iCost)
IF NETWORK_IS_GAME_IN_PROGRESS()
RETURN NETWORK_GET_CAN_SPEND_FROM_BANK_AND_WALLET(iCost)
ENDIF
RETURN (GET_TOTAL_CASH(GET_CURRENT_PLAYER_PED_ENUM()) >= iCost)
ENDFUNC
FUNC BOOL AM_I_DRIVING_CLOSEST_CAR_TO_CARWASH(COST_HALO& halo, VEHICLE_INDEX &vehOut)
INT iCount, i
INT iCar = -1
FLOAT fDist, fMinDist = 1.0
VEHICLE_INDEX array[32]
IF NOT NETWORK_IS_GAME_IN_PROGRESS()
RETURN TRUE
ENDIF
IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
RETURN FALSE
ENDIF
iCount = GET_PED_NEARBY_VEHICLES(PLAYER_PED_ID(), array)
REPEAT iCount i
IF IS_ENTITY_OK(array[i])
fDist = GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(array[i], halo.vTriggerPoint)
IF (fDist < fMinDist) OR (fMinDist = -1.0)
fMinDist = fDist
iCar = i
ENDIF
ENDIF
ENDREPEAT
//CPRINTLN(DEBUG_MISSION, "[CARWASH] - CDM:iCar = ", iCar)
IF (iCar = -1)
//DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.2, "STRING", "NO CAR")
RETURN FALSE
ENDIF
//CPRINTLN(DEBUG_MISSION, "[CARWASH] - CDM: driver = ", (GET_PED_IN_VEHICLE_SEAT(array[iCar]) != PLAYER_PED_ID()))
IF (GET_PED_IN_VEHICLE_SEAT(array[iCar]) != PLAYER_PED_ID())
RETURN FALSE
//DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.2, "STRING", "NOT DRIVING CAR")
ENDIF
vehOut = array[iCar]
RETURN TRUE
ENDFUNC
FUNC INT COUNT_NUMBER_OF_CARS_IN_CARWASH_HALO(COST_HALO& halo)
INT iCount, i
VEHICLE_INDEX array[32]
FLOAT fDist
INT iCarCount
iCount = GET_PED_NEARBY_VEHICLES(PLAYER_PED_ID(), array)
REPEAT iCount i
IF IS_ENTITY_OK(array[i])
fDist = GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(array[i], halo.vTriggerPoint)
IF (fDist <= (halo.fTriggerDist * 2.5))
iCarCount ++
ENDIF
ENDIF
ENDREPEAT
RETURN iCarCount
ENDFUNC
FUNC BOOL CAN_PLAYER_TRIGGER_CARWASH_HALO_IN_CAR(COST_HALO& halo)
VEHICLE_INDEX array[32]
INT iCount, i
INT iCar = -1
FLOAT fDist, fMinDist = 1.0
IF NOT NETWORK_IS_GAME_IN_PROGRESS()
RETURN TRUE
ENDIF
iCount = GET_PED_NEARBY_VEHICLES(PLAYER_PED_ID(), array)
REPEAT iCount i
IF IS_ENTITY_OK(array[i])
fDist = GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(array[i], halo.vTriggerPoint)
IF (fDist <= (halo.fTriggerDist * 2.5))
IF (fDist < fMinDist) OR (fMinDist = -1.0)
fMinDist = fDist
iCar = i
ENDIF
ENDIF
ENDIF
ENDREPEAT
IF (iCar = -1)
//DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.2, "STRING", "NO CAR")
RETURN FALSE
ENDIF
/*
DRAW_DEBUG_LINE(GET_ENTITY_COORDS(array[iCar]) - <<0, 0, 2>>, GET_ENTITY_COORDS(array[iCar]) + <<0, 0, 2>>)
DRAW_DEBUG_LINE(GET_ENTITY_COORDS(array[iCar]), GET_ENTITY_COORDS(PLAYER_PED_ID()))
*/
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), array[iCar])
//DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.2, "STRING", "PLAYER NOT IN CAR")
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Updates the cost halos
/// PARAMS:
/// halo - array of halos
/// hndlr - handler reference (string and other stuff)
/// bNoWay - if we've passed the no way check
/// bFadeLaunch - do we fade when we launch
/// RETURNS:
/// Returns true if we have launched the script
FUNC BOOL UPDATE_CARWASH_COSTHALO_HANDLER(COST_HALO& halo[], COSTHALO_HANDLER& hndlr, BOOL bNoWay = FALSE, BOOL bFadeLaunch = FALSE, BOOL bAutoLaunch = TRUE, INT iStack = DEFAULT_STACK_SIZE)
INT i
VEHICLE_INDEX vehCheck
IF (hndlr.bShowMarkers)
i = 0
REPEAT COUNT_OF(halo) i
DRAW_COST_HALO(halo[i])
ENDREPEAT
ENDIF
SWITCH (hndlr.selectState)
CASE APPROACH_HALO
i = 0
IF IS_COSTHALO_ALLOWED_TO_LAUNCH(hndlr.bAllowOnMission)
//CPRINTLN(DEBUG_MISSION, "[CARWASH] - CDM: IS_COSTHALO_ALLOWED_TO_LAUNCH TRUE")
REPEAT COUNT_OF(halo) i
//CPRINTLN(DEBUG_MISSION, "[CARWASH] - CDM: halo[",i,"].bIsActive:", halo[i].bIsActive)
IF IS_PLAYER_IN_COST_HALO(halo[i]) AND (halo[i].bIsActive)
//CPRINTLN(DEBUG_MISSION, "[CARWASH] - CDM: IS_PLAYER_IN_COST_HALO TRUE")
hndlr.iSelectedHalo = i
IF IS_PLAYER_ON_MP_AMBIENT_SCRIPT(PLAYER_ID(), MPAM_TYPE_TIME_TRIAL) OR IS_PLAYER_ON_MP_AMBIENT_SCRIPT(PLAYER_ID(), MPAM_TYPE_RC_TIME_TRIAL)
SET_COSTHALO_HANDLER_STATE(hndlr, CLOSED_HALO)
ELIF (halo[i].bClosed) OR (GET_MISSION_FLAG() AND (hndlr.bAllowOnMission = FALSE))
SET_COSTHALO_HANDLER_STATE(hndlr, CLOSED_HALO)
ELIF (GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0)
SET_COSTHALO_HANDLER_STATE(hndlr, WANTED_HALO)
ELIF (bNoWay)
SET_COSTHALO_HANDLER_STATE(hndlr, DENIED_HALO)
ELIF (halo[i].bCustomCheck)
SET_COSTHALO_HANDLER_STATE(hndlr, CUSTOMCHECK_HALO)
//ELIF (GET_CARWASH_CURRENT_PLAYER_PED_ACCOUNT_BALANCE() < halo[hndlr.iSelectedHalo].iCost)
ELIF NOT DO_WE_HAVE_ENOUGH_MONEY_FOR(halo[hndlr.iSelectedHalo].iCost)
SET_COSTHALO_HANDLER_STATE(hndlr, CANTAFFORD_HALO)
ELIF IS_PLAYER_IN_A_BUST_VEHICLE()
SET_COSTHALO_HANDLER_STATE(hndlr, DAMAGED_HALO)
ELIF AM_I_DRIVING_CLOSEST_CAR_TO_CARWASH(halo[i], vehCheck)
SET_COSTHALO_HANDLER_STATE(hndlr, TRIGGER_HALO)
ENDIF
//CPRINTLN(DEBUG_MISSION, "[CARWASH] - CDM: IS_PLAYER_IN_A_BUST_VEHICLE:",IS_PLAYER_IN_A_BUST_VEHICLE())
//CPRINTLN(DEBUG_MISSION, "[CARWASH] - CDM: AM_I_DRIVING_CLOSEST_CAR_TO_CARWASH:",AM_I_DRIVING_CLOSEST_CAR_TO_CARWASH(halo[i], vehCheck))
ENDIF
ENDREPEAT
ELSE
CLEAR_COSTHALO_HANDLER_HELP(hndlr)
ENDIF
BREAK
CASE CUSTOMCHECK_HALO
IF NOT (hndlr.bTriggerHelpShown)
PRINT_COSTHALO_HELP(hndlr, hndlr.sCustomString)
ENDIF
IF IS_PLAYER_OUT_OF_COST_HALO(halo[hndlr.iSelectedHalo]) OR (halo[i].bCustomCheck = FALSE)
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN FALSE
ENDIF
BREAK
CASE CANTAFFORD_HALO
IF NOT (hndlr.bTriggerHelpShown)
PRINT_COSTHALO_HELP_WITH_NUMBER(hndlr, hndlr.sPoorString, halo[hndlr.iSelectedHalo].iCost)
ENDIF
IF IS_PLAYER_OUT_OF_COST_HALO(halo[hndlr.iSelectedHalo]) OR DO_WE_HAVE_ENOUGH_MONEY_FOR(halo[hndlr.iSelectedHalo].iCost) //(GET_CARWASH_CURRENT_PLAYER_PED_ACCOUNT_BALANCE() >= halo[hndlr.iSelectedHalo].iCost)
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN FALSE
ENDIF
BREAK
CASE CLOSED_HALO
IF NOT (hndlr.bTriggerHelpShown)
PRINT_COSTHALO_HELP(hndlr, hndlr.sBrokenString)
ENDIF
IF IS_PLAYER_OUT_OF_COST_HALO(halo[hndlr.iSelectedHalo]) OR NOT IS_COSTHALO_ALLOWED_TO_LAUNCH(hndlr.bAllowOnMission)
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN FALSE
ENDIF
BREAK
CASE DENIED_HALO
IF NOT (hndlr.bTriggerHelpShown)
PRINT_COSTHALO_HELP(hndlr, hndlr.sNoWayString)
ENDIF
IF IS_PLAYER_OUT_OF_COST_HALO(halo[hndlr.iSelectedHalo]) OR (bNoWay = FALSE) OR NOT IS_COSTHALO_ALLOWED_TO_LAUNCH(hndlr.bAllowOnMission)
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN FALSE
ENDIF
BREAK
CASE DAMAGED_HALO
IF NOT (hndlr.bTriggerHelpShown)
PRINT_COSTHALO_HELP(hndlr, hndlr.sDamagedString)
ENDIF
IF IS_PLAYER_OUT_OF_COST_HALO(halo[hndlr.iSelectedHalo]) OR NOT IS_COSTHALO_ALLOWED_TO_LAUNCH(hndlr.bAllowOnMission)
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN FALSE
ENDIF
BREAK
CASE WANTED_HALO
IF NOT (hndlr.bTriggerHelpShown)
PRINT_COSTHALO_HELP(hndlr, hndlr.sWantedString)
ENDIF
IF IS_PLAYER_OUT_OF_COST_HALO(halo[hndlr.iSelectedHalo]) OR (GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) = 0)
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN FALSE
ENDIF
BREAK
CASE WRONGWAY_HALO
IF NOT (hndlr.bTriggerHelpShown)
IF IS_PLAYER_UPRIGHT()
PRINT_COSTHALO_HELP(hndlr, hndlr.sWrongWayString)
ELSE
PRINT_COSTHALO_HELP(hndlr, hndlr.sUpsideDownString)
ENDIF
ENDIF
IF IS_PLAYER_OUT_OF_COST_HALO(halo[hndlr.iSelectedHalo]) OR IS_PLAYER_WITHIN_HALO_TOLERANCE(halo[hndlr.iSelectedHalo])
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN FALSE
ENDIF
BREAK
CASE TRIGGER_HALO
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_CONTEXT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ROOF)
DISABLE_SELECTOR_THIS_FRAME()
IF (GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0)
SET_COSTHALO_HANDLER_STATE(hndlr, WANTED_HALO)
RETURN FALSE
ENDIF
IF (halo[hndlr.iSelectedHalo].bCustomCheck)
SET_COSTHALO_HANDLER_STATE(hndlr, CUSTOMCHECK_HALO)
RETURN FALSE
ENDIF
IF IS_PLAYER_OUT_OF_COST_HALO(halo[hndlr.iSelectedHalo]) OR NOT IS_COSTHALO_ALLOWED_TO_LAUNCH(hndlr.bAllowOnMission)
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN FALSE
ENDIF
// don't launch if browser is running
IF (g_bBrowserVisible)
RETURN FALSE
ENDIF
// need to add wrong type check here
IF (halo[hndlr.iSelectedHalo].haloType = HALO_VEHICLE)
IF (NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) OR (GET_SEAT_PED_IS_IN(PLAYER_PED_ID()) <> VS_DRIVER))
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN FALSE
ENDIF
ENDIF
IF (halo[hndlr.iSelectedHalo].bClosed) OR (GET_MISSION_FLAG() AND (hndlr.bAllowOnMission = FALSE))
SET_COSTHALO_HANDLER_STATE(hndlr, CLOSED_HALO)
RETURN FALSE
ENDIF
IF IS_PLAYER_IN_A_BUST_VEHICLE()
SET_COSTHALO_HANDLER_STATE(hndlr, DAMAGED_HALO)
RETURN FALSE
ENDIF
//IF (GET_CARWASH_CURRENT_PLAYER_PED_ACCOUNT_BALANCE() < halo[hndlr.iSelectedHalo].iCost)
IF NOT DO_WE_HAVE_ENOUGH_MONEY_FOR(halo[hndlr.iSelectedHalo].iCost)
SET_COSTHALO_HANDLER_STATE(hndlr, CANTAFFORD_HALO)
RETURN FALSE
ENDIF
/*
IF NOT (CAN_PLAYER_TRIGGER_CARWASH_HALO_IN_CAR(halo[hndlr.iSelectedHalo]))
//SET_COSTHALO_HANDLER_STATE(hndlr, DENIED_HALO)
//RETURN FALSE
DISPLAY_TEXT_WITH_LITERAL_STRING(0.5, 0.5, "STRING", "NO WAY")
ENDIF
*/
IF bNoWay
SET_COSTHALO_HANDLER_STATE(hndlr, DENIED_HALO)
RETURN FALSE
ENDIF
IF !bNoWay AND NOT (hndlr.bTriggerHelpShown)
PRINT_COSTHALO_HELP_WITH_NUMBER(hndlr, hndlr.sActivateString, halo[hndlr.iSelectedHalo].iCost)
ENDIF
// don't let player trigger if they are driving straight through it
// cant use a vehicle stuck on roof check as i need to add it so check for roll instead
IF (halo[hndlr.iSelectedHalo].haloType = HALO_VEHICLE)
/*
IF (GET_ENTITY_SPEED(PLAYER_PED_ID()) > 5.0)
RETURN FALSE
ENDIF
*/
// if ped is getting out of vehicle don't allow launch
IF (IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()))
RETURN FALSE
ENDIF
ENDIF
IF IS_PAUSE_MENU_ACTIVE() OR IS_SYSTEM_UI_BEING_DISPLAYED()
RETURN FALSE
ENDIF
// don't let a ped this if the player is on foot but on with both feet on the ground
IF IS_PED_ON_FOOT(PLAYER_PED_ID())
IF IS_PED_FALLING(PLAYER_PED_ID()) OR IS_PED_JUMPING(PLAYER_PED_ID()) OR IS_PED_JUMPING_OUT_OF_VEHICLE(PLAYER_PED_ID())
RETURN FALSE
ENDIF
IF IS_PED_RUNNING_RAGDOLL_TASK(PLAYER_PED_ID()) OR IS_PED_RAGDOLL(PLAYER_PED_ID()) OR IS_PED_GETTING_UP(PLAYER_PED_ID())
RETURN FALSE
ENDIF
IF IS_PED_CLIMBING(PLAYER_PED_ID())
RETURN FALSE
ENDIF
IF IS_PED_DUCKING(PLAYER_PED_ID()) OR IS_PED_SWIMMING(PLAYER_PED_ID())
RETURN FALSE
ENDIF
IF (GET_ENTITY_SPEED(PLAYER_PED_ID()) > 0.05)
RETURN FALSE
ENDIF
ENDIF
IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_CONTEXT) AND (hndlr.bTriggerHelpShown = TRUE) AND bNoWay = FALSE
IF NOT IS_PLAYER_WITHIN_HALO_TOLERANCE(halo[hndlr.iSelectedHalo])
SET_COSTHALO_HANDLER_STATE(hndlr, WRONGWAY_HALO)
ELSE
SET_COSTHALO_HANDLER_STATE(hndlr, LAUNCH_HALO)
ENDIF
ENDIF
BREAK
CASE LAUNCH_HALO
IF NETWORK_IS_GAME_IN_PROGRESS()
IF REQUEST_SCRIPT_AUDIO_BANK("SCRIPT\\CARWASH")
PRINTLN("[CARWASH] Audio bank loaded")
ENDIF
ENDIF
CLEAR_COSTHALO_HANDLER_HELP(hndlr)
halo[hndlr.iSelectedHalo].bCustomCheck = FALSE
IF NOT bAutoLaunch
SET_COSTHALO_HANDLER_STATE(hndlr, APPROACH_HALO)
RETURN TRUE
ENDIF
CLEAR_HELP()
CLEAR_AREA_OF_PROJECTILES(GET_ENTITY_COORDS(PLAYER_PED_ID()), 20.0)
IF NOT IS_STRING_NULL_OR_EMPTY(halo[hndlr.iSelectedHalo].sScriptName)
REQUEST_SCRIPT(halo[hndlr.iSelectedHalo].sScriptName)
WHILE NOT HAS_SCRIPT_LOADED(halo[hndlr.iSelectedHalo].sScriptName)
DISABLE_SELECTOR_THIS_FRAME()
IF IS_ENTITY_OK(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT g_bInMultiplayer
BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), 2)
ENDIF
ENDIF
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_CONTEXT)
REQUEST_SCRIPT(halo[hndlr.iSelectedHalo].sScriptName)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ROOF)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ENTER)
WAIT(0)
ENDWHILE
IF (bFadeLaunch)
DO_SCREEN_FADE_OUT(250)
ENDIF
IF HAS_SCRIPT_LOADED(halo[hndlr.iSelectedHalo].sScriptName)
IF (bFadeLaunch)
WHILE NOT IS_SCREEN_FADED_OUT()
IF IS_ENTITY_OK(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT g_bInMultiplayer
BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), 2)
ENDIF
ENDIF
SET_INPUT_EXCLUSIVE(FRONTEND_CONTROL, INPUT_CONTEXT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ROOF)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_EXIT)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ENTER)
DISABLE_SELECTOR_THIS_FRAME()
WAIT(0)
ENDWHILE
ENDIF
START_NEW_SCRIPT(halo[hndlr.iSelectedHalo].sScriptName, iStack)
SET_SCRIPT_AS_NO_LONGER_NEEDED(halo[hndlr.iSelectedHalo].sScriptName)
RETURN TRUE
ENDIF
ENDIF
BREAK
ENDSWITCH
RETURN FALSE
ENDFUNC
//----------------------
// DEBUG FUNCTIONS
//----------------------
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// Initializes Debug Widgets
PROC SETUP_DEBUG_CARWASH_HROLLER_WIDGETS(CARWASH_HROLLER &roll, STRING str = NULL)
IF IS_STRING_NULL_OR_EMPTY(str)
str = "Horizontal Roller"
ENDIF
START_WIDGET_GROUP(str)
ADD_WIDGET_FLOAT_SLIDER("Pivot Angle", roll.fRollerPivotAngle, 0.0, 360.0, 0.25)
ADD_WIDGET_FLOAT_SLIDER("Move Rate", roll.fMoveRate, 0.0, 15.0, 1.0)
ADD_WIDGET_FLOAT_SLIDER("Spin Rate", roll.fSpinRate, 0.0, 3600.0, 0.025)
ADD_WIDGET_FLOAT_SLIDER("Trigger Dist", roll.fTriggerDist, 0.0, 5.0, 0.125)
ADD_WIDGET_FLOAT_READ_ONLY("Spin Angle", roll.fRollerSpinAngle)
ADD_WIDGET_FLOAT_READ_ONLY("Ground Zero", roll.fGroundZero)
ADD_WIDGET_INT_READ_ONLY("Next Check Time", roll.iNextCheckTime)
ADD_WIDGET_INT_READ_ONLY("Next Shape Time", roll.iNextShapeTestTime)
STOP_WIDGET_GROUP()
ENDPROC
/// PURPOSE:
/// Initializes Debug Widgets
PROC SETUP_DEBUG_CARWASH_VERTROLLER_WIDGETS(CARWASH_VROLLER2 &roll, STRING str = NULL)
IF IS_STRING_NULL_OR_EMPTY(str)
str = "Vert Roller"
ENDIF
START_WIDGET_GROUP(str)
ADD_WIDGET_BOOL("Collision On", roll.bCollisionOn)
ADD_WIDGET_BOOL("Front Sensor", roll.bSensorOn[0])
ADD_WIDGET_FLOAT_SLIDER("Front Sensor Offset", roll.fSensorOffset[0], -5.0, 5.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Front Sensor Radius", roll.fSensorRadius[0], -5.0, 5.0, 0.001)
ADD_WIDGET_BOOL("Back Sensor", roll.bSensorOn[1])
ADD_WIDGET_FLOAT_SLIDER("FrontSensor Offset", roll.fSensorOffset[1], -5.0, 5.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("FrontSensor Radius", roll.fSensorRadius[1], -5.0, 5.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Left Offset", roll.fOffset[0], -5.0, -ROLLER_RADIUS, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Right Offset", roll.fOffset[1], ROLLER_RADIUS, 5.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Left TGT Offset", roll.fTgtOffset[0], -5.0, -ROLLER_RADIUS, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Right TGT Offset", roll.fTgtOffset[1], ROLLER_RADIUS, 5.0, 0.001)
ADD_WIDGET_FLOAT_SLIDER("Move Rate", roll.fMoveRate, 0.0, 15.0, 1.0)
ADD_WIDGET_FLOAT_SLIDER("Shut Down Move Rate", roll.fShutDownMoveRate, 0.0, 15.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("Spin Rate", roll.fSpinRate, 0.0, 3600.0, 10)
ADD_WIDGET_FLOAT_READ_ONLY("Spin Angle", roll.fRollerSpinAngle)
STOP_WIDGET_GROUP()
ENDPROC
PROC SETUP_DEBUG_CARWASH_CONSTANT_WIDGETS()
START_WIDGET_GROUP("Constants")
ADD_WIDGET_BOOL("Use New MP Rollers", bUseNewMPVertRollers)
ADD_WIDGET_INT_SLIDER("RollerCheck Interval", ROLLER_CHECK_INTERVAL, 1, 2000, 10)
ADD_WIDGET_INT_SLIDER("ShapeCheck Interval", SHAPE_CHECK_INTERVAL, 1, 2000, 10)
START_WIDGET_GROUP("Particle Values")
ADD_WIDGET_VECTOR_SLIDER("H Spray ROffset", vRollerHorzRotFX, -360, 360.0, 0.01)
ADD_WIDGET_VECTOR_SLIDER("V Spray ROffset", vRollerVertRotFX, -360, 360.0, 0.01)
ADD_WIDGET_VECTOR_SLIDER("V Spray POffset", vRollerVertPosFX, -5, 5, 0.01)
ADD_WIDGET_VECTOR_SLIDER("Jet Spray ROffset", vJetRotFX, -360, 360.0, 0.01)
ADD_WIDGET_VECTOR_SLIDER("Steam ROffset", vSteamRotFX, -360, 360.0, 0.01)
ADD_WIDGET_VECTOR_SLIDER("Steam POffset", vSteamPosFX, -8, 8, 0.01)
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
ENDPROC
/// PURPOSE:
/// Initializes Debug Widgets
PROC SETUP_DEBUG_CARWASH_JETS_WIDGETS(CARWASH_JETS &roll, STRING str = NULL)
IF IS_STRING_NULL_OR_EMPTY(str)
str = "Jets"
ENDIF
START_WIDGET_GROUP(str)
ADD_WIDGET_BOOL("Steam", roll.bSteam)
ADD_WIDGET_FLOAT_SLIDER("Trigger Dist", roll.fTriggerDist, 0.0, 5.0, 0.125)
ADD_WIDGET_FLOAT_SLIDER("Seperation", roll.fSeperation, 0.0, 5.0, 0.0625)
ADD_WIDGET_INT_READ_ONLY("Next Check Time", roll.iNextCheckTime)
STOP_WIDGET_GROUP()
ENDPROC
PROC SETUP_DEBUG_CARWASH_HANDLER_WIDGETS(CARWASH_HANDLER &ct)
START_WIDGET_GROUP("Carwash")
ADD_WIDGET_BOOL("Draw Debug", bDrawDebugCarwash)
ADD_WIDGET_BOOL("Use Old Verticle Brush Check", bUseOldVerticleBrushCheck)
ADD_WIDGET_BOOL("Use New Shape Test", bUseNewSweptSphereTest)
ADD_WIDGET_FLOAT_SLIDER("Sweep Sphere Radius", fSweepSphereRadius, 0.25, 3.0, 0.05)
ADD_WIDGET_FLOAT_SLIDER("X Seperation", fShapeTestXSeperation, 0.1, 5.0, 0.125)
ADD_WIDGET_BOOL("Aborted", ct.bCarwashAborted)
START_WIDGET_GROUP("Tasks")
ADD_WIDGET_BOOL("Clear Ped Tasks", bDebugForceClearPedTasks)
ADD_WIDGET_BOOL("Restart Ped Tasks", bDebugForceRestartTasks)
ADD_WIDGET_BOOL("Is Ped Runing Task", bIsDriverRunningCarwashSequence)
ADD_WIDGET_BOOL("Is Ped Done Task", bIsDriverFinishedCarwashSequence)
ADD_WIDGET_BOOL("Create Block Car", bCreateBlockCar)
ADD_WIDGET_FLOAT_SLIDER("Block Car T", fBlockCarPlaceT, -1.0, 2.0, 0.001)
ADD_WIDGET_INT_READ_ONLY("Task Sequence Progress", iDriverCarwashSequenceProgress)
ADD_WIDGET_INT_READ_ONLY("Task Sequence Size", ct.iTaskSequenceSize)
STOP_WIDGET_GROUP()
SETUP_DEBUG_CARWASH_HROLLER_WIDGETS(ct.horzRoller)
SETUP_DEBUG_CARWASH_VERTROLLER_WIDGETS(ct.vertRoller, "New Vert Roller")
SETUP_DEBUG_CARWASH_JETS_WIDGETS(ct.steamJets, "Steam")
SETUP_DEBUG_CARWASH_JETS_WIDGETS(ct.waterJets, "Water")
SETUP_DEBUG_CARWASH_JETS_WIDGETS(ct.soapJets, "Soaps")
ADD_WIDGET_FLOAT_SLIDER("Roll Shift Factor", ROLLER_SHIFT_FACTOR, 0.0, 2.0, 0.0001)
ADD_WIDGET_FLOAT_SLIDER("Forward", ct.fForwardSpeed, 0, 30.0, 0.01)
ADD_WIDGET_FLOAT_SLIDER("FCInterpolate", ct.fFinalCameraInterpolate, 0, 1.0, 0.01)
ADD_WIDGET_INT_READ_ONLY("Camera State", ct.iCurrentCameraState)
ADD_WIDGET_READ_ONLY_VECTOR("Direction", ct.cTrack.vDirection)
ADD_WIDGET_FLOAT_READ_ONLY("Car Ratio", fCarDebugRatio)
ADD_WIDGET_INT_READ_ONLY("Carwash Timer", iDebugCarWashTimer)
STOP_WIDGET_GROUP()
ENDPROC
PROC DRAW_DEBUG_BOX_WITH_HEADING(VECTOR vPos, VECTOR vDim, FLOAT fHeading)
VECTOR vBoxCorner[8]
VECTOR vMin = -vDim / 2.0
VECTOR vMax = vDim / 2.0
vBoxCorner[7] = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPos, fHeading, <<vMin.x, vMin.y, vMin.z>>)
vBoxCorner[6] = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPos, fHeading, <<vMax.x, vMin.y, vMin.z>>)
vBoxCorner[5] = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPos, fHeading, <<vMax.x, vMax.y, vMin.z>>)
vBoxCorner[4] = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPos, fHeading, <<vMin.x, vMax.y, vMin.z>>)
vBoxCorner[3] = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPos, fHeading, <<vMin.x, vMin.y, vMax.z>>)
vBoxCorner[2] = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPos, fHeading, <<vMax.x, vMin.y, vMax.z>>)
vBoxCorner[1] = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPos, fHeading, <<vMax.x, vMax.y, vMax.z>>)
vBoxCorner[0] = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vPos, fHeading, <<vMin.x, vMax.y, vMax.z>>)
DRAW_DEBUG_POLY(vBoxCorner[0], vBoxCorner[1], vBoxCorner[5], 200, 100, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[0], vBoxCorner[5], vBoxCorner[4], 200, 100, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[1], vBoxCorner[2], vBoxCorner[6], 200, 200, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[1], vBoxCorner[6], vBoxCorner[5], 200, 200, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[2], vBoxCorner[3], vBoxCorner[7], 200, 100, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[2], vBoxCorner[7], vBoxCorner[6], 200, 100, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[3], vBoxCorner[0], vBoxCorner[4], 200, 200, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[3], vBoxCorner[4], vBoxCorner[7], 200, 200, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[2], vBoxCorner[1], vBoxCorner[0], 200, 150, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[3], vBoxCorner[2], vBoxCorner[0], 200, 150, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[4], vBoxCorner[5], vBoxCorner[6], 200, 150, 0, 100)
DRAW_DEBUG_POLY(vBoxCorner[4], vBoxCorner[6], vBoxCorner[7], 200, 150, 0, 100)
ENDPROC
#ENDIF