Dessyreqt icon

FF6 info script (personal modifications)

Dessyreqt | PRO | 04/23/13 04:35:06 AM UTC | 0 ⭐ | 2251 👁️ | Never ⏰ | []
Lua |

30.26 KB

|

None

|

0 👍

/

0 👎

-- Features:
-- 1. Encounter prediction: predicts steps until encounter, and what will be encountered.
--    Does not predict front/back/pincer/side/preemptive variants, not will it work properly
--    on the floating continent. (there is tentative support for this (which actually makes up
--    a good part of the code), but it is buggy, and only works well when one is on the world map,
--    and has 3 or 4 chars in party, so it is disabled by default)
-- 2. Outline treasure chests and show their contents and status (green = untaken, red = taken)
-- 3. Outline squares that trigger events. Blue = transition to new area, light blue = transition
--    to same area, very light blue = transition to map, yellow = unclassified event.
-- 4. In battle, hp and mp bars are displayed over the enemies, as well as their battle gauges.
--    Their level is also displayed. On gau's turns, a "?" is displayed by any monster whose
--    rage is not known. Additionally, the enemies' resistances etc. are displayed in a compact
--    but hopefully readable manner, as a set of 4 3x3 sqares of pixels, where each has the
--    following format:
--      fil   ; fire (red) ice (blue) lightning (yellow)
--      pwp   ; poison (green) wind (gray) holy (white)
--      ew    ; earth (brown) water (blue)
--    The order of the sqares is, from left to right, absorb, nullify, resist, weak.
-- 5. Extra information is displayed for the currently selected monster.
--    normally, only its drops and hp/mp are displayed, but if locke is selecting the
--    monster with the steal command, its steals are also listed. If relm is selecting
--    a monster with control or sketch, that information will also be indicated.
-- 6. While in the rage menu, information about what the selected rage does is
--    displayed. Only the attack part of the rage is displayed so far, since I haven't thought
--    of a compact way of displaying all the status information associated with a rage.
 
addHours = 0
addMinutes = 4
addSeconds = 9
addFrames = 21
textX = 160
textY = 120
 
lMode1 = memory.readword(0x7e1501)
lMode2 = memory.readbyte(0x7e1503)
lMode3 = memory.readbyte
cMode1 = memory.readword(0x7e1501)
cMode2 = memory.readbyte(0x7e1503)
autoText = false
 
drawpixel = function(x,y,color)
    if x < 0 or y < 0 then return end
    if x >= 0x100 or y >= 0xE0 then return end
    gui.drawpixel(x,y,color)
end
-- the following section handles out of bounds checking.
-- This will hopefully not be necessary in later versions of snes9x-lua
-- The bounds checking for lines is slightly more complicated, so I did
-- not bother implementing it properly.
min = function(a,b) if a < b then return a else return b end end
max = function(a,b) if a < b then return b else return a end end
order = function(a,b) if a > b then return b, a else return a,b end end
olddrawbox = gui.drawbox
gui.drawbox = function(x1,y1,x2,y2,color)
    x1,x2 = order(x1,x2)
    y1,y2 = order(y1,y2)
    x1 = min(max(0,x1),255)
    y1 = min(max(0,y1),238)
    x2 = min(max(0,x2),255)
    y2 = min(max(0,y2),238)
    olddrawbox(x1,y1,x2,y2,nil,color)
end
oldtext = gui.text
gui.text = function(x,y,text)
    if x >= 0 and x < 256 and y >= 0 and y < 239 then
        oldtext(x,y,text)
    end
end
horline = function(x1,y,x2,color)
    x1,x2 = order(x1,x2)
    x1 = min(max(0,x1),255)
    x2 = min(max(0,x2),255)
    if y >= 0 and y < 239 then
        gui.drawline(x1,y,x2,y,color)
    end
end
vertline = function(x,y1,y2,color)
    y1,y2 = order(y1,y2)
    y1 = min(max(0,y1),238)
    y2 = min(max(0,y2),238)
    if x >= 0 and x < 256 then
        gui.drawline(x,y1,x,y2,color)
    end
end
 
 
startgauge = function(x,y,w)
    gx, gy, gw = x, y, w
end
drawgauge = function(c,m,col)
    if m == 0 then m = 1 end
    local g = c*gw/m
    horline(gx,gy,gx+g,col)
    horline(gx+g,gy,gx+gw,"#000000")
    gy = gy-1
end
 
tochar = function(i)
    if i < 0x80 then return ""
    elseif i < 0x9a then return string.char(string.byte("A")+i-0x80)
    elseif i < 0xb4 then return string.char(string.byte("a")+i-0x9a)
    elseif i < 0xbe then return string.char(string.byte("0")+i-0xb4)
    elseif i == 0xfe then return " "
    else return "" end
