Advertisement
Guest User

Untitled

a guest
Oct 16th, 2014
54
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 13.05 KB | None | 0 0
  1. # settings
  2. ROM_path          = "pokeblue.gbc"
  3. MapHeaderBanks    = 0xC23D
  4. MapHeaderPointers = 0x01AE
  5. Tilesets          = 0xC7BE
  6. KeyItemBitfield   = 0xE799
  7.  
  8. # aliases
  9. class String
  10.     def b ; self.unpack("C")[0] ; end
  11.     def w ; self.unpack("S")[0] ; end
  12. end
  13.  
  14. # >not a default method
  15. class Object
  16.     def indices(obj)
  17.         arr = []
  18.         off = -1
  19.        
  20.         loop do
  21.             idx  = self[(off + 1)..-1].index(obj)
  22.             break if(idx == nil)
  23.             off += idx + 1
  24.             arr << off
  25.         end
  26.        
  27.         return arr
  28.     end
  29. end
  30.  
  31. def isKeyItem(id)
  32.     # roughly same as the assembly
  33.     # RAM dependent return true
  34.    
  35.     return false if(id > 0xC8) # TMs
  36.     return true  if(id > 0xC3) # HMs
  37.     return true  if(id > 0x78) # RAM
  38.    
  39.     if(id > 0x00) # bitfield lookup
  40.         bitfield = ROM[KeyItemBitfield,15].unpack("b*")[0]
  41.         bit      = bitfield[id - 1]
  42.        
  43.         return [false,true][bit.to_i]
  44.     end
  45.    
  46.     return true # RAM
  47. end
  48.  
  49. # constants
  50. ROM   = IO.binread(ROM_path)
  51. RAM   = []
  52. BANKS = ROM.size / 0x4000
  53.  
  54. BANKS.times do |i_bank|
  55.     RAM[i_bank] = ROM[0x0000,0x4000] + ROM[i_bank * 0x4000,0x4000]
  56. end
  57.  
  58. # check map IDs for combos
  59. hash_banks = {}
  60. to_tileset = {}
  61.  
  62. 0x100.times do |i_map|
  63.     map_header_bank    = ROM[MapHeaderBanks    + i_map * 0x01,0x01].b
  64.     map_header_pointer = ROM[MapHeaderPointers + i_map * 0x02,0x02].w
  65.    
  66.     next if(map_header_bank >= BANKS)
  67.    
  68.     i_tileset = RAM[map_header_bank][map_header_pointer + 0x00,0x01].b
  69.     map_width = RAM[map_header_bank][map_header_pointer + 0x02,0x01].b
  70.     tileset   = ROM[Tilesets + i_tileset * 0x0C,0x03].unpack("CS")
  71.     bank      = tileset[0]
  72.     block     = tileset[1] # pointer
  73.    
  74.     next if(bank >= BANKS)
  75.    
  76.     # bank -> block -> map_width -> i_map
  77.     hash_banks[bank]                    = {} if(!hash_banks.has_key?(bank))
  78.     hash_banks[bank][block]             = {} if(!hash_banks[bank].has_key?(block))
  79.     hash_banks[bank][block][map_width]  = [] if(!hash_banks[bank][block].has_key?(map_width))
  80.     hash_banks[bank][block][map_width] << i_map
  81.    
  82.     key = "#{bank}:#{block}"
  83.    
  84.     to_tileset[key] = []         if(!to_tileset.has_key?(key))
  85.     to_tileset[key] << i_tileset if(!to_tileset[key].include?(i_tileset))
  86. end
  87.  
  88. # some data variables
  89. valid = {
  90.     0x01 => [(0x00..0x00).to_a,(0x02..0x0F).to_a],
  91.     0x09 => [(0x00..0x08).to_a,(0x0A..0x0F).to_a],
  92.     0x03 => [[0x02],[0x06,0x07,0x0A,0x0B,0x0E,0x0F]],
  93.     0x0B => [[0x02,0x03,0x06,0x07,0x0A],[0x0E,0x0F]]
  94. }
  95.  
  96. section = {
  97.     "all"    => (0..7).to_a,
  98.     "top"    => (0..3).to_a,
  99.     "bottom" => (4..7).to_a,
  100.     "left"   => [0,2,4,6],
  101.     "right"  => [1,3,5,7],
  102.     "top1"   => (0..1).to_a,
  103.     "top3"   => (0..5).to_a,
  104.     "tetris" => (0..4).to_a
  105. }
  106.  
  107. section["topleft"]     = section["top"]    & section["left"]
  108. section["bottomleft"]  = section["bottom"] & section["left"]
  109. section["bottomright"] = section["bottom"] & section["right"]
  110. section["top1left"]    = section["top1"]   & section["left"]
  111. section["top1right"]   = section["top1"]   & section["right"]
  112. section["top3right"]   = section["top3"]   & section["right"]
  113.  
  114. # late addition
  115. 0x100.times do |pkmn|
  116. puts(pkmn)
  117.  
  118. # iterate through combos
  119. log = File.open("logs/#{pkmn}.txt","w")
  120.  
  121. hash_banks.each_pair do |bank,hash_blocks|
  122.     next if([0x02,0x04,0x05].include?(bank))
  123.    
  124.     hash_blocks.each_pair do |block,hash_widths|
  125.         pkmn_blocks = [] # pkmn blocks
  126.         self_blocks = [] # self-terminating pkmn blocks
  127.         end_blocks  = {} # terminator blocks
  128.        
  129.         0x100.times do |i_block|
  130.             addr = block + i_block * 0x10
  131.             next if(addr > 0x7FFF)
  132.            
  133.             tiles        = RAM[bank][addr,0x10].unpack("C*")
  134.             pkmn_indices = tiles.indices(pkmn) & valid.keys
  135.             end_indices  = tiles.indices(0x50)
  136.            
  137.             pkmn_indices.each do |index|
  138.                 next if((end_indices & valid[index][0]).size > 0)
  139.                
  140.                 pkmn_blocks << [i_block,index]
  141.                 self_blocks << i_block if((end_indices & valid[index][1]).size > 0)
  142.             end
  143.            
  144.             # categorized by pairs to simplify checking
  145.             end_indices.each do |index|
  146.                 pair = index / 2
  147.                
  148.                 end_blocks[pair]  = [] if(!end_blocks.has_key?(pair))
  149.                 end_blocks[pair] << Regexp.escape(i_block.chr)
  150.             end
  151.         end
  152.        
  153.         next if(pkmn_blocks.size == 0)
  154.        
  155.         # further categorization
  156.         section_blocks = {}
  157.        
  158.         section.each_pair do |name,pairs|
  159.             section_blocks[name] = []
  160.            
  161.             pairs.each do |pair|
  162.                 section_blocks[name] += end_blocks[pair] if(end_blocks.has_key?(pair))
  163.             end
  164.            
  165.             section_blocks[name] = section_blocks[name].join
  166.         end
  167.        
  168.         bank_header = false
  169.        
  170.         # block outputs
  171.         pkmn_blocks.each do |pkmn_block|
  172.             i_block  = pkmn_block[0]
  173.             index    = pkmn_block[1]
  174.             index_qy = (index / 4) / 2
  175.             index_qx = (index % 4) / 2
  176.             index_q  = index_qy * 2 + index_qx
  177.            
  178.             block_header = false
  179.             results      = 0
  180.            
  181.             (0x01..hash_widths.keys.max).each do |map_width|
  182.                 actual_width = map_width + 6
  183.                 regex        = ""
  184.                
  185.                 # first get all preceeding blocks
  186.                
  187.                 # index_qy = 0 has extra row
  188.                 # index_qx = 0 bottom bottom bottomleft
  189.                 # index_qx = 1 bottomright bottom bottom
  190.                
  191.                 if(index_qy == 0)
  192.                     regex += "[^#{section_blocks["bottomright"]}]" if(index_qx == 1)
  193.                     regex += "[^#{section_blocks["bottom"]}]{2}"
  194.                     regex += "[^#{section_blocks["bottomleft"]}]"  if(index_qx == 0)
  195.                     regex += ".{#{actual_width - 3}}"
  196.                 end
  197.                
  198.                 # index_qx = 0 all all left
  199.                 # index_qx = 1 right all all
  200.                
  201.                 regex += "[^#{section_blocks["right"]}]" if(index_qx == 1)
  202.                 regex += "[^#{section_blocks["all"]}]{2}"
  203.                 regex += "[^#{section_blocks["left"]}]"  if(index_qx == 0)
  204.                 regex += ".{#{actual_width - 3}}"
  205.                
  206.                 # the pkmn block
  207.                
  208.                 regex += Regexp.escape(i_block.chr)
  209.                
  210.                 # now need to find valid screen compositions
  211.                 # if index_qy = 1, first two cant be in top or topleft
  212.                
  213.                 addrs = []
  214.                
  215.                 8.times do |i|
  216.                     temp = regex
  217.                    
  218.                     if(i > 1)
  219.                         temp += "."
  220.                         temp += "(?<![#{section_blocks["top"]}])" if(index_qy == 1)
  221.                         temp += "."
  222.                        
  223.                         if(index_qy == 1)
  224.                             temp += "(?<![#{section_blocks["topleft"]}])" if(index_qx == 0)
  225.                             temp += "(?<![#{section_blocks["top"]}])"     if(index_qx == 1)
  226.                         end
  227.                     end
  228.                    
  229.                     case(i)
  230.                         when(0)
  231.                             temp += "[#{section_blocks["all"]}]"
  232.                             temp += "(?<![#{section_blocks["top"]}])" if(index_qy == 1)
  233.                        
  234.                         when(1)
  235.                             temp += "."
  236.                             temp += "(?<![#{section_blocks["top"]}])" if(index_qy == 1)
  237.                             temp += "[#{section_blocks["left"]}]" if(index_qx == 0)
  238.                             temp += "[#{section_blocks["all"]}]"  if(index_qx == 1)
  239.                            
  240.                             if(index_qy == 1)
  241.                                 temp += "(?<![#{section_blocks["topleft"]}])" if(index_qx == 0)
  242.                                 temp += "(?<![#{section_blocks["top"]}])"     if(index_qx == 1)
  243.                             end
  244.                        
  245.                         when(2)
  246.                             temp += ".{#{actual_width - 2 - 1}}"
  247.                             temp += "[#{section_blocks["top3"]}]"      if(index_q == 0)
  248.                             temp += "[#{section_blocks["top3right"]}]" if(index_q == 1)
  249.                             temp += "[#{section_blocks["all"]}]"       if(index_q == 2)
  250.                             temp += "[#{section_blocks["right"]}]"     if(index_q == 3)
  251.                            
  252.                         when(3)
  253.                             temp += ".{#{actual_width - 2}}"
  254.                             temp += "[#{section_blocks["top3"]}]" if(index_qy == 0)
  255.                             temp += "[#{section_blocks["all"]}]"  if(index_qy == 1)
  256.                        
  257.                         when(4)
  258.                             temp += ".{#{actual_width - 2 + 1}}"
  259.                             temp += "[#{section_blocks["topleft"]}]" if(index_q == 0)
  260.                             temp += "[#{section_blocks["tetris"]}]"  if(index_q == 1)
  261.                             temp += "[#{section_blocks["left"]}]"    if(index_q == 2)
  262.                             temp += "[#{section_blocks["all"]}]"     if(index_q == 3)
  263.                        
  264.                         when(5)
  265.                             break if(index_qy == 0)
  266.                            
  267.                             temp += ".{#{actual_width * 2 - 2 - 1}}"
  268.                             temp += "[#{section_blocks["top1"]}]"      if(index_qx == 0)
  269.                             temp += "[#{section_blocks["top1right"]}]" if(index_qx == 1)
  270.                        
  271.                         when(6)
  272.                             temp += ".{#{actual_width * 2 - 2}}"
  273.                             temp += "[#{section_blocks["top1"]}]"
  274.                        
  275.                         when(7)
  276.                             break if(index_qx == 0)
  277.                            
  278.                             temp += ".{#{actual_width * 2 - 2 + 1}}"
  279.                             temp += "[#{section_blocks["top1left"]}]"
  280.                     end
  281.                    
  282.                     next if(temp.index("[]") != nil)
  283.                    
  284.                     temp        = temp.gsub("[^]",".")
  285.                     found_addrs = RAM[bank].indices(Regexp.new(temp,Regexp::MULTILINE))
  286.                    
  287.                     found_addrs.each do |found_addr|
  288.                         addrs << found_addr if(!addrs.include?(found_addr))
  289.                     end
  290.                 end
  291.                
  292.                 next if(addrs.size == 0)
  293.                
  294.                 if(!bank_header)
  295.                     log.puts("//" * 16)
  296.                     log.puts("//  TILESETS #{to_tileset["#{bank}:#{block}"].join(" ")}")
  297.                    
  298.                     list_maps = []
  299.                    
  300.                     hash_widths.each_value do |i_maps|
  301.                         i_maps.each do |i_map|
  302.                             list_maps << [i_map,isKeyItem(i_map) ? "*" : ""]
  303.                         end
  304.                     end
  305.                    
  306.                     log.print("//  MAPS")
  307.                    
  308.                     list_maps.sort.each do |list_map|
  309.                         log.print(" #{list_map.join}")
  310.                     end
  311.                    
  312.                     log.puts
  313.                     log.puts("//" * 16)
  314.                     log.puts
  315.                    
  316.                     bank_header = true
  317.                 end
  318.                
  319.                 if(!block_header)
  320.                     log.puts("// block #{i_block.to_s(16).upcase}")
  321.                     block_header = true
  322.                 end
  323.                
  324.                 addrs = addrs.sort
  325.                
  326.                 addrs.each do |addr|
  327.                     # level_offset = addr + map_width * (2 - index_qy) + 2
  328.                     # level_slot   = index_qy * 8 + 4 + index_qx * 2
  329.                     # v_level      = RAM[bank][level_offset,0x10].unpack("C*")[level_slot]
  330.                    
  331.                     log.print("insta(")
  332.                     log.print("tileset=#{to_tileset["#{bank}:#{block}"][0]},")
  333.                     log.print("offset=#{addr.to_s(16).rjust(4,"0")},")
  334.                     log.print("blocky=#{1 - index_qy},")
  335.                     log.print("blockx=#{index_qx},")
  336.                     log.print("width=#{map_width}")
  337.                     # log.print("level=#{v_level}")
  338.                     log.puts(")")
  339.                    
  340.                     # break
  341.                 end
  342.                
  343.                 results += 1
  344.                 # break if(results == 10)
  345.             end
  346.            
  347.             log.puts if(block_header)
  348.         end
  349.        
  350.         if(bank_header)
  351.             log.puts
  352.             log.puts
  353.         end
  354.     end
  355. end
  356.  
  357. log.close
  358. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement