-- 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;