User File #21301340743543930

Upload All User Files

#21301340743543930 - Auto analog input (works, but unfinished)

AutoInput.lua
System: Nintendo 64
745 downloads
Uploaded 3/9/2015 7:03 AM by TASeditor (see all 188)
Simply check for lag then it works. Here's a small demonstration of what it now looks like. It works for a variety of games.
TODOs:
- Fix rotation direction on start.
- Fix problems when going for angles near 0.
- Compare by position gain towards the direction of the angle, not by the angle itself.
- Better algorithm, also check inputs around the input that is the best that had been found.
- Add quick rotate.
- Add savestating support.
- Add non-linear support, for TAStudio.
-- Auto analog input script written by TASeditor

-- This function runs after the user clicked on the Start button.
function Start()

	if PauseFlag == false
	then if StartFlag == false
		 then if forms.ischecked(PosCheck) and not forms.ischecked(AngCheck)
			  then CalcAngle();
				   BestDiff = 99999;
				   Difference = 0;
				   FollowAngle = forms.gettext(AngFollow);
				   Direction = "right";
				   savestate.saveslot(0);
				   StartFlag = true;
				   forms.settext(StatLabel, "Started");				   
			  elseif not forms.ischecked(PosCheck) and forms.ischecked(AngCheck)
				  then BestDiff = 99999;
					   Difference = 0;
					   FollowAngle = forms.gettext(AngFollow);
					   Direction = "right";
					   savestate.saveslot(0);
					   StartFlag = true;
					   forms.settext(StatLabel, "Started");
				  elseif forms.ischecked(PosCheck) and forms.ischecked(AngCheck)
					  then forms.settext(StatLabel, "Error: Uncheck one checkbox");
					  
			  end;
		 end;
	end;
	
end;

-- This function runs after the user clicked on the Pause button.
function Pause()

	if StartFlag == true
	then if PauseFlag == false
		 then PauseFlag = true;
			  forms.settext(StatLabel, "Paused");
			  forms.settext(PauseButton, "Continue");
			  client.pause();
			  Xinput["P1 X Axis"] = 0;
			  Yinput["P1 Y Axis"] = 0;
			  joypad.setanalog(Xinput);
			  joypad.setanalog(Yinput);
			  BestDiff = 99999;
			  Difference = 0;
		 else PauseFlag = false
			  forms.settext(StatLabel, "Started");
			  forms.settext(PauseButton, "Pause");
		 end;
	end;

end;

-- This function runs after the user clicked on the Stop button.
function Stop()

	if StartFlag == true
	then StartFlag = false;
		 PauseFlag = false;
		 forms.settext(StatLabel, "Stopped");
		 forms.settext(PauseButton, "Pause");
		 client.pause();
		 Xinput["P1 X Axis"] = 0;
		 Yinput["P1 Y Axis"] = 0;
		 joypad.setanalog(Xinput);
		 joypad.setanalog(Yinput);
		 Direction = "right";
		 X = 0;
		 Y = 127;
	end;

end;

-- This function runs after the user clicked the "+" button.
function Add()

	AngF = math.floor((tonumber(forms.gettext(AngFollow)) + (tonumber(forms.gettext(AngAdd))*32768)/180) % 65536 + 0.5);
	forms.settext(AngFollow, AngF);
	BestDiff = 99999;

end;

function CalcAngle()

	DeltaX = forms.gettext(XPosGoto) - memory.readfloat(XPosAddr, true);
	DeltaY = forms.gettext(YPosGoto) - memory.readfloat(YPosAddr, true);
	Distance = math.sqrt(DeltaX^2 + DeltaY^2);
	Alpha = math.floor((math.acos(DeltaX / Distance) * 32768)/math.pi);
	forms.settext(AngFollow, Alpha);
		
end;

