User File #24001524923673408

Upload All User Files

#24001524923673408 - GBA Alien Hominid - Missile Mastar piloting script

AHmm_.lua
1130 downloads
Uploaded 7/8/2015 9:32 PM by FatRatKnight (see all 245)
Exhibit #8. At one point, I was planning an April Fool's submission. That never happened.
Speaking of which, I even have a write-up somewhere. Let's see if I can't find it...
... Alas, I can't seem to find it. It may have been lost somewhere. Sad.
The script itself is a state machine that deals with detecting which object it wants to avoid. When it approaches the "target", it tries to avoid any planes that spawn in a bad spot with a rather bad timing. Hopefully, it is a robust enough algorithm to survive and hit the target indefinitely.
--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.