What to do if multiple tables start with the same value?

HeyoI have a dictionary of moves which has a table for sequence (the keys you need to press to perform the move) like this

[3] = {
    Name          = "Grab";
    Sequence      = {"G","B"};
},
[4] = {
    Name          = "Light Punch";
    Sequence      = {"G"};
};

And then I have a script which has a function to check if what the player inputted matches with any of the moves and it works however turns out there’s an issue where if there’s multiple moves that start with the same input it doesn’t know which one to do. So if I’m trying to do the grab move I’ll go press G, but my code is gonna think I’m trying to do light punch and yeah. How can I fix this?

If you’re still planning it out then the easiest solution is try not to match up keys at the front of a sequence - for example, if you want all your moves to start with G, instead make them end with G and keep the different parts of the code at the start.

The other option which is a bit more work and has a bit of latency is to add a key delay where the next key needs to be pressed before a certain time. If I press G then the script will have to wait X amount of time in order to know if I really only want to do a light punch or if I want to continue entering keys for a different move. Then there is a balance in making the delay short enough so it doesn’t feel laggy for shorter sequences and still long enough to allow flexible timing.

Hm you think you could give me an example of how how I could add a key delay? By the way my current script is all connected to a RenderStep so it’s constantly running and I use a thing called a FIFO queue which I thought I needed, but I’m starting to feel like maybe I don’t need it, but basically when a key is entered it gets put into a queue and then added to a table.

Main.UIS.InputBegan:Connect(function(inputObj, processed)
	if (processed) or (Modules.PauseGame.Paused) then return end

	local Key = Main.UIS:GetStringForKeyCode(inputObj.KeyCode)
	if CommandInputs[Key] then
		AddToFrame(Key)
		local input = CommandInputs[Key]
		--push input to the queue
		Queue:push({INPUT = input, TIME = tick()})
	end
end)
--This is inside a function which is connected to a RenderStepped
AddToInputSequence(data['INPUT'])
local function AddToInputSequence(input)
	table.insert(InputSequence, input)
	CheckSequence()
end

Is CheckSequence the function that decides which move is being used?

Yeah it is
Uhhh random stuff to pass limit

What I would do is to make a sort of timer system where it would work like this

  1. Detected input start timer
  2. Put input into array
  3. Wait an specified amount of time
  4. If an input occurs within that time then restart the timer.
  5. Else check the input and try to match with the dictionary of different combos.

So, maybe something like this.

local ComboInput = {}
local ComboActive = false
local ComboLength = 0
local PrevComboLength = 0
local ComboInputSpeed = 0.3 
UserInputService.InputBegan:Connect(function(InputObject,GameProccessed)
    if GameProccessed then return end
    if InputObject.UserInputType == Enum.UserInputType.Keyboard then
        if not ComboActive then
            ComboInput = {}                
        end
        if InputObject.KeyCode == (Enum.KeyCode.G or Enum.KeyCode.R) then -- You should put all the keys that can be available to be used for a combo
            table.insert(ComboInput,InputObject.KeyCode)
            -- Here is where the combo check will do
            PrevComboLength = #ComboInput
            delay(ComboInputSpeed,function() -- User has 0.3 seconds to press another key. If not the fight code runs
                ComboLength = #ComboInput -- We are using the fact that when we add a move to a combo the length changes. So if the length hasn't changed in the 0.3 seconds we will run the fight code.
                if ComboInput == <find the combo that is correct> then -- NOTE: I highly reccommend you use a string instead of an array here. I have used an array so checking if an array is the same as another requires a lot more code than an if statement. I think it is much more simpler to use a string to hold combos as it is a lot more easier to understand and more readable. Plus the elements don't really need to be separated.#
                    if ComboLength == PrevComboLength then
                        --FIght code here
                        --Fight code for each combo should be put here.
                    end
                end
            end)
        end
    end
end)

I am pretty sure this will work. Let me know if it doesn’t.

Of course there might be a better solution due to the fight code will not run only after 0.3 seconds.
I think it might even be better to lessen the combo length time between keypress