end
 
readsnesstring = function(from,maximum)
    local res = ""
    local tmp = memory.readbyte(from)
    local i = 0
    while tmp ~= 0xFF do
        if i == maximum then break end
        res = res .. tochar(tmp)
        from = from+1
        tmp = memory.readbyte(from)
        i = i+1
    end
    return res
end
 
getitemname = function(id)
    return readsnesstring(0xd2b300+0xd*id+1,12)
end
getmonstername = function(id)
    return readsnesstring(0xcfc050+0xa*id,10)
end
getattackname = function(id)
    local x = 0
    local maxlen = 10
    if id < 0x36 then
        x = id*7
        maxlen = 7
    elseif id < 0x51 then
        x = id*8-0x36
        maxlen = 8
    elseif id < 0x56 then x = id*0xA-0xd8
    else x = id*0xA-0xd8 -- vet ikke hvorfor indeksen blir d8 her.
    --else id < 0x5b then x = id*0xA-0xc4
    end
    return readsnesstring(0xe6f567+x,maxlen)
end
 
 
-- This is probably not the best way of determining the game mode, but it works.
mode_battle = function()
    return memory.readword(0x7e1501) == 0x0ba7 and memory.readbyte(0x7e1503) == 0xC1
end
mode_cave = function()
    return memory.readword(0x7e1501) == 0x0182 and memory.readbyte(0x7e1503) == 0xC0
end
mode_map  = function()
    return memory.readword(0x7e1501) == 0xa728 and memory.readbyte(0x7e1503) == 0xEE
end
mode_menu = function()
    return memory.readword(0x7e1501) == 0x1387 and memory.readbyte(0x7e1503) == 0xC3
end
function HandleKeys()
    keys = input.get()
 
    if press('T') then
        autoText = not autoText
    end
    
    last_keys = keys                                              
end
function press(button)
    if keys[button] and not last_keys[button] then
        return true
    end
    return false
end
 
hours = 0
minutes = 0
seconds = 0
milliseconds = 0
 
function CalculateTime()
    frames = snes9x.framecount()
    frames = frames + addHours * 216000 + addMinutes * 3600 + addSeconds * 60 + addFrames
    hours = math.floor(frames / 216000)
    minutes = math.floor((frames - hours * 216000) / 3600)
    seconds = math.floor((frames - hours * 216000 - minutes * 3600) / 60)
    milliseconds = math.floor((frames - hours * 216000 - minutes * 3600 - seconds * 60) * 100 / 60)
end
 
function OutputTime()
    gui.text(textX, textY, "Time: " .. hours .. ":" .. string.format("%02d",minutes) .. ":" .. string.format("%02d",seconds) .. "." .. string.format("%02d",milliseconds))
    gui.text(textX, textY + 10, "Offset: " .. addHours .. ":" .. string.format("%02d",addMinutes) .. ":" .. string.format("%02d",addSeconds) .. "." .. string.format("%02d",math.floor(addFrames * 100 / 60)))
end
 
 
-- prints a compact representation of elemental properties.
-- There are 8 elements. Each is assigned a color, and a place
-- in a 3x3 matrix of pixels.
-- fil   ; fire (red) ice (blue) lightning (yellow)
-- pwp   ; poison (green) wind (gray) holy (white)
-- ew    ; earth (brown) water (blue)
-- Colors need not be uniqe, as the position fixes things.
-- This is then surrounded by black border.
print_element = function(x,y,elem)
    -- first draw the border
    horline(x, y, x+4, "#404040")
    vertline(x+4, y, y+4, "#404040")
    vertline(x, y, y+4, "#404040")
    horline(x, y+4, x+4, "#404040")
    -- now draw the elements
    local x,y=x+1,y+1
    putpix = function(x,y,b,c)
        if b == 1 then drawpixel(x,y,c) else drawpixel(x,y,"#000000") end
    end
    cols = {
        "#ff0000","#0000ff","#ffff00",
        "#00ff00","#808080","#ffffff",
        "#a08000","#0000ff","#000000"
    }
    for i = 1, 9 do
        dx, dy = (i-1)%3, math.floor((i-1)/3)
        putpix(x+dx,y+dy,elem % 2,cols[i])
        elem = math.floor(elem/2)
    end
end
 
