User File #32371288816853050

Upload All User Files

#32371288816853050 - Bugs Bunny Lost in Time Lua

bblit.lua
883 downloads
Uploaded 7/19/2016 7:58 PM by Warepire (see all 18)
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()