User File #17428142883917495

Upload All User Files

#17428142883917495 - GBA Kingdom Hearts: Chain of Memories -- Prize Card scan bot v1

KH_CardScanBot_v1.lua
747 downloads
Uploaded 9/15/2014 8:43 PM by FatRatKnight (see all 245)
Refinements need to be made to the output & display, but this bot is working its magic!
Find the exact moment where the game generates a card, pick a few frames before that moment, run the script, and unpause. If you don't know precisely when the RNG is used, try four frames before the white flash.
Anyway, I still need to fix up the output, as it doesn't know the concept of limited screen space, but I have something!
local R1u= memory.readbyte
local R2s= memory.readwordsigned
local W4s= memory.writedword
local R4s= memory.readdwordsigned

--*****************************************************************************
local function Roll(rTbl)  -- [1], [2], [3], [4]
--*****************************************************************************
    return bit.band(0xFFFFFFFF,bit.bxor(
        bit.lshift(rTbl[2], 2),bit.lshift(rTbl[4], 1),
        bit.rshift(rTbl[1],30),bit.rshift(rTbl[3],31)
    ))
end

local T= {0,0,0,0}
for i= 1, 4 do
    T[i]= R4s(0x02034030+4*(i-1))
end

local z= savestate.create()
savestate.save(z)

local Error= 0
local M_Prize= {}
local E_Prize= {}
--*****************************************************************************
local function Fn()
--*****************************************************************************
    local X= 0
    local Total= 0
    local ValTotal= {[0]=0,0,0,0,0,0,0,0,0,0}
    for k,v in pairs(M_Prize) do
        local TypeTotal= 0
        gui.text(X,0,string.format("%4d",k),0x00FF00FF)
        for i= 0, 9 do
            gui.text(X,7+7*i,string.format("%4d",v[i]))
            ValTotal[i]= ValTotal[i]+v[i]
            TypeTotal= TypeTotal+v[i]
        end
        gui.text(X,77,string.format("%4d",TypeTotal),0x00FFFFFF)
        Total= Total+TypeTotal
        X= X+18
    end
    for i= 0, 9 do  gui.text(X,7+7*i,string.format("%4d",ValTotal[i]),0x00FFFFFF)  end
    gui.text(X,77,string.format("%4d",Total),0xFF8000FF)

    X= 0
    for k,v in pairs(E_Prize) do
        gui.text(X,152,string.format("%3d:%4d",k,v))
        X= X+40
    end
    gui.text(208,152,string.format("%8d",Error),0xFF2000FF)
end
gui.register(Fn)

--#############################################################################
--#############################################################################

--*****************************************************************************
local function LocateCombatAddr()
--*****************************************************************************
    local addr= R4s(0x02039B84)

--This is the limits of my error checking. Make sure I'm looking correctly!
    if addr == 0                     then return false end -- No combat
    if R4s(addr-0x20) ~= -0x200      then return false end -- Wrong size
    if R4s(addr-0x08) ~=  0x081213DC then return false end -- ptr not in use

    return addr  -- MainCombatPointer
end


--*****************************************************************************
local function IdentifyPrize(obj_RAM)
--*****************************************************************************
--I have "PrizeCardInit". "PrizeCard" is two indirections away.
    local obj_PrizeCard= R4s(R4s(obj_RAM+0x10)+4)

--Now I have the object!
    local ID,val= R2s(obj_PrizeCard+0x3C),R2s(obj_PrizeCard+0x3E)

    M_Prize[ID]= M_Prize[ID] or {[0]=0,0,0,0,0,0,0,0,0,0}
    M_Prize[ID][val]= M_Prize[ID][val]+1

    return true  -- We're good
end

--*****************************************************************************
local function HeartlessPrize(obj_RAM)
--*****************************************************************************
--I have the object!
    local CardID= R2s(obj_RAM+0x1A0)
    E_Prize[CardID]= E_Prize[CardID] or 0  -- Ensure it exists
    E_Prize[CardID]= E_Prize[CardID]+1

    return true  -- Data recorded
end

--*****************************************************************************
local function SeekPrize(addr)  --Input: Obj_active_start
--*****************************************************************************
    while addr ~= 0 do
        local obj= R4s(addr)
        local ROM_ptr= R4s(obj)

        if     ROM_ptr == 0x9EE75F0 then --PrizeCardInit
            return IdentifyPrize(R4s(obj+4))
        elseif ROM_ptr == 0x9EE77A4 then --Heartless card
            return HeartlessPrize(R4s(obj+4))
        end

        addr= R4s(addr+8) -- Next object
    end

    return false  -- Something wrong...
end


--*****************************************************************************
local function Botty()
--*****************************************************************************
  while true do
--Run the simulation
    for i= 1, 4 do
        W4s(0x02034030+4*(i-1),T[i])
    end
    for t= 0, 6 do  emu.frameadvance()  end

--Analyze the data
    local addr= LocateCombatAddr()
    if addr then
        addr= R4s(addr+0x34)
        if not SeekPrize(addr) then Error=Error+1 end
    else
        Error=Error+1
    end

--    local ID,v= R1u(0x02018F9C),R1u(0x02018F9E)
--    tbl[ID]= tbl[ID] or {[0]=0,0,0,0,0,0,0,0,0,0}
--    tbl[ID][v]= tbl[ID][v]+1

--Reset the experiment
    savestate.load(z)
    table.insert(T,1,Roll(T)); T[5]= nil
  end
end
Botty()

--*****************************************************************************
while true do
--*****************************************************************************
    emu.frameadvance()
end