[RESOLVED] Same key to do and undo an action


#1

Hi everyone !

I would like to set a mechanism pretty simple in appearence :

Press ‘E’ to do something.
While something is doing
Press ‘E’ to stop doing this thing

I can’t get it working.

It’s working well if it’s not the same key to do and stop doing but I really want to use the same key.

Here is my code so far. It pops the ‘Press E to do something’, it’s doing the thing and It also pops the ‘Press E to stop doing the thing’ but it doesn’t stop it.

-- Listen for Player to be near something
Citizen.CreateThread(function()
	while true do
		Citizen.Wait(1)
		if(IsNearSomething() == 're') then
			doRecolt()
		elseif(IsNearSomething() == 'tr') then
			DisplayHelpText("Appuyez sur ~INPUT_PICKUP~ pour traiter.")
			doTreatment()
		elseif(IsNearSomething() == 'se') then
			DisplayHelpText("Appuyez sur ~INPUT_PICKUP~ pour vendre.")
			doSell()
		else
			isRecolting, isTreating, isSelling = false
		end
	end
end)

-- Actions de récolte
function doRecolt()
	if (isRecolting == false) then
		DisplayHelpText("Appuyez sur ~INPUT_PICKUP~ pour récolter.")
	else
		DisplayHelpText("Appuyez sur ~INPUT_PICKUP~ pour ~r~arrêter~w~ de récolter.")
		drawTxt("~b~Récolte~w~ en cours...",10,0,0.4,0.95,0.4,255,255,255,255)
		Citizen.Wait(timeForRecolt - 800)
		TriggerEvent("player:receiveItem", tonumber(JOBS[jobId].recolt_item_id), 1)
		drawTxt("~g~+1~w~".. tostring(JOBS[jobId].recolt_item_libelle),10,0,0.4,0.95,0.4,255,255,255,255)
	end
	if IsControlJustPressed(1, 38) then -- If INPUT_PICKUP Is pressed (touche E)
		isRecolting = not isRecolting
	end
end

Do you have any ideas how to perform this trick ? Am I close ?

Edit : The messages from the drawText function doesn’t stay at screen. That’s another problem, if you have a solution I would like too.

Thank’s in advance fellow developers


#2

Like press e to pickup and drop something? Because the toggle looks right to me at the bottom.


#3

Not really. What I want is this :

The player is near a place where he can recolt something.
The server pops this kind of message :
http://imgur.com/M7NrE1h
Then the player press the ‘E’ key
The server pops this message :
http://imgur.com/Fy1Dqmn
It also should pops a message in the bottom of the screen telling the player that he is recolting something but this message is really quick, it doesn’t stay at screen.

Then, the key to stop doing the action isn’t working it’s doing nothing.


#4

OK so basically while they are doing something if they want to kinda cancel out the action they just press e again. I’m sorry just a bit confused.


#5

Yes, that exactly the behavior i’m looking for.


#6

What I would do is make a variable.

local isMoving = false

When they click e the first time check if they are close enough and if isMoving is false then start recolting if they are really close enough and isMoving = true then stop recolting then reset variable back to false.

I am sorry I am on my phone so examples are limited.


#7

I’m already using a variable to know if the player isRecolting or not.
By default the variable is set to FALSE
When he first clicks on ‘E’ the variable is set to TRUE and if he press ‘E’ again it should return to FALSE

It’s shown in my code example.
Doesn’t seems to work that way sadly.


#8

Maybe put the is control just pressed statement above everything. Sorry I am just thinking because that looks right to me. But out of all of us there is always something small we look over.


#9

Maybe put the control in another thread. I believe your issue is you’re using Citizen.Wait on your thread which, is stopping the code from executing the IsControlJustPressed(1, 38) function.

Better Explanation:

function doRecolt()
	if (isRecolting == false) then
		DisplayHelpText("Appuyez sur ~INPUT_PICKUP~ pour récolter.")
	else
		Citizen.Wait(timeForRecolt - 800) -- Stops the thread for "timeForRecolt" miliseconds
		TriggerEvent("player:receiveItem", tonumber(JOBS[jobId].recolt_item_id), 1) -- After "timeForRecolt" seconds, the thread can run again (this and other code can run)
	end
	if IsControlJustPressed(1, 38) then -- Has to wait until the thread is running again
		isRecolting = not isRecolting
	end
end

So, try something like this, along side your current code:

Citizen.CreateThread(function()
  while true do
    Citizen.Wait(0) -- Needed
    if IsControlJustPressed(1, 38) then
       isRecolting = not isRecolting
    end
  end
end)

#10

With this code, isRecolting is never FALSE neither it’s TRUE. I think the two IsControlJustPressed are executed at the same time.

The solution should be very simple in theory, I can’t figure out why it’s so difficult to get the desired behavior.


#11

I apologize if I was no help earlier I don’t have Internet at home so I can’t really use my pc to help. So I am stuck to my phone.


#12

This could be the case. Are you printing the various variables to the console to see what values they are and when certain stuff is happening (e.g. when the button is pressed)? You should also remove the original IsControlJustPressed as they can both fire at the same time and the isRecolting will look like it’s not changing when in fact, it’s changing twice instantly.