1 Like

Then I think that is where you would put your wait time code - when you call CheckSequence, wait X time before you pick which move to use. Have a counter that represents the number of keys pressed - you store that number locally in the function before you wait, and then after the wait, check if the updated number has increased (ie the function was called again for another key press). If the number went up from what it was at the start of the function call then another key was pressed so you don’t do anything and let the new function call handle picking which move to use with the updated key list. Once a move is selected just reset the counter.

Well this is just one idea, @koziahss also has some good ideas

So I’m a bit confused although I might just be to tired to understand this lol, but basically if I’m understanding this correctly inside the function I’d do this?

local function CheckSequence()
	local KeysPressed = 0
	wait(1) --just an example idk how to long to actually wait for
    --check stuff 
end

The only thing is how would I increase this? because it’s just gonna reset every time it gets called unless you mean put the counter outside of the function which probably makes more sense.

Also here’s the current CheckSequence function if you’re itnerested.

local function CheckSequence()
	local commandInputIndex = 0 --stores the index of the InputSequence table
	local lastMatchIndex = 0 --stores the last matching move
	local matchedInputCount = 0 --stores the amount of matching inputs

	for moveIndex = 1, #Moveset do
		commandInputIndex = ((#InputSequence - 1) + 1) --makes sure that it always stays at 1
		matchedInputCount = 0 --sets it to zero for each move in the moveset
		--walk backwards through the sequence
		for inputIndex = #Moveset[moveIndex].Sequence, 1, -1 do
			--"consume" the InputSequence until it is no more or we found our target input.
			while (commandInputIndex >= 0) do
				if Moveset[moveIndex].Sequence[inputIndex] == InputSequence[commandInputIndex] then
					matchedInputCount += 1
					break
				end
				commandInputIndex -= 1 --decrease the InputSequence's index
			end
		end
		
		if (matchedInputCount == #Moveset[moveIndex].Sequence) then
			lastMatchIndex = moveIndex
			local move = Moveset[lastMatchIndex] 	
			if not Compare(move.Sequence, InputSequence) then
				for i, moveData in pairs(Moveset) do
					if Compare(moveData.Sequence,InputSequence) then
						move = moveData
						break
					end
				end
			end			
			print("you performed: "..move.Name)
			Modules.ClientCombat:MoveInputted(move)
			InputSequence = {} --reset InputSequence table
		end
	end
end

Yes this is what I meant (although you still need to store the old value in the function so that you are checking against it after the wait).

So trying to do this right now, but lol I for some reason just have no idea what I’m doing this is what I tried to do.

local Counter = 0 

Main.UIS.InputBegan:Connect(function(inputObj, processed)
	Counter += 1
end)

local function CheckSequence()
	local OldCounter = Counter
	wait(1)
	if KeysPressed == OldKeysPressed then
		--Code here?
	end
end

Edit: Wait I think this is correct lol

local function CheckSequence()
    Counter += 1
	local OldCounter = Counter
	wait(1)
	if OldCounter == Counter then
		--Code here?
	end
end

Instead of hooking Counter to update on any UIS input event, update it in CheckSequence since you are controlling when it is called. Plus you don’t want to check against the old key because if one of your combos is ‘G’-‘G’-__ for example then you won’t be able to catch consecutive same-key presses.

Nah it’s not any key I have this in the input event

	local Key = Main.UIS:GetStringForKeyCode(inputObj.KeyCode)
	if CommandInputs[Key] then
		KeysPressed += 1
	end

although I didn’t eve think about increasing the counter inside the function so I’ll do that. Anyways overall this seems to work the only thing that sucks is having to delay the input, but it doesn’t seem like it’s that noticeable.

If the delay thing is too noticeable then having a startup animation that doesn’t use the full effect of the move can let you still make it feel responsive but while keeping the delay to overwrite a new move if more keys are pressed afterwards. Though obviously this requires much more work to setup in terms of adjusting animations and timing everything. Ideally, finding the sweet spot for the delay should be the first thing to try and see if it improves the experience without needing startup animations.