1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
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
|