User File #65756259523988954

Upload All User Files

#65756259523988954 - TAStudio Individual Player Input Remover

TAStudio_remove_individual_input.lua
Game: Unknown Game ( NES, see all files )
312 downloads
Uploaded 8/31/2020 8:02 AM by Dacicus (see all 26)
Lua script that allows you to remove input from individual players in BizHawk's TAStudio while leaving other players unaffected. Please read the comments at the top of the script, since there are some quirks to how it works.
--[[
This script allows you to remove input from one or more individual players in TAStudio while not affecting other players.  Input from the following frames is shifted up to replace the old input.  Currently hardcoded to support 1-4 players.
The script requires that you have at least one branch in the run.
Toggle the script while TAStudio is active to bring up a dialog box.
After the dialog box appears, load the branch that you want to edit.  This is necessary in order to determine the current branch, since there's no getcurrentbranch() function like in FCEUX.
Enter the starting and ending frames of the block that you would like to remove, then select which players to edit before pressing the button.
Pressing the button more than once causes an error.  There are two ways to prevent this:
1. Update the branch after each button press, thereby making the changes permanent.
2. Reload the branch, thereby undoing the changes.

Feel free to improve upon this.

Dacicus 2020/08/31
--]]

local number_of_players = 2
local current_branch = {}
local current_keys = {}
local option_form, box_text, box_frame_start, box_frame_end
local check_boxes = {}
local form = {["width"] = 300, ["height"] = 300, ["title"] = "TAStudio Input Remover"}
local text = {["bg_color"] = 0x00000000, ["startx"] = 10, ["starty"] = 10, ["startm"] = "Starting frame:",
  ["endx"] = 10, ["endy"] = 40, ["endm"] = "Ending frame:",
  ["remx"] = 10, ["remy"] = (form["height"] / 3) - 20, ["remm"] = "Input to remove:"}
local box = {["startw"] = 100, ["starth"] = 20, ["startx"] = 15 + form["width"] / 2, ["starty"] = 10,
  ["endw"] = 100, ["endh"] = 20, ["endx"] = 15 + form["width"] / 2, ["endy"] = 40}
local button = {["caption"] = "Remove input", ["x"] = (form["width"] / 2) - 75, ["y"] = 2 * form["height"] / 3,
  ["width"] = 150, ["height"] = 50}

local function get_current_keys(curr_keys)
  for k, v in pairs(joypad.get()) do
    if string.find(k, "P1", 1, true) then
      local curr_key = string.gsub(k, "P1 ", "")
      table.insert(curr_keys, curr_key)
    end
  end
  table.sort(curr_keys)
end

get_current_keys(current_keys)

local function set_branch(idx)
  current_branch["index"] = idx
  current_branch["id"] = tastudio.getbranches()[idx]["Id"]
end

tastudio.onbranchload(set_branch)

local function display_text(box, text)
  forms.setDefaultTextBackground(box, text["bg_color"])
  forms.drawText(box, text["startx"], text["starty"], text["startm"])
  forms.drawText(box, text["endx"], text["endy"], text["endm"])
  forms.drawText(box, text["remx"], text["remy"], text["remm"])
end

local function initialize_input_boxes(form, box)
  local box_start = forms.textbox(form, "0", box["startw"], box["starth"], "UNSIGNED", box["startx"], box["starty"])
  local box_end = forms.textbox(form, "0", box["endw"], box["endh"], "UNSIGNED", box["endx"], box["endy"])
  return box_start, box_end
end

local function initialize_checkboxes(form, players, xpos, ypos)
  local check_box = {}
  for i = 1, players do
    local curr_x = 10 + ((i - 1) % 2) * (xpos / 2)
    local curr_y = ypos + math.floor((i - 1) / 2) * 30
    check_box[i] = forms.checkbox(form, "P" .. i, curr_x, curr_y)
  end
  return check_box
end

local function clear_input(fr)
  for player = 1, number_of_players do
    if forms.ischecked(check_boxes[player]) then
      for curr_key = 1, #current_keys do
        tastudio.clearinputchanges()
        tastudio.submitinputchange(fr, "P" .. player .. " " .. current_keys[curr_key], false)
        tastudio.applyinputchanges()
      end
    end
  end
end

local function replace_input(old, new)
  local input_new = tastudio.getbranchinput(current_branch["id"], new)
  for player = 1, number_of_players do
    if forms.ischecked(check_boxes[player]) then
      for curr_key = 1, #current_keys do
        tastudio.clearinputchanges()
        local key_string = "P" .. player .. " " .. current_keys[curr_key]
        tastudio.submitinputchange(old, key_string, input_new[key_string])
        tastudio.applyinputchanges()
      end
    end
  end
end

local function process_frame(fr, ln, diff)
-- Subtract 1 in next line in order to prevent an error on line 91: "invalid arguments to method call"
-- It seems like the last frame show in TAStudio doesn't actually exist?  It always has to be empty.
  if fr + diff > ln - 1 then
    clear_input(fr)
  else
    replace_input(fr, fr + diff)
  end
end

local function process_button()
  local frame_start = tonumber(forms.gettext(box_frame_start))
  local frame_end = tonumber(forms.gettext(box_frame_end))
  local movie_length = movie.length()
  if frame_start > frame_end then
    console.writeline("ERROR: Starting frame cannot be greater than ending frame.")
  elseif frame_end > movie_length then
    console.writeline("ERROR: Ending frame cannot be after movie end.")
  else
    local frame_diff = frame_end - frame_start + 1
-- Subtract 1 in next line in order to prevent 1 extra frame from being added at the end of the movie.
    for curr_frame = frame_start, movie_length - 1 do
      process_frame(curr_frame, movie_length, frame_diff)
    end
  end
end

local function initialize_button(form, b)
  forms.button(form, b["caption"], process_button, b["x"], b["y"], b["width"], b["height"])
end

if number_of_players < 1 then
  console.writeline("ERROR: Must have at least 1 player.")
elseif number_of_players > 4 then
  console.writeline("ERROR: Cannot have more than 4 players.")
elseif not tastudio.engaged() then
  console.writeline("ERROR: TAStudio is not active.")
else
  option_form = forms.newform(form["width"], form["height"], form["title"])
  box_text = forms.pictureBox(option_form, 0, 0, form["width"] / 2, form["height"] / 3)
  display_text(box_text, text)
  box_frame_start, box_frame_end = initialize_input_boxes(option_form, box)
  check_boxes = initialize_checkboxes(option_form, number_of_players, form["width"], form["height"] / 3)
  initialize_button(option_form, button)
end