get_special = function(id)
    -- Information about the special attack
    -- This is used by rage, sketch, control.
    local special = memory.readbyte(0xcf001f+0x20*id)
    local specialn = readsnesstring(0xcfd0d0+id*10,10)
    local no_damage,no_dodge = bit(special, 6),bit(special,7)
    special = special % 0x40
    desc = "???"
    if special == 0x30 then desc = "absorb hp"
    elseif special == 0x31 then desc = "absorb mp"
    elseif special >= 0x32 then desc = "remove reflect"
    elseif special >= 0x20 then desc = string.format("+%d%%",(special-0x1f)*50)
    else
        local descs = { "Dark","Zombie","Poison","MagiTek","Clear","Imp","Petrify",
            "Death", "Condemned", "Near Fatal", "Image", "Mute", "Berserk",
            "Muddle", "Seizure", "Sleep", "Dance", "Regen", "Slow", "Haste",
            "Stop", "Shell", "Safe", "Reflect", "Rage", "Freeze", "Life 3",
            "Morph", "Chant!", "Disappear!", "Dog block", "Float" }
        desc = descs[special+1]
    end
    specialn = specialn.." ("..desc..")"
    return specialn, no_damage, no_dodge
end
 
 
print_status = function(status)
    -- Må finne ut hva bitsene i hver status byte betyr.
end
 
-- bit operations, since lua is silly enough to miss these
bit = function(n,i) return math.floor(n/2^i) % 2 end
bor = function(a,b)
    local c = 0
    local pot = 1
    while a ~= 0 or b ~= 0 do
        if a % 2 == 1 or b % 2 == 1 then c = c+pot end
        a = math.floor(a/2)
        b = math.floor(b/2)
        pot = pot*2
    end
    return c
end
 
-- to get the pixel distance from an encounter, we
-- need to fix an occational off-by-1 error for
-- count. this happens on the first frame when we reach
-- a whole square. we thus need to keep track of whether
-- the last position was whole or not
last_position_whole = true
 
