So I've run into an interesting issue.
joypad.get(1) returns nil if there's only one controller in the core. Easy way to see this is to call it in the Gambatte core. Why is this interesting?
Language: lua
-- PRNG BOT version 2 (Greentext)
-- Changes (2015-11-07):
-- P1 and P2 are now independently checked rather than just using the global joypad.get() results.
-- This makes blacklisting less of a chore as joypad.whatever, when passed a player number,
-- actually omits the player number prefix.
-- The upshot is that perfecting the Blacklist is a little easier.
--
-- Also, I removed the Buttons Pressed counter. It was not seeing any practical use.
-- It was originally a debug variable, but I ended up debugging using the console anyway.
--
-- Also also, documentation. This is the Greentext Update.
-- Global variable declarations --
checkTime = 0 -- Placeholder variable. I don't like passing expressions as arguments.
keyNamesP1 = {} -- Player 1 Key Names array.
keysArrayP1 = {} -- Player 1 Key State array.
keyNamesP2 = {} -- Player 2 Key Names array.
keysArrayP2 = {} -- Player 2 Key State array.
blacklist = {"Power", "Reset"} -- Blacklisted keys array.
frequency = 10 -- How often should the bot be updating? Also influences how long the keys are held.
mplay = false -- Is there a P2 controller? If not, we don't want to bother mucking around with P2 stuff.
function core() -- I like to have a manager functon that only handles calling other functions.
checkTime = emu.framecount() % frequency -- Set the frame count checker to the frame count modulo the frequency.
if (checkTime == 0) then -- If we're on the right frame, then go ahead and generate a new random key.
sendRandomButtonPressP1() -- For the technically-minded, it's actually pseudorandom, but let's not be overly pedantic.
if mplay == true then -- If Player 2's controller exists, generate keypresses for it as well.
sendRandomButtonPressP2()
end
elseif (checkTime < frequency/2) then -- Now, not all games accept single-frame inputs.
joypad.set(keysArrayP1,1) -- One of the games I tested with had this problem.
if mplay == true then -- So, for half of the frames between new keypress generations, send the same presses.
joypad.set(keysArrayP2,2) -- This allows 'slower' games to keep up, though it also slows down high-precision games.
end -- But do you really want to use a PRNG with a high-precision game?
end
end
function getButtonNames() -- Scraping joypad.get(x) for key names.
k = 1
j = 1
for key,v in pairs(joypad.get(1)) do -- For each pair in joypad.get(x)
keyNamesP1[k] = key -- keyNamesPX in position k is assigned key... uhh, key.
k = k+1 -- and k is incremented.
end
if joypad.get(2) ~= nil then -- As long as there's a table for P2, do the same for P2.
for key,v in pairs(joypad.get(2)) do
keyNamesP2[j] = key -- This can be rewritten to use one less for loop.
j = j+1 -- However, I like it written this way since it's one less if-then than would be needed.
mplay = true -- Since boolean mplay starts false, we set it true.
end -- This allows me to tell other functions to skip the P2 stuff if there's no P2.
end
end
function sendRandomButtonPressP1() -- So let's look at sending random keys to player 1's controller.
keysArrayP1 = joypad.get(1) -- First, fetch the current keys array.
i = math.random(table.getn(keyNamesP1)) -- Generate a random number between 1 and the length of the Player 1 Key Names Array.
push = keyNamesP1[i] -- Grab the key referenced by the generated random number.
if checkBlacklist(push) == true then -- If the key is not blacklisted,
keysArrayP1[push] = "True" -- then set the key to be pressed.
end
joypad.set(keysArrayP1,1) -- Finally, send the keys array to BizHawk for pressing.
end
function sendRandomButtonPressP2() -- This is a doublicate of the P1 variant.
keysArrayP2 = joypad.get(2) -- Technically, these can be rewritten as a single function with clever argument use.
i = math.random(table.getn(keyNamesP2)) -- It's on the docket for the next revision.
push = keyNamesP2[i]
if checkBlacklist(push) == true then
keysArrayP2[push] = "True"
end
joypad.set(keysArrayP2,2)
end
function checkBlacklist(key) -- Long story short, certain keys (such as the power button) shouldn't be pressed.
result = true
for i, v in pairs(blacklist) do
if key == blacklist[i] then -- Check to make sure the button is not on the blacklist.
result = false -- If it's on the blacklist, DO NOT PRESS THE BUTTON.
end
end
return result
end
function initializeKeyArray() -- Just taking the key names and putting them into our placeholder arrays.
keysArrayP1 = joypad.get(1) -- We don't actually need to do this now, as they're reinitialized every time keys are sent.
if mplay == true then -- It's just best practice to initialize variables before using them.
keysArrayP2 = joypad.get(2) -- With that said, I do call the arrays before they get defined otherwise.
end -- I can't remember if I actually tested without this function.
end
---------------------------------------- AND NOW, FOR THE ACTUAL FUNCTION CALLS
getButtonNames()
initializeKeyArray()
while true do
core()
emu.frameadvance()
end