-- This function creates the main window.
function WindowForm()

	Window = forms.newform(300, 500, "Auto analog input");

	PosCheck = forms.checkbox(Window, "Go to position:", 5, 20); 
	forms.label(Window, "X =", 110, 10, 30, 15);
	XPosGoto = forms.textbox(Window, "0", 120, 20, nil, 140, 5);
	forms.label(Window, "Y =", 110, 40, 30, 15);
	YPosGoto = forms.textbox(Window, "0", 120, 20, nil, 140, 35);
	
	AngCheck = forms.checkbox(Window, "Follow angle:", 5, 75);
	forms.label(Window, "a =", 110, 80, 30, 15);
	AngFollow = forms.textbox(Window, "0", 120, 20, nil, 140, 75);
	
	AngAdd = forms.textbox(Window, "0", 80, 20, nil, 110, 110);
	forms.label(Window, "�", 190, 110, 10, 15);
	forms.button(Window, "+", Add, 205, 110, 20,23);
	
	forms.label(Window, "Status:", 5, 150, 40, 15);
	StatLabel = forms.label(Window, "Stopped", 45, 150, 200, 15);
	
	forms.button(Window, "Start", Start, 5, 180);
	PauseButton = forms.button(Window, "Pause", Pause, 105, 180);
	forms.button(Window, "Stop", Stop, 205, 180);
	
	forms.label(Window, "Information:", 5, 220, 70, 15);
	
	forms.label(Window, "Current angle:", 5, 240, 80, 15);
	CurrAngLabel = forms.label(Window, "", 85, 240, 40, 15);
	forms.label(Window, "Difference:", 130, 240, 60, 15);
	DiffCurrAngLabel = forms.label(Window, "", 200, 240, 40, 15);
	
	forms.label(Window, "Best angle:", 5, 260, 60, 15);
	BestAngLabel = forms.label(Window, "", 85, 260, 40, 15);
	forms.label(Window, "Difference:", 130, 260, 60, 15);
	DiffBestAngLabel = forms.label(Window, "", 200, 260, 40, 15);

end;

-- This function checks wheter the user has typed in the memory addresses or not.
-- It doesn't check if the typed address is the correct one.
-- The "0x" should not be deleted.
function Check()
	
	-- Reading the addresses as a string.
	XPosAddr = forms.gettext(XPosAddrTxt);
	YPosAddr = forms.gettext(YPosAddrTxt);
	MovAngAddr = forms.gettext(MovAngAddrTxt);
	
	if XPosAddr ~= "0x" and YPosAddr ~= "0x" and MovAngAddr ~= "0x"
	then -- Converting the string into an integer number.
		 XPosAddr = tonumber(XPosAddr); 
	     YPosAddr = tonumber(YPosAddr);
	     MovAngAddr = tonumber(MovAngAddr);
		 
		 -- Writes the addresses into a text file.
		 -- The user doesn't have to type in the addresses everytime.
		 AddrFile = io.open(ROMname, "a");
		 AddrFile:write(XPosAddr, "\n", YPosAddr, "\n", MovAngAddr);
		 AddrFile:close();
		 
		 -- Closes the form where the user typed in the addresses.
		 forms.destroy(Addr);
		 WindowForm();
	end;
	
end;

-- This function creates the form where the user needs to type in memory addresses.
function AddrForm()

	Addr = forms.newform(320, 190, "Memory addresses");
	
	forms.label(Addr, "Type in horizontal position addresses:", 5, 5, 280, 20);
	forms.label(Addr, "X =",5, 30, 30, 15);
	XPosAddrTxt = forms.textbox(Addr, "0x", 70, 20, nil, 40, 25);
	forms.label(Addr, "Y =",120, 30, 30, 15); 
	YPosAddrTxt = forms.textbox(Addr, "0x", 70, 20, nil, 155, 25);
	
	forms.label(Addr, "Type in horizontal movement angle address:", 5, 65, 350, 20);
	forms.label(Addr, "a =", 5, 90, 30, 15); 
	MovAngAddrTxt = forms.textbox(Addr, "0x", 70, 20, "", 40, 85);
	
	forms.button(Addr, "Done", Check, 5, 120);

end;

-- Reads out the memory addresses from the file, if there's content in the file.
-- The memory addresses are saved in decimal numbers.
-- The file is in the main BizHawk folder and is called "<romname>.txt".
-- The main window will open.

XPosAddr = nil;
YPosAddr = nil;
MovAngAddr = nil;
AddrFile = nil;

ROMname = gameinfo.getromname()..".txt";
AddrFile = io.open(ROMname, "r");

if AddrFile ~= nil
then XPosAddr = tonumber(AddrFile:read("*line"));
     YPosAddr = tonumber(AddrFile:read("*line"));
     MovAngAddr = tonumber(AddrFile:read("*line"));
	 WindowForm(); 
	 AddrFile:close();
end;
 
-- If there's no content in the file a window will open, where the user types in the memory addresses once.
if XPosAddr == nil and YPosAddr == nil and MovAngAddr == nil
then AddrForm();
	 -- Prevents crash.
	 XPosAddr = 0;
	 YPosAddr = 0;
	 MovAngAddr = 0;
end



--**************************************************************************************************--
--Brute force script																				--
--**************************************************************************************************--

Xinput = {};
Yinput = {};

StartFlag = false;
PauseFlag = false;
Difference = 0;
Flipped = false;
Direction = "right";
DirectionChange = 0; -- 0: from right to left; 1: from left to right
X = 0; Y = 127;

