--A few sanities I want to make:
local R4s= memory.readdwordsigned --Read 4 bytes, signed
local R2u= memory.readword --Read 2 bytes, unsigned
--*****************************************************************************
local function GuiTextRight(x,y,str,c1,c2)
--*****************************************************************************
str= tostring(str)
x= x - (#str)*4
gui.text(x,y,str,c1,c2)
end
--*****************************************************************************
local function HexStr(v)
--*****************************************************************************
local str= ""
if v < 0 then
str= "-"
v= -v
end
return str .. string.upper(string.format("%x",v))
end
--#############################################################################
--#############################################################################
--Object detection Module
--*****************************************************************************
local function NextLink(ptr)
--*****************************************************************************
--Returns two values: An object pointer (possibly nil) and a link pointer.
local PTR= R4s(ptr)
local OBJ= R4s(PTR+8)
if OBJ == 0 then OBJ= nil end
return OBJ, PTR
end
local H= {}
--*****************************************************************************
local function PutStat(obj,index)
--*****************************************************************************
local tbl= H[index] or {}
tbl.obj= obj
tbl.X= R4s(obj+0x80)
tbl.Y= R4s(obj+0x84)
tbl.type= R4s(obj+0x68)
H[index]= tbl
end
--*****************************************************************************
local function WalkList()
--*****************************************************************************
local obj, ptr= NextLink(0x03000518)
local count= 0
while obj do
count= count+1
if count > 200 then error("FRK goofed, shutting down") end --Panic.
PutStat(obj,count)
obj, ptr= NextLink(ptr)
end
H[count+1]= nil
end
--#############################################################################
--#############################################################################
--Bot
local status= "Unknown..."
local Up= {up=true}
local Dn= {down=true}
--*****************************************************************************
local function Action(In,frames)
--*****************************************************************************
for i= 1, frames do joypad.set(1,In); emu.frameadvance() end
end
--*****************************************************************************
local function Wait(frames) for i= 1, frames do emu.frameadvance() end end
--*****************************************************************************
--*****************************************************************************
local function YLoc(obj) return math.floor(R4s(obj+0x84)/0x400) - 0x20 end
local function XLoc(obj) return math.floor(R4s(obj+0x84)/0x200) - 0x20 end
--*****************************************************************************
-- XLoc works differently... Because plane speed is 0x600 while others is 0x400
-- I use greatest common divisor.
--*****************************************************************************
local function GoTo(Ypos)
--*****************************************************************************
-- Trivializes movement to a specific location.
local PlY= H[2].Y/0x400 - 0x20
if PlY > Ypos then Action(Up,PlY-Ypos)
else Action(Dn,Ypos-PlY)
end
return PlY-Ypos
end
local BackPtr
--*****************************************************************************
local function CheckNewObj()
--*****************************************************************************
-- Ensure that a new object has spawned.
-- Will return the object pointer, or nil if it's not a new object.
local NewObj= R4s(0x0300051C)
if NewObj == BackPtr then return end
BackPtr= NewObj
NewObj= R4s(NewObj+8)
if NewObj == H[2].obj then return end
return NewObj
end
--*****************************************************************************
local function HandleBird(obj) -- Because even a bird can destroy the Missile
--*****************************************************************************
if H[1].X < R4s(obj+0x80) then return false end --Approaching target?
status= "Spotted bird"
GoTo(0x22) -- No intelligence needed! Go there.
Wait( R4s(obj+0x80)/0x400 - 14 ) -- Sit still.
return true -- Back to being "bleh"...
end
--*****************************************************************************
local function HandleCopter(obj) -- Some pilot in there forgot how to decend
--*****************************************************************************
if H[1].X < R4s(obj+0x80) then return false end --Approaching target?
status= "Spotted copter"
Action(Dn, 62) -- Only reasonable action is to dive to the bottom...
return true
end
--*****************************************************************************
local function HandleAlmostThere(obj) -- Those sneaky planes! Curse them!
--*****************************************************************************
status= "A Sneak-attack plane!"
local PlaneY= math.floor(R4s(obj+0x84)/0x400,1) - 0x20
if (PlaneY < 0x18) or (PlaneY > 0x48) then return false end -- Ignore it.
if PlaneY > 0x30 then
GoTo(PlaneY-0x18)
else
GoTo(PlaneY+0x18)
end
Wait( math.floor(R4s(obj+0x80)/0x600) - 6 )
return false -- We're definitely there now!
end
--*****************************************************************************
local function HandlePlane(obj) -- Powered by white blocks, like the Missile
--*****************************************************************************
if H[1].X < 0x30000 then return false end
if H[1].X < 0x49000 then return HandleAlmostThere(obj) end
status= "Spotted plane"
if R4s(obj+0x84) < 0x1D800 then
Action(Dn, math.floor(R4s(obj+0x80)/0x600) - 6 )
else
GoTo(0x3D)
Wait( math.floor(R4s(obj+0x80)/0x600) - 6 )
end
return true
end
--*****************************************************************************
local function AwaitNextFoe() -- Huh, wouldn't hurt to see what lies ahead.
--*****************************************************************************
local NewObj= CheckNewObj()
if NewObj then
local Fn= R4s(NewObj+0x68)
-- Bah, pointers to object types. The pointer itself is good enough for me.
if Fn == 0x87EC230 then Fn= HandleBird
elseif Fn == 0x87EC254 then Fn= HandleCopter
elseif Fn == 0x87EC20C then Fn= HandlePlane
end
-- If Fn is still a number and not a function at this point, I WANT an error!
if not Fn(NewObj) then return true end
end
status= "Bleh"
return false -- Idle mode.
end
--*****************************************************************************
local function Overhead()
--*****************************************************************************
WalkList()
if (H[1].X < 0x30000) or AwaitNextFoe() then
status= "Victory!" -- I'm so confident I won't bother checking if I lost.
GoTo(0x30)
while R4s(0x02000458) == 64 do emu.frameadvance() end
while R4s(0x02000458) ~= 64 do emu.frameadvance() end
else
Action(Dn,1) -- Default "dodge surprise copter" action.
end
-- Incidentally, the time I'm idling is when it's most expensive on the
-- processing power. When it comes down to it, objects don't come frequently
-- enough to interfere with my basic strategy. Only when the "target" is in
-- reach do I need any strange exceptions, and even then, no major processing.
end
gui.register(function() -- Debugging interface. Display stuff goes here.
gui.text(1,1,status)
gui.text(1,9,HexStr(H[1].X)) -- H[1] is the "target".
if H[3] then
gui.text(1,17,HexStr(YLoc(H[3].obj)))
end
end)
while true do Overhead() end -- Overhead() has everything it needs.