nwn-lib 0.3.6 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/BINARIES +40 -45
- data/CHANGELOG +4 -0
- data/CHEATSHEET +7 -73
- data/COPYING +1 -1
- data/DATA_STRUCTURES +50 -0
- data/README +27 -37
- data/Rakefile +7 -5
- data/SCRIPTING +44 -0
- data/SETTINGS +80 -0
- data/TYPE_VALUE_INFERRING +93 -0
- data/bin/nwn-dsl +28 -0
- data/bin/nwn-gff +192 -0
- data/bin/nwn-irb +51 -0
- data/data/gff-common-nwn1.yaml +982 -0
- data/lib/nwn/all.rb +7 -0
- data/lib/nwn/gff.rb +47 -861
- data/lib/nwn/gff/api.rb +88 -0
- data/lib/nwn/gff/cexolocstr.rb +28 -0
- data/lib/nwn/gff/field.rb +105 -0
- data/lib/nwn/gff/list.rb +2 -0
- data/lib/nwn/gff/reader.rb +220 -0
- data/lib/nwn/gff/struct.rb +34 -0
- data/lib/nwn/gff/writer.rb +201 -0
- data/lib/nwn/helpers.rb +1 -30
- data/lib/nwn/infer.rb +125 -0
- data/lib/nwn/kivinen.rb +55 -0
- data/lib/nwn/scripting.rb +129 -0
- data/lib/nwn/settings.rb +7 -0
- data/lib/nwn/twoda.rb +105 -7
- data/lib/nwn/yaml.rb +276 -5
- data/scripts/clean_locstrs.rb +46 -0
- data/scripts/extract_all_items.rb +19 -0
- data/scripts/fix_facings.rb +22 -0
- data/scripts/truncate_floats.rb +18 -0
- data/tools/migrate_03x_to_04x.sh +17 -0
- data/tools/verify.sh +35 -0
- metadata +36 -8
- data/bin/nwn-gff-import +0 -69
- data/bin/nwn-gff-irb +0 -62
- data/bin/nwn-gff-print +0 -133
data/lib/nwn/settings.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
if ENV['NWN_LIB_INFER_DATA_FILE'] && ENV['NWN_LIB_INFER_DATA_FILE'] != ""
|
2
|
+
NWN::Gff.load_struct_defaults(ENV['NWN_LIB_INFER_DATA_FILE'])
|
3
|
+
end
|
4
|
+
|
5
|
+
if ENV['NWN_LIB_2DA_LOCATION'] && ENV['NWN_LIB_2DA_LOCATION'] != ""
|
6
|
+
NWN::TwoDA::Cache.setup ENV['NWN_LIB_2DA_LOCATION']
|
7
|
+
end
|
data/lib/nwn/twoda.rb
CHANGED
@@ -2,7 +2,42 @@ require 'shellwords'
|
|
2
2
|
|
3
3
|
module NWN
|
4
4
|
module TwoDA
|
5
|
+
|
6
|
+
# A Row is simply an Array with some helpers.
|
7
|
+
# It wraps a data row in a TwoDA::Table.
|
8
|
+
#
|
9
|
+
# You can access Table columns in a row by simply
|
10
|
+
# calling a method with the same name.
|
11
|
+
#
|
12
|
+
# For example (spells.2da):
|
13
|
+
#
|
14
|
+
# table.rows.select {|x| x.Wiz_Sorc == "9" }
|
15
|
+
#
|
16
|
+
# selects all level 9 arcane spells.
|
17
|
+
class Row < Array
|
18
|
+
attr_accessor :table
|
19
|
+
|
20
|
+
# Returns the id of this row.
|
21
|
+
def ID
|
22
|
+
@table.rows.index(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing meth, *args
|
26
|
+
if idx = @table.columns.index(meth.to_s.downcase) || idx = @table.columns.index(meth.to_s)
|
27
|
+
if meth.to_s =~ /=$/
|
28
|
+
self[idx] = args.shift or raise ArgumentError,
|
29
|
+
"Need a paramenter for assignments .."
|
30
|
+
else
|
31
|
+
self[idx]
|
32
|
+
end
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
5
39
|
class Table
|
40
|
+
CELL_PAD_SPACES = 4
|
6
41
|
|
7
42
|
# An array of all column names present in this 2da table.
|
8
43
|
attr_accessor :columns
|
@@ -68,8 +103,16 @@ module NWN
|
|
68
103
|
end
|
69
104
|
|
70
105
|
# [1..-1]: Strip off the ID
|
71
|
-
data[row[0].to_i] = row = row[1..-1]
|
72
|
-
|
106
|
+
data[row[0].to_i] = row = Row.new(row[1..-1])
|
107
|
+
row.table = self
|
108
|
+
|
109
|
+
row.map! {|cell|
|
110
|
+
cell = case cell
|
111
|
+
when nil; nil
|
112
|
+
when "****"; ""
|
113
|
+
else cell
|
114
|
+
end
|
115
|
+
}
|
73
116
|
raise ArgumentError,
|
74
117
|
"Row #{idx} does not have the appropriate amount of cells (has: #{row.size}, want: #{header.size}) (while parsing #{row[0,3].join(' ')})." if
|
75
118
|
row.size != header.size
|
@@ -86,7 +129,7 @@ module NWN
|
|
86
129
|
# [+column+] The column to retrieve (name or id), or nil for all columns.
|
87
130
|
def by_row row, column = nil
|
88
131
|
column = column_name_to_id column
|
89
|
-
column.nil? ? @rows[row.to_i] : @rows[row.to_i][column]
|
132
|
+
column.nil? ? @rows[row.to_i] : (@rows[row.to_i].nil? ? nil : @rows[row.to_i][column])
|
90
133
|
end
|
91
134
|
|
92
135
|
|
@@ -97,7 +140,7 @@ module NWN
|
|
97
140
|
def by_col column, row = nil
|
98
141
|
column = column_name_to_id column
|
99
142
|
raise ArgumentError, "column must not be nil." if column.nil?
|
100
|
-
row.nil? ? @rows.map {|v| v[column] } : @rows[row.to_i][column]
|
143
|
+
row.nil? ? @rows.map {|v| v[column] } : (@rows[row.to_i].nil? ? nil : @rows[row.to_i][column])
|
101
144
|
end
|
102
145
|
|
103
146
|
|
@@ -120,15 +163,70 @@ module NWN
|
|
120
163
|
# Returns this table as a valid 2da to be written to a file.
|
121
164
|
def to_2da
|
122
165
|
ret = []
|
166
|
+
|
167
|
+
# Contains the maximum string length by each column,
|
168
|
+
# from which we can calulate the padding we need that
|
169
|
+
# things align properly.
|
170
|
+
id_cell_size = @rows.size.to_s.size + CELL_PAD_SPACES
|
171
|
+
max_cell_size_by_column = @columns.map {|col|
|
172
|
+
([col] + by_col(col)).inject(0) {|max, cell|
|
173
|
+
cell.to_s.size > max ? cell.to_s.size : max
|
174
|
+
} + CELL_PAD_SPACES
|
175
|
+
}
|
176
|
+
|
123
177
|
ret << "2DA V2.0"
|
124
178
|
ret << ""
|
125
|
-
|
126
|
-
|
127
|
-
|
179
|
+
|
180
|
+
rv = []
|
181
|
+
rv << " " * id_cell_size
|
182
|
+
@columns.each_with_index {|column, column_idx|
|
183
|
+
rv << column + " " * (max_cell_size_by_column[column_idx] - column.size)
|
184
|
+
}
|
185
|
+
ret << rv.join("").rstrip
|
186
|
+
|
187
|
+
@rows.each_with_index {|row, row_idx|
|
188
|
+
rv = []
|
189
|
+
rv << row_idx.to_s + " " * (id_cell_size - row_idx.to_s.size)
|
190
|
+
row.each_with_index {|cell, column_idx|
|
191
|
+
cell = "****" if cell == ""
|
192
|
+
rv << cell + " " * (max_cell_size_by_column[column_idx] - cell.size)
|
193
|
+
}
|
194
|
+
ret << rv.join("").rstrip
|
128
195
|
}
|
129
196
|
ret.join("\r\n")
|
130
197
|
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# This is a simple 2da cache.
|
201
|
+
module Cache
|
202
|
+
@_cache = {}
|
203
|
+
@_roots = []
|
204
|
+
|
205
|
+
# Set the file system path spec where all 2da files reside.
|
206
|
+
# Call this on application startup.
|
207
|
+
# path spec is a colon-separated list of pathes, just like $PATH.
|
208
|
+
def self.setup root_directories
|
209
|
+
@_roots = root_directories.split(':').compact.reject {|x| "" == x.strip }
|
210
|
+
end
|
211
|
+
|
212
|
+
# Get the 2da file with the given name. +name+ is without extension.
|
213
|
+
def self.get(name)
|
214
|
+
raise Exception,
|
215
|
+
"You need to set up the cache first through the environment variable NWN_LIB_2DA_LOCATION." unless
|
216
|
+
@_roots.size > 0
|
217
|
+
@_cache[name.downcase] ||= read_2da(name.downcase)
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.read_2da name # :nodoc:
|
221
|
+
@_roots.each {|root|
|
222
|
+
file = root + '/' + name + '.2da'
|
223
|
+
next unless FileTest.exists?(file)
|
224
|
+
return Table.parse(IO.read(file))
|
225
|
+
}
|
226
|
+
raise Errno::ENOENT, name + ".2da"
|
227
|
+
end
|
131
228
|
|
229
|
+
private_class_method :read_2da
|
132
230
|
end
|
133
231
|
end
|
134
232
|
end
|
data/lib/nwn/yaml.rb
CHANGED
@@ -1,17 +1,288 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
|
3
|
+
# See http://www.taguri.org/ for the exact meaning of this.
|
4
|
+
NWN::YAML_DOMAIN = "nwn-lib.elv.es,2008-12"
|
5
|
+
|
6
|
+
class Array
|
7
|
+
attr_accessor :to_yaml_style
|
8
|
+
end
|
9
|
+
class Hash
|
10
|
+
attr_accessor :to_yaml_style
|
11
|
+
end
|
12
|
+
|
3
13
|
class Hash
|
4
14
|
# Replacing the to_yaml function so it'll serialize hashes sorted (by their keys)
|
5
15
|
# Original function is in /usr/lib/ruby/1.8/yaml/rubytypes.rb
|
6
|
-
def to_yaml(
|
7
|
-
YAML::quick_emit(
|
8
|
-
out.map(
|
9
|
-
|
10
|
-
|
16
|
+
def to_yaml(opts = {})
|
17
|
+
YAML::quick_emit(nil, opts) do |out|
|
18
|
+
out.map(taguri, to_yaml_style) do |map|
|
19
|
+
if keys.map {|v| v.class }.size > 0
|
20
|
+
each do |k, v|
|
21
|
+
map.add(k, v)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
sort.each do |k, v|
|
25
|
+
map.add(k, v)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module NWN::Gff::Struct
|
34
|
+
def to_yaml_type
|
35
|
+
"!#{NWN::YAML_DOMAIN}/struct"
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_yaml(opts = {})
|
39
|
+
YAML::quick_emit(nil, opts) do |out|
|
40
|
+
out.map(taguri, to_yaml_style) do |map|
|
41
|
+
# Inline certain structs that are small enough.
|
42
|
+
map.style = :inline if self.size <= 1 &&
|
43
|
+
self.values.select {|x|
|
44
|
+
NWN::Gff::YAMLNonInlineableFields.index(x['type'])
|
45
|
+
}.size == 0
|
46
|
+
|
47
|
+
map.add('__' + 'data_type', @data_type) if @data_type
|
48
|
+
map.add('__' + 'data_version', @data_version) if @data_version && !can_infer_data_version?
|
49
|
+
map.add('__' + 'struct_id', @struct_id) if @struct_id && !can_infer_struct_id?
|
50
|
+
|
51
|
+
reject {|k, v|
|
52
|
+
# Dont emit fields that would result in their default values anyways.
|
53
|
+
ENV['NWN_LIB_CLEAR_KNOWN_VALUES'] && v.can_infer_type? &&
|
54
|
+
v.can_infer_str_ref? && v.can_infer_value?
|
55
|
+
}.sort.each {|k,v|
|
56
|
+
map.add(k,v)
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module NWN::Gff::Field
|
64
|
+
|
65
|
+
def to_yaml(opts = {})
|
66
|
+
|
67
|
+
if !ENV['NWN_LIB_DONT_COMPACT_LIST_STRUCTS'] && field_type == :list && can_compact_as_list?
|
68
|
+
YAML::quick_emit(nil, opts) do |out|
|
69
|
+
out.seq("!", to_yaml_style) do |seq|
|
70
|
+
field_value.each {|item|
|
71
|
+
struct_id_of_item = NWN::Gff.get_struct_defaults_for(item.path, '__struct_id')
|
72
|
+
|
73
|
+
calf = get_compact_as_list_field
|
74
|
+
case calf
|
75
|
+
when Array
|
76
|
+
style = NWN::Gff.get_struct_defaults_for(item.path, '__inline')
|
77
|
+
|
78
|
+
non_inferrable = (item.keys.reject {|x|
|
79
|
+
item[x].can_infer_type? && item[x].can_infer_value?
|
80
|
+
} - calf).sort
|
81
|
+
raise NWN::Gff::GffError, "cannot compact list struct at #{item.path}, would " +
|
82
|
+
"LOSE fields: #{non_inferrable.inspect}" if non_inferrable.size > 0
|
83
|
+
|
84
|
+
ar = calf.map {|ik| item[ik] || NWN::Gff.get_struct_default_value(item.path, ik) }
|
85
|
+
missing = ar.map {|x| x.nil? ? calf[ar.index(x)] : nil }.compact
|
86
|
+
|
87
|
+
raise NWN::Gff::GffError, "cannot compact list-struct at #{item.path}, does not " +
|
88
|
+
"have all compactable field values set or are inferrable (missing fields: #{missing.inspect})." if
|
89
|
+
missing.size > 0
|
90
|
+
|
91
|
+
ar.to_yaml_style = :inline if style
|
92
|
+
|
93
|
+
ar.unshift(item.struct_id) if struct_id_of_item == 'inline'
|
94
|
+
seq.add(ar)
|
95
|
+
else
|
96
|
+
isv = NWN::Gff.get_struct_defaults_for(self.path, '__inline')
|
97
|
+
seq.style = :inline if isv.nil? || isv === true
|
98
|
+
|
99
|
+
seq.add(item.struct_id) if struct_id_of_item == 'inline'
|
100
|
+
seq.add(item[calf])
|
101
|
+
end
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
elsif !ENV['NWN_LIB_DONT_COMPACT_FIELDS'] && can_compact_print?
|
107
|
+
field_value_as_compact.to_yaml(opts)
|
108
|
+
|
109
|
+
else
|
110
|
+
YAML::quick_emit(nil, opts) do |out|
|
111
|
+
out.map(taguri, to_yaml_style) do |map|
|
112
|
+
map.style = :inline unless NWN::Gff::YAMLNonInlineableFields.index(self['type'])
|
113
|
+
map.add('type', self['type']) unless can_infer_type?
|
114
|
+
map.add('str_ref', self['str_ref']) unless can_infer_str_ref?
|
115
|
+
map.add('value', self['value']) unless can_infer_value?
|
11
116
|
end
|
12
117
|
end
|
13
118
|
end
|
14
119
|
end
|
15
120
|
end
|
16
121
|
|
122
|
+
# This parses the struct and extends all fields with their proper type.
|
123
|
+
YAML.add_domain_type(NWN::YAML_DOMAIN,'struct') {|t,hash|
|
124
|
+
struct = {}.taint
|
125
|
+
struct.extend(NWN::Gff::Struct)
|
126
|
+
|
127
|
+
# The metadata
|
128
|
+
struct.struct_id = hash.delete('__struct_id')
|
129
|
+
struct.data_type = hash.delete('__data_type')
|
130
|
+
struct.data_version = hash.delete('__data_version')
|
131
|
+
struct.data_version ||= NWN::Gff::Struct::DEFAULT_DATA_VERSION
|
132
|
+
|
133
|
+
if struct.struct_id.nil? && s_id = NWN::Gff.get_struct_defaults_for(struct.path, '__struct_id')
|
134
|
+
struct.struct_id = s_id.to_i
|
135
|
+
elsif struct.struct_id.nil?
|
136
|
+
raise NWN::Gff::GffError, "Cannot infer implicit struct_id for struct at #{struct.path}."
|
137
|
+
end
|
138
|
+
|
139
|
+
hash.each {|label,element|
|
140
|
+
label.freeze
|
141
|
+
element = case element
|
142
|
+
when Hash # already uncompacted or a compacted exolocstr
|
143
|
+
default_type = NWN::Gff.get_struct_default_type(struct.path, label)
|
144
|
+
raise NWN::Gff::GffError,
|
145
|
+
"Cannot parse compacted hash with no contents and no infer data at #{struct.path}/#{label}." if
|
146
|
+
element.size == 0 && default_type == nil
|
147
|
+
|
148
|
+
# It has only got numbers as key, we *assume* its a cexoloc.
|
149
|
+
# Thats okay, because type inferration will catch it later and bite us. Hopefully.
|
150
|
+
if element.keys.select {|x| x.to_s !~ /^(str_ref|\d+)$/}.size == 0
|
151
|
+
element = {
|
152
|
+
'type' => :cexolocstr,
|
153
|
+
'str_ref' => element.delete('str_ref') || NWN::Gff::Field::DEFAULT_STR_REF,
|
154
|
+
'value' => element,
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
element
|
159
|
+
|
160
|
+
when Array # compacted struct-list
|
161
|
+
element = {
|
162
|
+
'type' => :list,
|
163
|
+
'value' => element,
|
164
|
+
}
|
165
|
+
path = struct.data_type + "/" + label
|
166
|
+
unpack_struct_element = NWN::Gff.get_struct_defaults_for(path, '__compact')
|
167
|
+
if unpack_struct_element
|
168
|
+
# If it doesn't have unpack data, we need to assume its a compacted list itself.
|
169
|
+
# Sorry.
|
170
|
+
# Hope this wont bite anyone later on.
|
171
|
+
|
172
|
+
#raise NWN::Gff::GffError,
|
173
|
+
# "Cannot unpack compacted struct list at #{path}, no infer data available." unless
|
174
|
+
# unpack_struct_element
|
175
|
+
|
176
|
+
unpack_struct_element_struct_id = NWN::Gff.get_struct_defaults_for(path, "__struct_id")
|
177
|
+
|
178
|
+
unpack_struct_elements = [unpack_struct_element].flatten.freeze
|
179
|
+
|
180
|
+
unpack_struct_element_types = unpack_struct_elements.map {|unpack_struct_element|
|
181
|
+
raise NWN::Gff::GffError, "While unpacking #{path}: " +
|
182
|
+
"#{unpack_struct_element} is not a field-naime, dummy." unless
|
183
|
+
unpack_struct_element.is_a?(String)
|
184
|
+
|
185
|
+
unpack_struct_element_type =
|
186
|
+
NWN::Gff.get_struct_default_type(path, unpack_struct_element)
|
187
|
+
|
188
|
+
unpack_struct_element_type
|
189
|
+
}.freeze
|
190
|
+
|
191
|
+
last_struct_id = -1
|
192
|
+
element['value'].map! {|kv|
|
193
|
+
st = {}
|
194
|
+
st.extend(NWN::Gff::Struct)
|
195
|
+
st.struct_id = case unpack_struct_element_struct_id
|
196
|
+
when 'iterative'
|
197
|
+
last_struct_id += 1
|
198
|
+
when 'inline'
|
199
|
+
kv.shift
|
200
|
+
when Fixnum
|
201
|
+
unpack_struct_element_struct_id
|
202
|
+
else
|
203
|
+
kv['__struct_id'] || raise(NWN::Gff::GffError,
|
204
|
+
"dont know how to handle struct_id #{unpack_struct_element_struct_id} at #{label} = #{kv.inspect}")
|
205
|
+
end
|
206
|
+
st.data_type = path
|
207
|
+
|
208
|
+
unpack_struct_elements.each_with_index {|use, index|
|
209
|
+
case kv
|
210
|
+
when Hash
|
211
|
+
if !kv[use]
|
212
|
+
uset, usev = unpack_struct_element_types[index],
|
213
|
+
NWN::Gff.get_struct_default_value(path, use)
|
214
|
+
else
|
215
|
+
uset = kv[use]['type']
|
216
|
+
usev = kv[use]['value']
|
217
|
+
end
|
218
|
+
when Array
|
219
|
+
uset = unpack_struct_element_types[index]
|
220
|
+
usev = kv[index]
|
221
|
+
if usev.is_a?(Hash)
|
222
|
+
uset, usev = usev['type'], usev['value']
|
223
|
+
end
|
224
|
+
when String, Numeric, Symbol
|
225
|
+
uset = unpack_struct_element_types[index]
|
226
|
+
usev = kv
|
227
|
+
else
|
228
|
+
raise "Dont know how to unpack list-struct element: #{kv.inspect}"
|
229
|
+
end
|
230
|
+
|
231
|
+
raise NWN::Gff::GffError, "Cannot infer type of #{path}/#{use} (got: #{uset.inspect})" unless
|
232
|
+
uset && NWN::Gff::Types.index(uset)
|
233
|
+
raise NWN::Gff::GffError, "Cannot get or infer value of #{path}/#{use} (got: #{usev.inspect})" unless
|
234
|
+
usev && (usev.is_a?(String) || usev.is_a?(Numeric) || usev.is_a?(Symbol))
|
235
|
+
|
236
|
+
# Figure out the default value (which we'll need to re-add?) if
|
237
|
+
# it was filtered while outputting.
|
238
|
+
#kv[index] = NWN::Gff.get_struct_default_value(path, use) if !kv[index]
|
239
|
+
#raise NWN::Gff::GffError, "field present in compacted struct-list, and cant " +
|
240
|
+
# "infer default value at #{use}/#{index} (#{kv.inspect})" if !kv[index]
|
241
|
+
|
242
|
+
el = st[use] = {
|
243
|
+
'label' => use,
|
244
|
+
'type' => uset,
|
245
|
+
'value' => usev
|
246
|
+
}
|
247
|
+
el.extend(NWN::Gff::Field)
|
248
|
+
el.extend_meta_classes
|
249
|
+
el.parent = st
|
250
|
+
}
|
251
|
+
st
|
252
|
+
}
|
253
|
+
end
|
254
|
+
element
|
255
|
+
|
256
|
+
when Numeric, String # compacted scalar
|
257
|
+
{'value' => element}
|
258
|
+
|
259
|
+
else
|
260
|
+
fail "Don't know how to un-compact /#{label}: #{element.inspect}, klass #{element.class.to_s}"
|
261
|
+
end
|
262
|
+
|
263
|
+
element.extend(NWN::Gff::Field)
|
264
|
+
element.field_label = label
|
265
|
+
element.parent = struct
|
266
|
+
element.str_ref ||= NWN::Gff::Field::DEFAULT_STR_REF if element.respond_to?('str_ref=')
|
267
|
+
|
268
|
+
infer_field_type = NWN::Gff.get_struct_default_type(struct.path, element.field_label)
|
269
|
+
|
270
|
+
if element.field_type && infer_field_type && infer_field_type != element.field_type
|
271
|
+
raise NWN::Gff::GffError, "/#{label} has field_type #{element.field_type.inspect}, but infer data says #{infer_field_type.inspect}."
|
272
|
+
|
273
|
+
elsif element.field_type.nil? && infer_field_type.nil?
|
274
|
+
raise NWN::Gff::GffError, "Cannot infer implicit type for /#{label} while parsing struct-id #{struct.struct_id}."
|
275
|
+
|
276
|
+
elsif element.field_type.nil? && infer_field_type
|
277
|
+
element.field_type = infer_field_type
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
element.extend_meta_classes
|
282
|
+
|
283
|
+
struct[label] = element.taint
|
284
|
+
}
|
17
285
|
|
286
|
+
NWN::Gff.__yaml_postparse nil, struct if struct.data_type
|
287
|
+
struct
|
288
|
+
}
|