User File #23965959787784345

Upload All User Files

#23965959787784345 - GBA D&D: Eye of the Beholder - VBA data script

EotB_Data.lua
665 downloads
Uploaded 7/7/2015 7:06 AM by FatRatKnight (see all 245)
Fourth exhibit.
This is the data extraction script I've been using for that... One game... For the GBA. Actually, it's less of a script and more of a set of functions. I forget what I was using it for last, but I've adjusted the code every time I needed to get at another piece of information.
The code could be better organized, but anyone messing with this had better know a few things about lua before trying this script. I have put no provisions for others to use this, as it was strictly for me to use, and me alone. Oh, and anyone messing with this script should also have a really good idea about data structures, and a helping of some rather interesting intuition, since it was certainly non-trivial to work out what every one of those internal bytes in the game meant.
Not for the casual viewer. The more technical you are, the better. If you have no confidence in computer stuff, well, tough. You're looking at the wrong script. It's bleeding edge experimental stuff that can only be operated by someone willing to put significant time into it.
For use with VBA, though.
local R1u= memory.readbyte
local R1s= memory.readbytesigned
local R2u= memory.readword
local R2s= memory.readwordsigned
local R4s= memory.readdwordsigned

--*****************************************************************************
local function ToHex(v)
--*****************************************************************************
    return string.format("%X%X", math.floor(v/16),v%16 )
end

--*****************************************************************************
local function GetString(addr,len)
--*****************************************************************************
    local s= ""
    for i= 0, len-1 do
        local v= R1u(addr+i)
        if v == 0 then s= s .. " "
        else           s= s .. string.char(R1u(addr+i))
        end
    end
    return s
end

--*****************************************************************************
local function GetString_nonlen(addr)
--*****************************************************************************
    local s= ""
    local i= 0
    local c= R1u(addr+i)
    while (c >= 0x20) and (c < 0x80) do
        s= s .. string.char(c)
        i= i+1
        c= R1u(addr+i)
    end
    if c ~= 0 then s= s .. "  - Bad terminator:" .. string.format("%02X",c) end
    return s
end

