@@ -10,93 +10,195 @@ def generate_build_data(balance_data_path):
10
10
abilities = {}
11
11
units = {}
12
12
13
+ ability_lookup = {}
14
+
13
15
for xml_file_path in glob .glob (os .path .join (balance_data_path , "*.xml" )):
14
16
tree = xml .etree .ElementTree .parse (xml_file_path )
15
17
root = tree .getroot ()
16
18
17
19
for ability_element in root .findall ("./abilities/ability" ):
18
- if ability_element .get ("index" ) and ability_element .get ("id" ):
19
- abilities [ability_element .get ("index" )] = ability_element .get ("id" )
20
+ ability_name = ability_element .get ("id" )
21
+ if ability_element .get ("index" ) and ability_name :
22
+ abilities [ability_element .get ("index" )] = ability_name
23
+
24
+ if ability_name not in ability_lookup :
25
+ ability_lookup [ability_name ] = []
26
+
27
+ for command_element in ability_element .findall ("./command" ):
28
+ command_id = command_element .get ("id" )
29
+ command_index_str = command_element .get ("index" )
30
+
31
+ if command_id and command_index_str :
32
+ command_index = int (command_index_str )
20
33
21
- unit_name = root .get ("id" )
34
+ # Pad potential gaps in command indices with empty strings
35
+ while len (ability_lookup [ability_name ]) <= command_index :
36
+ ability_lookup [ability_name ].append ("" )
37
+
38
+ command_name = command_id if command_id != "Execute" else ability_name
39
+ ability_lookup [ability_name ][command_index ] = command_name
40
+
41
+ unit_id = root .get ("id" )
22
42
23
43
meta_element = root .find ("./meta" )
24
44
25
- if unit_name and meta_element is not None and meta_element .get ("index" ):
26
- units [meta_element .get ("index" )] = unit_name
45
+ if unit_id and meta_element is not None and meta_element .get ("index" ):
46
+ units [meta_element .get ("index" )] = unit_id
27
47
28
- build_unit_element = root .find ("./builds/unit" )
29
- if build_unit_element is not None :
30
- build_ability_index = build_unit_element .get ("ability" )
48
+ build_unit_elements = root .findall ("./builds/unit" )
49
+ if build_unit_elements :
50
+ build_ability_index = build_unit_elements [ 0 ] .get ("ability" )
31
51
32
- if unit_name == "SCV" :
52
+ if unit_id == "SCV" :
33
53
build_ability_name = "TerranBuild"
34
- elif unit_name == "Probe" :
54
+ elif unit_id == "Probe" :
35
55
build_ability_name = "ProtossBuild"
36
- elif unit_name == "Drone" :
56
+ elif unit_id == "Drone" :
37
57
build_ability_name = "ZergBuild"
38
58
else :
39
- build_ability_name = "{}Build" .format (unit_name )
59
+ build_ability_name = "{}Build" .format (unit_id )
40
60
41
61
if build_ability_index :
42
62
abilities [build_ability_index ] = build_ability_name
43
63
64
+ if build_ability_name not in ability_lookup :
65
+ ability_lookup [build_ability_name ] = []
66
+
67
+ for element in build_unit_elements :
68
+ built_unit_id = element .get ("id" )
69
+ command_index_str = element .get ("index" )
70
+
71
+ if built_unit_id and command_index_str :
72
+ command_index = int (command_index_str )
73
+
74
+ # Pad potential gaps in command indices with empty strings
75
+ while len (ability_lookup [build_ability_name ]) <= command_index :
76
+ ability_lookup [build_ability_name ].append ("" )
77
+
78
+ build_command_name = "Build{}" .format (built_unit_id )
79
+ ability_lookup [build_ability_name ][command_index ] = build_command_name
80
+
44
81
train_unit_elements = root .findall ("./trains/unit" )
45
82
if train_unit_elements :
46
83
train_ability_index = train_unit_elements [0 ].get ("ability" )
47
84
48
85
if train_ability_index :
49
- abilities [train_ability_index ] = "{}Train" .format (unit_name )
86
+ train_ability_name = "{}Train" .format (unit_id )
87
+ abilities [train_ability_index ] = train_ability_name
88
+
89
+ if train_ability_name not in ability_lookup :
90
+ ability_lookup [train_ability_name ] = []
50
91
51
- # Handle cases where a unit can train other units using multiple ability indices.
52
- # The Nexus is currently the only known example.
53
- for element in train_unit_elements [1 :]:
92
+ for element in train_unit_elements :
54
93
element_ability_index = element .get ("ability" )
55
94
trained_unit_name = element .get ("id" )
56
95
57
- if element_ability_index != train_ability_index and trained_unit_name :
58
- train_ability_index = element_ability_index
96
+ if trained_unit_name :
97
+ # Handle cases where a unit can train other units using multiple ability indices.
98
+ # The Nexus is currently the only known example.
99
+ if element_ability_index != train_ability_index :
100
+ train_ability_index = element_ability_index
101
+
102
+ train_ability_name = "{}Train{}" .format (unit_id , trained_unit_name )
103
+ abilities [train_ability_index ] = train_ability_name
104
+
105
+ if train_ability_name not in ability_lookup :
106
+ ability_lookup [train_ability_name ] = []
107
+
108
+ command_index_str = element .get ("index" )
109
+
110
+ if command_index_str :
111
+ command_index = int (command_index_str )
59
112
60
- abilities [train_ability_index ] = "{}Train{}" .format (unit_name , trained_unit_name )
113
+ # Pad potential gaps in command indices with empty strings
114
+ while len (ability_lookup [train_ability_name ]) <= command_index :
115
+ ability_lookup [train_ability_name ].append ("" )
61
116
62
- research_upgrade_element = root .find ("./researches/upgrade" )
63
- if research_upgrade_element is not None :
64
- research_ability_index = research_upgrade_element .get ("ability" )
65
- research_ability_name = "{}Research" .format (unit_name )
117
+ ability_lookup [train_ability_name ][command_index ] = train_ability_name
118
+ else :
119
+ command_index_str = element .get ("index" )
120
+
121
+ if command_index_str :
122
+ command_index = int (command_index_str )
123
+
124
+ # Pad potential gaps in command indices with empty strings
125
+ while len (ability_lookup [train_ability_name ]) <= command_index :
126
+ ability_lookup [train_ability_name ].append ("" )
127
+
128
+ train_command_name = "Train{}" .format (trained_unit_name )
129
+ ability_lookup [train_ability_name ][command_index ] = train_command_name
130
+
131
+ research_upgrade_elements = root .findall ("./researches/upgrade" )
132
+ if research_upgrade_elements :
133
+ research_ability_index = research_upgrade_elements [0 ].get ("ability" )
134
+ research_ability_name = "{}Research" .format (unit_id )
66
135
67
136
abilities [research_ability_index ] = research_ability_name
68
137
69
- sorted_abilities = collections .OrderedDict (sorted (abilities .items (), key = lambda x : int (x [0 ])))
138
+ if research_ability_name not in ability_lookup :
139
+ ability_lookup [research_ability_name ] = []
140
+
141
+ for element in research_upgrade_elements :
142
+ researched_upgrade_id = element .get ("id" )
143
+ command_index_str = element .get ("index" )
144
+
145
+ if researched_upgrade_id and command_index_str :
146
+ command_index = int (command_index_str )
147
+
148
+ # Pad potential gaps in command indices with empty strings
149
+ while len (ability_lookup [research_ability_name ]) <= command_index :
150
+ ability_lookup [research_ability_name ].append ("" )
151
+
152
+ research_command_name = "Research{}" .format (researched_upgrade_id )
153
+ ability_lookup [research_ability_name ][command_index ] = research_command_name
154
+
70
155
sorted_units = collections .OrderedDict (sorted (units .items (), key = lambda x : int (x [0 ])))
156
+ sorted_abilities = collections .OrderedDict (sorted (abilities .items (), key = lambda x : int (x [0 ])))
157
+
158
+ unit_lookup = [[unit_name , unit_name ] for _ , unit_name in sorted_units .items ()]
71
159
72
- return sorted_units , sorted_abilities
160
+ return sorted_units , sorted_abilities , unit_lookup , ability_lookup
73
161
74
162
75
163
def main ():
76
- parser = argparse .ArgumentParser (description = 'Generate [BUILD_VERSION]_abilities.csv and [BUILD_VERSION]_units.csv'
77
- ' files from exported balance data.' )
164
+ parser = argparse .ArgumentParser (description = 'Generate [BUILD_VERSION]_abilities.csv, [BUILD_VERSION]_units.csv,'
165
+ ' ability_lookup.csv and unit_lookup.csv files from exported balance'
166
+ ' data.' )
78
167
parser .add_argument ('build_version' , metavar = 'BUILD_VERSION' , type = int ,
79
168
help = 'the build version of the balance data export' )
80
169
parser .add_argument ('balance_data_path' , metavar = 'BALANCE_DATA_PATH' , type = str ,
81
170
help = 'the path to the balance data export' )
82
171
83
172
args = parser .parse_args ()
84
173
85
- units , abilities = generate_build_data (args .balance_data_path )
174
+ units , abilities , unit_lookup , ability_lookup = generate_build_data (args .balance_data_path )
86
175
87
176
if not units or not abilities :
177
+ parser .print_help ()
178
+ print ("\n " )
179
+
88
180
raise ValueError ("No balance data found at provided balance data path." )
89
181
90
182
with open ('{}_units.csv' .format (args .build_version ), 'w' , newline = '' ) as csvfile :
91
- csv_writer = csv .writer (csvfile , delimiter = ',' )
183
+ csv_writer = csv .writer (csvfile , delimiter = ',' , lineterminator = os . linesep )
92
184
for unit_index , unit_name in units .items ():
93
185
csv_writer .writerow ([unit_index , unit_name ])
94
186
95
187
with open ('{}_abilities.csv' .format (args .build_version ), 'w' , newline = '' ) as csvfile :
96
- csv_writer = csv .writer (csvfile , delimiter = ',' )
188
+ csv_writer = csv .writer (csvfile , delimiter = ',' , lineterminator = os . linesep )
97
189
for ability_index , ability_name in abilities .items ():
98
190
csv_writer .writerow ([ability_index , ability_name ])
99
191
192
+ with open ('unit_lookup.csv' .format (args .build_version ), 'w' , newline = '' ) as csvfile :
193
+ csv_writer = csv .writer (csvfile , delimiter = ',' , lineterminator = os .linesep )
194
+ for lookup_entry in unit_lookup :
195
+ csv_writer .writerow (lookup_entry )
196
+
197
+ with open ('ability_lookup.csv' .format (args .build_version ), 'w' , newline = '' ) as csvfile :
198
+ csv_writer = csv .writer (csvfile , delimiter = ',' , lineterminator = os .linesep )
199
+ for ability_name , commands in ability_lookup .items ():
200
+ csv_writer .writerow ([ability_name ] + commands )
201
+
100
202
101
203
if __name__ == "__main__" :
102
204
main ()
0 commit comments