Just a quick update. The PRNG Button press function itself has been genericized and now takes player as an int argument. It shouldn't be passed anything else as an argument simply because it passes player to joypad.get() and joypad.set().
Unfortunately, I haven't put in the return nil case kludge yet, this was just a patch job to get the refactoring started. In other words, it will fail for any core in which joypad.get(1) returns nil. In other other words, it will fail if the core only expects one controller (such as GBx)
Language: lua
-- PRNG BOT version 3 (Refraction)
-- Just rewriting some variables and sendRandomButtonPress to allow for on-the-fly expansion up to five(!?) players in future updates.
-- TODO: return-nil kludge, learn and implement forms. Prepare other functions for on-the-fly expansion.
-- Global variable declarations --
checkTime = 0 -- Placeholder variable. I don't like passing expressions as arguments.
keyNames = {[1] = {},[2] = {}} -- Key Names array.
keysArray = {[1] = {},[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.
sendRandomButtonPress(1) -- 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.
sendRandomButtonPress(2)
end
elseif (checkTime < frequency/2) then -- Now, not all games accept single-frame inputs.
joypad.set(keysArray[1],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(keysArray[2],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)
keyNames[1][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
keyNames[2][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 sendRandomButtonPress(player) -- So let's look at sending random keys to player 1's controller.
keysArray[player] = joypad.get(player) -- First, fetch the current keys array.
i = math.random(table.getn(keyNames[player])) -- Generate a random number between 1 and the length of the Player 1 Key Names Array.
push = keyNames[player][i] -- Grab the key referenced by the generated random number.
if checkBlacklist(push) == true then -- If the key is not blacklisted,
keysArray[player][push] = "True" -- then set the key to be pressed.
else
sendRandomButtonPress(player)
end
joypad.set(keysArray[player],player) -- Finally, send the keys array to BizHawk for pressing.
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.
keysArray[1] = 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.
keysArray[2] = 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
E: So, the upshot is now I'm going to be requesting a new joypad function: joypad.countPlayers(). Should just return the number of controllers the core will accept inputs for at that time - example, if in N64 mode you have it set up for three controllers, joypad.countPlayers() should return 3.