--*****************************************************************************
local function StringSearch(str,start,len)
--*****************************************************************************
    if (type(str) ~= "string") or (#str == 0) then return end -- Forget it
    start= start or 0x08000000
    len= len or (0x08400000 - start - #str - 1)

    for addr= start, start+len do
        local success= true
        for c= 1, #str do
            if R1u(addr+c-1) ~= string.byte(str,c) then success= false; break end
        end
        if success then  return addr  end
    end
end

--local zz= StringSearch("Moon Elf",0x08000000,0x00300000)
--local zz= StringSearch(string.char(0x70,0x2C,0x03,0x08),0x08000000,0x00300000)
local zz= StringSearch(string.char(0x90,0xC7,0x1B,0x08),0x08000000,0x00300000)
--local zz= StringSearch(string.char(0x3C,0x2C,0x03,0x08),0x08000000,0x00300000)
if zz then print(string.format("%8X",zz))
else print("Fail")
end

for i= 0, 26 do
    local addr= R4s(0x081BC78C + 4*i)
    local s= GetString_nonlen(addr)
    print(string.format("%08X:%s",addr,s))
end


--*****************************************************************************
local function OutputBDAT(addr)
--*****************************************************************************
    print(string.format("%8X>BDAT|%8X|%s%s|%4X:%4X|%s",addr,
        R4s(addr+0x04),         --Bytes taken by data (including header)
        ToHex(R1u(addr+0x08)),  --Unknown, always 01
        ToHex(R1u(addr+0x09)),  --Unknown, always 01
        R2u(addr+0x0A),         --Count
        R2u(addr+0x0C),         --Size of data
        GetString(addr+0x0E,18) --Name
    ))
end

--*****************************************************************************
local function BDATGet(bdat,index, start)
--*****************************************************************************
    local size= R1u(bdat+0x0C)
    local STR= ""
    local addr= bdat + 0x20 + index*size
    start= start or 0
    for i= start, size-1 do
        STR= STR .. ToHex(R1u(addr+i))
    end
    return STR
end
print(BDATGet(0x083A10FE,0x01))
--for i= 0x2A, 0x63 do
--    print(BDATGet(0x083A137A,i))
--end

--*****************************************************************************
local function BasicDice(addr)
--*****************************************************************************
    local STR
    local v= R1s(addr+0)
    if v == 0 then STR= "        "
    else
        if v < 0 then STR= "-"; v= -v
        else          STR= " "
        end
        STR= string.format("%s%2dd%2d",
            STR,v,R1u(addr+1)
        )
    end
    v= R1s(addr+2)
    if v == 0 then STR= STR .. "    "
    elseif v < 0 then STR= string.format("%s-%2d",STR,-v)
    else              STR= string.format("%s+%2d",STR, v)
    end
    return STR
end

--*****************************************************************************
local function StandardDice(addr)
--*****************************************************************************
--+##d##+## : +##d##+##/#Lv
    local STR= BasicDice(addr) .. " : "

    local Lv= R1u(addr+6)
    if Lv == 0 then return STR .. "             " end

    return string.format("%s%s/%dLv",STR,BasicDice(addr+3),Lv)
end

--*****************************************************************************
local function UnpackBDAT_treasure(i)
--*****************************************************************************
    local a= 0x083A30C6 + 8*i

    local STR= BasicDice(a) .. "|"

    local index= R2u(a+4)
    local finish= index + R1u(a+6)
    while index < finish do
        local addr= 0x83A3546 + 4*index
        STR= string.format("%s:%2X>%sx%2d",STR,
            R1u(addr+0),
            GetString(0x839C0C3+0x3C*R1u(addr+0),18),
            R1u(addr+1)
        )
        index= index+1
    end
    return STR
end
--for i= 0, 0x8B do print(ToHex(i),UnpackBDAT_treasure(i)) end

--=============================================================================
local MapFX= {
--=============================================================================
[0]= function(addr) -- 0:Armor Class
    return string.format("%s:%2X",
        StandardDice(addr+0),
        R1u(addr+7)
    )
end,

function(addr)  -- 1:Attack Roll
    return string.format("%s:%2X",
        StandardDice(addr+0),
        R1u(addr+7)
    )
end,
function(addr)  -- 2:Damage
    return string.format("%2X:%s",
        R1u(addr+0),
        StandardDice(addr+1)
    )
end,
function(addr)  -- 3:Heal
    return StandardDice(addr+0)
end,
function(addr)  -- 4:Saving Throw
    return string.format("%2X:%s:%2X%2X",
        R1u(addr+0),
        StandardDice(addr+1),
        R1u(addr+8),
        R1u(addr+9)
    )
end,
function(addr)  -- 5:State
    return string.format("%2X",R1u(addr+0))
end,
function(addr)  -- 6:Weapon (unused)
    return "ID06:wpn"
end,
function(addr)  -- 7:Ability
    return string.format("%2X:%s",
        R1u(addr+0),
        StandardDice(addr+1)
    )
end,
function(addr)  -- 8:Action (unused)
    return "ID08:act"
end,
function(addr)  -- 9:Skill
    return string.format("%2X:%s",
        R1u(addr+0),
        StandardDice(addr+1)
    )
end,
function(addr)  --10:Poison
    return string.format("%s>%2X|%s>%2X",
        BasicDice(addr+0),
        R1u(addr+3),
        BasicDice(addr+4),
        R1u(addr+7)
    )
end,
function(addr)  --11:Energy Drain
    return StandardDice(addr+0)
end,
function(addr)  --12:Immune Spell
    return string.format("%2X%2X%2X%2X",
        R1u(addr+0),R1u(addr+1),R1u(addr+2),R1u(addr+3)
    )
end,
function(addr)  --13:Immune Special
    return string.format("%2X%2X%2X%2X",
        R1u(addr+0),R1u(addr+1),R1u(addr+2),R1u(addr+3)
    )
end,
function(addr)  --14:Immune State
    return string.format("%2X%2X%2X%2X",
        R1u(addr+0),R1u(addr+1),R1u(addr+2),R1u(addr+3)
    )
end,
function(addr)  --15:Dmg Resist
    return string.format("%2X:%2X",
        R1u(addr+0),R1u(addr+1)
    )
end,
function(addr)  --16:Dmg Type Reduce
    return string.format("%2X:%2X",
        R1u(addr+0),R1u(addr+1)
    )
end,
function(addr)  --17:Dmg Type Modifier
    return string.format("%2X:%2X",
        R1u(addr+0),R1u(addr+1)
    )
end,
function(addr)  --18:Temp HP
    return StandardDice(addr+0)
end,
function(addr)  --19:Immune Effect
    return string.format("%2X%2X%2X%2X",
        R1u(addr+0),R1u(addr+1),R1u(addr+2),R1u(addr+3)
    )
end
}

--*****************************************************************************
local function UnpackBDAT_spell()
--*****************************************************************************
--MapFX
end

--print(BDATGet(0x083A1442,0x1E))
--for i= 0, 0x42 do    print(BDATGet(0x083A085E,i))   end

--*****************************************************************************
local function enchand_skill(a)
--*****************************************************************************
    return string.format("[S:%2d %s>%s]",
        R1u(a+1),
        GetString(0x839BD43+0x20*R1u(a+0),16),
        GetString(a+2,11)
    )
end

--*****************************************************************************
local function enchand_item(a)
--*****************************************************************************
    return string.format("[I:%s>%s]",
        GetString(0x839C0C3+0x3C*R1u(a+0),18),
        GetString(a+1,11)
    )
end
--*****************************************************************************
local function enchand_spell(a)
--*****************************************************************************
    return string.format("[M:%s>%s]",
        GetString(0x83A1463+0x38*R1u(a+0),21),
        GetString(a+1,11)
    )
end

local Talk_Type=  {[0]= " ","I","B","D"}
local Talk_Lie=   {[0]= " ","L"}
local Talk_Fail_Fight= {[0]= " ","F"}
--*****************************************************************************
local function enchand_talk(a)
--*****************************************************************************
    return string.format("[T:%s%2d>%s:%s|%s:%s%s|%2d]",
        Talk_Type[R1u(a+0x00)] or "?",
        R1u(a+0x01),
        GetString(a+0x02,11), Talk_Lie[R1u(a+0x0E)] or "?",
        GetString(a+0x0F,11), Talk_Lie[R1u(a+0x1B)] or "?",
        Talk_Fail_Fight[R1u(a+0x1C)],
        R1u(a+0x1D)
    )
end

--local enchand_Fn= {enchand_talk, enchand_spell, enchand_skill, enchand_item}
--*****************************************************************************
local function enchand(a,t_enchand)
--*****************************************************************************
    local str= string.format("%s>%s:%s ",
        ToHex(R1u(a+0x00)),
        GetString(a+0x01,11),
        ToHex(R1u(a+0x0D))
    )

    local v= R1u(a+0x00)
    if v ~= 0 then
-- Huhn... Use the BDAT header to find our address.
        local StartPoint= R1u(a+0x0E)
        local EndPoint= R1u(a+0x0F)
        local addr= t_enchand[v]
        local size= R2u(addr+0x0C)
        addr= addr+0x20
        for i= 1, EndPoint do
            local address= addr + (StartPoint+i-1)*size
            str= str .. string.format("(%s)",enchand_Fn[v](address))
        end
    end
    return str
end

--[[
local TTT= {0x0837E90E,0x0837E89E,0x0837E8CE,0x0837E87E}  --enc_00
--local TTT= {0x08381012,0x08380F82,0x08380FE2,0x08380F52}  --enc_01
for i= 0, 0x15 do
--    local a= 0x0837E77E+0x10*i
    local a= 0x08380DF2+0x10*i
    print(enchand(a,TTT))
end
]]--

--for addr= 0x08383FF6, 0x083841A6, 0x10 do
--for addr= 0x0838FA46, 0x0838FAD6, 0x10 do
--    print(enchand_spell(addr))
--end


local enchand_Fn= {enchand_item, enchand_skill, enchand_spell, enchand_talk}
local enchand_order= {4,2,3,1}
--*****************************************************************************
local function Unpack_enchand(T,index)
--*****************************************************************************
    local addr= T[0]+0x20+R2u(T[0]+0x0C)*index
    local STR= string.format("%d:%s:%X",
        R1u(addr+0x00),
        GetString(addr+0x01,12),
        R1u(addr+0x0D)
    )
    local Type= enchand_order[R1u(addr+0x00)]
    if Type then
        local index= R1u(addr+0x0E)
        local finish= index + R1u(addr+0x0F)
        while index < finish do
            local a= T[Type] + 0x20 + R1u(T[Type]+0x0C)*index
            STR= string.format("%s %s",STR,enchand_Fn[Type](a))
            index= index+1
        end
    end
    return STR
end

local enc_dir= {[0]="^",">","v","<"}
local enc_ud= {[4]="u",[5]="d"}
--=============================================================================
local Unpack_enc_Fn={
--=============================================================================

[8]= function(bdat,i) -- Portal  Size: 8 bytes
    local addr= bdat+0x20+8*i

    return string.format("%2X F%X:x%2d y%2d %s ",
        R1u(addr+0), R1u(addr+1), R1u(addr+2), R1u(addr+3),
        enc_dir[R1u(addr+4)] or "?"
    )
end ,

[9]= function(bdat,i) -- Signpost  Size: 16 bytes
    local addr= bdat+0x20+16*i
    local STR= GetString(addr,11)

    local forged= R1u(addr+0x0C)
    if forged ~= 0 then STR= STR .. "!DC" .. R1u(addr+0x0D)
    else STR= STR .. "     " end

    return STR
end ,

[10]= function(bdat,i) -- Stair  Size: 8 bytes
    local addr= bdat+0x20+8*i

    return string.format("F%X:x%2d y%2d %s%s:::",
        R1u(addr+0), R1u(addr+1), R1u(addr+2),
        enc_dir[R1u(addr+3)] or "?",
        enc_ud[ R1u(addr+4)] or " "
    )
end
}

local enc_order={
[0]= 5, -- Monster
    12, -- Trap
     1, -- Chest
   nil, -- Unknown
    13, -- Vendor
     3, -- Healer
     9, -- Signpost
    11, -- Switch
     8, -- Portal
    10, -- Stair
     2, -- Door
     7, -- NPC
   nil, -- False stuff?
}
-- That leaves healer_spe, monster_mo, and vendor_ite

--*****************************************************************************
local function UnpackBDAT_enc(addr)
--*****************************************************************************
-- Give this the BDAT address of an enc object.
    local Count= R2u(addr+0x0A)
    local Size=  R2u(addr+0x0C)
    local Start= addr+0x20

-- Get addresses of BDAT_enc_OtherThings
    local v= addr
    local T= {[0]=addr} -- Index zero is us.
    for i= 1, 19 do
        v= v + R4s(v+0x04)
        if GetString(v,4) ~= "BDAT" then
            local OldV= v
            v= StringSearch("BDAT",v,0x100)
            if not v then error(  -- Ensure we're good!
            string.format("Not a BDAT:%d -%8X", i, OldV)) end
        end
        T[i]= v
    end
    local T_enchand= {}
    for i= 0, 4 do
        T_enchand[i]= T[i+15]
    end

-- Time to loop through our stuff
    for i= 0, Count-1 do
        local a= addr+0x20+i*Size
        local STR= string.format("%s:%X>%s:%s|%3d:%s%s|%s|%2d:",
           ToHex(R1u(a)),
           R1u(a+1),
           GetString(a+0x02,22),
           GetString(a+0x18,22),
           R1u(a+0x2E),
           ToHex(R1u(a+0x2F)),ToHex(R1u(addr+0x30)),
           GetString(a+0x31,24),
           R1u(a+0x49)
        )
        local v= enc_order[R1u(a+0x01)]
        if v then
            local ReadFn= Unpack_enc_Fn[v] or BDATGet
            STR= STR .. ReadFn(T[v],R1u(a+0x49)) .. "|"
        end

        local c= R1u(a+0x4B)
        local index= R1u(a+0x4A)
        while c > 0 do
            STR= STR .. Unpack_enchand(T_enchand,index)
            c= c-1; index= index+1
        end

        print(STR)
    end
end
--[[
UnpackBDAT_enc(0x837DF7A); print("==--==--==--==") -- level 0 (inn)
UnpackBDAT_enc(0x837F942); print("==--==--==--==") -- level 1
UnpackBDAT_enc(0x838135A); print("==--==--==--==") -- level 2
UnpackBDAT_enc(0x838465E); print("==--==--==--==") -- level 3
UnpackBDAT_enc(0x83873BA); print("==--==--==--==") -- level 4
UnpackBDAT_enc(0x8389672); print("==--==--==--==") -- level 5
UnpackBDAT_enc(0x838D5A6); print("==--==--==--==") -- level 6
UnpackBDAT_enc(0x839095A); print("==--==--==--==") -- level 7
UnpackBDAT_enc(0x839366E); print("==--==--==--==") -- level 8
UnpackBDAT_enc(0x8395E6A); print("==--==--==--==") -- level 9
UnpackBDAT_enc(0x8397CFE) -- level10
]]--
local SpecialMap= {
[0]= 3,  --  Armor Class    (unused)
     4,  --  Attack Roll
     5,  --  Damage
    10,  --  Heal
    14,  --  Saving Throw
    16,  --  State
   nil,  --  ??Action??
     1,  --  Ability
   nil,  --  ??Weapon??
    15,  --  Skill          (unused)
    13,  --  Poison
     9,  --  Energy Drain
    11,  --  Immune Special (unused)
   nil,  --  Immune Spell   (not listed)
    12,  --  Immune State
     6,  --  Dmg Resist
     8,  --  Dmg Type Resist
     7,  --  Dmg Type Modifier
   nil,  --  Temp HP        (not listed)
   nil,  --  Immune Effect  (not listed)
}

local SaveType= {[0]="W","R","F"," "}
local SavePower={[0]="N","h"," "}
--*****************************************************************************
local function UnpackBDAT_special()
--*****************************************************************************
    local T= {}
    local v= 0x83A098A
    for i= 1, 16 do
        v= v + R4s(v+0x04)
        if GetString(v,4) ~= "BDAT" then
            local OldV= v
            v= StringSearch("BDAT",v,0x100)
            if not v then error(  -- Ensure we're good!
            string.format("Not a BDAT:%d -%8X", i, OldV)) end
        end
        T[i]= v
    end
    for i= 0, 0x2A do
        local addr= 0x083A098A + 0x20 + 0x28*i

        local STR= string.format("%s:%d%X|%s|",
            ToHex(R1u(addr+0x00)),R1u(addr+0x01),R1u(addr+0x02),
            GetString(addr+0x03,22)
        )
        for i= 0x19,0x21 do
            STR= STR .. ToHex(R1u(addr+i))
        end
        STR= string.format("%s|%s%s%2d|",
            STR,
            SaveType[ R1u(addr+0x22)] or "?",
            SavePower[R1u(addr+0x23)] or "?",
            R1u(addr+0x24)
        )

        local index= R1u(addr+0x25)
        local count= R1u(addr+0x26)
        while count > 0 do
            local a= 0x83A139A + 4*index
            STR= string.format("%s %s>%s",
                STR,
                R1u(a),
                BDATGet(T[SpecialMap[R1u(a)]],R1u(a+1))
            )
            count= count-1; index= index+1
        end

        print(STR)
    end
end
--UnpackBDAT_special()

--*****************************************************************************
local function PrintExpandedBDAT(addr)
--*****************************************************************************
    if GetString(addr,4) ~= "BDAT" then print("ERROR:",addr); return end

    local z= addr+0x20
    local i= 0
    local Size, Count= R2u(addr+0x0C), R2u(addr+0x0A)
    while (i < Count) do
        local s= "-> "
        for j= 0, Size-1 do
            s= s .. ToHex(R1u(z+i*Size+j))
        end
        print(s)
        i= i+1
    end
end
--PrintExpandedBDAT(0x83A1442);print("----")
--PrintExpandedBDAT(0x83A0676);print("----")
--PrintExpandedBDAT(0x83A079A);print("----")
--PrintExpandedBDAT(0x83A085E);print("----")
--PrintExpandedBDAT(0x83893FA);print("----")
--PrintExpandedBDAT(0x838C13E);print("----")
--PrintExpandedBDAT(0x838FA26);print("----")
--PrintExpandedBDAT(0x83933DA);print("----")
--PrintExpandedBDAT(0x8395872);print("----")
--PrintExpandedBDAT(0x8397A6E);print("----")
--PrintExpandedBDAT(0x8399FE6);print("----")

local function PrintSpellBDAT(addr)
    if GetString(addr,4) ~= "BDAT" then print("ERROR:",addr); return end

    local z= addr+0x20
    local i= 0
    local Size, Count= R2u(addr+0x0C), R2u(addr+0x0A)
    while (i < Count) do
        local a= z+i*Size
        local s= string.format("-> %2X%s|",R1u(a),GetString(a+1,21))
        for j= 22, Size-1 do
            s= s .. ToHex(R1u(z+i*Size+j))
        end
        print(s)
        i= i+1
    end
end
--PrintSpellBDAT(0x83A1442)

--*****************************************************************************
local function FindBDATs()
--*****************************************************************************
    local addr= StringSearch("BDAT",0x0837D000,0x00040000)
    local PANIC= 0
    while addr do
        OutputBDAT(addr)
        addr= StringSearch("BDAT",addr+1,0x083A4000-addr)
        PANIC= PANIC+1
        if PANIC > 10000 then error("Very long loop!") end
    end
end
--FindBDATs()

--*****************************************************************************
local function Get_item_weapon_range(v)
--*****************************************************************************
    local addr= 0x839FB12 + 4*v
    return string.format("%2X %2X %2X %2X",
        R1u(addr),R1u(addr+1),R1u(addr+2),R1u(addr+3)
    )
end

--*****************************************************************************
local function Get_item_weapon_ammo(v)
--*****************************************************************************
    local addr= 0x839FAD2 + 4*v
    return string.format("%2X %2X %2X %2X",
        R1u(addr),R1u(addr+1),R1u(addr+2),R1u(addr+3)
    )
end

local wpn_primarytype= {[0]="Natural","Melee","Range","Ammo "}
local wpn_damagetype= {[0]="N/A", "Slash", "Pierce", "Blunt"}
local wpn_complexity= {[0]="Simple","Martial","Exotic"}
local sizes= {[0]="Fine","Diminutive","Tiny","Small","Medium","Large","Huge"}
--*****************************************************************************
local function Get_item_weapon(v)
--*****************************************************************************
    local addr= 0x0839F72E + 12*v
    local temp= R1u(addr+0)
    if     (temp == 2) then temp= Get_item_weapon_range(R1u(addr+9))
    elseif (temp == 3) then temp= Get_item_weapon_ammo(R1u(addr+9))
    else temp= ""
    end
    return string.format("%dd%2d+%d c:%2dx%d:%s %s %s %s %s",
        R1u(addr+2), R1u(addr+3), R1u(addr+4),  -- Damage (dice,sides,bonus)
        R1u(addr+7), R1u(addr+8), -- Critical (threat range, multiplier)
        temp,
        sizes[R1u(addr+5)],
        wpn_complexity[R1u(addr+6)],
        wpn_damagetype[R1u(addr+1)],
        wpn_primarytype[R1u(addr+0)]
    )
end

local arm_type= {[0]="Light","Medium","Heavy","Shield","Clothing"}
--*****************************************************************************
local function Get_item_armor(v)
--*****************************************************************************
    local addr= 0x0839F4EA + 4*v
    return string.format("%2d -%d %2d%% %s",
        R1u(addr+1),
        R1u(addr+2),
        R1u(addr+3),
        arm_type[R1u(addr+0)]
    )
end

--*****************************************************************************
local function Get_item_potion(v)
--*****************************************************************************
    return BDATGet(0x0839F566,v)
end
--*****************************************************************************
local function Get_item_scroll(v)
--*****************************************************************************
    return BDATGet(0x0839F5BA,v)
end
--*****************************************************************************
local function Get_item_wand(v)
--*****************************************************************************
    return BDATGet(0x0839F66E,v)
end

--*****************************************************************************
local function Get_item_special(v)
--*****************************************************************************
end


local Item_Material= {[0]= "Steel  ", "Silver ", "Gold   ", "? ? ? ?","Mithral",
    "Wood   ", "Stone  ", "Glass  ", "Paper  ", "Leather", "Fabric ", "Bone   ", "Flesh  "}
local Item_Magic= {[0]= "  ", "??", "+0", "+1", "+2", "+3"}

local ItemClass= {[0]="Wpn","Arm","Msc","Ptn","Rng","Scr","Wnd"}
local ItemClassFn= {[0]= Get_item_weapon , Get_item_armor , nil ,
    Get_item_potion , nil , Get_item_scroll , Get_item_wand}

local EquipType= {[0]="Head","Neck","Body","Arms","Hand","Fngr","Feet","----","All ","Quiv"}
--*****************************************************************************
local function OutputItemData()
--*****************************************************************************
--    print("##>Name              |Price|?t:ID|AD|")

    for i= 0, 221 do
        local addr= 0x0839C0C2 + 0x3C*i
        local STR= string.format("%s>%s:%s|%5d|%d%d|%s|%s:%s|%s:",
            ToHex(R1u(addr)),
            GetString(addr+0x01,18),
            GetString(addr+0x17,21),
            R2u(addr+0x2E),  -- Price
            R1u(addr+0x32),  -- Attack bonus
            R1u(addr+0x33),  -- AC bonus
            EquipType[R1u(addr+0x30)] or "????", -- Equip slot
            Item_Material[R1u(addr+0x34)] or "???????",
            Item_Magic[R1u(addr+0x35)] or "??",
            ItemClass[R1u(addr+0x31)] or "???"
        )

        local Fn= ItemClassFn[R1u(addr+0x31)]
        if Fn then STR= STR .. Fn(R1u(addr+0x37)) end

        print(STR)
    end
end
--OutputItemData()

local WpnType1= {[0]="Natural","Melee","Launcher","Ammo"}
local WpnType2= {[0]="N/A","Slash","Pierce","Blunt"}
--*****************************************************************************
local function Output_item_weapon()
--*****************************************************************************
   print("##>Name              |Price|#d##+#|")
   for i= 0, 221 do
      local addr= 0x0839C0C2 + 0x3C*i
      if R1u(addr+0x31) == 0 then
         local WpnAddr= 0x0839F72E + 12*R1u(addr+0x37)
         local STR= ToHex(R1u(addr)) .. ">"

         STR= STR .. GetString(addr+0x01,18)

         STR= STR .. string.format("|%5d|%dd%2d+%d|%s %s",
            R2u(addr+0x2E),
            R1u(WpnAddr+2),
            R1u(WpnAddr+3),
            R1u(WpnAddr+4),
            WpnType1[R1u(WpnAddr+0)],
            WpnType2[R1u(WpnAddr+1)]
         )

         print(STR)
      end
   end
end
--Output_item_weapon()

local ArmType= {[0]="Light", "Medium", "Heavy", "Shield", "None"}
--*****************************************************************************
local function Output_item_armor()
--*****************************************************************************

   for i= 0, 221 do
      local addr= 0x0839C0C2 + 0x3C*i
      if R1u(addr+0x31) == 1 then
         local ArmAddr= 0x0839F4EA + 4*R1u(addr+0x37)
         local STR= ToHex(R1u(addr)) .. ">"

         STR= STR .. GetString(addr+0x01,18)

         STR= STR .. string.format("|%5d|%d:%2d|-%d:%2d|%s",
            R2u(addr+0x2E),
            R1u(addr+0x33),
            R1u(ArmAddr+1),
            R1u(ArmAddr+2),
            R1u(ArmAddr+3),
            ArmType[R1u(ArmAddr+0)]
         )

         print(STR)
      end
   end
end
--Output_item_armor()

local Alignment= {[0]="  ","LG","LN","LE","NG","N ","NE","CG","CN","CE"}
--*****************************************************************************
local function Output_monster()
--*****************************************************************************
    for i= 0, 31 do
        local addr= 0x0839FB5A + 0x4C*i

        local STR= string.format("%s>%s|%s%s|%s %6s %s|%2d:%2d:%2d:%2d:%2d:%2d|%2d:%2d:%2d|%s|%2dd%2d+%2d:%2d:%2d:%3d|",
            ToHex(R1u(addr+0x00)),    -- ID
            GetString(addr+0x01,20),  -- Name1

            ToHex(R1u(addr+0x2D)),    -- Creature type
            ToHex(R1u(addr+0x2E)),    -- ?

            Alignment[R1u(addr+0x2F)] or "??",
            sizes[R1u(addr+0x30)] or "??????",
            ToHex(R1u(addr+0x31)),    -- Miniature

            R1u(addr+0x32), -- STR
            R1u(addr+0x33), -- DEX
            R1u(addr+0x34), -- CON
            R1u(addr+0x35), -- INT
            R1u(addr+0x36), -- WIS
            R1u(addr+0x37), -- CHA

            R1s(addr+0x38), -- Saves (Fortitude?)
            R1s(addr+0x39), -- Saves (Reflex?)
            R1s(addr+0x3A), -- Saves (Will?)

            ToHex(R1u(addr+0x3B)),    -- ?

            R1u(addr+0x3C), -- Hit dice
            R1u(addr+0x3D), -- Sides of hit dice
            R1u(addr+0x3E), -- Flat HP bonus
            R1u(addr+0x3F), -- AC
            R1u(addr+0x40), -- Speed
            R1u(addr+0x41)  -- Base experience?
        )
        print(STR)

        print("Feats")
        local i,c= R1u(addr+0x42),R1u(addr+0x43)
        while c > 0 do
            local z= R1u(0x83A04FA+4*i) -- Get Feat index
            if z >= 0x1A then print(string.format("ID:%X",z))
            else              print(GetString(0x839B9E3+0x20*z,20))
            end
            c= c-1; i= i+1
        end
        print()

        print("Inventory")
        i,c= R1u(addr+0x44),R1u(addr+0x45)
        while c > 0 do
            local z= R1u(0x83A0696+4*i) -- Get Item index
            print(R1u(0x83A0697+4*i),GetString(0x839C0C3+0x3C*z,18))
            c= c-1; i= i+1
        end
        print()

        print("Special")
        i,c= R1u(addr+0x46),R1u(addr+0x47)
        while c > 0 do
            local z= R1u(0x83A07BA+4*i) -- Get Special index
            print(GetString(0x83A09AD+0x28*z,22))
            c= c-1; i= i+1
        end
        print()

        print("Spells")
        i,c= R1u(addr+0x48),R1u(addr+0x49)
        while c > 0 do
            local z= R1u(0x83A087E+4*i) -- Get Spell index
            print(R1u(0x83A087F+4*i),GetString(0x83A1463+0x38*z,21))
            c= c-1; i= i+1
        end
        print()
--[[
        local STR= string.format("%s>%s:%s|",
            ToHex(R1u(addr+0x00)),
            GetString(addr+0x01,22),
            GetString(addr+0x17,22)
        )
        for j= 0x2D, 0x4B do STR= STR .. ToHex(R1u(addr+j)) end
]]--
    end
end
--Output_monster()

--*****************************************************************************
local function Output_feat()
--*****************************************************************************
    for i= 0, 25 do
        local addr= 0x0839B9E2 + 0x20*i
        local STR= ToHex(R1u(addr)) .. GetString(addr+0x01,20)
        for j= 0x17, 0x1F do
            STR= STR .. ToHex(R1u(addr+j))
        end
        print(STR)
    end
end
--Output_feat()

--*****************************************************************************
local function Output_skill()
--*****************************************************************************
    for i= 0, 26 do
        local addr= 0x0839BD42 + 0x20*i
        local STR= ToHex(R1u(addr)) .. GetString(addr+0x01,16)
        for j= 0x17, 0x1F do
            STR= STR .. ToHex(R1u(addr+j))
        end
        print(STR)
    end
end
--Output_skill()

--*****************************************************************************
local function Output_special()
--*****************************************************************************
    for i= 0, 0x2A do
        local addr= 0x083A09AA + 0x28*i
        local STR= string.format("%s%s%s|%s|",
            ToHex(R1u(addr+0)),
            ToHex(R1u(addr+1)),
            ToHex(R1u(addr+2)),
            GetString(addr+3,22)
        )
        for j= 0x19,0x27 do
            STR= STR .. ToHex(R1u(addr+j))
        end
        print(STR)
    end
end
--Output_special()

local fx_tbl= {
[0]=0x083A26A2, -- 0 spellfx_armorclas
    0x083A273A, -- 1 spellfx_attackrol
    0x083A27A2, -- 2 spellfx_damage
    0x083A2906, -- 3 spellfx_heal
    0x083A2A3A, -- 4 spellfx_savingthr
    0x083A2BA6, -- 5 spellfx_state
    0x083A2682, --?? spellfx_action
    0x083A261A, -- 7 spellfx_ability
    0x083A2C26, --?? spellfx_weapon
    0x083A2B56, -- 9 spellfx_skill
    0x083A2A12, -- A spellfx_poison
    0x083A28DE, -- B spellfx_energydra
    0x083A2986, -- C spellfx_immunespe 
    0x083A29BE, -- D spellfx_immunespe
    0x083A29EA, -- E spellfx_immunesta
    0x083A287A, -- F spellfx_dmgresist
    0x083A28BE, --?? spellfx_dmgtypere
    0x083A289E, --?? spellfx_dmgtypemo
    0x083A2BF6, --12 spellfx_temphp
    0x083A294E  --13 spellfx_immuneeff
}

--*****************************************************************************
local function Output_spell()
--*****************************************************************************
    for i= 0, 0x50 do
        local addr= 0x083A1462 + 0x38*i
        local STR= (string.format("%s>%s|%X%X:%X:%X|%2d|",
            ToHex(R1u(addr+0x00)),
            GetString(addr+0x01,21),
            R1u(addr+0x1B), -- Range
            R1u(addr+0x24), -- Targeting
            R1u(addr+0x23), -- Duration
            R1u(addr+0x18), -- Element
            R1u(addr+0x25)  -- ... Uh, best read in decimal...
        ))
        STR= STR .. string.format("%X",R1u(addr+0x17))
        STR= STR .. string.format("%X",R1u(addr+0x1E))
        STR= STR .. string.format("%X",R1u(addr+0x21))
        STR= STR .. string.format("%X",R1u(addr+0x22))
        STR= STR .. string.format("%X",R1u(addr+0x28))
        STR= STR .. string.format("%X",R1u(addr+0x2D))
        STR= STR .. string.format("%X",R1u(addr+0x2E))
        STR= STR .. string.format("%X",R1u(addr+0x2F))
        STR= STR .. string.format("%X",R1u(addr+0x30))
        STR= STR .. string.format("%X",R1u(addr+0x31))
        STR= STR .. string.format("%X",R1u(addr+0x32))
        STR= STR .. string.format("%X",R1u(addr+0x33))
        STR= STR .. string.format("%X",R1u(addr+0x34))

        STR= STR .. " "
        local EndPoint= R1u(addr+0x36)
        if EndPoint > 0 then
            local StartPoint= R1u(addr+0x35)-1
            for i= 1, EndPoint do
                local a= 0x083A2C66 + (StartPoint+i)*4
                STR= STR .. ToHex(R1u(a)) .. ">"
                STR= STR .. BDATGet(spellfx_tbl[R1u(a)],R1u(a+1)) .. " "
--                STR= STR .. string.format("%s%s ",ToHex(R1u(a)),ToHex(R1u(a+1)))
            end
        end
        print(STR)
    end
end
--Output_spell()

--[[
local enc_order={
[0]= 5, -- Monster
    12, -- Trap
     1, -- Chest
   nil, -- Unknown
    13, -- Vendor
     3, -- Healer
     9, -- Signpost
    11, -- Switch
     8, -- Portal
    10, -- Stair
     2, -- Door
     7, -- NPC
   nil, -- False stuff?
} ]]--
-- That leaves healer_spe, monster_mo, and vendor_ite


--*****************************************************************************
local function Output_mons_list(addr)
--*****************************************************************************
-- Give this the BDAT address of an enc object.
    local Count= R2u(addr+0x0A)
    local Size=  R2u(addr+0x0C)
    local Start= addr+0x20

-- Get addresses of BDAT_enc_OtherThings
    local v= addr
    local T= {[0]=addr} -- Index zero is us.
    for i= 1, 6 do
        v= v + R4s(v+0x04)
        if GetString(v,4) ~= "BDAT" then
            local OldV= v
            v= StringSearch("BDAT",v,0x100)
            if not v then error(  -- Ensure we're good!
                string.format("Not a BDAT:%d -%8X", i, OldV)) end
        end
        T[i]= v
    end

    local MonsEnc= T[5]+0x20
    local MonsList=T[6]+0x20

-- Time to loop through our stuff
    for i= 0, Count-1 do
        local a= addr+0x20+i*Size
        if R1u(a+1) == 0 then
            local ThisEnc= MonsEnc + 4*R1u(a+0x49)
            print(string.format("%s:%s|",
              GetString(a+0x02,22),
              GetString(a+0x18,22)
            ))
            print(UnpackBDAT_treasure(R1u(ThisEnc)))

            local i,c= R1u(ThisEnc+2), R1u(ThisEnc+3)
            while c > 0 do
                local MonsID= R1u(MonsList+4*i+1)
                print(GetString(0x839FB5B+0x4C*MonsID,20) .. "*")
                c= c-1; i=i+1
            end
            print()
        end
--[[
        local STR= string.format("%s:%X>%s:%s|%3d:%s%s|%s|%2d:",
           ToHex(R1u(a)),
           R1u(a+1),
           GetString(a+0x02,22),
           GetString(a+0x18,22),
           R1u(a+0x2E),
           ToHex(R1u(a+0x2F)),ToHex(R1u(addr+0x30)),
           GetString(a+0x31,24),
           R1u(a+0x49)
        )
        local v= enc_order[R1u(a+0x01)]
        if v then
            local ReadFn= Unpack_enc_Fn[v] or BDATGet
            STR= STR .. ReadFn(T[v],R1u(a+0x49)) .. "|"
        end

        print(STR)
]]--
    end
end
--[[
Output_mons_list(0x837DF7A); print("==--==--==--==") -- level 0 (inn)
Output_mons_list(0x837F942); print("==--==--==--==") -- level 1
Output_mons_list(0x838135A); print("==--==--==--==") -- level 2
Output_mons_list(0x838465E); print("==--==--==--==") -- level 3
Output_mons_list(0x83873BA); print("==--==--==--==") -- level 4
Output_mons_list(0x8389672); print("==--==--==--==") -- level 5
Output_mons_list(0x838D5A6); print("==--==--==--==") -- level 6
Output_mons_list(0x839095A); print("==--==--==--==") -- level 7
Output_mons_list(0x839366E); print("==--==--==--==") -- level 8
Output_mons_list(0x8395E6A); print("==--==--==--==") -- level 9
Output_mons_list(0x8397CFE) -- level10
]]--

--*****************************************************************************
local function Output_treasure_list(addr)
--*****************************************************************************
-- Give this the BDAT address of an enc object.
    local Count= R2u(addr+0x0A)
    local Size=  R2u(addr+0x0C)
    local Start= addr+0x20

-- Get addresses of BDAT_enc_OtherThings
    local v= addr
    local T= {[0]=addr} -- Index zero is us.
    for i= 1, 6 do
        v= v + R4s(v+0x04)
        if GetString(v,4) ~= "BDAT" then
            local OldV= v
            v= StringSearch("BDAT",v,0x100)
            if not v then error(  -- Ensure we're good!
                string.format("Not a BDAT:%d -%8X", i, OldV)) end
        end
        T[i]= v
    end

    local Treas_List= T[1]+0x20

-- Time to loop through our stuff
    for i= 0, Count-1 do
        local a= addr+0x20+i*Size
        if R1u(a+1) == 2 then
            local ThisEnc= Treas_List + 8*R1u(a+0x49)
            print(string.format("%s:%s|",
              GetString(a+0x02,22),
              GetString(a+0x18,22)
            ))
            print(UnpackBDAT_treasure(R1u(ThisEnc)))

--[[
            local i,c= R1u(ThisEnc+2), R1u(ThisEnc+3)
            while c > 0 do
                local MonsID= R1u(MonsList+4*i+1)
                print(GetString(0x839FB5B+0x4C*MonsID,20) .. "*")
                c= c-1; i=i+1
            end
]]--
            print()
        end
--[[
        local STR= string.format("%s:%X>%s:%s|%3d:%s%s|%s|%2d:",
           ToHex(R1u(a)),
           R1u(a+1),
           GetString(a+0x02,22),
           GetString(a+0x18,22),
           R1u(a+0x2E),
           ToHex(R1u(a+0x2F)),ToHex(R1u(addr+0x30)),
           GetString(a+0x31,24),
           R1u(a+0x49)
        )
        local v= enc_order[R1u(a+0x01)]
        if v then
            local ReadFn= Unpack_enc_Fn[v] or BDATGet
            STR= STR .. ReadFn(T[v],R1u(a+0x49)) .. "|"
        end

        print(STR)
]]--
    end
end

--Output_treasure_list(0x837DF7A); print("==--==--==--==") -- level 0 (inn)
--Output_treasure_list(0x837F942); print("==--==--==--==") -- level 1
--Output_treasure_list(0x838135A); print("==--==--==--==") -- level 2
--Output_treasure_list(0x838465E); print("==--==--==--==") -- level 3
--Output_treasure_list(0x83873BA); print("==--==--==--==") -- level 4
--Output_treasure_list(0x8389672); print("==--==--==--==") -- level 5
--Output_treasure_list(0x838D5A6); print("==--==--==--==") -- level 6
--Output_treasure_list(0x839095A); print("==--==--==--==") -- level 7
--Output_treasure_list(0x839366E); print("==--==--==--==") -- level 8
--Output_treasure_list(0x8395E6A); print("==--==--==--==") -- level 9
--Output_treasure_list(0x8397CFE) -- level10