while true do
    -- Are we in battle?
    offset = 100
    if mode_battle() then
        --snes9x.speedmode("maximum")
        
        -- memory.writebyte(0x7e3bfc, 0)
        -- memory.writebyte(0x7e3bfd, 0)
        -- memory.writebyte(0x7e3bfe, 0)
        -- memory.writebyte(0x7e3bff, 0)
        -- memory.writebyte(0x7e3c00, 0)
        -- memory.writebyte(0x7e3c01, 0)
        -- memory.writebyte(0x7e3c02, 0)
        -- memory.writebyte(0x7e3c03, 0)
        -- memory.writebyte(0x7e3c04, 0)
        -- memory.writebyte(0x7e3c05, 0)
        -- memory.writebyte(0x7e3c06, 0)
        -- memory.writebyte(0x7e3c07, 0)
        
        sel_side, sel_i = memory.readbyte(0x7e7ace), memory.readbyte(0x7e7acf)
        sel_enemy, sel_party = memory.readbyte(0x7e7b7e),memory.readbyte(0x7e7b7d)
        sel_multi = memory.readbyte(0x7e7b7f)
        -- loop through present monsters
        for i = 0, 5 do
            -- a few shortcuts
            j, k = 2*i, 2*(4+i)
            state = memory.readword(0x7e3aa0+k)
            if state ~= 0 and bit(state,15) ~= 1 then
            -- get coordinates (we should know the size of the monster too, but we don't)
            x = memory.readbyte(0x7e80c2+1+j)
            -- this size is really the x-offset of the pointing hand relative to the start
            -- of the sprite. For a normal attack, this works fine, but for monsters on the
            -- right hand side of the screen, this offset is 0, as the hand is on their left
            -- side. To do things properly, I should get this in a more direct fashion, but
            -- I can't be bothered
            xsize = memory.readbyte(0x7e807a+1+j)
            if xsize == 0 then xsize = 0x20 end
            y = memory.readbyte(0x7e80ce+1+j)
            -- other interesting information
            id   = memory.readword(0x7e3388+j)
            xp   = memory.readword(0x7e3d8c+j)
            gold = memory.readword(0x7e3da0+j)
            hp   = memory.readword(0x7e3bf4+k)
            mp   = memory.readword(0x7e3c08+k)
            mhp  = memory.readword(0x7e3c1c+k)
            mmp  = memory.readword(0x7e3c30+k)
            level= memory.readbyte(0x7e3b18+k)
            speed= memory.readbyte(0x7e3b19+k)
            gauge= memory.readword(0x7e3218+k)
            -- elements
            absorb  =  memory.readbyte(0x7e3bcc+k)
            nullify =  memory.readbyte(0x7e3bcd+k)
            resist  =  memory.readbyte(0x7e3be1+k)
            weak    =  memory.readbyte(0x7e3be0+k)
            stealn  =  memory.readbyte(0x7e3311+j)
            stealr  =  memory.readbyte(0x7e3310+j)
            dropn   =  memory.readbyte(0xcf3000+4*id+3)
            dropr   =  memory.readbyte(0xcf3000+4*id+2)
 
            name = getmonstername(id)
 
            -- Print the gauges
            startgauge(x,y,xsize)
            drawgauge(mp, mmp, "#0000ff")
            drawgauge(hp, mhp, "#00ff00")
            drawgauge(gauge, 0x10000, "#ff0000")
            by = gy
            gui.text(x-16, by-8, string.format("%2d",level))
            print_element(x, by-6, absorb)
            print_element(x+4, by-6, nullify)
            print_element(x+8, by-6, resist)
            print_element(x+12, by-6, weak)
            gui.text(x+18, by-8, ""..hp)
 
            active_slot = memory.readbyte(0x7e0201)
            active_player = memory.readbyte(0x7e3ed8+active_slot*2)
            menu_pos = memory.readbyte(0x7e890f+active_slot)
            relm_info = active_player == 8 and menu_pos == 1
            locke_info = active_player == 1 and menu_pos == 1
            gau_info = active_player == 0xb
 
            if gau_info then
                local id_byte, id_bit = math.floor(id/8), id % 8
                if bit(memory.readbyte(0x7e1d2c+id_byte),id_bit) == 0 then
                    -- monster not known!
                    gui.text(x-8,y,"?")
                end
            end
            
            -- More detailed information for the monster we point to.
            -- This will depend on how it is being pointed to
            if (sel_side == 0 or sel_side == 2) and sel_i == i and
                sel_multi == 0 and sel_enemy ~= 0 then
                --gui.text(10,offset,"Level "..level.." "..name)
                --offset = offset+10
                gui.text(10,offset,string.format("HP:%d/%d, MP:%d/%d",hp,mhp,mp,mmp))
                offset = offset+10
                --gui.text(10,offset,string.format("XP:%d, gold:%d",xp,gold))
                --offset = offset+10
                if locke_info then
                    gui.text(10,offset,string.format("Steal %s/%s", getitemname(stealn), getitemname(stealr)))
                    offset = offset+10
                end
                gui.text(10,offset,string.format("Drops %s/%s", getitemname(dropn), getitemname(dropr)))
                offset = offset+10
                -- Special attack description
                specialn = get_special(id)
                -- Sketch
                sketch1 = memory.readbyte(0xcf4300+2*id)
                sketch2 = memory.readbyte(0xcf4300+2*id+1)
                -- control
                control, controln = {}, {}
                for ctrl_i = 0, 3 do
                    control[ctrl_i] = memory.readbyte(0xcf3d00+4*id+ctrl_i)
                end
                if sketch1 == 0xEF then sketch1n = specialn else sketch1n = getattackname(sketch1) end
                if sketch2 == 0xEF then sketch2n = specialn else sketch2n = getattackname(sketch2) end
                for ctrl_i = 0, 3 do
                    local ctrl,foo = control[ctrl_i]
                    if ctrl == 0xEF then foo = specialn
                    elseif ctrl == 0xFF then foo = "Nothing"
                    else foo = getattackname(ctrl) end
                    controln[ctrl_i] = foo
                end
                if relm_info then
                    gui.text(10,offset,string.format("Sketch %s/%s", sketch2n, sketch1n))
                    offset = offset+10
                    gui.text(10,offset,string.format("Control %s/%s",controln[0],controln[1]))
                    offset = offset+10
                    gui.text(10,offset,string.format("        %s/%s",controln[2],controln[3]))
                    offset = offset+10
                end
            end
        end end
        -- Rage information when in the rage menu
        if memory.readbyte(0x7e7bd4) == 0x24 then
            x = memory.readbyte(0x7e892f)
            y = memory.readbyte(0x7e8933)
            scroll = memory.readbyte(0x7e892b)
            i = 2*(y+scroll)+x
            id = memory.readbyte(0x7e257e + i)
            if id ~= 0xFF then
                -- What rages does this monster have?
                rage1 = memory.readbyte(0xcf4600+2*id)
                rage2 = memory.readbyte(0xcf4600+2*id+1)
                -- Special attack description
                specialn = get_special(id)
                if rage1 == 0xEF then rage1n = specialn else rage1n = getattackname(rage1) end
                if rage2 == 0xEF then rage2n = specialn else rage2n = getattackname(rage2) end
                gui.text(10,offset,string.format("%s/%s", rage1n, rage2n))
                offset = offset+10
            end
        end
    elseif mode_cave() then
        snes9x.speedmode("normal")
        -- get the screen position
        sx     = memory.readword(0x7e8297)
        sy     = memory.readword(0x7e8299)
        if sx >= 0x8000 then sx = sx-0x10000 end
        if sy >= 0x8000 then sy = sy-0x10000 end
        -- prepare to loop through treasures
        area   = memory.readword(0x7e0082)
        table  = 0xed8634
        i      = memory.readword(0xed82f4+2*area)
        to     = memory.readword(0xed82f4+2*(area+1))
        -- loop through the treasures
        while i ~= to do
            -- read from the treasure information array
            xi     = memory.readbyte(table+i)
            yi     = memory.readbyte(table+i+1)
            flagi  = memory.readword(table+i+2)
            item   = memory.readbyte(table+i+4)
            name   = getitemname(item)
            -- Has the box been taken? To find out, we need to
            -- do some bit manipulation.
            byte_index = math.floor(flagi/8)
            bit_index = flagi % 8
            if byte_index >= 0x40 then
                byte_index = byte_index - 0x40*math.floor(byte_index/0x40)
            end
            flag = memory.readbyte(0x7e1e40+byte_index)
            flag = flag % (2^(bit_index+1))
            flag = math.floor(flag/ 2^bit_index)
            -- flag is now 0 if not taken and 1 if taken
            if flag == 0 then color = "#00ff00" else color = "#ff0000" end
 
            -- get the real x,y position, using the fact that
            -- each square is 0x10 big.
            x,y = 0x10*xi, 0x10*yi
            -- relative coordinates
            rx, ry = x-sx, y-sy
 
            -- draw a nice red box around the treasure box
            gui.drawbox(rx, ry, rx+0x10, ry+0x10, color)
            gui.text(rx, ry-5, name)
 
            i = i + 5
        end
        table = 0xdfbb00
        i     = memory.readword(table+2*area)
        to    = memory.readword(table+2*(area+1))
        -- loop through the transitions
        while i ~= to do
            -- read from the treasure information array
            xi     = memory.readbyte(table+i)
            yi     = memory.readbyte(table+i+1)
            hmm    = memory.readword(table+i+2)
            xti    = memory.readbyte(table+i+4)
            yti    = memory.readbyte(table+i+5)
            area2 = hmm % 0x200
            -- is it to the same area? If so, color it
            -- light blue. Else make it normal blue.
            if area2 == area then color = "#8080ff"
            else color = "#0000ff" end
 
            -- get the real x,y position, using the fact that
            -- each square is 0x10 big.
            x,y = 0x10*xi, 0x10*yi
            -- relative coordinates
            rx, ry = x-sx, y-sy
            gui.drawbox(rx, ry, rx+0x10, ry+0x10, color)
 
            i = i + 6
        end
        table = 0xedf480
        i     = memory.readword(table+2*area)
        to    = memory.readword(table+2*(area+1))
        -- loop through the wide transitions
        while i ~= to do
            -- read from the treasure information array
            xi     = memory.readbyte(table+i)
            yi     = memory.readbyte(table+i+1)
            dxi    = memory.readbyte(table+i+2)
            dyi    = 0
            hmm    = memory.readword(table+i+3)
            xti    = memory.readbyte(table+i+5)
            yti    = memory.readbyte(table+i+6)
            area2 = hmm % 0x200
            if dxi >= 0x80 then dxi, dyi = 0, dxi % 0x80 end
            -- is it to the same area? If so, color it
            -- light blue. Else make it normal blue.
            if area2 == area then color = "#8080ff"
            elseif area2 == 0x1ff then color = "#b0b0ff"
            else color = "#0000ff" end
 
            -- get the real x,y position, using the fact that
            -- each square is 0x10 big.
            x,y,dx,dy = 0x10*xi, 0x10*yi, 0x10*dxi, 0x10*dyi
            -- relative coordinates
            rx, ry = x-sx, y-sy
            gui.drawbox(rx, ry, rx+dx+0x10, ry+dy+0x10, color)
 
            i = i + 7
        end
        table= 0xc40000
        i    = memory.readword(0xc40000+2*area)
        to   = memory.readword(0xc40000+2*(area+1))
        -- loop through the reactions
        while i ~= to do
            -- read from the treasure information array
            xi     = memory.readbyte(table+i)
            yi     = memory.readbyte(table+i+1)
            react1 = memory.readword(table+i+2)
            react2 = memory.readbyte(table+i+4)
            color = "#ffff00"
 
            -- get the real x,y position, using the fact that
            -- each square is 0x10 big.
            x,y = 0x10*xi, 0x10*yi
            -- relative coordinates
            rx, ry = x-sx, y-sy
            gui.drawbox(rx, ry, rx+0x10, ry+0x10, color)
 
            i = i + 5
        end
    else
        snes9x.speedmode("normal")
    end
    -- encounter counter
    if mode_map() or mode_cave() then
        -- Equipment-derived information is not kept permanently, it is recomputed
        -- at the beginning of every frame, I think. We need to know if the party
        -- has the moogle charm or charm bangle effect.
        -- We will therefore loop through the equipment of all characters.
        field_effects = 0
        status_effects = 0
        char_in_party = 0
        for id = 0, 0xF do
            tmp = memory.readbyte(0x7e1850+id)
            if tmp % 8 == memory.readbyte(0x7e1a6d) then
                -- character is present. If necessary, information about
                -- row and slot is also awailable in tmp.
                char_in_party = char_in_party + 1
                x = id*0x25+0x1F -- start of equipment
                for i = 0, 5 do
                    item = memory.readbyte(0x7e1600+x+i)
                    if item ~= 0xFF then
                        -- item actually equipped
                        field_effects = bor(field_effects,memory.readbyte(0xd85005+item*0x1e))
                        status_effects = bor(status_effects,memory.readbyte(0xd8500a+item*0x1e))
                    end
                end
            end
        end
        -- field_effects is what is later put in 11df
 
        if mode_map() then
            terrain = memory.readbyte(0x7e11f9) % 8
            at_22 = memory.readbyte(0xc0c28f+terrain) -- lave tall, men hva betyr de?
            a = memory.readbyte(0xc0c297+terrain) -- denne arrayen følger rett etter. samme størrelsesorden.
            -- b og c er faktisk x og y-posisjonen på kartet til *forrige encounter*!
            last_x = memory.readbyte(0x7e1f60)
            last_y = memory.readbyte(0x7e1f61)
            zone_x, zone_y = math.floor(last_x/0x20),math.floor(last_y/0x20)
            zone = memory.readbyte(0x7e1f64)*0x40+zone_y*8+zone_x
 
            -- a må inneholde en mapping fra terreng til offsets i følgende array.
            -- merkelig at slikt trengs.
            pack_index = memory.readbyte(0xcf5400+zone*4+a)
            gui.text(textX, textY + 30, "pack index: " .. pack_index)
            -- den høye byten her angir kanskje om det er world of balance eller ruin eller noe annet?
            encounter_rate_index = math.floor(memory.readbyte(0xcf5800+zone) / 4^at_22) % 4
             -- field_effects har info om charm bangle etc. encounter_rate_index info om more/less enc.
            x = (field_effects)%4*8 + encounter_rate_index*2
            -- x er nå indeks inn i encounter rate-tabellen.
            encounter_rate = memory.readword(0xc0c29f+x)
        else
            area = memory.readword(0x7e0082)
            ax,ay = math.floor(area/4), area % 4
            a = (memory.readbyte(0xcf5880+ax) / 4^ay) % 4
            x = ((memory.readbyte(0x7e11df) % 4) * 4 + a) * 2
            encounter_rate = memory.readword(0xc0c2bf+x)
            if bit(memory.readbyte(0x7e0525),7) == 0 then
                encounter_rate = 0
            end
            pack_index = memory.readbyte(0xcf5600+area)
            gui.text(textX, textY + 30, "pack index: " .. pack_index)
        end
        enc1 = memory.readword(0x7e1f6e)
        enc2 = memory.readbyte(0x7e1fa1)
        enc3 = memory.readbyte(0x7e1fa4)
        count = 1
        if encounter_rate ~= 0 then
            for i = 0, 100 do
                enc1 = enc1 + encounter_rate
                if enc1 >= 0x10000 then enc1 = 0xff00 end
                enc2 = (enc2+1) % 0x100
                if enc2 == 0 then enc3 = (enc3 + 0x11) % 0x100 end
                if (memory.readbyte(0xc0fd00+enc2)+enc3) % 0x100 < math.floor(enc1/0x100) then break end
                count = count+1
            end
            gui.text(10,offset,"Encounter in ".. count.." steps.")
            offset = offset+10
 
            -- Veldt?
            if pack_index == 0xFF then
                enc_veldt = (memory.readbyte(0x7e1fa5)+1) % 0x40
                -- find a nonzero byte in the encountered formations bitarray.
                while memory.readbyte(0x7e1ddd+enc_veldt) == 0 do
                    enc_veldt = (enc_veldt+1) % 0x40
                end
                enc5 = memory.readbyte(0x7e1fa3)
                enc4 = (memory.readbyte(0x7e1fa2)+1) % 0x100
                if enc4 == 0 then enc5 = enc5 + 0x17 end
                bit_index = (memory.readbyte(0x7ec0fd00+enc4)+enc5) % 0x8
                bitset = memory.readbyte(0x7e1ddd+enc_veldt)
                -- find a nonzero bit, starting at a random position
                while bit(bitset,bit_index) == 0 do
                    bit_index = (bit_index+1) % 8
                end
                formation = enc_veldt*8+bit_index
            else
                x = pack_index*8
                -- Encounter type. x is the index into the monster pack array
                enc1 = (memory.readbyte(0x7e1fa2)+1) % 0x100
                enc2 = memory.readbyte(0x7e1fa3)
                if enc1 == 0 then enc2 = enc2+0x17 end
                a = (memory.readbyte(0xc0fd00+enc1)+enc2) % 0x100
 
                if a > 0x50 then x = x+2 end
                if a > 0xa0 then x = x+2 end
                if a > 0xf0 then x = x+2 end
                formation = memory.readword(0xcf4800+x)
            end
 
-- At this point, we have all the frame-independent information about the
-- encounter we can get. The following is an attempt to handle the frame-
-- dependent information by predicting at what frame an encounter will occur.
-- This is formation variation (on the floating continent only), attack type
-- (front, back, pincer, side) and preemptiv or not. However, this ended in
-- failure. It works for 3-4 chars in party on the map, mostly, but not for
-- fewer chars, and not when not on the world map. If you want to enable it,
-- comment the following line
            skip_frame_dependent = true
 
            if not skip_frame_dependent then
                -- To find out more about the encounter, we need the frame-
                -- dependent be variable. We must first predict the number
                -- of pixels we are away from an encounter.
                if mode_map() then
                    faceing = memory.readbyte(0x7e00f6)
                    xpos = memory.readword(0x7e00c6)
                    ypos = memory.readword(0x7e00c8)
                else
                -- have to loop through all chars to find out who is the leader?
                -- However, the position we get this way does not move smoothly. Bleh.
                    for id = 0, 0xF do
                        local delta = 0x29*id
                        xpos, ypos = 0,0
                        if bit(memory.readbyte(0x7e0867+delta),7) == 1 then
                            faceing = memory.readbyte(0x7e086f+delta)
                            xpos = memory.readword(0x7e086a+delta)
                            ypos = memory.readword(0x7e086d+delta)
                            break
                        end
                    end
                end
                if faceing == 0 then pixels = ypos % 0x10
                elseif faceing == 1 then
                    pixels = xpos % 0x10
                    if pixels ~= 0 then pixels = 0x10-pixels end
                elseif faceing == 2 then
                    pixels = ypos % 0x10
                    if pixels ~= 0 then pixels = 0x10-pixels end
                else pixels = xpos % 0x10
                end
                -- this is the pixels left in our current step. then add the number
                -- of whole steps
                standing_still = false
                if pixels == 0 then
                    -- this is a whole position. was the last position whole too?
                    if last_position_whole then
                        standing_still = true
                        pixels = 0x10*count
                    else pixels = 0x10*(count-1) end
                    last_position_whole = true
                else
                    pixels = pixels + 0x10*(count-1)
                    last_position_whole = false
                end
                -- sprint shoes?
                if mode_cave() and bit(status_effects,5) then
                    pixels = math.floor(pixels/2)
                end
                -- compensate for the time it takes to start moving
                if standing_still then
                    if mode_map() then pixels = pixels+2
                    else
                        if bit(status_effects,5) == 1 then
                            pixels = pixels + memory.readbyte(0x7e0021e) % 4
                        else pixels = pixels + memory.readbyte(0x7e0021e) % 4 end
                    end
                end
                -- we assume that we are walking with maximum speed of 1 pixel per frame
                -- this will lead to be getting this value at the beginning of battle
                be = 4*((memory.readbyte(0x7e021e)+pixels+0x22) % 0x3c)
                gui.text(10,90,string.format("be: %x vs %x, %x %x", memory.readbyte(0x7e00be), be,pixels,xpos))
 
                if math.floor(formation / 0x8000) == 1 then
                    -- High bit of formation set: randomly add 0..3 to formation
                    be = (be+1) % 0x100
                    a = memory.readbyte(0xc0fd00+be) % 4
                    formation = (formation+a) % 0x8000
                end
            end
            info1 = memory.readbyte(0xcf5900+4*formation)
            info2 = memory.readbyte(0xcf5900+4*formation+1)
            info3 = memory.readbyte(0xcf5900+4*formation+2)
            info4 = memory.readbyte(0xcf5900+4*formation+3)
 
            -- Build monster list
            start = 0xcf6201+15*formation
            present = memory.readbyte(start)
            which = {}
            number_of_enemies = 0
            for i = 1, 6 do
                if present % 2 == 1 then
                    id = memory.readbyte(start+i)
                    if which[id] then which[id] = which[id]+1
                    else which[id] = 1 end
                    number_of_enemies = number_of_enemies + 1
                end
                present = math.floor(present/2)
            end
            -- Display list
            for id, num in pairs(which) do
                gui.text(10, offset, ""..num.." "..getmonstername(id))
                offset = offset + 10
            end
 
            if not skip_frame_dependent then
                -- What kind of encounter?
                variant = math.floor(info1 / 0x10) % 0x10
                -- variant is four bits long, and those bits are front, back, pincer, side; inverted.
                -- from high to low.
                -- let us extract these
                allowed = {}
                allowed_number = 0
                for i = 0, 3 do
                    allowed[i] = 1 - variant % 2
                    allowed_number = allowed_number + allowed[i]
                    variant = math.floor(variant/2)
                end
                if bit(status_effects,1) == 1 then
                    -- back guard, disable back and pincer.
                    -- This will prefer to remove pincer if not
                    -- both can be removed.
                    for i = 1, 2 do if allowed_number > 1 then
                        allowed[i] = 0
                        allowed_number = allowed_number-1
                    end end
                end
                if char_in_party < 3 and allowed_number > 1 then
                    -- not enough characters to do side attack
                    allowed[3] = 0
                    allowed_number = allowed_number - 1
                end
 
                -- Now we pick one of the possibilities
                -- First find the sum of the weights
                local sum = 0
                for i = 0, 3 do if allowed[i] == 1 then
                    sum = sum + memory.readbyte(0xc25279+i)+1
                end end
                -- before this point, be has been incremented by other things
                be = be + 0xa + 2*number_of_enemies + char_in_party
                -- get a random number from 0 to sum-1, using be
                be = (be+1) % 0x100
                rnd = math.floor(memory.readbyte(0xc0fd00+be)*sum/0x100)
                -- now loop through again, and pick the first that is bigger
                -- than the number
                sum = 0
                for i = 0, 3 do if allowed[3-i] == 1 then
                    sum = sum + memory.readbyte(0xc25279+i)+1
                    if sum > rnd then
                        chosen = 3-i
                        break
                    end
                end end
 
                vardesc = { "Front", "Back", "Pincer", "Side" }
 
                -- Finally, describe the result
                if chosen ~= 0 then
                    gui.text(10, offset, string.format("%s attack",vardesc[chosen+1]))
                    offset = offset+10
                end
            end
        end
    end
    HandleKeys()
 
    if autoText then
        gui.text(textX,textY + 20,"(T) Auto Text : On")          
    else
        gui.text(textX,textY + 20,"(T) Auto Text : Off")          
    end
 
    if autoText and (snes9x.framecount() % 6  == 0 or ((snes9x.framecount() - 1) % 6 == 0)) then
        curPad = joypad.get()
        curPad.A = true
        joypad.set(curPad)
    end
 
    if (memory.readbyte(0x7e1dd2) % 2 == 0) and (memory.readword(0x7e1501) == 0xa509) and (memory.readbyte(0x7e1503) == 0xEE) then 
        x1 = memory.readword(0x7e0b00)
        y1 = memory.readword(0x7e0b02)
        x2 = memory.readword(0x7e0b04)
        y2 = memory.readword(0x7e0b06)
        
        gui.line(x1 + 176, 156, x1 + 176, 219, "#008080")
        gui.line(176, y1 + 156, 239, y1 + 156, "#008080")
        gui.line(x2 + 176, 156, x2 + 176, 219, "#008080")
        gui.line(176, y2 + 156, 239, y2 + 156, "#008080")
        gui.pixel(x1 + 176, y1 + 156, "#00ffff")
        gui.pixel(x2 + 176, y2 + 156, "#00ffff")
        
    end
 
    --for moviemaking
    --cMode1, cMode2 = memory.readword(0x7e1501), memory.readbyte(0x7e1503)
    --if lMode1 ~= cMode1 and lMode2 ~= cMode2 then
    --  snes9x.pause()
    --end
    --lMode1 = cMode1
    --lMode2 = cMode2
 
    CalculateTime()
    OutputTime()
    
    
    snes9x.frameadvance()
end

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