function RotateRight()

	--console.log("Rotate right");
	
	if Direction == "right"
	then X = X + 1;
		 if X >= 127
		 then Direction = "down";
			  X = 127;
		 end;
	elseif Direction == "down"
		then Y = Y - 1;
			if Y <= -128
			then Direction = "left";
				 Y = -128;
			end;
		elseif Direction == "left"
			then X = X - 1;
				if X <= -128
				then Direction = "up"
					 X = -128;
				end;
			elseif Direction == "up"
				then Y = Y + 1;
					if Y >= 127
					then Direction = "right";
						 Y = 127;
					end;
				end;
		
	savestate.loadslot(0);

end;

function RotateLeft()

	--console.log("Rotate left");
	if Direction == "left"
	then X = X - 1;
		 if X <= -128
		 then Direction = "down";
			  X = -128;
		 end;
	elseif Direction == "down"
		then Y = Y - 1;
			if Y <= -128
			then Direction = "right";
				 Y = -128;
			end;
		elseif Direction == "right"
			then X = X + 1;
				if X >= 127
				then Direction = "up"
					 X = 127;
				end;
			elseif Direction == "up"
				then Y = Y + 1;
					if Y >= 127
					then Direction = "left";
						 Y = 127;
					end;
				end;
				
	savestate.loadslot(0);

end;

function ChangeRotationDirection()
    --console.writeline("changed direction ");
	if Direction == "right"
	then Direction = "left"; --console.writeline("from right to left");
	elseif Direction == "left"
		then Direction = "right"; --console.writeline("from left to right");
		elseif Direction == "up"
			then Direction = "down"; --console.writeline("from up to down");
			elseif Direction == "down"
				then Direction = "up"; --console.writeline("from down to up");
	end;

end;

function BruteForce()

	XPosition = memory.readfloat(XPosAddr, true);
	YPosition = memory.readfloat(YPosAddr, true);
	MovAngle = memory.read_u16_be(MovAngAddr);

	if Flipped == true
	then savestate.saveslot(0);
		 Flipped = false; --console.writeline("flipped");
		 Difference = 0;
		 BestDiff = 99999;
		
	end;
		
	Xinput["P1 X Axis"] = X;
	Yinput["P1 Y Axis"] = Y;
	joypad.setanalog(Xinput);
	joypad.setanalog(Yinput);
		
	LastDifference = Difference;
	Difference = MovAngle - FollowAngle;
		
	if Flipped == false
	then if Difference > 0
		 then if DirectionChange == 1
			  then DirectionChange = 0;
				   ChangeRotationDirection();
			  end;
			  RotateRight(); --console.writeline("r");
				  
		 elseif Difference < 0
			then if DirectionChange == 0
				 then DirectionChange = 1;
					  ChangeRotationDirection();
				 end;
				 RotateLeft();	--console.writeline("l");
					  
		 else savestate.saveslot(0);
			  BestDiff = 99999;
			  Difference = 0;
		 end;
		 
	else --flipped = true; console.writeline("f = true");
	end;
				
	if (LastDifference < 0) and (Difference > 0)
	then Flipped = true;-- console.writeline("f = true");
		--console.writeline("lda < 0 and da > 0");
	end;
	
	if (LastDifference > 0) and (Difference < 0)
	then Flipped = true; --console.writeline("f = true");
		 --console.writeline("lda > 0 and da < 0");
	end;
		
	--XCoordAngle = math.cos(MovAngle*math.pi/32768)*75;
	--YCoordAngle = math.sin(MovAngle*math.pi/32768)*75;	
	--gui.drawLine(230, 90, 230+XCoordAngle, 90-YCoordAngle, 0xFF000000);

	--console.writeline("Direction: "..Direction..", DireChan: "..DirectionChange);
	--console.writeline("Diff: "..Difference..", LastDiff: "..LastDifference);
	
	--gui.text(480, 2, AngleFollow);
	--gui.text(480, 17, MovAngle);
	
	if (Difference < math.abs(BestDiff)) and (Difference > - math.abs(BestDiff))
	then BestDiff = Difference;
		 forms.settext(DiffBestAngLabel, BestDiff);
		 forms.settext(BestAngLabel, MovAngle);
	
	end;
	
	forms.settext(CurrAngLabel, MovAngle);
	forms.settext(DiffCurrAngLabel, Difference);
	
	-- TODO: better algorithm
	
end;
		

while true do
	
	if StartFlag and not PauseFlag and not emu.islagged()
	then BruteForce();
	end;
	
	
	emu.frameadvance();
end;