class RandTileGenerator def initialize @sections = {} end def section(name) @sections[name] ||= {entries: []} @current_section = @sections[name] yield end def random(range, type=:both, numbers=nil) case range when Range # Regular handling numbers = range if numbers.nil? @current_section[:entries] << {range: range, type: type, numbers: numbers.to_a} when Numeric # One number random(range..range, type, numbers) when Enumerable # An array or something else similar numbers = range if numbers.nil? range.each { |r| random(r, type, numbers) } end end def pack # first, work out an offset for every section and entry # also, collect the data for each individual entry into an Array current_offset = 8 + (@sections.count * 4) all_entry_data = [] @sections.each_pair do |name, section| section[:offset] = current_offset current_offset += 8 section[:entries].each do |entry| entry[:offset] = current_offset all_entry_data << entry[:numbers] current_offset += 8 end end # assign an offset to each piece of entry data data_offsets = {} all_entry_data.uniq! all_entry_data.each do |data| data_offsets[data] = current_offset current_offset += data.size end # assign an offset to each section name name_offsets = {} @sections.keys.each do |name| name_offsets[name] = current_offset current_offset += name.size + 1 end # now pack it all together header = ['NwRT', @sections.count].pack('a4 N') offsets = @sections.each_value.map{|s| s[:offset]}.pack('N*') section_data = @sections.each_pair.map do |name, section| name_offset = name_offsets[name] - section[:offset] entry_count = section[:entries].count entry_data = section[:entries].map do |entry| lower_bound = entry[:range].min upper_bound = entry[:range].max count = entry[:numbers].count type = [:none, :horz, :vert, :both].index(entry[:type]) num_offset = data_offsets[entry[:numbers]] - entry[:offset] [lower_bound, upper_bound, count, type, num_offset].pack('CCCC N') end [name_offset, entry_count].pack('NN') + entry_data.join end output = [header, offsets] output += section_data output += all_entry_data.map{|data| data.pack('C*')} output << @sections.keys.join("\0") output << "\0" output.join end def regular_terrain # Left Side random([0x10, 0x20, 0x30, 0x40], :vert) # Right Side random([0x11, 0x21, 0x31, 0x41], :vert) # Top Side random(2..7, :horz) # Bottom Side random(0x22..0x27, :horz) # Middle random(0x12..0x17) end def sub_terrain # Left Side random([0x18, 0x28, 0x38, 0x48], :vert) # Right Side random([0x19, 0x29, 0x39, 0x49], :vert) # Top Side random(0xA..0xF, :horz) # Bottom Side random(0x2A..0x2F, :horz) # Middle random(0x1A..0x1F) end end g = RandTileGenerator.new g.section('TestTileset') do g.random(1..20) g.random(21..24, :none) g.random(250..255, :vert, 0..5) end g.section('Pa1_nohara') do g.regular_terrain g.sub_terrain end File.open('/home/me/Games/Newer/DolphinPatch/NewerRes/RandTiles.bin', 'wb') do |f| f.write g.pack end