Improved and cleaned up Autowalk(), fixed the issue where Bugs would randomly not move when Autowalk() was enabled.
Comes with some pretty LStick visualization, just because.
--local module definitions first
local bblitGUI = {}
do
local areaX, areaY
function bblitGUI.SetArea(x, y)
areaX = x
areaY = y
end
function bblitGUI.DrawValue(token, value)
gui.text(areaX, areaY, string.format("%s: %d", token, value))
areaY = areaY + 20
end
function bblitGUI.DrawVector3(token, value1, value2, value3)
gui.text(areaX,areaY, string.format("%s: (%6d,%6d,%6d)", token, value1, value2, value3))
areaY = areaY + 20
end
function bblitGUI.DrawLStick(x, y)
gui.drawEllipse(400, 10, 256, 256, "white")
gui.drawLine(400+128, 10+128, 400+x, 10+y, "red")
gui.drawEllipse(400 + x-2, 10 + y-2, 4, 4, "red", "red")
end
end
local bblitAngle = {}
do
-- Conversions as per: http://electronicstechnician.tpub.com/14091/css/14091_316.htm
function bblitAngle.DegreesToBAMS(degrees)
-- no conversion necessary
if degrees == 360 or degrees == 0 then
return 0
end
-- need to convert
local returnValue = 0
local BAMSbits = 0x800
local angularDegrees = 180
while BAMSbits > 0 do
if degrees >= angularDegrees then
returnValue = returnValue + BAMSbits
degrees = degrees - angularDegrees
end
BAMSbits = math.floor(BAMSbits / 2)
angularDegrees = angularDegrees / 2
end
return returnValue
end
function bblitAngle.BAMStoDegrees(bams)
if bams == 4096 or bams == 0 then
return 0
end
local returnValue = 0
local BAMSbits = 0x800
local angularDegrees = 180
while bams > 0 do
if bams >= BAMSbits then
returnValue = returnValue + angularDegrees
bams = bams - BAMSbits
end
BAMSbits = math.floor(BAMSbits / 2)
angularDegrees = angularDegrees / 2
end
return returnValue
--console.log("Function not implemented! bblitAngle.BAMStoDegrees")
end
function bblitAngle.ClampBAMS(bams)
if bams < 0 then
bams = bams + 4096
end
if bams >= 4096 then
bams = bams - 4096
end
return bams
end
function bblitAngle.Vector2ToDegrees(x, y)
local angle = math.atan2(x, y)
if angle < 0 then
angle = angle + (math.pi * 2)
end
angle = math.deg(angle)
return angle
end
end
local bblitKeyboard = {}
do
local keysToCheck = {"J", "K", "L"}
local keys = {}
local keysPrev = {}
local keysDown = {}
function bblitKeyboard.GetInput()
keys = input.get()
for i, v in ipairs(keysToCheck) do
if keys[v] == true and keysPrev[v] ~= true then
keysDown[v] = true
else
keysDown[v] = false
end
end
keysPrev = keys
end
function bblitKeyboard.GetKey(token)
return keys[token] == true
end
function bblitKeyboard.GetKeyDown(token)
return keysDown[token] == true
end
end
local bblitJoypad = {}
do
function bblitJoypad.SetAnalog(x, y)
local analogInput = {}
analogInput["LStick X"] = x
analogInput["LStick Y"] = y
joypad.setanalog(analogInput, 1)
end
end
local gui = bblitGUI
local angle = bblitAngle
local keyboard = bblitKeyboard
local joypad = bblitJoypad
-----------------------
-----------------------
------modules end------
-----------------------
-----------------------
local function CheckModule(name,mod)
if mod ~= nil and mod ~= true then
console.log("Module " .. name .. " successfully loaded.")
else
console.log("Module " .. name .. " failed to load! (value = " .. mod .. ")")
end
end
do
--Due to that the game internally runs at 30 fps despite rendering at 60 fps
--the speed values cannot be updated each frame.
--Apply some simpler logic to only update this once per 2 frames by using an
--address that increments at 30 fps.
local Counter30FPS = 0
local Counter30FPSOld = 0
function CheckDoUpdate()
Counter30FPS = memory.read_u32_le(0x00076010)
if Counter30FPS == Counter30FPSOld then
return false
end
Counter30FPSOld = Counter30FPS
return true
end
end
local Xpos, Ypos, Zpos = 0, 0, 0
local XposOld, YposOld, ZposOld = 0, 0, 0
local Xspeed, Yspeed, Zspeed = 0, 0, 0
local XZspeed, XYZspeed = 0, 0
local Xwaypoint, Ywaypoint, Zwaypoint = 0, 0, 0
local waypointActive,autowalkActive = false, false
local camAngle, bugsAngle, waypointAngle = 0, 0, 0
local diffAngle = 0
local inputX, inputY = 128, 128
local function SetWaypoint()
--disable waypoints by 'double tapping' on the same spot
if waypointActive == true and Xwaypoint == Xpos and Ywaypoint == Ypos and Zwaypoint == Zpos then
waypointActive = false
else
waypointActive = true
Xwaypoint = Xpos
Ywaypoint = Ypos
Zwaypoint = Zpos
end
end
local function SetAutowalk()
autowalkActive = not autowalkActive
if not autowalkActive then
inputX = 128
inputY = 128
joypad.SetAnalog(inputX, inputY)
console.log("Autowalk disabled.")
else
console.log("Autowalk enabled.")
end
end
local function CalculateAutowalk()
local Xdistance = Xpos - Xwaypoint
local Zdistance = Zpos - Zwaypoint
local diffAngleRadians = math.rad(angle.BAMStoDegrees(diffAngle))
-- Add 0.5 to round the float correctly as we go to integers
-- Interpolate the X/Y from the angle as per: http://mathforum.org/sarah/hamilton/ham.1side.1angle.html
-- X/Y are inverted (X = Y and Y = X) compared to the angle, they're also inverted along their own axis (X 255 = X 0)
inputY = math.abs(math.max(0, math.min(math.floor(((math.cos(diffAngleRadians) * 128) + 128) + 0.5), 255)) - 255)
inputX = math.abs(math.max(0, math.min(math.floor(((math.sin(diffAngleRadians) * 128) + 128) + 0.5), 255)) - 255)
if math.sqrt(Xdistance*Xdistance + Zdistance*Zdistance) < 150 then
inputX = 128
inputY = 128
end
end
local function Update()
if not CheckDoUpdate() then return end
--Actual speed vector addresses:
--addr 00069D30 X Speed [signed dword]
--addr 00069D34 Y Speed(?) [signed dword]
--addr 00069D38 Z Speed [signed dword]
--This is not reliable as it shows the speed Bugs want to travel at,
--not the actual speed that he moves at.
--Use position as a source for speed instead
Xpos = memory.read_s32_le(0x00069DC0)
Ypos = memory.read_s32_le(0x00069DC4)
Zpos = memory.read_s32_le(0x00069DC8)
Xspeed = Xpos - XposOld
Yspeed = Ypos - YposOld
Zspeed = Zpos - ZposOld
XZspeed = math.sqrt(Xspeed*Xspeed + Zspeed*Zspeed)
XYZspeed = math.sqrt(Xspeed*Xspeed + Yspeed*Yspeed + Zspeed*Zspeed)
camAngle = angle.ClampBAMS(-2048 + memory.read_s16_le(0x00069402))
if XZspeed > 10 then
bugsAngle = angle.DegreesToBAMS(angle.Vector2ToDegrees(Xspeed, Zspeed))
end
--bugsAngle = angle.ClampBAMS(memory.read_s16_le(0x000B8AAA))
if waypointActive then
local Xdistance = Xpos - Xwaypoint
local Zdistance = Zpos - Zwaypoint
waypointAngle = angle.ClampBAMS(-2048 + angle.DegreesToBAMS(angle.Vector2ToDegrees(Xdistance, Zdistance)))
diffAngle = angle.ClampBAMS(camAngle - waypointAngle)
if autowalkActive == true then
CalculateAutowalk()
--console.log("Attempting to set input " .. inputX .. " " .. inputY)
joypad.SetAnalog(inputX, inputY)
end
end
XposOld = Xpos
YposOld = Ypos
ZposOld = Zpos
end
local function main()
CheckModule("GUI", gui)
CheckModule("Angle", angle)
CheckModule("Keyboard", keyboard)
client.SetGameExtraPadding(600, 0, 0, 0)
joypad.SetAnalog(128, 128)
while true do
keyboard.GetInput()
Update()
if keyboard.GetKeyDown("J") == true then
SetWaypoint()
end
if keyboard.GetKeyDown("K") == true then
SetAutowalk()
end
gui.SetArea(20, 56)
gui.DrawVector3("Position ", Xpos, Ypos, Zpos)
gui.DrawVector3("Speed ", Xspeed, Yspeed, Zspeed)
gui.DrawValue( "XZ Speed ", XZspeed)
gui.DrawValue( "XYZ Speed", XYZspeed)
gui.DrawValue( "Camera BAM Angle", camAngle)
gui.DrawValue( "Bugs BAM Angle ", bugsAngle)
if waypointActive then
gui.DrawVector3("Waypoint ", Xwaypoint, Ywaypoint, Zwaypoint)
gui.DrawValue( "Waypoint BAM angle", waypointAngle)
gui.DrawValue( "Diff BAM angle", diffAngle)
end
if autowalkActive then
local Xdistance = Xpos - Xwaypoint
local Zdistance = Zpos - Zwaypoint
gui.DrawValue( "Autowalk X", inputX)
gui.DrawValue( "Autowalk Y", inputY)
gui.DrawValue( "Autowalk distance", math.sqrt(Xdistance*Xdistance + Zdistance*Zdistance))
end
gui.DrawLStick(inputX, inputY)
emu.frameadvance()
end
end
main()