Also, what is “timeForRecolt”? I see that you’re taking 800 away from it, why is that? I hope that you’re also aware that the Wait function takes the number of milliseconds to wait (1 second = 1000 milliseconds).

Note: If you’ve still not figured this out in half an hour, I’ll see if I can cobble something together for you :slight_smile:


#13

I’m not printing the variables but I will do.
Nevertheless I’m pretty sure that the both are firing at the same time. When I try to ‘Press E’ in game nothing happen.

timeForRecolt is a variable, it’s role is to wait before the player receive an item from his recolting action. Otherwise he would receive an item at each tick.

This system is part of a recolt / treatment / sell system that I try to build.

That’s very nice of you to try to cobble something, i’m waiting for you. To wait, i’m going to print the variables and test other things.

Thank’s in advance

EDIT :

-- Listen for Player to be near something
Citizen.CreateThread(function()
	while true do
		Citizen.Wait(1)
		if(IsNearSomething() == 're') then
			doRecolt()
		elseif(IsNearSomething() == 'tr') then
			DisplayHelpText("Appuyez sur ~INPUT_PICKUP~ pour traiter.")
			doTreatment()
		elseif(IsNearSomething() == 'se') then
			DisplayHelpText("Appuyez sur ~INPUT_PICKUP~ pour vendre.")
			doSell()
		else
			isRecolting, isTreating, isSelling = false
		end
	end
end)

-- Actions de récolte
function doRecolt()
	if IsControlJustPressed(1, 38) then -- If INPUT_PICKUP Is pressed (touche E)
		isRecolting = not isRecolting
	end
	if (isRecolting == false) then
		DisplayHelpText("Appuyez sur ~INPUT_PICKUP~ pour récolter.")
	else
		DisplayHelpText("Appuyez sur ~INPUT_PICKUP~ pour ~r~arrêter~w~ de récolter.")
		drawTxt("~b~Récolte~w~ en cours...",10,0,0.4,0.95,0.4,255,255,255,255)
		--Citizen.Wait(timeForRecolt - 800)
		TriggerEvent("player:receiveItem", tonumber(JOBS[jobId].recolt_item_id), 1)
		drawTxt("~g~+1~w~".. tostring(JOBS[jobId].recolt_item_libelle),10,0,0.4,0.95,0.4,255,255,255,255)
	end
end

Ok, when I comment this line --Citizen.Wait(timeForRecolt - 800) it’s working very well ! Exactly what I want.
Well, nearly, I receive 30 items / second when i’m recolting, how can I set a timer which wouldn’t mess up my script ?


Press button for recolt
#14

So, the code below allows the player to “toggle” the action:

local isRecolting = false -- Is player recolting?
local recoltTime = 1000 -- 1 second

Citizen.CreateThread(function()
    Citizen.Trace("Created control thread")
    while true do
        Citizen.Wait(1)
        if IsControlJustPressed(1, 38) then -- When they press INPUT_PICKUP (default e)
            isRecolting = not isRecolting -- Toggle the boolean
        end

        -- Show the different messages
        if isRecolting then
            -- Show the message telling them how to stop
        else
            -- Show the message telling them how to start
        end
    end
end)
-- Thread to give the player stuff when recolting
Citizen.CreateThread(function()
    Citizen.Trace("Created main thread")
    while true do
        Citizen.Wait(1)

        if isRecolting then
            Citizen.Wait(recoltTime) -- Wait for recoltTime (1 second)
            -- Since isRecolting could have changed since we started waiting. Double check it
            if isRecolting then
                -- TODO: Give the player stuff?
                Citizen.Trace("Giving player something!")
            end
        end
    end
end)

Obviously, you’ll need to change it to fit your specific use case but, the basics are there :slight_smile:


[Release] Harvest/Treatment/Selling Jobs System v1.1
#15

Thank’s a lot, that works very well !
Still some details to fix but my mains problems are gone, really, thank’s a lot. :slight_smile:


#16

Or should we put this .?


#17

Hey ! Thanks for your help, it works but I have an issue.
I’m using this to show the message :

function DisplayHelpText(str)
	SetTextComponentFormat("STRING")
	AddTextComponentString(str)
	DisplayHelpTextFromStringLabel(0, 0, 1, -1)
end
if isRecolting then
            -- Show the message telling them how to stop
			DisplayHelpText("Appuyer sur ~INPUT_PICKUP~ pour ~r~arrêter~w~.")
			else
            -- Show the message telling them how to start
			DisplayHelpText("Appuyer sur ~INPUT_PICKUP~ pour ~g~récolter~w~.")
			end

The issue is that I have the “pop-up GTA sound” playing in a loop and that’s really annoying, do you know if I can mute it or show the message in the top left corner of the screen without this pop up sound ?

Thanks :slight_smile:


#18

I’ll leave this native here for you (in future, have a look at <game>/citizen/scripting/lua/natives.lua for a better understanding of some natives :wink:).

function DisplayHelpTextFromStringLabel(p0, loop, beep, shape)
	return _in(0x238FFE5C7B0498A6, p0, loop, beep, shape)
end

#####Hint: Change your 1 into a 0 :stuck_out_tongue_winking_eye:


#19

Thanks <3 I should’ve done that on my own sorry ^^