local M = {} local volume, pitch = 1.5, 1 local camNode = 0 local timer = 0 local lastDoorState = false local doorChimePlaying = false local nextDoorChimeTime = 0 local chimeDuration = 1.0 -- door chime duration -- Parking brake chime state local parkingBrakeChimePlaying = false local nextParkingBrakeChimeTime = 0 local parkingBrakeChimeDuration = 0.5 -- independent duration for parking brake chime local lastParkingBrakeOn = false -- track state for release/apply sound -- Auto-brake "frein assisté" state local autoBrakeApplied = false local autoReleased = false local lastIgnition = 0 local brakeEngagedThisFrame = false local function inside() local cam = obj:getCameraPosition() local seat = obj:getPosition() + obj:getNodePosition(camNode) return cam and seat and cam:distance(seat) <= 0.6 end local function handleAutoBrake(anyDoorOpen, throttle, ignitionLevel, parkingBrakeInput, parkingBrakePhys) -- Reset flags when ignition turns off if ignitionLevel == 0 and lastIgnition > 0 then autoBrakeApplied = false autoReleased = false end -- Auto apply below ignition 2 if not already applied if ignitionLevel < 2 then if parkingBrakeInput < 0.01 and not autoBrakeApplied then input.event("parkingbrake", 1) -- apply brake autoBrakeApplied = true autoReleased = false end elseif ignitionLevel >= 2 then -- Release logic: only if input = 1, throttle pressed, doors closed, not released yet if parkingBrakeInput > 0.01 and throttle > 0.05 and not anyDoorOpen and not autoReleased then input.event("parkingbrake", 0) -- release brake autoReleased = true elseif parkingBrakeInput < 0.01 and not autoBrakeApplied then input.event("parkingbrake", 1) -- ensure brake applied if needed autoBrakeApplied = true end end lastIgnition = ignitionLevel end local function update(dt) -- Door / trunk / hood check local driverDoorOpen = (electrics.values['door_FL_coupler_notAttached'] == 1) local passengerDoorOpen = (electrics.values['door_FR_coupler_notAttached'] == 1 or electrics.values['door_RL_coupler_notAttached'] == 1 or electrics.values['door_RR_coupler_notAttached'] == 1 or electrics.values['tailgateCoupler_notAttached'] == 1 or electrics.values['hoodLatchCoupler_notAttached'] == 1) local anyDoorOpen = driverDoorOpen or passengerDoorOpen local ignitionLevel = electrics.values['ignitionLevel'] or 0 local lightsState = electrics.values['lights_state'] or 0 local lightsOn = (lightsState == 1 or lightsState == 2) local throttle = electrics.values.throttle or 0 -- Door chime logic local doorChimeActive = false if ignitionLevel == 2 then doorChimeActive = passengerDoorOpen elseif ignitionLevel == 1 then doorChimeActive = lightsOn end -- Parking brake state local parkingBrakePhys = electrics.values.parkingbrake or 0 local parkingBrakeInput = electrics.values.parkingbrake_input or 0 local brakeChimeActive = (ignitionLevel > 1) and (parkingBrakeInput < 0.01) and driverDoorOpen -- === Door chime playback === if inside() then if doorChimeActive then if not doorChimePlaying then obj:playSFXOnce("VivacedoorChime.wav", camNode, volume, pitch) doorChimePlaying = true nextDoorChimeTime = timer + chimeDuration elseif timer >= nextDoorChimeTime then obj:playSFXOnce("VivacedoorChime.wav", camNode, volume, pitch) nextDoorChimeTime = timer + chimeDuration end else if doorChimePlaying then doorChimePlaying = false obj:playSFXOnce("chimeOff.wav", camNode, volume, pitch) end end else doorChimePlaying = false end -- === Parking brake chime playback === if inside() then if brakeChimeActive then if not parkingBrakeChimePlaying then obj:playSFXOnce("parkingbrake.wav", camNode, volume, pitch) parkingBrakeChimePlaying = true nextParkingBrakeChimeTime = timer + parkingBrakeChimeDuration elseif timer >= nextParkingBrakeChimeTime then obj:playSFXOnce("parkingbrake.wav", camNode, volume, pitch) nextParkingBrakeChimeTime = timer + parkingBrakeChimeDuration end else parkingBrakeChimePlaying = false end else parkingBrakeChimePlaying = false end -- === Auto parking brake handling === handleAutoBrake(anyDoorOpen, throttle, ignitionLevel, parkingBrakeInput, parkingBrakePhys) -- === Parking brake sounds === if parkingBrakePhys > 0.01 and not lastParkingBrakeOn then if inside() then obj:playSFXOnce("parkingBrakeOn.wav", camNode, 0.2, 1.3) else obj:playSFXOnce("parkingBrakeOn.wav", camNode, 1.2, 1.3) end elseif lastParkingBrakeOn and parkingBrakePhys < 0.01 then if inside() then obj:playSFXOnce("parkingBrakeOff.wav", camNode, 0.2, 1.3) else obj:playSFXOnce("parkingBrakeOff.wav", camNode, 1.2, 1.3) end end lastParkingBrakeOn = parkingBrakePhys > 0.01 timer = timer + dt lastDoorState = doorChimeActive end local function init() camNode = beamstate.nodeNameMap["driver"] or 0 obj:createSFXSource("/art/sound/vivace/VivacedoorChime.wav", "Audio2D", "VivacedoorChime.wav", -1) obj:createSFXSource("/art/sound/vivace/chimeOff.wav", "Audio2D", "chimeOff.wav", -1) obj:createSFXSource("/art/sound/vivace/parkingbrake.wav", "Audio2D", "parkingbrake.wav", -1) obj:createSFXSource("/art/sound/vivace/parkingBrakeOff.wav", "Audio2D", "parkingBrakeOff.wav", -1) obj:createSFXSource("/art/sound/vivace/parkingBrakeOn.wav", "Audio2D", "parkingBrakeOn.wav", -1) end M.onInit = init M.updateGFX = update return M