Dessyreqt

FF6 info script (personal modifications)

Apr 22nd, 2013
603
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- Features:
  2. -- 1. Encounter prediction: predicts steps until encounter, and what will be encountered.
  3. --    Does not predict front/back/pincer/side/preemptive variants, not will it work properly
  4. --    on the floating continent. (there is tentative support for this (which actually makes up
  5. --    a good part of the code), but it is buggy, and only works well when one is on the world map,
  6. --    and has 3 or 4 chars in party, so it is disabled by default)
  7. -- 2. Outline treasure chests and show their contents and status (green = untaken, red = taken)
  8. -- 3. Outline squares that trigger events. Blue = transition to new area, light blue = transition
  9. --    to same area, very light blue = transition to map, yellow = unclassified event.
  10. -- 4. In battle, hp and mp bars are displayed over the enemies, as well as their battle gauges.
  11. --    Their level is also displayed. On gau's turns, a "?" is displayed by any monster whose
  12. --    rage is not known. Additionally, the enemies' resistances etc. are displayed in a compact
  13. --    but hopefully readable manner, as a set of 4 3x3 sqares of pixels, where each has the
  14. --    following format:
  15. --      fil   ; fire (red) ice (blue) lightning (yellow)
  16. --      pwp   ; poison (green) wind (gray) holy (white)
  17. --      ew    ; earth (brown) water (blue)
  18. --    The order of the sqares is, from left to right, absorb, nullify, resist, weak.
  19. -- 5. Extra information is displayed for the currently selected monster.
  20. --    normally, only its drops and hp/mp are displayed, but if locke is selecting the
  21. --    monster with the steal command, its steals are also listed. If relm is selecting
  22. --    a monster with control or sketch, that information will also be indicated.
  23. -- 6. While in the rage menu, information about what the selected rage does is
  24. --    displayed. Only the attack part of the rage is displayed so far, since I haven't thought
  25. --    of a compact way of displaying all the status information associated with a rage.
  26.  
  27. addHours = 0
  28. addMinutes = 4
  29. addSeconds = 9
  30. addFrames = 21
  31. textX = 160
  32. textY = 120
  33.  
  34. lMode1 = memory.readword(0x7e1501)
  35. lMode2 = memory.readbyte(0x7e1503)
  36. lMode3 = memory.readbyte
  37. cMode1 = memory.readword(0x7e1501)
  38. cMode2 = memory.readbyte(0x7e1503)
  39. autoText = false
  40.  
  41. drawpixel = function(x,y,color)
  42.     if x < 0 or y < 0 then return end
  43.     if x >= 0x100 or y >= 0xE0 then return end
  44.     gui.drawpixel(x,y,color)
  45. end
  46. -- the following section handles out of bounds checking.
  47. -- This will hopefully not be necessary in later versions of snes9x-lua
  48. -- The bounds checking for lines is slightly more complicated, so I did
  49. -- not bother implementing it properly.
  50. min = function(a,b) if a < b then return a else return b end end
  51. max = function(a,b) if a < b then return b else return a end end
  52. order = function(a,b) if a > b then return b, a else return a,b end end
  53. olddrawbox = gui.drawbox
  54. gui.drawbox = function(x1,y1,x2,y2,color)
  55.     x1,x2 = order(x1,x2)
  56.     y1,y2 = order(y1,y2)
  57.     x1 = min(max(0,x1),255)
  58.     y1 = min(max(0,y1),238)
  59.     x2 = min(max(0,x2),255)
  60.     y2 = min(max(0,y2),238)
  61.     olddrawbox(x1,y1,x2,y2,nil,color)
  62. end
  63. oldtext = gui.text
  64. gui.text = function(x,y,text)
  65.     if x >= 0 and x < 256 and y >= 0 and y < 239 then
  66.         oldtext(x,y,text)
  67.     end
  68. end
  69. horline = function(x1,y,x2,color)
  70.     x1,x2 = order(x1,x2)
  71.     x1 = min(max(0,x1),255)
  72.     x2 = min(max(0,x2),255)
  73.     if y >= 0 and y < 239 then
  74.         gui.drawline(x1,y,x2,y,color)
  75.     end
  76. end
  77. vertline = function(x,y1,y2,color)
  78.     y1,y2 = order(y1,y2)
  79.     y1 = min(max(0,y1),238)
  80.     y2 = min(max(0,y2),238)
  81.     if x >= 0 and x < 256 then
  82.         gui.drawline(x,y1,x,y2,color)
  83.     end
  84. end
  85.  
  86.  
  87. startgauge = function(x,y,w)
  88.     gx, gy, gw = x, y, w
  89. end
  90. drawgauge = function(c,m,col)
  91.     if m == 0 then m = 1 end
  92.     local g = c*gw/m
  93.     horline(gx,gy,gx+g,col)
  94.     horline(gx+g,gy,gx+gw,"#000000")
  95.     gy = gy-1
  96. end
  97.  
  98. tochar = function(i)
  99.     if i < 0x80 then return ""
  100.     elseif i < 0x9a then return string.char(string.byte("A")+i-0x80)
  101.     elseif i < 0xb4 then return string.char(string.byte("a")+i-0x9a)
  102.     elseif i < 0xbe then return string.char(string.byte("0")+i-0xb4)
  103.     elseif i == 0xfe then return " "
  104.     else return "" end
  105. end
  106.  
  107. readsnesstring = function(from,maximum)
  108.     local res = ""
  109.     local tmp = memory.readbyte(from)
  110.     local i = 0
  111.     while tmp ~= 0xFF do
  112.         if i == maximum then break end
  113.         res = res .. tochar(tmp)
  114.         from = from+1
  115.         tmp = memory.readbyte(from)
  116.         i = i+1
  117.     end
  118.     return res
  119. end
  120.  
  121. getitemname = function(id)
  122.     return readsnesstring(0xd2b300+0xd*id+1,12)
  123. end
  124. getmonstername = function(id)
  125.     return readsnesstring(0xcfc050+0xa*id,10)
  126. end
  127. getattackname = function(id)
  128.     local x = 0
  129.     local maxlen = 10
  130.     if id < 0x36 then
  131.         x = id*7
  132.         maxlen = 7
  133.     elseif id < 0x51 then
  134.         x = id*8-0x36
  135.         maxlen = 8
  136.     elseif id < 0x56 then x = id*0xA-0xd8
  137.     else x = id*0xA-0xd8 -- vet ikke hvorfor indeksen blir d8 her.
  138.     --else id < 0x5b then x = id*0xA-0xc4
  139.     end
  140.     return readsnesstring(0xe6f567+x,maxlen)
  141. end
  142.  
  143.  
  144. -- This is probably not the best way of determining the game mode, but it works.
  145. mode_battle = function()
  146.     return memory.readword(0x7e1501) == 0x0ba7 and memory.readbyte(0x7e1503) == 0xC1
  147. end
  148. mode_cave = function()
  149.     return memory.readword(0x7e1501) == 0x0182 and memory.readbyte(0x7e1503) == 0xC0
  150. end
  151. mode_map  = function()
  152.     return memory.readword(0x7e1501) == 0xa728 and memory.readbyte(0x7e1503) == 0xEE
  153. end
  154. mode_menu = function()
  155.     return memory.readword(0x7e1501) == 0x1387 and memory.readbyte(0x7e1503) == 0xC3
  156. end
  157. function HandleKeys()
  158.     keys = input.get()
  159.  
  160.     if press('T') then
  161.         autoText = not autoText
  162.     end
  163.    
  164.     last_keys = keys                                              
  165. end
  166. function press(button)
  167.     if keys[button] and not last_keys[button] then
  168.         return true
  169.     end
  170.     return false
  171. end
  172.  
  173. hours = 0
  174. minutes = 0
  175. seconds = 0
  176. milliseconds = 0
  177.  
  178. function CalculateTime()
  179.     frames = snes9x.framecount()
  180.     frames = frames + addHours * 216000 + addMinutes * 3600 + addSeconds * 60 + addFrames
  181.     hours = math.floor(frames / 216000)
  182.     minutes = math.floor((frames - hours * 216000) / 3600)
  183.     seconds = math.floor((frames - hours * 216000 - minutes * 3600) / 60)
  184.     milliseconds = math.floor((frames - hours * 216000 - minutes * 3600 - seconds * 60) * 100 / 60)
  185. end
  186.  
  187. function OutputTime()
  188.     gui.text(textX, textY, "Time: " .. hours .. ":" .. string.format("%02d",minutes) .. ":" .. string.format("%02d",seconds) .. "." .. string.format("%02d",milliseconds))
  189.     gui.text(textX, textY + 10, "Offset: " .. addHours .. ":" .. string.format("%02d",addMinutes) .. ":" .. string.format("%02d",addSeconds) .. "." .. string.format("%02d",math.floor(addFrames * 100 / 60)))
  190. end
  191.  
  192.  
  193. -- prints a compact representation of elemental properties.
  194. -- There are 8 elements. Each is assigned a color, and a place
  195. -- in a 3x3 matrix of pixels.
  196. -- fil   ; fire (red) ice (blue) lightning (yellow)
  197. -- pwp   ; poison (green) wind (gray) holy (white)
  198. -- ew    ; earth (brown) water (blue)
  199. -- Colors need not be uniqe, as the position fixes things.
  200. -- This is then surrounded by black border.
  201. print_element = function(x,y,elem)
  202.     -- first draw the border
  203.     horline(x, y, x+4, "#404040")
  204.     vertline(x+4, y, y+4, "#404040")
  205.     vertline(x, y, y+4, "#404040")
  206.     horline(x, y+4, x+4, "#404040")
  207.     -- now draw the elements
  208.     local x,y=x+1,y+1
  209.     putpix = function(x,y,b,c)
  210.         if b == 1 then drawpixel(x,y,c) else drawpixel(x,y,"#000000") end
  211.     end
  212.     cols = {
  213.         "#ff0000","#0000ff","#ffff00",
  214.         "#00ff00","#808080","#ffffff",
  215.         "#a08000","#0000ff","#000000"
  216.     }
  217.     for i = 1, 9 do
  218.         dx, dy = (i-1)%3, math.floor((i-1)/3)
  219.         putpix(x+dx,y+dy,elem % 2,cols[i])
  220.         elem = math.floor(elem/2)
  221.     end
  222. end
  223.  
  224. get_special = function(id)
  225.     -- Information about the special attack
  226.     -- This is used by rage, sketch, control.
  227.     local special = memory.readbyte(0xcf001f+0x20*id)
  228.     local specialn = readsnesstring(0xcfd0d0+id*10,10)
  229.     local no_damage,no_dodge = bit(special, 6),bit(special,7)
  230.     special = special % 0x40
  231.     desc = "???"
  232.     if special == 0x30 then desc = "absorb hp"
  233.     elseif special == 0x31 then desc = "absorb mp"
  234.     elseif special >= 0x32 then desc = "remove reflect"
  235.     elseif special >= 0x20 then desc = string.format("+%d%%",(special-0x1f)*50)
  236.     else
  237.         local descs = { "Dark","Zombie","Poison","MagiTek","Clear","Imp","Petrify",
  238.             "Death", "Condemned", "Near Fatal", "Image", "Mute", "Berserk",
  239.             "Muddle", "Seizure", "Sleep", "Dance", "Regen", "Slow", "Haste",
  240.             "Stop", "Shell", "Safe", "Reflect", "Rage", "Freeze", "Life 3",
  241.             "Morph", "Chant!", "Disappear!", "Dog block", "Float" }
  242.         desc = descs[special+1]
  243.     end
  244.     specialn = specialn.." ("..desc..")"
  245.     return specialn, no_damage, no_dodge
  246. end
  247.  
  248.  
  249. print_status = function(status)
  250.     -- Må finne ut hva bitsene i hver status byte betyr.
  251. end
  252.  
  253. -- bit operations, since lua is silly enough to miss these
  254. bit = function(n,i) return math.floor(n/2^i) % 2 end
  255. bor = function(a,b)
  256.     local c = 0
  257.     local pot = 1
  258.     while a ~= 0 or b ~= 0 do
  259.         if a % 2 == 1 or b % 2 == 1 then c = c+pot end
  260.         a = math.floor(a/2)
  261.         b = math.floor(b/2)
  262.         pot = pot*2
  263.     end
  264.     return c
  265. end
  266.  
  267. -- to get the pixel distance from an encounter, we
  268. -- need to fix an occational off-by-1 error for
  269. -- count. this happens on the first frame when we reach
  270. -- a whole square. we thus need to keep track of whether
  271. -- the last position was whole or not
  272. last_position_whole = true
  273.  
  274. while true do
  275.     -- Are we in battle?
  276.     offset = 100
  277.     if mode_battle() then
  278.         --snes9x.speedmode("maximum")
  279.        
  280.         -- memory.writebyte(0x7e3bfc, 0)
  281.         -- memory.writebyte(0x7e3bfd, 0)
  282.         -- memory.writebyte(0x7e3bfe, 0)
  283.         -- memory.writebyte(0x7e3bff, 0)
  284.         -- memory.writebyte(0x7e3c00, 0)
  285.         -- memory.writebyte(0x7e3c01, 0)
  286.         -- memory.writebyte(0x7e3c02, 0)
  287.         -- memory.writebyte(0x7e3c03, 0)
  288.         -- memory.writebyte(0x7e3c04, 0)
  289.         -- memory.writebyte(0x7e3c05, 0)
  290.         -- memory.writebyte(0x7e3c06, 0)
  291.         -- memory.writebyte(0x7e3c07, 0)
  292.        
  293.         sel_side, sel_i = memory.readbyte(0x7e7ace), memory.readbyte(0x7e7acf)
  294.         sel_enemy, sel_party = memory.readbyte(0x7e7b7e),memory.readbyte(0x7e7b7d)
  295.         sel_multi = memory.readbyte(0x7e7b7f)
  296.         -- loop through present monsters
  297.         for i = 0, 5 do
  298.             -- a few shortcuts
  299.             j, k = 2*i, 2*(4+i)
  300.             state = memory.readword(0x7e3aa0+k)
  301.             if state ~= 0 and bit(state,15) ~= 1 then
  302.             -- get coordinates (we should know the size of the monster too, but we don't)
  303.             x = memory.readbyte(0x7e80c2+1+j)
  304.             -- this size is really the x-offset of the pointing hand relative to the start
  305.             -- of the sprite. For a normal attack, this works fine, but for monsters on the
  306.             -- right hand side of the screen, this offset is 0, as the hand is on their left
  307.             -- side. To do things properly, I should get this in a more direct fashion, but
  308.             -- I can't be bothered
  309.             xsize = memory.readbyte(0x7e807a+1+j)
  310.             if xsize == 0 then xsize = 0x20 end
  311.             y = memory.readbyte(0x7e80ce+1+j)
  312.             -- other interesting information
  313.             id   = memory.readword(0x7e3388+j)
  314.             xp   = memory.readword(0x7e3d8c+j)
  315.             gold = memory.readword(0x7e3da0+j)
  316.             hp   = memory.readword(0x7e3bf4+k)
  317.             mp   = memory.readword(0x7e3c08+k)
  318.             mhp  = memory.readword(0x7e3c1c+k)
  319.             mmp  = memory.readword(0x7e3c30+k)
  320.             level= memory.readbyte(0x7e3b18+k)
  321.             speed= memory.readbyte(0x7e3b19+k)
  322.             gauge= memory.readword(0x7e3218+k)
  323.             -- elements
  324.             absorb  =  memory.readbyte(0x7e3bcc+k)
  325.             nullify =  memory.readbyte(0x7e3bcd+k)
  326.             resist  =  memory.readbyte(0x7e3be1+k)
  327.             weak    =  memory.readbyte(0x7e3be0+k)
  328.             stealn  =  memory.readbyte(0x7e3311+j)
  329.             stealr  =  memory.readbyte(0x7e3310+j)
  330.             dropn   =  memory.readbyte(0xcf3000+4*id+3)
  331.             dropr   =  memory.readbyte(0xcf3000+4*id+2)
  332.  
  333.             name = getmonstername(id)
  334.  
  335.             -- Print the gauges
  336.             startgauge(x,y,xsize)
  337.             drawgauge(mp, mmp, "#0000ff")
  338.             drawgauge(hp, mhp, "#00ff00")
  339.             drawgauge(gauge, 0x10000, "#ff0000")
  340.             by = gy
  341.             gui.text(x-16, by-8, string.format("%2d",level))
  342.             print_element(x, by-6, absorb)
  343.             print_element(x+4, by-6, nullify)
  344.             print_element(x+8, by-6, resist)
  345.             print_element(x+12, by-6, weak)
  346.             gui.text(x+18, by-8, ""..hp)
  347.  
  348.             active_slot = memory.readbyte(0x7e0201)
  349.             active_player = memory.readbyte(0x7e3ed8+active_slot*2)
  350.             menu_pos = memory.readbyte(0x7e890f+active_slot)
  351.             relm_info = active_player == 8 and menu_pos == 1
  352.             locke_info = active_player == 1 and menu_pos == 1
  353.             gau_info = active_player == 0xb
  354.  
  355.             if gau_info then
  356.                 local id_byte, id_bit = math.floor(id/8), id % 8
  357.                 if bit(memory.readbyte(0x7e1d2c+id_byte),id_bit) == 0 then
  358.                     -- monster not known!
  359.                     gui.text(x-8,y,"?")
  360.                 end
  361.             end
  362.            
  363.             -- More detailed information for the monster we point to.
  364.             -- This will depend on how it is being pointed to
  365.             if (sel_side == 0 or sel_side == 2) and sel_i == i and
  366.                 sel_multi == 0 and sel_enemy ~= 0 then
  367.                 --gui.text(10,offset,"Level "..level.." "..name)
  368.                 --offset = offset+10
  369.                 gui.text(10,offset,string.format("HP:%d/%d, MP:%d/%d",hp,mhp,mp,mmp))
  370.                 offset = offset+10
  371.                 --gui.text(10,offset,string.format("XP:%d, gold:%d",xp,gold))
  372.                 --offset = offset+10
  373.                 if locke_info then
  374.                     gui.text(10,offset,string.format("Steal %s/%s", getitemname(stealn), getitemname(stealr)))
  375.                     offset = offset+10
  376.                 end
  377.                 gui.text(10,offset,string.format("Drops %s/%s", getitemname(dropn), getitemname(dropr)))
  378.                 offset = offset+10
  379.                 -- Special attack description
  380.                 specialn = get_special(id)
  381.                 -- Sketch
  382.                 sketch1 = memory.readbyte(0xcf4300+2*id)
  383.                 sketch2 = memory.readbyte(0xcf4300+2*id+1)
  384.                 -- control
  385.                 control, controln = {}, {}
  386.                 for ctrl_i = 0, 3 do
  387.                     control[ctrl_i] = memory.readbyte(0xcf3d00+4*id+ctrl_i)
  388.                 end
  389.                 if sketch1 == 0xEF then sketch1n = specialn else sketch1n = getattackname(sketch1) end
  390.                 if sketch2 == 0xEF then sketch2n = specialn else sketch2n = getattackname(sketch2) end
  391.                 for ctrl_i = 0, 3 do
  392.                     local ctrl,foo = control[ctrl_i]
  393.                     if ctrl == 0xEF then foo = specialn
  394.                     elseif ctrl == 0xFF then foo = "Nothing"
  395.                     else foo = getattackname(ctrl) end
  396.                     controln[ctrl_i] = foo
  397.                 end
  398.                 if relm_info then
  399.                     gui.text(10,offset,string.format("Sketch %s/%s", sketch2n, sketch1n))
  400.                     offset = offset+10
  401.                     gui.text(10,offset,string.format("Control %s/%s",controln[0],controln[1]))
  402.                     offset = offset+10
  403.                     gui.text(10,offset,string.format("        %s/%s",controln[2],controln[3]))
  404.                     offset = offset+10
  405.                 end
  406.             end
  407.         end end
  408.         -- Rage information when in the rage menu
  409.         if memory.readbyte(0x7e7bd4) == 0x24 then
  410.             x = memory.readbyte(0x7e892f)
  411.             y = memory.readbyte(0x7e8933)
  412.             scroll = memory.readbyte(0x7e892b)
  413.             i = 2*(y+scroll)+x
  414.             id = memory.readbyte(0x7e257e + i)
  415.             if id ~= 0xFF then
  416.                 -- What rages does this monster have?
  417.                 rage1 = memory.readbyte(0xcf4600+2*id)
  418.                 rage2 = memory.readbyte(0xcf4600+2*id+1)
  419.                 -- Special attack description
  420.                 specialn = get_special(id)
  421.                 if rage1 == 0xEF then rage1n = specialn else rage1n = getattackname(rage1) end
  422.                 if rage2 == 0xEF then rage2n = specialn else rage2n = getattackname(rage2) end
  423.                 gui.text(10,offset,string.format("%s/%s", rage1n, rage2n))
  424.                 offset = offset+10
  425.             end
  426.         end
  427.     elseif mode_cave() then
  428.         snes9x.speedmode("normal")
  429.         -- get the screen position
  430.         sx     = memory.readword(0x7e8297)
  431.         sy     = memory.readword(0x7e8299)
  432.         if sx >= 0x8000 then sx = sx-0x10000 end
  433.         if sy >= 0x8000 then sy = sy-0x10000 end
  434.         -- prepare to loop through treasures
  435.         area   = memory.readword(0x7e0082)
  436.         table  = 0xed8634
  437.         i      = memory.readword(0xed82f4+2*area)
  438.         to     = memory.readword(0xed82f4+2*(area+1))
  439.         -- loop through the treasures
  440.         while i ~= to do
  441.             -- read from the treasure information array
  442.             xi     = memory.readbyte(table+i)
  443.             yi     = memory.readbyte(table+i+1)
  444.             flagi  = memory.readword(table+i+2)
  445.             item   = memory.readbyte(table+i+4)
  446.             name   = getitemname(item)
  447.             -- Has the box been taken? To find out, we need to
  448.             -- do some bit manipulation.
  449.             byte_index = math.floor(flagi/8)
  450.             bit_index = flagi % 8
  451.             if byte_index >= 0x40 then
  452.                 byte_index = byte_index - 0x40*math.floor(byte_index/0x40)
  453.             end
  454.             flag = memory.readbyte(0x7e1e40+byte_index)
  455.             flag = flag % (2^(bit_index+1))
  456.             flag = math.floor(flag/ 2^bit_index)
  457.             -- flag is now 0 if not taken and 1 if taken
  458.             if flag == 0 then color = "#00ff00" else color = "#ff0000" end
  459.  
  460.             -- get the real x,y position, using the fact that
  461.             -- each square is 0x10 big.
  462.             x,y = 0x10*xi, 0x10*yi
  463.             -- relative coordinates
  464.             rx, ry = x-sx, y-sy
  465.  
  466.             -- draw a nice red box around the treasure box
  467.             gui.drawbox(rx, ry, rx+0x10, ry+0x10, color)
  468.             gui.text(rx, ry-5, name)
  469.  
  470.             i = i + 5
  471.         end
  472.         table = 0xdfbb00
  473.         i     = memory.readword(table+2*area)
  474.         to    = memory.readword(table+2*(area+1))
  475.         -- loop through the transitions
  476.         while i ~= to do
  477.             -- read from the treasure information array
  478.             xi     = memory.readbyte(table+i)
  479.             yi     = memory.readbyte(table+i+1)
  480.             hmm    = memory.readword(table+i+2)
  481.             xti    = memory.readbyte(table+i+4)
  482.             yti    = memory.readbyte(table+i+5)
  483.             area2 = hmm % 0x200
  484.             -- is it to the same area? If so, color it
  485.             -- light blue. Else make it normal blue.
  486.             if area2 == area then color = "#8080ff"
  487.             else color = "#0000ff" end
  488.  
  489.             -- get the real x,y position, using the fact that
  490.             -- each square is 0x10 big.
  491.             x,y = 0x10*xi, 0x10*yi
  492.             -- relative coordinates
  493.             rx, ry = x-sx, y-sy
  494.             gui.drawbox(rx, ry, rx+0x10, ry+0x10, color)
  495.  
  496.             i = i + 6
  497.         end
  498.         table = 0xedf480
  499.         i     = memory.readword(table+2*area)
  500.         to    = memory.readword(table+2*(area+1))
  501.         -- loop through the wide transitions
  502.         while i ~= to do
  503.             -- read from the treasure information array
  504.             xi     = memory.readbyte(table+i)
  505.             yi     = memory.readbyte(table+i+1)
  506.             dxi    = memory.readbyte(table+i+2)
  507.             dyi    = 0
  508.             hmm    = memory.readword(table+i+3)
  509.             xti    = memory.readbyte(table+i+5)
  510.             yti    = memory.readbyte(table+i+6)
  511.             area2 = hmm % 0x200
  512.             if dxi >= 0x80 then dxi, dyi = 0, dxi % 0x80 end
  513.             -- is it to the same area? If so, color it
  514.             -- light blue. Else make it normal blue.
  515.             if area2 == area then color = "#8080ff"
  516.             elseif area2 == 0x1ff then color = "#b0b0ff"
  517.             else color = "#0000ff" end
  518.  
  519.             -- get the real x,y position, using the fact that
  520.             -- each square is 0x10 big.
  521.             x,y,dx,dy = 0x10*xi, 0x10*yi, 0x10*dxi, 0x10*dyi
  522.             -- relative coordinates
  523.             rx, ry = x-sx, y-sy
  524.             gui.drawbox(rx, ry, rx+dx+0x10, ry+dy+0x10, color)
  525.  
  526.             i = i + 7
  527.         end
  528.         table= 0xc40000
  529.         i    = memory.readword(0xc40000+2*area)
  530.         to   = memory.readword(0xc40000+2*(area+1))
  531.         -- loop through the reactions
  532.         while i ~= to do
  533.             -- read from the treasure information array
  534.             xi     = memory.readbyte(table+i)
  535.             yi     = memory.readbyte(table+i+1)
  536.             react1 = memory.readword(table+i+2)
  537.             react2 = memory.readbyte(table+i+4)
  538.             color = "#ffff00"
  539.  
  540.             -- get the real x,y position, using the fact that
  541.             -- each square is 0x10 big.
  542.             x,y = 0x10*xi, 0x10*yi
  543.             -- relative coordinates
  544.             rx, ry = x-sx, y-sy
  545.             gui.drawbox(rx, ry, rx+0x10, ry+0x10, color)
  546.  
  547.             i = i + 5
  548.         end
  549.     else
  550.         snes9x.speedmode("normal")
  551.     end
  552.     -- encounter counter
  553.     if mode_map() or mode_cave() then
  554.         -- Equipment-derived information is not kept permanently, it is recomputed
  555.         -- at the beginning of every frame, I think. We need to know if the party
  556.         -- has the moogle charm or charm bangle effect.
  557.         -- We will therefore loop through the equipment of all characters.
  558.         field_effects = 0
  559.         status_effects = 0
  560.         char_in_party = 0
  561.         for id = 0, 0xF do
  562.             tmp = memory.readbyte(0x7e1850+id)
  563.             if tmp % 8 == memory.readbyte(0x7e1a6d) then
  564.                 -- character is present. If necessary, information about
  565.                 -- row and slot is also awailable in tmp.
  566.                 char_in_party = char_in_party + 1
  567.                 x = id*0x25+0x1F -- start of equipment
  568.                 for i = 0, 5 do
  569.                     item = memory.readbyte(0x7e1600+x+i)
  570.                     if item ~= 0xFF then
  571.                         -- item actually equipped
  572.                         field_effects = bor(field_effects,memory.readbyte(0xd85005+item*0x1e))
  573.                         status_effects = bor(status_effects,memory.readbyte(0xd8500a+item*0x1e))
  574.                     end
  575.                 end
  576.             end
  577.         end
  578.         -- field_effects is what is later put in 11df
  579.  
  580.         if mode_map() then
  581.             terrain = memory.readbyte(0x7e11f9) % 8
  582.             at_22 = memory.readbyte(0xc0c28f+terrain) -- lave tall, men hva betyr de?
  583.             a = memory.readbyte(0xc0c297+terrain) -- denne arrayen følger rett etter. samme størrelsesorden.
  584.             -- b og c er faktisk x og y-posisjonen på kartet til *forrige encounter*!
  585.             last_x = memory.readbyte(0x7e1f60)
  586.             last_y = memory.readbyte(0x7e1f61)
  587.             zone_x, zone_y = math.floor(last_x/0x20),math.floor(last_y/0x20)
  588.             zone = memory.readbyte(0x7e1f64)*0x40+zone_y*8+zone_x
  589.  
  590.             -- a må inneholde en mapping fra terreng til offsets i følgende array.
  591.             -- merkelig at slikt trengs.
  592.             pack_index = memory.readbyte(0xcf5400+zone*4+a)
  593.             gui.text(textX, textY + 30, "pack index: " .. pack_index)
  594.             -- den høye byten her angir kanskje om det er world of balance eller ruin eller noe annet?
  595.             encounter_rate_index = math.floor(memory.readbyte(0xcf5800+zone) / 4^at_22) % 4
  596.              -- field_effects har info om charm bangle etc. encounter_rate_index info om more/less enc.
  597.             x = (field_effects)%4*8 + encounter_rate_index*2
  598.             -- x er nå indeks inn i encounter rate-tabellen.
  599.             encounter_rate = memory.readword(0xc0c29f+x)
  600.         else
  601.             area = memory.readword(0x7e0082)
  602.             ax,ay = math.floor(area/4), area % 4
  603.             a = (memory.readbyte(0xcf5880+ax) / 4^ay) % 4
  604.             x = ((memory.readbyte(0x7e11df) % 4) * 4 + a) * 2
  605.             encounter_rate = memory.readword(0xc0c2bf+x)
  606.             if bit(memory.readbyte(0x7e0525),7) == 0 then
  607.                 encounter_rate = 0
  608.             end
  609.             pack_index = memory.readbyte(0xcf5600+area)
  610.             gui.text(textX, textY + 30, "pack index: " .. pack_index)
  611.         end
  612.         enc1 = memory.readword(0x7e1f6e)
  613.         enc2 = memory.readbyte(0x7e1fa1)
  614.         enc3 = memory.readbyte(0x7e1fa4)
  615.         count = 1
  616.         if encounter_rate ~= 0 then
  617.             for i = 0, 100 do
  618.                 enc1 = enc1 + encounter_rate
  619.                 if enc1 >= 0x10000 then enc1 = 0xff00 end
  620.                 enc2 = (enc2+1) % 0x100
  621.                 if enc2 == 0 then enc3 = (enc3 + 0x11) % 0x100 end
  622.                 if (memory.readbyte(0xc0fd00+enc2)+enc3) % 0x100 < math.floor(enc1/0x100) then break end
  623.                 count = count+1
  624.             end
  625.             gui.text(10,offset,"Encounter in ".. count.." steps.")
  626.             offset = offset+10
  627.  
  628.             -- Veldt?
  629.             if pack_index == 0xFF then
  630.                 enc_veldt = (memory.readbyte(0x7e1fa5)+1) % 0x40
  631.                 -- find a nonzero byte in the encountered formations bitarray.
  632.                 while memory.readbyte(0x7e1ddd+enc_veldt) == 0 do
  633.                     enc_veldt = (enc_veldt+1) % 0x40
  634.                 end
  635.                 enc5 = memory.readbyte(0x7e1fa3)
  636.                 enc4 = (memory.readbyte(0x7e1fa2)+1) % 0x100
  637.                 if enc4 == 0 then enc5 = enc5 + 0x17 end
  638.                 bit_index = (memory.readbyte(0x7ec0fd00+enc4)+enc5) % 0x8
  639.                 bitset = memory.readbyte(0x7e1ddd+enc_veldt)
  640.                 -- find a nonzero bit, starting at a random position
  641.                 while bit(bitset,bit_index) == 0 do
  642.                     bit_index = (bit_index+1) % 8
  643.                 end
  644.                 formation = enc_veldt*8+bit_index
  645.             else
  646.                 x = pack_index*8
  647.                 -- Encounter type. x is the index into the monster pack array
  648.                 enc1 = (memory.readbyte(0x7e1fa2)+1) % 0x100
  649.                 enc2 = memory.readbyte(0x7e1fa3)
  650.                 if enc1 == 0 then enc2 = enc2+0x17 end
  651.                 a = (memory.readbyte(0xc0fd00+enc1)+enc2) % 0x100
  652.  
  653.                 if a > 0x50 then x = x+2 end
  654.                 if a > 0xa0 then x = x+2 end
  655.                 if a > 0xf0 then x = x+2 end
  656.                 formation = memory.readword(0xcf4800+x)
  657.             end
  658.  
  659. -- At this point, we have all the frame-independent information about the
  660. -- encounter we can get. The following is an attempt to handle the frame-
  661. -- dependent information by predicting at what frame an encounter will occur.
  662. -- This is formation variation (on the floating continent only), attack type
  663. -- (front, back, pincer, side) and preemptiv or not. However, this ended in
  664. -- failure. It works for 3-4 chars in party on the map, mostly, but not for
  665. -- fewer chars, and not when not on the world map. If you want to enable it,
  666. -- comment the following line
  667.             skip_frame_dependent = true
  668.  
  669.             if not skip_frame_dependent then
  670.                 -- To find out more about the encounter, we need the frame-
  671.                 -- dependent be variable. We must first predict the number
  672.                 -- of pixels we are away from an encounter.
  673.                 if mode_map() then
  674.                     faceing = memory.readbyte(0x7e00f6)
  675.                     xpos = memory.readword(0x7e00c6)
  676.                     ypos = memory.readword(0x7e00c8)
  677.                 else
  678.                 -- have to loop through all chars to find out who is the leader?
  679.                 -- However, the position we get this way does not move smoothly. Bleh.
  680.                     for id = 0, 0xF do
  681.                         local delta = 0x29*id
  682.                         xpos, ypos = 0,0
  683.                         if bit(memory.readbyte(0x7e0867+delta),7) == 1 then
  684.                             faceing = memory.readbyte(0x7e086f+delta)
  685.                             xpos = memory.readword(0x7e086a+delta)
  686.                             ypos = memory.readword(0x7e086d+delta)
  687.                             break
  688.                         end
  689.                     end
  690.                 end
  691.                 if faceing == 0 then pixels = ypos % 0x10
  692.                 elseif faceing == 1 then
  693.                     pixels = xpos % 0x10
  694.                     if pixels ~= 0 then pixels = 0x10-pixels end
  695.                 elseif faceing == 2 then
  696.                     pixels = ypos % 0x10
  697.                     if pixels ~= 0 then pixels = 0x10-pixels end
  698.                 else pixels = xpos % 0x10
  699.                 end
  700.                 -- this is the pixels left in our current step. then add the number
  701.                 -- of whole steps
  702.                 standing_still = false
  703.                 if pixels == 0 then
  704.                     -- this is a whole position. was the last position whole too?
  705.                     if last_position_whole then
  706.                         standing_still = true
  707.                         pixels = 0x10*count
  708.                     else pixels = 0x10*(count-1) end
  709.                     last_position_whole = true
  710.                 else
  711.                     pixels = pixels + 0x10*(count-1)
  712.                     last_position_whole = false
  713.                 end
  714.                 -- sprint shoes?
  715.                 if mode_cave() and bit(status_effects,5) then
  716.                     pixels = math.floor(pixels/2)
  717.                 end
  718.                 -- compensate for the time it takes to start moving
  719.                 if standing_still then
  720.                     if mode_map() then pixels = pixels+2
  721.                     else
  722.                         if bit(status_effects,5) == 1 then
  723.                             pixels = pixels + memory.readbyte(0x7e0021e) % 4
  724.                         else pixels = pixels + memory.readbyte(0x7e0021e) % 4 end
  725.                     end
  726.                 end
  727.                 -- we assume that we are walking with maximum speed of 1 pixel per frame
  728.                 -- this will lead to be getting this value at the beginning of battle
  729.                 be = 4*((memory.readbyte(0x7e021e)+pixels+0x22) % 0x3c)
  730.                 gui.text(10,90,string.format("be: %x vs %x, %x %x", memory.readbyte(0x7e00be), be,pixels,xpos))
  731.  
  732.                 if math.floor(formation / 0x8000) == 1 then
  733.                     -- High bit of formation set: randomly add 0..3 to formation
  734.                     be = (be+1) % 0x100
  735.                     a = memory.readbyte(0xc0fd00+be) % 4
  736.                     formation = (formation+a) % 0x8000
  737.                 end
  738.             end
  739.             info1 = memory.readbyte(0xcf5900+4*formation)
  740.             info2 = memory.readbyte(0xcf5900+4*formation+1)
  741.             info3 = memory.readbyte(0xcf5900+4*formation+2)
  742.             info4 = memory.readbyte(0xcf5900+4*formation+3)
  743.  
  744.             -- Build monster list
  745.             start = 0xcf6201+15*formation
  746.             present = memory.readbyte(start)
  747.             which = {}
  748.             number_of_enemies = 0
  749.             for i = 1, 6 do
  750.                 if present % 2 == 1 then
  751.                     id = memory.readbyte(start+i)
  752.                     if which[id] then which[id] = which[id]+1
  753.                     else which[id] = 1 end
  754.                     number_of_enemies = number_of_enemies + 1
  755.                 end
  756.                 present = math.floor(present/2)
  757.             end
  758.             -- Display list
  759.             for id, num in pairs(which) do
  760.                 gui.text(10, offset, ""..num.." "..getmonstername(id))
  761.                 offset = offset + 10
  762.             end
  763.  
  764.             if not skip_frame_dependent then
  765.                 -- What kind of encounter?
  766.                 variant = math.floor(info1 / 0x10) % 0x10
  767.                 -- variant is four bits long, and those bits are front, back, pincer, side; inverted.
  768.                 -- from high to low.
  769.                 -- let us extract these
  770.                 allowed = {}
  771.                 allowed_number = 0
  772.                 for i = 0, 3 do
  773.                     allowed[i] = 1 - variant % 2
  774.                     allowed_number = allowed_number + allowed[i]
  775.                     variant = math.floor(variant/2)
  776.                 end
  777.                 if bit(status_effects,1) == 1 then
  778.                     -- back guard, disable back and pincer.
  779.                     -- This will prefer to remove pincer if not
  780.                     -- both can be removed.
  781.                     for i = 1, 2 do if allowed_number > 1 then
  782.                         allowed[i] = 0
  783.                         allowed_number = allowed_number-1
  784.                     end end
  785.                 end
  786.                 if char_in_party < 3 and allowed_number > 1 then
  787.                     -- not enough characters to do side attack
  788.                     allowed[3] = 0
  789.                     allowed_number = allowed_number - 1
  790.                 end
  791.  
  792.                 -- Now we pick one of the possibilities
  793.                 -- First find the sum of the weights
  794.                 local sum = 0
  795.                 for i = 0, 3 do if allowed[i] == 1 then
  796.                     sum = sum + memory.readbyte(0xc25279+i)+1
  797.                 end end
  798.                 -- before this point, be has been incremented by other things
  799.                 be = be + 0xa + 2*number_of_enemies + char_in_party
  800.                 -- get a random number from 0 to sum-1, using be
  801.                 be = (be+1) % 0x100
  802.                 rnd = math.floor(memory.readbyte(0xc0fd00+be)*sum/0x100)
  803.                 -- now loop through again, and pick the first that is bigger
  804.                 -- than the number
  805.                 sum = 0
  806.                 for i = 0, 3 do if allowed[3-i] == 1 then
  807.                     sum = sum + memory.readbyte(0xc25279+i)+1
  808.                     if sum > rnd then
  809.                         chosen = 3-i
  810.                         break
  811.                     end
  812.                 end end
  813.  
  814.                 vardesc = { "Front", "Back", "Pincer", "Side" }
  815.  
  816.                 -- Finally, describe the result
  817.                 if chosen ~= 0 then
  818.                     gui.text(10, offset, string.format("%s attack",vardesc[chosen+1]))
  819.                     offset = offset+10
  820.                 end
  821.             end
  822.         end
  823.     end
  824.     HandleKeys()
  825.  
  826.     if autoText then
  827.         gui.text(textX,textY + 20,"(T) Auto Text : On")          
  828.     else
  829.         gui.text(textX,textY + 20,"(T) Auto Text : Off")          
  830.     end
  831.  
  832.     if autoText and (snes9x.framecount() % 6  == 0 or ((snes9x.framecount() - 1) % 6 == 0)) then
  833.         curPad = joypad.get()
  834.         curPad.A = true
  835.         joypad.set(curPad)
  836.     end
  837.  
  838.     if (memory.readbyte(0x7e1dd2) % 2 == 0) and (memory.readword(0x7e1501) == 0xa509) and (memory.readbyte(0x7e1503) == 0xEE) then
  839.         x1 = memory.readword(0x7e0b00)
  840.         y1 = memory.readword(0x7e0b02)
  841.         x2 = memory.readword(0x7e0b04)
  842.         y2 = memory.readword(0x7e0b06)
  843.        
  844.         gui.line(x1 + 176, 156, x1 + 176, 219, "#008080")
  845.         gui.line(176, y1 + 156, 239, y1 + 156, "#008080")
  846.         gui.line(x2 + 176, 156, x2 + 176, 219, "#008080")
  847.         gui.line(176, y2 + 156, 239, y2 + 156, "#008080")
  848.         gui.pixel(x1 + 176, y1 + 156, "#00ffff")
  849.         gui.pixel(x2 + 176, y2 + 156, "#00ffff")
  850.        
  851.     end
  852.  
  853.     --for moviemaking
  854.     --cMode1, cMode2 = memory.readword(0x7e1501), memory.readbyte(0x7e1503)
  855.     --if lMode1 ~= cMode1 and lMode2 ~= cMode2 then
  856.     --  snes9x.pause()
  857.     --end
  858.     --lMode1 = cMode1
  859.     --lMode2 = cMode2
  860.  
  861.     CalculateTime()
  862.     OutputTime()
  863.    
  864.    
  865.     snes9x.frameadvance()
  866. end
RAW Paste Data