Trying to use LUA trigger to repair vehicle

Discussion in 'Programming' started by KAMUS_, Feb 22, 2025.

  1. KAMUS_

    KAMUS_
    Expand Collapse

    Joined:
    Nov 11, 2023
    Messages:
    28
    Hello,
    I'm trying to make working pit stops on my map. I want to use LUA triggers to repair vehicle when trigger is entered.

    First I tried this:
    Code:
    local function trigger_repair(data)
        print("Trigger activated. Event: " .. tostring(data.event)) -- Debugging line
    
        if data.event == 'enter' then
            print("Player entered the trigger.") -- Debugging line
            be:reloadVehicle(-1) -- Reloads the player's vehicle
            print("Vehicle reloaded!") -- Debugging line
        end
    end
    
    return trigger_repair
    It works (like clicking Ctrl+R), but the problem is it does it to every vehicle on map.
    Then I tried to get vehicle ID and to reload only the one that entered the trigger
    Code:
    local function trigger_repair(data)
        print("Trigger activated. Event: " .. tostring(data.event)) -- Debugging line
    
        if data.event == 'enter' then
            print("Player entered the trigger.") -- Debugging line
    
            local vid = be:getPlayerVehicleID(0) -- Get player's vehicle ID
            if vid then
                local vehicle = scenetree.findObjectById(vid) -- Get vehicle object from ID
                if vehicle then
                    print("Vehicle found. ID: " .. tostring(vid)) -- Debugging line
                    be:reloadVehicle(vid) -- Reload only the player's vehicle
                    print("Vehicle reloaded!") -- Debugging line
                else
                    print("Vehicle object not found!") -- Debugging line
                end
            else
                print("No valid player vehicle ID found!") -- Debugging line
            end
        end
    end
    
    return trigger_repair
    And the problem with this code it that it does nothing. It works without an error and the debugging lines in console display as if everything has worked out, but it has no effect on players vehicle.
    Code:
    7669.236|I|GELua.print|Trigger activated. Event: enter
    7669.236|I|GELua.print|Player entered the trigger.
    7669.236|I|GELua.print|Vehicle found. ID: 33986
    7669.236|I|GELua.print|Vehicle reloaded!
    
    Any ideas?
     
  2. MegaKnight

    MegaKnight
    Expand Collapse

    Joined:
    Sep 12, 2024
    Messages:
    218
    I just did a bit of testing. The following code seems to work:

    Code:
    local function resetVehicle(data)
        if data.event == "enter" then
            local vehid = data.subjectID
            if vehid == be:getPlayerVehicleID(0) then
                be:reloadVehicle(0)      -- reloads player vehicle
            end
        end
    end
    
    return resetVehicle

    The only issue is that the vehicle gets stuck in a reset loop. You would need a variable that changes value when the player enters the trigger and prevents the reset until the player exits the trigger.

    Code:
    isPlayerInTrigger = false
    
    local function resetVehicle(data)
        if data.event == "enter" then
            if not isPlayerInTrigger then
                isPlayerInTrigger = true
                local vehid = data.subjectID
                if vehid == be:getPlayerVehicleID(0) then
                    be:reloadVehicle(0)
                end
            end
        end
        if data.event == "exit" then
            isPlayerInTrigger = false
        end
    end
    
    return resetVehicle

    However, that doesn't seem to work with just one lua trigger. I think the reason is that reloading the vehicle counts as exiting the trigger. If you use two triggers (one for reset/pitstop, the other for registering the exit) that call functions from mainLevel.lua, it does work. The mainLevel.lua is needed to save the state of wether the player was inside the pit stop or not, as this info cannot be passed between triggers afaik.

    So, the code for your reset trigger could look like this:

    Code:
    local function test(data)
        mainLevel.resetVehicle(data)
    end
    
    return test

    When exiting the pit stop, a trigger with the following code is entered:

    Code:
    local function test(data)
        mainLevel.exitPit()
    end
    
    return test

    And the code inside the mainLevel.lua that is called could look like this:

    Code:
    local M = {}
    
    local isPlayerInPit = false
    
    local function resetVehicle(data)
        if data.event == "enter" then
            if not isPlayerInPit then
                isPlayerInPit = true
                local vehid = data.subjectID
                if vehid == be:getPlayerVehicleID(0) then
                    be:reloadVehicle(0)   --  reloads player vehicle (0 => vehicle the player is currently using)
                end
            end
        end
    end
    
    local function exitPit()
        isPlayerInPit = false
    end
    
    M.resetVehicle = resetVehicle
    M.exitPit = exitPit
    
    return M

    I just experimented myself, so there might be better solutions. I hope it's helpful anyway :)
     
  3. KAMUS_

    KAMUS_
    Expand Collapse

    Joined:
    Nov 11, 2023
    Messages:
    28
    Thanks a lot!
    I've tweaked things a bit, I've used 2 lua triggers as you can see in this screenshot
    Screenshot_16.jpg

    For vehicle reload - Yellow - "pit1"
    After player enters it, vehicle reloads and trigger "pit1" hides to prevent looping when player restarts vehicle.

    Code:
    local isPlayerInPit = false
    local function trigger_reset(data)
        if data.event == "enter" then
            if not isPlayerInPit then  -- Ensures the vehicle only resets once per entry
                isPlayerInPit = true
                local vehid = data.subjectID
                if vehid == be:getPlayerVehicleID(0) then
                    be:reloadVehicle(0)  -- Reloads the player's vehicle only
                    local pit1 = scenetree.findObject("pit1")
                    if pit1 then
                        pit1:setHidden(true)
                    end
                end
            end
        end
    end
    
    return trigger_reset
    The purple one - "exit_pit"
    for unhiding "pit1" so player can reload vehicle again

    Code:
    local function exit_pit(data)
        if data.event == "enter" then
            local obj = scenetree.findObject("pit1")
            if obj then
                obj:setHidden(false)
            end
        end
    end
    
    return exit_pit
    (red triggers are for decoration)

    Here is vid demonstration:
     
  4. MegaKnight

    MegaKnight
    Expand Collapse

    Joined:
    Sep 12, 2024
    Messages:
    218
    That's a great way to do it!
    I'm glad I was able to help.
     
  5. Riccarr

    Riccarr
    Expand Collapse

    Joined:
    Jul 28, 2024
    Messages:
    20
    That's a cool idea to make a pit stop repair! Have you figured out all your logic for how to deal with the trigger? I've coded a few in my stuff. There are "enter", "exit" and "tick" possible values in data.event.

    Something fun to consider would be to use a check on vehicle velocity combined with delay timer/update so you only perform the vehicle reload once the vehicle comes to a stop, and then only after a certain amount of time has elapsed, to similar a repair time. If you knew how much damage was on the vehicle then you could vary the delay time before reload.

    I don't want to just throw out a bunch of code snippets at you, so just ask if you have a specific task about this.
     
  6. Barbent Servo GT

    Barbent Servo GT
    Expand Collapse

    Joined:
    Jun 4, 2023
    Messages:
    653
    Thanks a lot for the "be:reloadVehicle(0)" line! That's exactly what I was looking for :).

    Some additional thoughts:

    If you'd like to start the action only if the vehicle comes to stop, you have to use a ticking trigger, cause obviously a vehicle cannot enter a trigger with zero speed. So for this cases I have two triggers, with the same position and size. One of them is ticking. Since a ticking tirigger can't send enter/exit events, there has to be the second one to recognize the exit event.

    So the logic is to check by the ticking trigger if the player vehicle has zero speed (and thus must be in the trigger) and a dedicated flag variable signals "place clear". The action whatever needed (refill or repair) is then processed and the flag variable is set to "place occupied". If the player drives on this is recognized by the second trigger and the flag variable is set to "place clear" again, what means the place is ready for a new action.

    There is a random delay between the moment the player stopped (of course in the trigger) and the action is started depending on the (absolute) ticking time. If you give the ticking trigger a relatively long time (e.g. 2sec), the delay will be from 0 to 2sec by chance and this feels quite realistic, imo.

    The advantage to realize the "place (is) clear" logic by an exit event instead of testing if the speed of the player rises again is that it is proof to recognize any irregular disappearing of the vehicle, for example by a map or [F7] jump or by removing the car.

    How to check the speed:
    Code:
    vehObj = be:getObjectByID(data.subjectID) -- Convert trigger subject into vehicle object
    airspeed = vehObj:getVelocity():length() -- in m/s
    Hope I wrote something useful :)
    --- Post updated ---
    BTW: Does anyone know how to test if the player vehicle is the unicycle (avatar)?
     
    #6 Barbent Servo GT, Mar 20, 2025
    Last edited: Mar 20, 2025
    • Like Like x 1
  7. MegaKnight

    MegaKnight
    Expand Collapse

    Joined:
    Sep 12, 2024
    Messages:
    218
    Thank you, that's very useful! I didn't know about ticking triggers before ;)

    You can test for the unicycle using the following code:
    Code:
    if core_vehicle_manager.getPlayerVehicleData().mainPartName == "unicycle" then
       -- some code
    end
    
    -- alternative, works for non-player vehicles as well, if you have their id --
    local vehicle = getPlayerVehicle(0)
    if core_vehicle_manager.getVehicleData(vehicle:getId()).mainPartName == "unicycle" then
       -- some code
    end
    You can also use this to test for specific vehicles, eg. "us_semi", "etk800" or "simplified_traffic".

    Edit:
    I did some testing myself and my ticking triggers can send enter/exit events :confused: I use the following order of if-statements: if data.event == "enter" ... elseif data.event == "exit" ... elseif data.event == "tick"
    It might not work if you have the "tick"-query first, as I think the tick-event is always sent. It also works if I put the tick-query first.
     
    #7 MegaKnight, Mar 20, 2025
    Last edited: Mar 20, 2025
    • Like Like x 1
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice