Advertisement
partyboy1a

snes9x-sprites-killer-wip2.lua

Sep 13th, 2011
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.07 KB | None | 0 0
  1. -- snes blinking sprites marker
  2. -- to understand what's going on here you must read
  3. -- http://patpend.net/technical/snes/snes.txt
  4.  
  5.  
  6. --[[ HOW TO USE:
  7. - playback a movie file
  8. - start the script when you got to the start of an interesting section
  9. - press numpad+ to see sprite data
  10. --]]
  11. local count = 0
  12.  
  13. oam = {}
  14.  
  15. sprite_size_table = { -- note: width==height
  16.     {8,16},{8,32},{8,64},
  17.     {16,32},{16,64},{32,64}
  18. }
  19.  
  20. bit_select = {[0]=1,[1]=2,[2]=4,[3]=8,[4]=16,[5]=32,[6]=64,[7]=128}
  21. function bit(val,bit)
  22.     return AND(val,bit_select[bit])/bit_select[bit]
  23. end
  24.  
  25. spritedata = {}
  26. spritegroup = {}
  27.  
  28. potentialgroups = {
  29.     --[[
  30.     all colliding sprites go here, if they are drawn directly after one another
  31.    
  32.     [frame][1].start
  33.     [frame][1].finish
  34.     [frame][2].start
  35.     [frame][2].finish
  36.     --]]
  37. }
  38.  
  39. collisionstatistics = {
  40. --[[
  41.     [b2][b3].count
  42.     [b2][b3][xoffset1][yoffset1][b2][b3].count,
  43.     [b2][b3][xoffset1][yoffset1][b2][b3][xoffset2][yoffset2][b2][b3].count
  44. --]]
  45. }
  46.  
  47.  
  48. function parse_oam(frame)
  49.     -- here are still some programming errors left...
  50.  
  51.     spritedata[frame] = {}
  52. --[[
  53. |   0     Byte   0             xxxxxxxx           x: X-location.             |
  54. |         Byte   1             yyyyyyyy           y: Y-location.             |
  55. |         Byte   2             abcdeeeC           a: Vertical flip.          |
  56. |                                                 b: Horizontal flip.        |
  57. |                                                 c: Playfield priority.     |
  58. |                                                 d: Playfield priority.     |
  59. |                                                 e: Pallete #.              |
  60. |         Byte   3             CCCCCCCC           C: Character data.         |
  61. |                                                                            |
  62. |starting at oam byte 512:                                                   |
  63. |2 bits are defined for each OBJ (eg. byte #0 holds the info for OBJ 0, 1, 2,|
  64. |and 3; byte #1 holds the info for OBJ 4, 5, 6, and 7). Therefore, 128/4 is  |
  65. |32 bytes of data for the following table:                                   |
  66. |                                  ab                                        |
  67. |                                  ||____Size toggle bit.                    |
  68. |                                  |_____MSB of X-position bit.              |
  69. |                                                                            |
  70. |So, the 4 bytes/sprites + the block are put into the OAM table by consec-   |
  71. |utive writes to the OAM data register. You first should set the OAM address |
  72. |to $0000, then shove your data into it.                                     |
  73. --]]
  74.     for i=0,31 do for j=0,3 do
  75.         spritedata[frame][4*i+j] = {}
  76.         spritedata[frame][4*i+j].x = oam[frame][4*(4*i+j)] + 256 * bit(oam[frame][512+i],2*j)
  77.        
  78.         temp = oam[frame][4*(4*i+j)+1]
  79.         if temp < 224 then
  80.             spritedata[frame][4*i+j].y = temp
  81.         else
  82.             spritedata[frame][4*i+j].y = temp - 256
  83.         end
  84.         spritedata[frame][4*i+j].width = sprite_size[bit(oam[frame][512+i],2*j+1) + 1]
  85.         if real_x == 256 + 128 then --don't draw this one, it doesn't exist
  86.             spritedata[frame][4*i+j].enabled = false
  87.         else
  88.             spritedata[frame][4*i+j].enabled = true
  89.         end
  90.         spritedata[frame][4*i+j].verticalflip   = (bit(oam[frame][4*(4*i+j)+2], 0) == 1)
  91.         spritedata[frame][4*i+j].horizontalflip = (bit(oam[frame][4*(4*i+j)+2], 1) == 1)
  92.         spritedata[frame][4*i+j].playfieldpriority = 2*bit(oam[frame][4*(4*i+j)+2], 2) + bit(oam[frame][4*(4*i+j)+2], 3)
  93.         spritedata[frame][4*i+j].pallete = 4*bit(oam[frame][4*(4*i+j)+2], 4) + 2*bit(oam[frame][4*(4*i+j)+2], 5) + bit(oam[frame][4*(4*i+j)+2], 6)
  94.         spritedata[frame][4*i+j].characterdata = 256 * bit(oam[frame][4*(4*i+j)+2], 7) + oam[frame][4*(4*i+j)+3]
  95.     end end
  96. end
  97.  
  98. function read_oam()
  99.     b = memory.readword(0x2101)
  100.     name_base = AND(b, 1+2+4) * 4096
  101.     name_bits = AND(b, 8+16)
  102.     sprite_size_bits = AND(b, 32+64+128) / 32
  103.     --sprite_size = {8,16} --should be sprite_size_table[sprite_size_bits + 1]
  104.     sprite_size = {16,32}
  105.    
  106.     oam[cf] = {}
  107.     memory.writeword(0x2102,0)
  108.     for i = 0,512+32-1 do
  109.         --memory.writeword(0x2102,i)
  110.         w = memory.readbyte(0x2138)
  111.         oam[cf][i] = w
  112.         --oam[2*i+1] = w % 256
  113.     end
  114. end
  115. --vram_sprite_offset
  116.  
  117. start = savestate.create()
  118. savestate.save(start)
  119.  
  120. function detectspritegroups(frame)
  121.     spritegroup[frame] = {}
  122.    
  123.     groupcount = 0
  124.     i = 0
  125.     while i < 127 do
  126.         groupcount = groupcount + 1
  127.         spritegroup[frame][groupcount] = {
  128.             min_x = spritedata[frame][i].x,
  129.             max_x = spritedata[frame][i].x,
  130.             min_y = spritedata[frame][i].y,
  131.             max_y = spritedata[frame][i].y,
  132.             numberofsprites = 1,
  133.             first = i
  134.         }
  135.         j = i + 1
  136.         while not spritedata[frame][j].enabled and j < 127 do
  137.             j = j + 1
  138.         end
  139.         while (
  140.             -- spritedata[frame][i].characterdata == spritedata[frame][j].characterdata and
  141.             math.mod(spritedata[frame][i].x - spritedata[frame][j].x, spritedata[frame][i].width) == 0 and
  142.             math.mod(spritedata[frame][i].y - spritedata[frame][j].y, spritedata[frame][i].width) == 0 ) and
  143.             ( spritedata[frame][i].x == spritedata[frame][j].x or spritedata[frame][i].y == spritedata[frame][j].y)
  144.             do
  145.            
  146.             spritegroup[frame][groupcount].min_x = math.min(spritegroup[frame][groupcount].min_x, spritedata[frame][j].x)
  147.             spritegroup[frame][groupcount].max_x = math.max(spritegroup[frame][groupcount].max_x, spritedata[frame][j].x)
  148.             spritegroup[frame][groupcount].min_y = math.min(spritegroup[frame][groupcount].min_y, spritedata[frame][j].y)
  149.             spritegroup[frame][groupcount].max_y = math.max(spritegroup[frame][groupcount].max_y, spritedata[frame][j].y)
  150.             spritegroup[frame][groupcount].numberofsprites = spritegroup[frame][groupcount].numberofsprites + 1
  151.             j = j + 1
  152.             if j == 128 then break end
  153.            
  154.         end
  155.         i = j
  156.        
  157.     end
  158. end
  159.  
  160. function findblinkingspritegroups(frame, distx, disty)
  161.     if spritegroup[frame] == nil or spritegroup[frame+1] == nil or
  162.         spritegroup[frame+2] == nil or spritegroup[frame-1] == nil or
  163.         spritegroup[frame-2] == nil then
  164.        
  165.         return
  166.     end
  167.     for i,group in pairs(spritegroup[frame]) do
  168.        
  169.         local help = function(offset, name)
  170.             for j,group2 in pairs(spritegroup[frame+offset]) do
  171.                 if math.abs(group.min_x - group2.min_x) <= distx and
  172.                     math.abs(group.min_y - group2.min_y) <= disty and
  173.                     group.max_x - group.min_x == group2.max_x - group2.min_x and
  174.                     group.max_y - group.min_y == group2.max_y - group2.min_y and (
  175.                         group.characterdata == group2.characterdata or (
  176.                         group.numberofsprites == group2.numberofsprites and
  177.                         group.numberofsprites > 1))
  178.                     then
  179.                    
  180.                     spritegroup[frame][i][name] = j
  181.                 end
  182.             end
  183.         end
  184.         help(1,"normalmovement")
  185.         help(2,"twostepmovement")
  186.         help(-1,"normalbackwardmovement")
  187.         help(-2,"twostepbackwardmovement")
  188.        
  189.         group.blinking = (not group.normalmovement and group.twostepmovement)
  190.             or (not group.normalbackwardmovement and group.twostepbackwardmovement)
  191.             or (not group.normalmovement and not group.normalbackwardmovement)
  192.     end
  193. end
  194.  
  195. while(true) do
  196.     snes9x.frameadvance()
  197.     cf = emu.framecount()
  198.     spritedata[cf] = {}
  199.     read_oam()
  200.     parse_oam(cf)
  201.     detectspritegroups(cf)
  202.     keys = input.get()
  203.     if keys["numpad+"] then break end
  204. end
  205.  
  206. function drawspritegroups(frame, color)
  207.     for i,group in pairs(spritegroup[frame]) do
  208.         gui.box(math.max(0,group.min_x), math.max(0,group.min_y), group.max_x + 16, group.max_y + 16, "transparent", color)
  209.     end
  210.     for i,group in pairs(spritegroup[frame]) do
  211.         gui.text(group.min_x, group.min_y, string.format("%i / %i / %i / %i", group.first, group.numberofsprites, group.min_x, group.min_y))
  212.         if group.blinking then
  213.             gui.text(group.min_x, group.min_y+8, "BLINKING")
  214.         end
  215.         if group.offset_x then
  216.             gui.text(group.max_x, group.max_y, tostring(group.offset_x) .. "|" .. tostring(group.offset_y))
  217.         end
  218.     end
  219. end
  220.  
  221. savestate.load(start)
  222.  
  223. emu.registerbefore(function()
  224.     cf = emu.framecount()
  225.     if spritegroup[cf - 1] == nil or spritegroup[cf] == nil or spritegroup[cf + 1] == nil then return end
  226.    
  227.     deletecount=0
  228.    
  229.     for i,group in pairs(spritegroup[cf]) do
  230.         if group.blinking then
  231.             deletegroup(cf,group)
  232.             deletecount = deletecount+1
  233.         end
  234.     end
  235.    
  236.     gui.text(0,0,tostring(deletecount))
  237.     --if deletecount > 0 then emu.pause() end
  238.     writeoam(cf)
  239. end)
  240.  
  241. function writeoam(frame)
  242.     memory.writebyte(0x2102,0)
  243.     for i=0,512+32-1 do
  244.         memory.writebyte(0x2104,oam[frame][i])
  245.     end
  246. end
  247.  
  248. function deletegroup(frame,group)
  249.     for i=group.first,group.first+group.numberofsprites-1 do
  250.         --send sprite to x = 384
  251.         oam[frame][4*i] = 255
  252.         oam[frame][4*i+1] = 224
  253.         --[[
  254.         local manipulate = 512 + math.floor(i/4)
  255.         local bitnum = 2 * math.mod(i,4)
  256.         local b = bit(oam[frame][manipulate], bitnum)
  257.         if b == 1 then oam[frame][manipulate] = oam[frame][manipulate] - bit_select[bitnum] end
  258.         --]]
  259.     end
  260. end
  261.  
  262. while(true) do
  263.     cf = emu.framecount()
  264.     findblinkingspritegroups(cf, 10, 10)
  265.    
  266.     m = math.mod(cf, 4)
  267.     colors = {[0]="red", [1]="green", [2]="red",[3]="green"}
  268.     --if spritedata[cf] ~= nil then drawspritegroups(cf, colors[m]) end
  269.     --if spritedata[cf-1] ~= nil then drawspritegroups(cf-1, colors[m+1]) end
  270.    
  271.     snes9x.frameadvance()
  272. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement