Advertisement
Guest User

Untitled

a guest
Aug 27th, 2016
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 52.52 KB | None | 0 0
  1. --This Lua script was developed for the BizHawk emulator, available at github.com/weatherton/BizHawkMarioKart64--
  2. --Purpose: Partially automate the process of executing perfect maneuvers in Mario Kart 64------------------------
  3. console.clear()
  4.  
  5. function GetInputQueue()
  6.     return bizstring.split(forms.gettext(InputQueueTextBox), "\r\n")
  7. end
  8.  
  9. function SetInputQueue(table_data)
  10.     local tableStr = ""
  11.     local i = 1
  12.  
  13.     while i <= #table_data do
  14.         if (i > 1) then
  15.           tableStr = tableStr .. "\r\n"
  16.         end
  17.        
  18.         tableStr = tableStr .. table_data[i]
  19.         i = i +1
  20.     end
  21.    
  22.     forms.settext(InputQueueTextBox, tableStr)
  23. end
  24.  
  25. --User has clicked the "Generate Input" button
  26. function GenerateButton()
  27.     --Variables, from Interface:
  28.     Direction = forms.gettext(DirectionDropdown)
  29.     Maneuver = forms.gettext(ManeuverDropdown)
  30.     GlideType = forms.gettext(GlideDropdown)
  31.     BlankLeadingFrames = tonumber(forms.gettext(TextBoxBlankLeadingFrames))
  32.  
  33.     --Input Catalog Logic-----------------------------------------------------------------
  34.     --NOTE: We use the bk2 N64 movie mnemonic format (|..|    0,    0,...........A......|)
  35.     --|rP| -XXX, -YYY,UDLRUDLRSZBAudrllr|
  36.     --|rP| -XXX, -YYY,
  37.     --      (+ analog)UDLR
  38.     --             (D-pad)UDLR
  39.     --                        SZBA
  40.     --                 (C buttons)udrl
  41.     --                      (Shoulder)lr|
  42.  
  43.     --Add an array to store inputs in
  44.     FramesQueue = {}
  45.  
  46.     -- Add any desired blank frames to the start
  47.     local CatalogFrameCount = 1
  48.  
  49.     while CatalogFrameCount <= tonumber(forms.gettext(TextBoxBlankLeadingFrames)) do
  50.         FramesQueue[#FramesQueue+1] = string.format("%06i", CatalogFrameCount)..":|..|    0,    0,...........A......|"
  51.         CatalogFrameCount = CatalogFrameCount + 1
  52.     end
  53.  
  54.     -- Add specific maneuver inputs
  55.     if Maneuver == "1.Outward MT (fastest)" then
  56.         X_Array = {65,20,20,20,-35,65,-65,-65,-60,-60,-60,-60,-60,-60,-60,39,-50,-50,-50,-50,39,-65,-65,-65,-65,-65,-65,-65,-65,-65,-65,63}
  57.         R_End = 21
  58.         ManeuverComment = "Outward MT"
  59.  
  60.     elseif Maneuver == "2.Straight MT (faster)" then
  61.         X_Array = {62,20,20,20,-35,64,-60,-60,-60,-60,-60,-60,-60,-60,-60,39,-50,-50,-50,-50,50,-56,-65,-65,-65,-65,-65,-65,-65,-65,-65,-65,61}
  62.         R_End = 21
  63.         ManeuverComment = "Straight MT"
  64.  
  65.     elseif Maneuver == "3.Inward MT (fast)" then
  66.         X_Array = {65,65,65,20,20,65,-65,-65,-65,-60,-60,-60,-60,-60,-60,39,-50,-50,-50,-50,40,-55,-65,-65,-65,-65,-65,-65,-65,-65,-65,-65,-65,65}
  67.         R_End = 21
  68.         ManeuverComment = "Inward MT"
  69.  
  70.     elseif Maneuver == "4.Shroom Slide" then
  71.         OuterFramesPer = tonumber(forms.gettext(TextBoxOuterFramesPer))
  72.         InnerMagnitude = tonumber(forms.gettext(TextBoxInnerMagnitude))
  73.         ShroomSlideFrames = tonumber(forms.gettext(TextBoxTotalShroomSlideFrames))
  74.         X_Array = {}
  75.         ManeuverComment = "Shroom Slide"
  76.  
  77.         local i = 0
  78.         while i <= ShroomSlideFrames do
  79.             local j = 0
  80.             while j < OuterFramesPer do
  81.                 X_Array[#X_Array+1] = -65
  82.                 j = j + 1
  83.                 i = i +1
  84.             end
  85.  
  86.             X_Array[#X_Array+1] = InnerMagnitude
  87.             i = i +1
  88.         end
  89.  
  90.         R_End = table.getn(X_Array)
  91.     end
  92.  
  93.     TableSize = table.getn(X_Array)
  94.  
  95.     -- Make turn glide, if needed
  96.     if GlideType == "Turn" then
  97.         X_Array[R_End] = 65
  98.        
  99.         i = 1
  100.         while i <= 10 do
  101.             X_Array[R_End + i] = 65
  102.             i = i + 1
  103.         end
  104.  
  105.         X_Array[R_End + 11] = -55
  106.  
  107.         TableSize = R_End + 11
  108.     end
  109.  
  110.     -- Generate the input in the mnemonic format
  111.     local MT_Iterator = 1
  112.     while MT_Iterator <= TableSize do
  113.  
  114.         X_Value = X_Array[MT_Iterator]
  115.         if Direction == "Left" then
  116.             X_Value = -X_Array[MT_Iterator]
  117.         end
  118.    
  119.         FramesQueue[#FramesQueue+1] = string.format("%06i", CatalogFrameCount)..":|..| "
  120.         FramesQueue[#FramesQueue] = FramesQueue[#FramesQueue]..string.format("%4i", X_Value)
  121.  
  122.         if MT_Iterator == 1 then
  123.             FramesQueue[#FramesQueue] = FramesQueue[#FramesQueue]..",    0,...........A.....r|#"..ManeuverComment
  124.         elseif MT_Iterator <= R_End then
  125.             FramesQueue[#FramesQueue] = FramesQueue[#FramesQueue]..",    0,...........A.....r|#"
  126.         else
  127.             FramesQueue[#FramesQueue] = FramesQueue[#FramesQueue]..",    0,...........A......|#"
  128.         end
  129.  
  130.         MT_Iterator = MT_Iterator + 1
  131.         CatalogFrameCount = CatalogFrameCount + 1
  132.     end
  133.  
  134.     -- Append any desired blank frames to the end
  135.     local BlankTrailingFrameIterator = 0
  136.  
  137.     while BlankTrailingFrameIterator < tonumber(forms.gettext(TextBoxBlankTrailingFrames)) do
  138.         FramesQueue[#FramesQueue+1] = string.format("%06i", CatalogFrameCount)..":|..|    0,    0,...........A......|#"
  139.         CatalogFrameCount = CatalogFrameCount + 1
  140.         BlankTrailingFrameIterator = BlankTrailingFrameIterator + 1
  141.     end
  142.  
  143.     -- Convert the FramesQueue table
  144.     local i = 1
  145.     local tableStr = ""
  146.     while i <= #FramesQueue do
  147.         if (i > 1) then
  148.             tableStr = tableStr .. "\r\n"
  149.         end
  150.         tableStr = tableStr .. FramesQueue[i]
  151.         i = i +1
  152.     end
  153.     -- Output to the Main Window
  154.     forms.settext(GeneratedTextBox, tableStr)
  155. end
  156.  
  157. local InputQueue = nil
  158. local queueIterator = nil
  159.  
  160. --Need to add blanks at the end of these arrays
  161. ModeArray = {" ","GP","TT","VS","BT"}
  162. EngineArray = {" ","50","100","150"}
  163. CourseArray = {" ","MR","CM","BC","BB","YV","FS","KTB","RRy","LR","MMF","TT","KD","SL","RRd","WS","BF","SS","DD","DK","BD","TC"}
  164.  
  165. SelectedMode = 1
  166. SelectedEngine = 1
  167. SelectedCourse = 1
  168. SelectedPlayers = " "
  169.  
  170. --User has clicked the "Execute Input" button
  171. function ExecuteButton()
  172.     if forms.ischecked(QueueJournalingCheckBox) == true then
  173.         local handle = io.open("MarioKart64_InputQueueJournal"..os.date("_%Y-%m-%d")..".txt", "a+")
  174.         handle:write("\r\n" .. "\r\n" .. os.date("%c") .."["..SelectedMode.."-"..SelectedEngine.."-"..SelectedCourse.."-"..SelectedPlayers.."p] ".. "\r\n" .. forms.gettext(InputQueueTextBox))
  175.         handle:close()
  176.     end
  177.  
  178.     InputQueue = GetInputQueue()
  179.     queueIterator = 1
  180.    
  181.     forms.setproperty(ExecuteButtonHandle, "Enabled", false)
  182.     forms.setproperty(RecordButtonHandle, "Enabled", false)
  183.     forms.setproperty(ExecuteItemBotButtonHandle, "Enabled", false)
  184. end
  185.  
  186. --For storing hud option states
  187. Check_LapPosition = true
  188. Check_Coordinates = true
  189. Check_Rivals = true
  190. Check_Time = true
  191. Check_SpeedState = true
  192. Check_MetricsState = true
  193.  
  194. function CheckLapPosition()
  195.     Check_LapPosition = not Check_LapPosition
  196. end
  197. function CheckCoordinates()
  198.     Check_Coordinates = not Check_Coordinates
  199. end
  200. function CheckRivals()
  201.     Check_Rivals = not Check_Rivals
  202. end
  203. function CheckTime()
  204.     Check_Time = not Check_Time
  205. end
  206. function CheckSpeedState()
  207.     Check_SpeedState = not Check_SpeedState
  208. end
  209. function CheckMetricsState()
  210.     Check_MetricsState = not Check_MetricsState
  211. end
  212.  
  213. --User has clicked the "HUD Options" button
  214. function HudButton()
  215.     HudWindow = forms.newform(225, 120, "HUD Options")
  216.  
  217.     --HUD Customizations
  218.     forms.label(HudWindow, "HUD Settings: (Uncheck to hide)", 10, 6, 240, 18)
  219.     CheckboxHUD_LapPosition = forms.checkbox(HudWindow, "Lap / Position", 10, 21)
  220.     CheckboxHUD_Coordinates = forms.checkbox(HudWindow, "Coordinates", 10, 40)
  221.     CheckboxHUD_Rivals = forms.checkbox(HudWindow, "Rivals", 10, 59)
  222.     CheckboxHUD_Time = forms.checkbox(HudWindow, "Time", 120, 21)
  223.     CheckboxHUD_SpeedState = forms.checkbox(HudWindow, "Speed / State", 120, 40)
  224.     CheckboxHUD_MetricsState = forms.checkbox(HudWindow, "Metrics", 120, 59)
  225.    
  226.     forms.setproperty(CheckboxHUD_LapPosition, "Checked", Check_LapPosition)
  227.     forms.setproperty(CheckboxHUD_Coordinates, "Checked", Check_Coordinates)
  228.     forms.setproperty(CheckboxHUD_Rivals, "Checked", Check_Rivals)
  229.     forms.setproperty(CheckboxHUD_Time, "Checked", Check_Time)
  230.     forms.setproperty(CheckboxHUD_SpeedState, "Checked", Check_SpeedState)
  231.     forms.setproperty(CheckboxHUD_MetricsState, "Checked", Check_MetricsState)
  232.    
  233.     forms.addclick(CheckboxHUD_LapPosition, CheckLapPosition)
  234.     forms.addclick(CheckboxHUD_Coordinates, CheckCoordinates)
  235.     forms.addclick(CheckboxHUD_Rivals, CheckRivals)
  236.     forms.addclick(CheckboxHUD_Time, CheckTime)
  237.     forms.addclick(CheckboxHUD_SpeedState, CheckSpeedState)
  238.     forms.addclick(CheckboxHUD_MetricsState, CheckMetricsState)
  239. end
  240. HudButton()
  241. forms.destroy(HudWindow)
  242.  
  243. WaypointsWindow = forms.newform(482, 700, "Mario Kart 64 Waypoint Dashboard")
  244. forms.destroy(WaypointsWindow)
  245.  
  246. --User has clicked the "Waypoints" button
  247. function WaypointsButton()
  248.     WaypointsWindow = forms.newform(482, 700, "Mario Kart 64 Waypoint Dashboard")
  249.  
  250.     WaypointFilename = forms.textbox(WaypointsWindow, "WaypointFile", 366, 18, "", 53, 3, true, true)
  251.     SaveWaypoint1Handle = forms.button(WaypointsWindow, "Save", SaveWaypoint1Button, 0, 0, 50, 23)
  252.     OpenWaypoint1Handle = forms.button(WaypointsWindow, "Open", OpenWaypoint1Button, 422, 0, 50, 23)
  253.  
  254. -- Waypoint 1------------------------------------------------------------------------------------------------------------
  255. -- Waypoint 1, Point 1
  256.     forms.label(WaypointsWindow, "____________________________________________________________________________________", 0, 11, 477, 14)
  257.    
  258.     forms.label(WaypointsWindow, "Waypoint 1:", 0, 30, 64, 18)
  259.  
  260.     SetWaypoint1Handle = forms.button(WaypointsWindow, "Set from location", SetWaypoint1Button, 185, 110, 94, 23)
  261.     SetWaypoint1Handle2 = forms.button(WaypointsWindow, "Set from location", SetWaypoint1Button2, 378, 110, 94, 23)
  262.     -- Create checkbox for toggling this waypoint's visiblity
  263.     CheckboxWayline1 = forms.checkbox(WaypointsWindow, "Line segment", 295, 110)
  264.     -- This starts as visible but is changed to invisible to reveal coordinates for the optional line segment end point
  265.     Waypoint1Cover2 = forms.label(WaypointsWindow, "", 320, 50, 160, 60)
  266.     Waypoint1TitleTextBox = forms.textbox(WaypointsWindow, "Waypoint 1", 408, 20, "", 64, 27, true, true)
  267.  
  268.     Waypoint1XTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 185, 50, false, true)
  269.     Waypoint1XLabel = forms.label(WaypointsWindow, "X:", 171, 55, 17, 15)
  270.     Waypoint1X = tonumber(forms.gettext(Waypoint1XTextBox))
  271.  
  272.     Waypoint1YTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 185, 70, false, true)
  273.     forms.label(WaypointsWindow, "Y:", 171, 75, 17, 15)
  274.     Waypoint1Y = tonumber(forms.gettext(Waypoint1YTextBox))
  275.  
  276.     Waypoint1ZTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 185, 90, false, true)
  277.     forms.label(WaypointsWindow, "Z:", 171, 95, 17, 15)
  278.     Waypoint1Z = tonumber(forms.gettext(Waypoint1ZTextBox))
  279.  
  280. -- Waypoint 1, Point 2
  281.     Waypoint1X2TextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 340, 50, false, true)
  282.     forms.label(WaypointsWindow, "X2:", 320, 55, 24, 15)
  283.     Waypoint1X2 = tonumber(forms.gettext(Waypoint1X2TextBox))
  284.  
  285.     Waypoint1Y2TextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 340, 70, false, true)
  286.     forms.label(WaypointsWindow, "Y2:", 320, 75, 24, 15)
  287.     Waypoint1Y2 = tonumber(forms.gettext(Waypoint1Y2TextBox))
  288.  
  289.     Waypoint1Z2TextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 340, 90, false, true)
  290.     forms.label(WaypointsWindow, "Z2:", 320, 95, 24, 15)
  291.     Waypoint1Z2 = tonumber(forms.gettext(Waypoint1Z2TextBox))
  292.  
  293. -- Distances
  294.     forms.label(WaypointsWindow, "Distances:", 10, 53, 60, 15)
  295.     Waypoint1XYTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 33, 70, false, true)
  296.     forms.label(WaypointsWindow, "XY:", 10, 75, 25, 20)
  297.  
  298.     Waypoint1XYZTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 33, 90, false, true)
  299.     forms.label(WaypointsWindow, "XYZ:", 3, 95, 32, 20)
  300.  
  301.     CheckboxWaypoint1OnScreen = forms.checkbox(WaypointsWindow,"On-Screen",40,110)
  302.     forms.setproperty(CheckboxWaypoint1OnScreen,"Checked",true)
  303.  
  304. -- Waypoint 2------------------------------------------------------------------------------------------------------------
  305. -- Waypoint 2, Point 1
  306.     forms.label(WaypointsWindow, "____________________________________________________________________________________", 0, 123, 477, 14)
  307.    
  308.     SetWaypoint2Handle = forms.button(WaypointsWindow, "Set from location", SetWaypoint2Button, 185, 222, 94, 23)
  309.     Waypoint2TitleTextBox = forms.textbox(WaypointsWindow, "Waypoint 2", 388, 20, "", 84, 139, true, true)
  310.     CheckboxWaypoint2 = forms.checkbox(WaypointsWindow, "Waypoint 2:", 3, 137)
  311.    
  312.     Waypoint2XTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 185, 162, false, true)
  313.     Waypoint2XLabel = forms.label(WaypointsWindow, "X:", 171, 167, 17, 15)
  314.     Waypoint2X = tonumber(forms.gettext(Waypoint1XTextBox))
  315.  
  316.     Waypoint2YTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 185, 182, false, true)
  317.     forms.label(WaypointsWindow, "Y:", 171, 187, 17, 15)
  318.     Waypoint2Y = tonumber(forms.gettext(Waypoint1YTextBox))
  319.  
  320.     Waypoint2ZTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 185, 202, false, true)
  321.     forms.label(WaypointsWindow, "Z:", 171, 207, 17, 15)
  322.     Waypoint2Z = tonumber(forms.gettext(Waypoint1ZTextBox))
  323.  
  324. -- Waypoint 1, Point 2
  325.     SetWaypoint2Handle2 = forms.button(WaypointsWindow, "Set from location", SetWaypoint2Button2, 378, 222, 94, 23)
  326.  
  327.     -- Create checkbox for toggling this waypoint's visiblity
  328.     CheckboxWayline2 = forms.checkbox(WaypointsWindow, "Line segment", 295, 222)
  329.     -- This starts as visible but is changed to invisible to reveal coordinates for the optional line segment end point
  330.     Waypoint2Cover2 = forms.label(WaypointsWindow, "", 320, 162, 160, 60)
  331.  
  332.     Waypoint2X2TextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 340, 162, false, true)
  333.     forms.label(WaypointsWindow, "X2:", 320, 167, 24, 15)
  334.     Waypoint2X2 = tonumber(forms.gettext(Waypoint1X2TextBox))
  335.  
  336.     Waypoint2Y2TextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 340, 182, false, true)
  337.     forms.label(WaypointsWindow, "Y2:", 320, 187, 24, 15)
  338.     Waypoint2Y2 = tonumber(forms.gettext(Waypoint1Y2TextBox))
  339.  
  340.     Waypoint2Z2TextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 340, 202, false, true)
  341.     forms.label(WaypointsWindow, "Z2:", 320, 207, 24, 15)
  342.     Waypoint2Z2 = tonumber(forms.gettext(Waypoint1Z2TextBox))
  343.  
  344. -- Distances
  345.     forms.label(WaypointsWindow, "Distances:", 10, 165, 60, 15)
  346.     Waypoint2XYTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 33, 182, false, true)
  347.     forms.label(WaypointsWindow, "XY:", 10, 187, 25, 20)
  348.  
  349.     Waypoint2XYZTextBox = forms.textbox(WaypointsWindow, "0", 132, 20, SIGNED, 33, 202, false, true)
  350.     forms.label(WaypointsWindow, "XYZ:", 3, 207, 32, 20)
  351.  
  352.     CheckboxWaypoint2OnScreen = forms.checkbox(WaypointsWindow,"On-Screen",40,222)
  353.     forms.setproperty(CheckboxWaypoint2OnScreen,"Checked",true)
  354. end
  355.  
  356. --User has clicked the "Save" button
  357. function SaveWaypoint1Button()
  358.  
  359.     if forms.ischecked(CheckboxWayline1) == true then
  360.         CheckboxWayline1State = "true"
  361.     else
  362.         CheckboxWayline1State = "false"
  363.     end
  364.  
  365.     if forms.ischecked(CheckboxWaypoint2) == true then
  366.         CheckboxWaypoint2State = "true"
  367.     else
  368.         CheckboxWaypoint2State = "false"
  369.     end
  370.  
  371.     if forms.ischecked(CheckboxWayline2) == true then
  372.         CheckboxWayline2State = "true"
  373.     else
  374.         CheckboxWayline2State = "false"
  375.     end
  376.  
  377.     local handle = io.open(forms.gettext(WaypointFilename) .. ".wpt", "w+")
  378.     handle:write(
  379.         CheckboxWayline1State .. "\n" ..
  380.         CheckboxWaypoint2State .. "\n" ..
  381.         CheckboxWayline2State .. "\n" ..
  382.  
  383.         forms.gettext(Waypoint1TitleTextBox) .. "\n" ..
  384.         forms.gettext(Waypoint1XTextBox) .. "\n" ..
  385.         forms.gettext(Waypoint1YTextBox) .. "\n" ..
  386.         forms.gettext(Waypoint1ZTextBox) .. "\n" ..
  387.  
  388.         forms.gettext(Waypoint1X2TextBox) .. "\n" ..
  389.         forms.gettext(Waypoint1Y2TextBox) .. "\n" ..
  390.         forms.gettext(Waypoint1Z2TextBox) .. "\n" ..
  391.  
  392.         forms.gettext(Waypoint2TitleTextBox) .. "\n" ..
  393.         forms.gettext(Waypoint2XTextBox) .. "\n" ..
  394.         forms.gettext(Waypoint2YTextBox) .. "\n" ..
  395.         forms.gettext(Waypoint2ZTextBox) .. "\n" ..
  396.  
  397.         forms.gettext(Waypoint2X2TextBox) .. "\n" ..
  398.         forms.gettext(Waypoint2Y2TextBox) .. "\n" ..
  399.         forms.gettext(Waypoint2Z2TextBox))
  400.     handle:close()
  401.  
  402.     console.log("Waypoint File Saved")
  403. end
  404.  
  405. --User has clicked the "Open" button
  406. function OpenWaypoint1Button()
  407.     SavedVariables = { }
  408.  
  409.     SavedVariables[0] = CheckboxWayline1
  410.     SavedVariables[1] = CheckboxWaypoint2
  411.     SavedVariables[2] = CheckboxWayline2
  412.  
  413.     SavedVariables[3] = Waypoint1TitleTextBox
  414.     SavedVariables[4] = Waypoint1XTextBox
  415.     SavedVariables[5] = Waypoint1YTextBox
  416.     SavedVariables[6] = Waypoint1ZTextBox
  417.     SavedVariables[7] = Waypoint1X2TextBox
  418.     SavedVariables[8] = Waypoint1Y2TextBox
  419.     SavedVariables[9] = Waypoint1Z2TextBox
  420.     SavedVariables[10] = Waypoint2TitleTextBox
  421.     SavedVariables[11] = Waypoint2XTextBox
  422.     SavedVariables[12] = Waypoint2YTextBox
  423.     SavedVariables[13] = Waypoint2ZTextBox
  424.     SavedVariables[14] = Waypoint2X2TextBox
  425.     SavedVariables[15] = Waypoint2Y2TextBox
  426.     SavedVariables[16] = Waypoint2Z2TextBox
  427.  
  428.     WaypointDirectory = forms.openfile()
  429.  
  430.     local i = 0
  431.  
  432.     for line in io.lines(WaypointDirectory) do
  433.  
  434.         --console.log(line)
  435.         if i < 3 then
  436.             forms.setproperty(SavedVariables[i],"Checked",line)
  437.         else
  438.             forms.settext(SavedVariables[i], line)
  439.         end
  440.  
  441.         i = i + 1
  442.     end
  443. end
  444.  
  445. function SetWaypoint1Button()
  446.     forms.settext(Waypoint1XTextBox, PlayerX)
  447.     forms.settext(Waypoint1YTextBox, PlayerY)
  448.     forms.settext(Waypoint1ZTextBox, PlayerZ)
  449. end
  450.  
  451. function SetWaypoint1Button2()
  452.     forms.settext(Waypoint1X2TextBox, PlayerX)
  453.     forms.settext(Waypoint1Y2TextBox, PlayerY)
  454.     forms.settext(Waypoint1Z2TextBox, PlayerZ)
  455. end
  456.  
  457. function SetWaypoint2Button()
  458.     forms.settext(Waypoint2XTextBox, PlayerX)
  459.     forms.settext(Waypoint2YTextBox, PlayerY)
  460.     forms.settext(Waypoint2ZTextBox, PlayerZ)
  461. end
  462.  
  463. function SetWaypoint2Button2()
  464.     forms.settext(Waypoint2X2TextBox, PlayerX)
  465.     forms.settext(Waypoint2Y2TextBox, PlayerY)
  466.     forms.settext(Waypoint2Z2TextBox, PlayerZ)
  467. end
  468.  
  469. function SaveInputQueueStateButton()
  470.     local handle = io.open("["..SelectedMode.."-"..SelectedEngine.."-"..SelectedCourse.."-"..SelectedPlayers.."p]_"..forms.gettext(SaveInputQueueFileName)..os.date("_[%Y-%m-%d_%H'%M'%S]")..".que","w")
  471.     handle:write(forms.gettext(InputQueueTextBox))
  472.     handle:close()
  473.     console.log("Input Queue file saved")
  474.  
  475.     if forms.ischecked(QueueSavestateCheckbox) == true then
  476.         savestate.save(forms.gettext(SaveInputQueueFileName)..os.date("_%Y-%m-%d_%H'%M'%S")..".State")
  477.         console.log("Input Queue save state stored")
  478.     end
  479. end
  480.  
  481. function OpenInputQueueStateButton()
  482.     InputQueueDirectory = forms.openfile()
  483.     LoadedFramesQueue = {}
  484.  
  485.     if InputQueueDirectory ~= '' then
  486.         for line in io.lines(InputQueueDirectory) do
  487.             --console.log(line)
  488.             LoadedFramesQueue[#LoadedFramesQueue+1] = line
  489.         end
  490.  
  491.         -- Convert the FramesQueue table
  492.         local i = 1
  493.         local LoadedTableStr = ""
  494.         while i <= #LoadedFramesQueue do
  495.             if (i > 1) then
  496.                 LoadedTableStr = LoadedTableStr .. "\r\n"
  497.             end
  498.             LoadedTableStr = LoadedTableStr .. LoadedFramesQueue[i]
  499.             i = i +1
  500.         end
  501.  
  502.         -- Output to the Main Window
  503.         forms.settext(InputQueueTextBox, LoadedTableStr)
  504.     end
  505. end
  506.  
  507. --Generate the User Interface
  508. ------------INPUTS ARE X,Y,WIDTH,HEIGHT  -- For Text Boxes: WIDTH, HEIGHT, "signed", X, Y-------
  509. WainWindowTitle = "Mario Kart 64 Automatic Transmission v2.0"
  510. MainWindow = forms.newform(905, 800, WainWindowTitle)
  511.  
  512. -- Blank frames
  513. TextBoxBlankLeadingFrames = forms.textbox(MainWindow, "0", 20, 18, "UNSIGNED", 10, 5)
  514. forms.label(MainWindow, "Blank leading frames", 28, 8, 105, 18)
  515.  
  516. TextBoxBlankTrailingFrames = forms.textbox(MainWindow, "10", 20, 18, "UNSIGNED", 140, 5)
  517. forms.label(MainWindow, "Blank trailing frames", 158, 8, 105, 18)
  518.  
  519. --Direction dropdown
  520. LabelDirection = forms.label(MainWindow, "facing", 58, 31, 40, 20)
  521. a = { }
  522. a[1] = "Left"
  523. a[2] = "Right"
  524. DirectionDropdown = forms.dropdown(MainWindow, a, 10, 28, 48, 20)
  525.  
  526. --Maneuver dropdown
  527. a = { }
  528. a[1] = "1.Outward MT (fastest)"
  529. a[2] = "2.Straight MT (faster)"
  530. a[3] = "3.Inward MT (fast)"
  531. a[4] = "4.Shroom Slide"
  532. ManeuverDropdown = forms.dropdown(MainWindow, a, 98, 28, 132, 20)
  533.  
  534. --Turn dropdown
  535. LabelGlide = forms.label(MainWindow, "glide", 295, 32, 60, 20)
  536. a = { }
  537. a[1] = "Straight"
  538. a[2] = "Turn"
  539. GlideDropdown = forms.dropdown(MainWindow, a, 235, 28, 60, 20)
  540.  
  541. --Shroomslide options
  542. forms.label(MainWindow, "Shroom slide", 12, 57, 67, 14)
  543. forms.label(MainWindow, "parameters", 14, 68, 66, 14)
  544. forms.label(MainWindow, "(                       :", 5, 62, 90, 14)
  545.  
  546. TextBoxTotalShroomSlideFrames = forms.textbox(MainWindow, "60", 20, 18, "UNSIGNED", 95, 59)
  547. forms.label(MainWindow, "Total frames", 113, 61, 65, 18)
  548.  
  549. forms.label(MainWindow, "Outer frames", 282, 55, 67, 14)
  550. forms.label(MainWindow, "per inner", 287, 66, 60, 14)
  551. forms.label(MainWindow, ")", 346, 60, 8, 14)
  552. TextBoxOuterFramesPer = forms.textbox(MainWindow, "1", 20, 18, "UNSIGNED", 260, 59)
  553.  
  554. forms.label(MainWindow, "Inner", 207, 55, 40, 14)
  555. forms.label(MainWindow, "magnitude", 201, 66, 60, 14)
  556. TextBoxInnerMagnitude = forms.textbox(MainWindow, "32", 20, 18, "UNSIGNED", 181, 59)
  557.  
  558. --Create Input
  559. GenerateButtonHandle = forms.button(MainWindow, "Generate Input", GenerateButton, 1, 95, 86, 23)
  560.  
  561. --Multi-Line Textbox for Generating Input
  562. forms.label(MainWindow, "INPUT CATALOG:", 166, 101, 110, 15)
  563. GeneratedTextBox = forms.textbox(MainWindow, "000001:|..|    0,    0,...........A......|#Comment", 408, 615, "", 1, 118, true, true,"BOTH")
  564. forms.setproperty(GeneratedTextBox, "MaxLength", "1000000000")
  565.  
  566. --HUD window creation
  567. HUDButtonHandle = forms.button(MainWindow, "HUD Options", HudButton, 1, 735, 86, 23)
  568.  
  569. --Waypoints Button
  570. forms.button(MainWindow, "Waypoints", WaypointsButton, 135, 735, 86, 23)
  571.  
  572. --Input Queue Save Button
  573. forms.button(MainWindow, "Save^", SaveInputQueueStateButton, 426, 735, 50, 23)
  574.  
  575. --Input Queue Save Name
  576. SaveInputQueueFileName = forms.textbox(MainWindow, "InputQueueFile",  230, 23, "", 560, 735, true, true)
  577.  
  578. --Input Queue Save Includes State
  579. QueueSavestateCheckbox = forms.checkbox(MainWindow, "+ Savestate", 479,735)
  580.  
  581. --Input Queue Open Button
  582. forms.button(MainWindow, "Open", OpenInputQueueStateButton, 790, 735, 45, 23)
  583.  
  584. --Input Queue Journaling
  585. QueueJournalingCheckBox = forms.checkbox(MainWindow, "Journal to file", 426, 0)
  586. forms.setproperty(QueueJournalingCheckBox,"Checked",true)
  587.  
  588. --Coordinate Units
  589. a = { }
  590. a[1] = " Meters"
  591. a[2] = "Game Units"
  592. UnitsDropdown = forms.dropdown(MainWindow, a, 325, 735, 85, 23)
  593. forms.label(MainWindow, "Coordinates:", 260, 739, 66, 23)
  594.  
  595. --Populate the Frame Reference Table
  596. function PopulateFrameReference()
  597.     local LoadFramecount = emu.framecount()
  598.     local i = 1
  599.     local j = 1
  600.     local k = 1
  601.    
  602.     local input_queue = GetInputQueue()
  603.     --console.log(input_queue)
  604.    
  605.     while k <= #input_queue do
  606.         local cur_line = input_queue[i]
  607.         if cur_line == nil then
  608.             k = k + 1
  609.         else
  610.  
  611.             local input_start = string.find(cur_line, "|")
  612.            
  613.             if input_start ~= nil then
  614.                 cur_line = string.sub(cur_line, input_start)
  615.                 cur_line = string.format("%06i", (LoadFramecount + (j-1)*2)) .. ":" .. cur_line
  616.                 j = j + 1
  617.             end
  618.        
  619.             input_queue[i] = cur_line
  620.         end
  621.         i = i + 1
  622.         k = k + 1
  623.  
  624.     end
  625.    
  626.     SetInputQueue(input_queue)
  627. end
  628.  
  629. event.onloadstate(PopulateFrameReference)
  630.  
  631. --Item selection dropdown
  632. itemOptions = { }
  633. itemOptions[0] = "01. Banana"
  634. itemOptions[1] = "02. Banana Bunch"
  635. itemOptions[2] = "03. Green Shell"
  636. itemOptions[3] = "04. Triple Green Shell"
  637. itemOptions[4] = "05. Red Shell"
  638. itemOptions[5] = "06. Triple Red Shell"
  639. itemOptions[6] = "07. Spiny Shell"
  640. itemOptions[7] = "08. Thunder Bolt"
  641. itemOptions[8] = "09. Fake Item Box"
  642. itemOptions[9] = "10. Super Star"
  643. itemOptions[10] = "11. Boo"
  644. itemOptions[11] = "12. Mushroom"
  645. itemOptions[13] = "14. Triple Mushrooms"
  646. itemOptions[14] = "15. Super Mushroom"
  647. ItemSelectionDropdown = forms.dropdown(MainWindow, itemOptions, 712, 2, 125, 20)
  648.  
  649. BooModeCheckbox = forms.checkbox(MainWindow, "Boo", 844,23)
  650.  
  651. --Multi-Line Textbox for Input Queue
  652. forms.label(MainWindow, "INPUT QUEUE:", 576, 9, 150, 15)
  653. forms.textbox(MainWindow, "Frame#:|rP| -XXX, -YYY,UDLRUDLRSZBAudrllr|#Mnemonic", 409, 20, "", 426, 24, true, true)
  654. InputQueueTextBox = forms.textbox(MainWindow, "000001:|..|    0,    0,...........A......|#Comment", 409, 690, "", 426, 43, true, true,"BOTH")
  655. forms.setproperty(InputQueueTextBox, "MaxLength", "1000000000")
  656.  
  657. --Execute Input
  658. ExecuteButtonHandle = forms.button(MainWindow, "Execute Input", ExecuteButton, 834, 46, 55, 688)
  659.  
  660. RecordButtonHandle = nil
  661.  
  662. RecordState = 0
  663.  
  664. function RecordButton()
  665.   if (RecordState == 0) then
  666.     forms.setproperty(ExecuteButtonHandle, "Enabled", false)
  667.     forms.setproperty(ExecuteItemBotButtonHandle, "Enabled", false)
  668.    
  669.     -- Clear the queue
  670.     forms.settext(GeneratedTextBox, "")
  671.    
  672.     -- set flag to indicate in record mode
  673.     RecordState = 1
  674.    
  675.     forms.settext(RecordButtonHandle, "Stop Recording")
  676.   else
  677.     forms.setproperty(ExecuteButtonHandle, "Enabled", true)
  678.     forms.setproperty(ExecuteItemBotButtonHandle, "Enabled", true)
  679.  
  680.     RecordState = 0
  681.  
  682.     forms.settext(RecordButtonHandle, "Record Input")
  683.   end
  684. end
  685.  
  686. RecordButtonHandle = forms.button(MainWindow, "Record Input", RecordButton, 334, 95, 77, 23)
  687. RecordMetricsCheckBox = forms.checkbox(MainWindow, "+ Metrics", 341, 77)
  688.  
  689. function ClearQueue()
  690.     InputQueue = nil
  691.     queueIterator = nil
  692.     forms.setproperty(ExecuteButtonHandle, "Enabled", true)
  693.     forms.setproperty(RecordButtonHandle, "Enabled", true)
  694.     forms.setproperty(ExecuteItemBotButtonHandle, "Enabled", true)
  695. end
  696.  
  697. function CopyInputButton()
  698.     forms.settext(InputQueueTextBox, forms.gettext(GeneratedTextBox))
  699. end
  700.  
  701. CopyInputHandle = forms.button(MainWindow, ">", CopyInputButton, 404, 150, 30, 23)
  702.  
  703. function AppendInputButton()
  704.     forms.settext(InputQueueTextBox, forms.gettext(InputQueueTextBox) .. "\r\n" .. forms.gettext(GeneratedTextBox))
  705. end
  706.  
  707. AppendInputHandle = forms.button(MainWindow, ">>", AppendInputButton, 404, 200, 30, 23)
  708.  
  709. -- Bot variables
  710. ItemBotState = -1
  711. ItemBotIteratorSave = -1
  712. ItemBotWantedItem = -1
  713. ExecuteItemBotButtonHandle = nil
  714.  
  715. -- Item bot States:
  716. -- -1: not active
  717. -- 0: searching for first chance to hit Z
  718. -- 1: about to press Z
  719. -- 2: Waiting to see what item we got
  720. -- 3: advancing one input frame past the last time we tried
  721. -- 4. Successful cleanup
  722.  
  723. function ExecuteItemBotButton()
  724.     if (ItemBotState ~= -1) then
  725.         -- disable the bot
  726.         ItemBotState = -1
  727.         ClearQueue()
  728.  
  729.         -- Change the button text to something
  730.         forms.settext(ExecuteItemBotButtonHandle, "Item Bot")
  731.     else
  732.         -- Set up the input queue
  733.         ExecuteButton()
  734.  
  735.         -- Make both buttons disabled
  736.         forms.setproperty(ExecuteButtonHandle, "Enabled", false)
  737.        
  738.         -- Make a starting state
  739.         savestate.save("ItemBotStartingState")
  740.        
  741.         -- Find the desired item
  742.         itemSelection = forms.gettext(ItemSelectionDropdown)
  743.         local i = 0
  744.         while (i < 15) do
  745.             if (itemOptions[i] == itemSelection) then
  746.                 ItemBotWantedItem = i + 1
  747.             end
  748.             i = i + 1
  749.         end
  750.  
  751.         forms.setproperty(ExecuteItemBotButtonHandle, "Enabled", true)
  752.         forms.settext(ExecuteItemBotButtonHandle, "Stop Bot")
  753.        
  754.         ItemBotState = 0
  755.     end
  756. end
  757.  
  758. --Item Select Bot Execute
  759. ExecuteItemBotButtonHandle = forms.button(MainWindow, "Item Bot", ExecuteItemBotButton, 835, 1, 55, 23)
  760.  
  761. function load_state_handler()
  762.     if (ItemBotState == -1) then
  763.         ClearQueue()
  764.     end
  765.    
  766.     if (RecordState == 1) then
  767.       forms.setproperty(ExecuteButtonHandle, "Enabled", true)
  768.       forms.setproperty(ExecuteItemBotButtonHandle, "Enabled", true)
  769.    
  770.       RecordState = 0
  771.    
  772.       forms.settext(RecordButtonHandle, "Record Input")
  773.     end
  774. end
  775.  
  776. loadstateEventHandle = event.onloadstate(load_state_handler, "load_state_handler")
  777.  
  778. TimerAddr = 0x0DC598
  779.  
  780. function ResetMetrics()
  781.     MetricOffGround = 0
  782.     MetricABspin = 0
  783.     MetricTotalXYDistance = 0
  784.     MetricAvgXYSpeed = 0
  785.     MetricTotalXYZDistance = 0
  786.     MetricAvgXYZSpeed = 0
  787.     PriorPlayerX = nil
  788.     PriorPlayerY = nil
  789.     PriorPlayerZ = nil
  790.     MetricMaxXYSpeed = 0
  791.     MetricMaxXYZSpeed = 0
  792.     MetricSumOfXYSpeed = 0
  793.     MetricSumOfXYZSpeed = 0
  794.     FramesSinceLoad = 0
  795.     MetricMT = 0
  796.     MetricSlide = 0
  797.     MetricShroomSlide = 0
  798.     LoadRaceTime = mainmemory.readfloat(TimerAddr, true)
  799. end
  800.  
  801. --Instantiate metric variables
  802. ResetMetrics()
  803.  
  804. event.onloadstate(ResetMetrics)
  805.  
  806. --WHILE TRUE LOOP--WHILE TRUE LOOP--WHILE TRUE LOOP--WHILE TRUE LOOP--WHILE TRUE LOOP--WHILE TRUE LOOP--WHILE TRUE LOOP--WHILE TRUE LOOP--
  807. while true do
  808.  
  809.     PlaceAddr = 0x1643BB
  810.     Place=mainmemory.read_u8(PlaceAddr)
  811.  
  812.     -- Dynamically consolidate game state details to be used when saving files
  813.     local ModeAddr = 0x0DC53F
  814.     local EngineAddr = 0x0DC54B
  815.     local CourseAddr = 0x0DC5A1
  816.     local PlayersAddr = 0x0DC53B
  817.  
  818.     SelectedModeIndex = mainmemory.read_u8(ModeAddr)
  819.     SelectedEngineIndex = mainmemory.read_u8(EngineAddr)
  820.     SelectedCourseIndex = mainmemory.read_u8(CourseAddr)
  821.     --Check to console
  822.     --console.log(SelectedCourseIndex)
  823.     SelectedPlayers = mainmemory.read_u8(PlayersAddr)
  824.  
  825.     SelectedMode = ModeArray[SelectedModeIndex+2]
  826.     SelectedEngine = EngineArray[SelectedEngineIndex+2]
  827.     SelectedCourse = CourseArray[SelectedCourseIndex+2]
  828.  
  829.     forms.setproperty(MainWindow, "Text", WainWindowTitle.." ["..SelectedMode.."-"..SelectedEngine.."-"..SelectedCourse.."-"..SelectedPlayers.."p]")
  830.  
  831.     -- Detect if this is a lag frame
  832.     isLag = emu.islagged()
  833.  
  834.     Timer=mainmemory.readfloat(TimerAddr, true)
  835.  
  836.     if Check_Time then
  837.         gui.text(client.borderwidth(),0, "TIME ".. string.format("%.2f", Timer),"orange",0x50000000,"topright")
  838.     end
  839.  
  840.     if Check_LapPosition then
  841.         local LapAddr = 0x164390
  842.         local PathAddr = 0x163288
  843.  
  844.         Lap=mainmemory.read_s32_be(LapAddr) + 1
  845.         Path=mainmemory.read_s32_be(PathAddr)
  846.         gui.text(client.borderwidth()+client.bufferwidth()*.1,0, "LAP ".. Lap .. "/3, Path " .. Path .. ", Place " .. (Place + 1) .. "/8",0xFFC758FF,0x50000000)
  847.     end
  848.    
  849.     --Instantiate position / velocity variables
  850.         local Xaddr = 0x0F69A4
  851.         local XvAddr = 0x0F69C4
  852.         local Yaddr = 0x0F69AC
  853.         local YvAddr = 0x0F69CC
  854.         local Zaddr = 0xF69A8
  855.         local ZvAddr = 0x0F69C8
  856.         local ZgroundAddr = 0x0F6A04
  857.  
  858.         UnitsChoice = forms.gettext(UnitsDropdown)
  859.  
  860.         if UnitsChoice == " Meters" then
  861.             Units = 18
  862.         else
  863.             Units = 1
  864.         end
  865.  
  866.         --A note about units
  867.         --In-game velocities are multipled by 12 to arrive at the values used for the in-game speedometer (oddly, in-game velocities do not correspond directly
  868.         -----to game units as traveling for 1 velocity unit per hour for one second results in traveling 60 game units (where a direct relationship would give 3.6)
  869.         --To convert the coordinate game units to meters, I tested using reverse which is a constant 12.000... km/h on flat ground. At this speed 60.000... game units
  870.         -----are traveled. 12 km/h is 3.333... m/s so we should be covering (10/3) meters. Thus (10/3) meters = 60 game units and thus 1 meter = (3/10) * 60 = 18 game units
  871.         -----Thus, to show coordinates in meters we must divide them by 18. This is helpful to do as then velocities and coordinates are provided in km/h and meters respectively
  872.  
  873.         PlayerX=mainmemory.readfloat(Xaddr, true) / Units
  874.         PlayerXv=mainmemory.readfloat(XvAddr, true) * 12
  875.  
  876.         PlayerY=mainmemory.readfloat(Yaddr, true) / Units
  877.         PlayerYv=mainmemory.readfloat(YvAddr, true) * 12
  878.  
  879.         PlayerZ=mainmemory.readfloat(Zaddr, true) / Units
  880.         PlayerZv=mainmemory.readfloat(ZvAddr, true) * 12
  881.  
  882.         XYspeed = math.sqrt (PlayerXv^2+PlayerYv^2)
  883.         XYZspeed = math.sqrt (PlayerXv^2+PlayerYv^2+PlayerZv^2)
  884.  
  885.     if Check_Coordinates then
  886.         gui.text(0,17, "X ".. string.format("%.3f", PlayerX),"white","black","bottomleft")
  887.         gui.text(0,2, "Xv ".. string.format("%.3f", PlayerXv),"white","black","bottomleft")
  888.  
  889.         gui.text(120,17, "Y ".. string.format("%.3f", PlayerY),"white","black","bottomleft")
  890.         gui.text(120,2, "Yv ".. string.format("%.3f", PlayerYv),"white","black","bottomleft")
  891.  
  892.         gui.text(240,17, "Z ".. string.format("%.3f", PlayerZ),"white","black","bottomleft")
  893.         gui.text(240,2, "Zv ".. string.format("%.3f", PlayerZv),"white","black","bottomleft")
  894.  
  895.         gui.text(360,2, "XYZv " .. string.format("%.3f", XYZspeed) .. " km/h","white","black","bottomleft")
  896.  
  897.         GroundHeight=mainmemory.readfloat(ZgroundAddr, true)
  898.         PlayerHeight=mainmemory.readfloat(Zaddr, true)
  899.         PlayerAGL=(PlayerHeight-GroundHeight-5.317) / Units
  900.         gui.text(360,17, "Z[AGL] " .. string.format("%.2f", PlayerAGL),"white","black","bottomleft")
  901.  
  902.     end
  903.    
  904.     if Check_Rivals then
  905.         local Rival1Addr = 0x163349
  906.         local Rival2Addr = 0x16334B
  907.  
  908.         characters = {"Mario","Luigi","Yoshi","Toad","DK","Wario","Peach","Bowser"}
  909.    
  910.         Rival1=mainmemory.read_u8(Rival1Addr)
  911.         Rival2=mainmemory.read_u8(Rival2Addr)
  912.  
  913.         gui.text(client.borderwidth()+client.bufferwidth()*.5,0, "R1:" .. characters[Rival1+1] .. " R2:" .. characters[Rival2+1],"white","black","topleft")
  914.     end
  915.  
  916.     local StateCAddr = 0x0F6A4C
  917.     StateC=mainmemory.read_u8(StateCAddr)
  918.  
  919.     local StateEAddr = 0x0F6A4E
  920.     StateE=mainmemory.read_u8(StateEAddr)
  921.  
  922.     local StateFAddr = 0x0F6A4F
  923.     StateF=mainmemory.read_u8(StateFAddr)
  924.  
  925.     local State5BAddr = 0x0F6A5B
  926.     State5B=mainmemory.read_u8(State5BAddr)
  927.  
  928.     local MTglideAddr = 0x0F6BCB
  929.     MTglide=mainmemory.read_u8(MTglideAddr)
  930.  
  931.     if Check_SpeedState then
  932.  
  933.         if MTglide > 0 then
  934.             gui.text(client.screenwidth()*.5-30,client.screenheight()*.5 - 30, "MT " .. (31 - MTglide),"red")
  935.         end
  936.  
  937.         if bit.check(StateF,3) then
  938.             gui.text(client.screenwidth()*.5-50,client.screenheight()*.5 - 15, "OFF GROUND","red")
  939.         end
  940.  
  941.         --This speed address is what actually feeds the speedometer but it is only the XY velocity and also stops reporting after a race ends
  942.         --local SpeedAddr = 0x18CFE4
  943.         --Speed=mainmemory.readfloat(SpeedAddr, true)
  944.         --I chose to calculate the velocity based on the XY velocity rather than reading the speedometer memory value
  945.  
  946.         SpeedometerText = string.format("%.3f", XYspeed).. " km/h"
  947.  
  948.         gui.text(client.screenwidth()*.5-(5*(string.len(SpeedometerText))),client.screenheight()*.5, SpeedometerText,"white","black")
  949.        
  950.         if bit.check(StateF,5) then
  951.             gui.text(client.screenwidth()*.5-55,client.screenheight()*.5 + 15, "AB SPINNING","red")
  952.         end
  953.  
  954.         if bit.check(StateE,5) then
  955.             gui.text(client.screenwidth()*.5-45,client.screenheight()*.5 + 30, "SHROOMING","red")
  956.         end
  957.     end
  958.    
  959.     if Check_MetricsState then
  960.  
  961.         if (isLag == false) then
  962.            
  963.             if bit.check(StateF,3) then
  964.                 MetricOffGround = MetricOffGround + 1
  965.             end
  966.  
  967.             if bit.check(StateF,5) then
  968.                 MetricABspin = MetricABspin + 1
  969.             end
  970.  
  971.             if MTglide > 0 then
  972.                 MetricMT = MetricMT + 1
  973.             end
  974.  
  975.             if bit.check(StateF,4) and not bit.check(StateF,1) and not bit.check(StateF,3) then
  976.                
  977.                 if bit.check(StateE,5) then
  978.                     MetricShroomSlide = MetricShroomSlide + 1
  979.                 else
  980.                     MetricSlide = MetricSlide + 1
  981.                 end
  982.             end
  983.  
  984.             if (PriorPlayerX ~= nil) then
  985.                 MetricTotalXYDistance = MetricTotalXYDistance + math.sqrt ((PriorPlayerX-PlayerX)^2+(PriorPlayerY-PlayerY)^2)
  986.                 MetricTotalXYZDistance = MetricTotalXYZDistance + math.sqrt ((PriorPlayerX-PlayerX)^2+(PriorPlayerY-PlayerY)^2+(PriorPlayerZ-PlayerZ)^2)
  987.  
  988.                 if FramesSinceLoad < 1 then
  989.  
  990.                     MetricAvgXYSpeed = XYspeed
  991.                     MetricMaxXYSpeed = MetricAvgXYSpeed
  992.                     MetricTotalXYDistance = 0
  993.                     MetricAvgXYZSpeed = XYZspeed
  994.                     MetricMaxXYZSpeed = MetricAvgXYZSpeed
  995.                     MetricTotalXYZDistance = 0
  996.                
  997.                 elseif FramesSinceLoad >= 1 then
  998.  
  999.                     if (Timer > LoadRaceTime) then
  1000.                         -- Add check of Units to ensure it's 18
  1001.                         MetricAvgXYSpeed = ((MetricTotalXYDistance / 1000) * (Units/18)) / ((Timer - LoadRaceTime) / (60 * 60))
  1002.                         MetricAvgXYZSpeed = ((MetricTotalXYZDistance / 1000) * (Units/18))/ ((Timer - LoadRaceTime) / (60 * 60))
  1003.                     end
  1004.  
  1005.                     if MetricMaxXYSpeed < XYspeed then
  1006.                         MetricMaxXYSpeed = XYspeed
  1007.                     end
  1008.  
  1009.                     if MetricMaxXYZSpeed < XYZspeed then
  1010.                         MetricMaxXYZSpeed = XYZspeed
  1011.                     end
  1012.                 end
  1013.             end
  1014.         end
  1015.  
  1016.         -- Frames Off Ground:
  1017.         gui.text(2, 90, "Off Ground:" .. MetricOffGround,"white","black","bottomright")
  1018.         -- Frames AB spinning:
  1019.         gui.text(2, 120, "AB Spin:" .. MetricABspin,"white","black","bottomright")
  1020.         -- Frames of MT Glide:
  1021.         gui.text(2, 105, "MT Glide:" .. MetricMT,"white","black","bottomright")
  1022.         -- Time sliding (No Shroom):
  1023.         gui.text(2, 75, "Slide:" .. MetricSlide,"white","black","bottomright")
  1024.         -- Time shroom sliding:
  1025.         gui.text(2, 60, "Shroomslide:" .. MetricShroomSlide,"white","black","bottomright")
  1026.  
  1027.         -- Frames Σ Distance; Avg. Speed; Max Speed:
  1028.         gui.text(2, 32, "Dist XY:" .. string.format("%.3f",MetricTotalXYDistance) .. " +Z:" .. string.format("%.3f",MetricTotalXYZDistance),"white","black","bottomright")
  1029.         gui.text(2, 17, "Avg XYv:" .. string.format("%.3f",MetricAvgXYSpeed) .. " +Z:" .. string.format("%.3f",MetricAvgXYZSpeed),"white","black","bottomright")
  1030.         gui.text(2, 2, "Max XYv:".. string.format("%.3f",MetricMaxXYSpeed) .. " +Z:" .. string.format("%.3f",MetricMaxXYZSpeed),"white","black","bottomright")
  1031.     end
  1032.  
  1033.     if forms.getproperty(WaypointsWindow,"WindowState") ~= "" then
  1034.         -- Waypoint 1 Logic
  1035.         Waypoint1X = tonumber(forms.gettext(Waypoint1XTextBox))
  1036.         Waypoint1Y = tonumber(forms.gettext(Waypoint1YTextBox))
  1037.         Waypoint1Z = tonumber(forms.gettext(Waypoint1ZTextBox))
  1038.  
  1039.         Waypoint1XY = math.sqrt ((Waypoint1X-PlayerX)^2+(Waypoint1Y-PlayerY)^2)
  1040.         forms.settext( Waypoint1XYTextBox, string.format("%.3f",Waypoint1XY))
  1041.         --gui.text(240,2, "Zv ".. string.format("%.3f", PlayerZv),"white","black","bottomleft")
  1042.  
  1043.         Waypoint1XYZ = math.sqrt ((Waypoint1X-PlayerX)^2+(Waypoint1Y-PlayerY)^2+(Waypoint1Z-PlayerZ)^2)
  1044.         forms.settext(Waypoint1XYZTextBox, string.format("%.3f",Waypoint1XYZ))
  1045.  
  1046.         if forms.ischecked(CheckboxWayline1) == false then
  1047.  
  1048.             forms.setproperty(Waypoint1Cover2,"Visible",true)
  1049.             forms.setproperty(SetWaypoint1Handle2,"Visible",false)
  1050.         else
  1051.             forms.setproperty(Waypoint1Cover2,"Visible",false)
  1052.             forms.setproperty(SetWaypoint1Handle2,"Visible",true)
  1053.  
  1054.             Waypoint1X2 = tonumber(forms.gettext(Waypoint1X2TextBox))
  1055.             Waypoint1Y2 = tonumber(forms.gettext(Waypoint1Y2TextBox))
  1056.             Waypoint1Z2 = tonumber(forms.gettext(Waypoint1Z2TextBox))
  1057.         end
  1058.  
  1059.         if forms.ischecked(CheckboxWaypoint2) == false then
  1060.  
  1061.             forms.setsize(WaypointsWindow, 482, 182)
  1062.             forms.setproperty(Waypoint2TitleTextBox,"Visible",false)
  1063.         else
  1064.             forms.setsize(WaypointsWindow, 482, 272)
  1065.             forms.setproperty(Waypoint2TitleTextBox,"Visible",true)
  1066.  
  1067.             -- Waypoint 2 Logic
  1068.             Waypoint2X = tonumber(forms.gettext(Waypoint2XTextBox))
  1069.             Waypoint2Y = tonumber(forms.gettext(Waypoint2YTextBox))
  1070.             Waypoint2Z = tonumber(forms.gettext(Waypoint2ZTextBox))
  1071.  
  1072.             Waypoint2XY = math.sqrt ((Waypoint2X-PlayerX)^2+(Waypoint2Y-PlayerY)^2)
  1073.             forms.settext(Waypoint2XYTextBox, string.format("%.3f",Waypoint2XY))
  1074.  
  1075.             Waypoint2XYZ = math.sqrt ((Waypoint2X-PlayerX)^2+(Waypoint2Y-PlayerY)^2+(Waypoint2Z-PlayerZ)^2)
  1076.             forms.settext(Waypoint2XYZTextBox, string.format("%.3f",Waypoint2XYZ))
  1077.         end
  1078.  
  1079.         if forms.ischecked(CheckboxWayline2) == false then
  1080.  
  1081.             forms.setproperty(Waypoint2Cover2,"Visible",true)
  1082.             forms.setproperty(SetWaypoint2Handle2,"Visible",false)
  1083.  
  1084.         else
  1085.             forms.setproperty(Waypoint2Cover2,"Visible",false)
  1086.             forms.setproperty(SetWaypoint2Handle2,"Visible",true)
  1087.  
  1088.             Waypoint2X2 = tonumber(forms.gettext(Waypoint2X2TextBox))
  1089.             Waypoint2Y2 = tonumber(forms.gettext(Waypoint2Y2TextBox))
  1090.             Waypoint2Z2 = tonumber(forms.gettext(Waypoint2Z2TextBox))
  1091.         end
  1092.  
  1093.         --Waypoint HUD
  1094.         if forms.ischecked(CheckboxWaypoint1OnScreen) == true then
  1095.             gui.text(1, client.screenheight()*.15, forms.gettext(Waypoint1TitleTextBox),"white","black","topright")
  1096.             gui.text(1, client.screenheight()*.15 + 15, "XY:" .. string.format("%.3f",Waypoint1XY),"white","black","topright")
  1097.             gui.text(1, client.screenheight()*.15 + 30, "XYZ:" .. string.format("%.3f",Waypoint1XYZ),"gray","black","topright")
  1098.         end
  1099.  
  1100.         if ((forms.ischecked(CheckboxWaypoint2OnScreen) == true) and (forms.ischecked(CheckboxWaypoint2) == true)) then
  1101.             gui.text(1, client.screenheight()*.15 + 55, forms.gettext(Waypoint2TitleTextBox),"white","black","topright")
  1102.             gui.text(1, client.screenheight()*.15 + 70, "XY:" .. string.format("%.3f",Waypoint2XY),"white","black","topright")
  1103.             gui.text(1, client.screenheight()*.15 + 85, "XYZ:" .. string.format("%.3f",Waypoint2XYZ),"gray","black","topright")
  1104.         end
  1105.  
  1106.     end
  1107.      
  1108.     if (RecordState == 1) then
  1109.         if (isLag == false) then
  1110.  
  1111.             --Option to store metrics as comments for recorded input
  1112.             MetricComment = "#"
  1113.  
  1114.             if forms.ischecked(RecordMetricsCheckBox) == true then
  1115.  
  1116.                 if bit.check(StateE,5) then
  1117.                     MetricFlagShroom = "Shrm"
  1118.                 else
  1119.                     MetricFlagShroom = "."
  1120.                 end
  1121.  
  1122.                 if bit.check(StateF,3) then
  1123.                     MetricFlagAir = "Air"
  1124.                 else
  1125.                     MetricFlagAir = "."
  1126.                 end
  1127.  
  1128.                 if bit.check(StateF,4) and not bit.check(StateF,1) and not bit.check(StateF,3) then
  1129.                     MetricFlagSlide = "Sld"
  1130.                 else
  1131.                     MetricFlagSlide = "."
  1132.                 end
  1133.  
  1134.                 if bit.check(StateE,0) then
  1135.                     MetricFlagMT = "MT"
  1136.                 else
  1137.                     MetricFlagMT = "."
  1138.                 end
  1139.  
  1140.                 if bit.check(StateF,5) then
  1141.                     MetricFlagABSpin = "AB"
  1142.                 else
  1143.                     MetricFlagABSpin = "."
  1144.                 end
  1145.  
  1146.                 if bit.check(State5B,0) or bit.check(State5B,1) or bit.check(State5B,3) or bit.check(State5B,7) then
  1147.                     MetricFlagOoB = "OoB"
  1148.                 else
  1149.                     MetricFlagOoB = "."
  1150.                 end
  1151.  
  1152.                 if bit.check(StateE,1) then
  1153.                     MetricFlagStar = "Star"
  1154.                 else
  1155.                     MetricFlagStar = "."
  1156.                 end
  1157.  
  1158.                 -- Time, Air, Sld, MT, Shrm, AB, OoB, Star, Speed, X, Y, Z
  1159.                 MetricComment = "#"..string.format("%.2f", Timer)..";"..MetricFlagAir..";"..MetricFlagSlide..";"..MetricFlagMT..";"..MetricFlagShroom..";"..MetricFlagABSpin..";"..MetricFlagOoB..";"..MetricFlagStar
  1160.                 ..";"..string.format("%.3f",XYspeed)..";"..string.format("%.3f",PlayerX)..";"..string.format("%.3f",PlayerY)..";"..string.format("%.3f",PlayerZ)
  1161.             end
  1162.  
  1163.             forms.settext(GeneratedTextBox, forms.gettext(GeneratedTextBox) .. string.format("%06i", emu.framecount()-1) .. ":" .. movie.getinputasmnemonic(emu.framecount()-1) .. MetricComment .. "\r\n")
  1164.         end
  1165.  
  1166.     elseif (InputQueue ~= nil) then
  1167.         if (isLag == false) then
  1168.             queueIterator = queueIterator + 1
  1169.         end
  1170.        
  1171.         local toPut = ""
  1172.        
  1173.         if (queueIterator < table.getn(InputQueue) + 1) then
  1174.             toPut = bizstring.replace(InputQueue[queueIterator], "\n", "")
  1175.  
  1176.             if (toPut ~= "") then
  1177.            
  1178.                 -- Remove the frame number and comments if present
  1179.                 local input_start = string.find(toPut, "|")
  1180.                 toPut = string.sub(toPut, input_start)
  1181.                 toPut = string.sub(toPut, 1, 35)
  1182.             end
  1183.         else
  1184.             ClearQueue()
  1185.         end
  1186.        
  1187.         if (ItemBotState >= 0) then
  1188.             if (queueIterator >= table.getn(InputQueue) + 1) then
  1189.                 -- We failed!
  1190.                 -- print out a message?
  1191.                 console.log("Item bot ran out of queued input!")
  1192.                
  1193.                 -- Re-enable the button
  1194.                 forms.settext(ExecuteItemBotButtonHandle, "Item Bot")
  1195.                
  1196.                 ItemBotState = -1
  1197.             else
  1198.                 -- If looking for the first chance to press z, check now
  1199.                 if (ItemBotState == 0) then
  1200.                     -- Read the delay timer value
  1201.                     local delayTimerAddr = 0x165F07
  1202.                     z_delay_timer = memory.read_u8(delayTimerAddr)
  1203.                    
  1204.                     -- Found it, switch states
  1205.                     if (((z_delay_timer == 0 or z_delay_timer == 1) and isLag == true) or forms.ischecked(BooModeCheckbox)) then
  1206.                         -- Make a state here
  1207.                         savestate.save("ItemBotIterator")
  1208.                        
  1209.                         -- Remember what spot we're on in the queue
  1210.                         ItemBotIteratorSave = queueIterator
  1211.                        
  1212.                         -- Change State
  1213.                         ItemBotState = 1
  1214.                     else
  1215.                         -- Still looking
  1216.                     end
  1217.                 elseif (ItemBotState == 1) then
  1218.                     if (isLag == false) then
  1219.                         -- We just successfully pressed Z
  1220.                         -- Change state to detection mode
  1221.                         ItemBotState = 2
  1222.                     end
  1223.                    
  1224.                 -- If waiting to see what item we got, check if its set yet, and if its what we want
  1225.                 elseif (ItemBotState == 2) then
  1226.                     item_we_got = memory.read_s8(0x165F5B)
  1227.                     --TEST TO CONSOLE
  1228.                     --console.log(item_we_got)
  1229.                     console.log(itemOptions[item_we_got-1])
  1230.                     z_delay_timer = memory.read_u8(0x165F07)
  1231.  
  1232.                     if (item_we_got > 0 or (z_delay_timer == 255 and forms.ischecked(BooModeCheckbox))) then
  1233.                         if (item_we_got == ItemBotWantedItem) then
  1234.                             -- We succeeded
  1235.                             local to_edit = bizstring.replace(InputQueue[ItemBotIteratorSave], "\n", "")
  1236.  
  1237.                                
  1238.                             -- Remove the frame number and comments if present
  1239.                             local input_start = string.find(to_edit, "|")
  1240.                             to_edit = string.sub(to_edit, input_start)
  1241.                             to_edit = string.sub(to_edit,1,25) .. "Z" .. string.sub(to_edit,27)
  1242.  
  1243.                             InputQueue[ItemBotIteratorSave] = to_edit
  1244.                             SetInputQueue(InputQueue)
  1245.                            
  1246.                             -- Clean up the queue
  1247.                             ClearQueue()
  1248.                            
  1249.                             -- Load the starting state
  1250.                             savestate.load("ItemBotStartingState")
  1251.                            
  1252.                             -- turn off the bot
  1253.                             ItemBotState = 4
  1254.                            
  1255.                             -- Pause
  1256.                             client.pause()
  1257.                         else
  1258.                             -- We failed
  1259.                             -- load the state
  1260.                             savestate.load("ItemBotIterator")
  1261.                            
  1262.                             -- load the iterator value
  1263.                             queueIterator = ItemBotIteratorSave
  1264.  
  1265.                             -- Switch to skip a frame mode
  1266.                             ItemBotState = 3
  1267.                         end
  1268.                     end
  1269.  
  1270.                 elseif (ItemBotState == 3) then
  1271.                     if (isLag == false) then
  1272.                         -- Save the state
  1273.                         savestate.save("ItemBotIterator")
  1274.  
  1275.                         -- Save the iterator
  1276.                         ItemBotIteratorSave = queueIterator
  1277.  
  1278.                         -- Switch to hitting state
  1279.                         ItemBotState = 1
  1280.                     end
  1281.                 elseif (ItemBotState == 4) then
  1282.                     ItemBotState = -1
  1283.  
  1284.                     -- Re-enable the button
  1285.                     forms.settext(ExecuteItemBotButtonHandle, "Item Bot")
  1286.                 end
  1287.             end
  1288.            
  1289.             if (ItemBotState == 1) then
  1290.                 -- Inject the Z to next state
  1291.                 toPut = string.sub(toPut,0,25) .. "Z" .. string.sub(toPut,27)
  1292.             end
  1293.         end
  1294.        
  1295.         if (toPut ~= "") then
  1296.             joypad.setfrommnemonicstr(toPut)
  1297.         end    
  1298.     end
  1299.  
  1300.     --Consider moving these
  1301.     PriorPlayerX = PlayerX
  1302.     PriorPlayerY = PlayerY
  1303.     PriorPlayerZ = PlayerZ
  1304.  
  1305.     if (isLag == false) then
  1306.         FramesSinceLoad = FramesSinceLoad + 1
  1307.     end
  1308.  
  1309.     -- --THIS SECTION IS INCOMPLETE, additional work is required to fully reverse engineer the RNGValue calculation
  1310.     -- --Item prediction, http://beckabney.com/mk64/items.php and https://github.com/abitalive/MarioKart64/blob/master/Notes/item_rng.txt
  1311.     -- --Formula: (RNGValue + ABRFrames + RaceFrames + LastItem) % 100
  1312.     -- itemLookupAddr = 0x1A7A90
  1313.     -- itemLookup = mainmemory.readbyterange(itemLookupAddr, 800)
  1314.  
  1315.     -- --RNGValue
  1316.     -- --0x802B7E34 RandomInt
  1317.     -- --Returns a random number between 0 and (a0 - 1)
  1318.     -- --NOTE THIS IS ACTUALLY THE ADDRESS OF THE RNG FUNCTION, it's result is stored directly into a register and so must be reverse engineered
  1319.     -- RNGValueAddr = 0x2B7E34
  1320.     -- RNGValue = mainmemory.read_u8(RNGValueAddr)
  1321.  
  1322.     -- --ABRFrames
  1323.     -- --0x801658FF 1b ButtonCounter
  1324.     -- --Increments by 1 each frame A/B/R are held on any active controller during a race
  1325.     -- --Increments by more than 1 if multiple buttons are held
  1326.     -- --Maxes at 255 then loops back to 0
  1327.     -- ABRFramesAddr = 0x1658FF
  1328.     -- ABRFrames = mainmemory.read_u8(ABRFramesAddr)
  1329.  
  1330.     -- --RaceFrames
  1331.     -- --0x8018D3FC 4b RaceTimer
  1332.     -- --Increments by 1 each frame during a race
  1333.     -- RaceFramesAddr = 0x18D3FC
  1334.     -- RaceFrames = mainmemory.read_s32_be(RaceFramesAddr)
  1335.  
  1336.     -- --LastItem
  1337.     -- --0x801658FD 1b ItemRandom
  1338.     -- --Random number between 0 and 99
  1339.     -- LastItemAddr = 0x1658FD
  1340.     -- LastItem = mainmemory.read_u8(LastItemAddr)
  1341.  
  1342.     -- ItemID = (RNGValue + ABRFrames + RaceFrames + LastItem) % 100
  1343.     -- ItemID = ItemID + (100 * Place)
  1344.     -- PredictedItem = itemLookup[ItemID]
  1345.  
  1346.     -- gui.text(client.borderwidth()+client.bufferwidth()*.25,client.borderwidth()+client.bufferwidth()*.25, "ItemID: "..ItemID..", Item: "..PredictedItem,0xFFC758FF,0x50000000)
  1347.  
  1348.     emu.frameadvance()
  1349. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement