55import java .util .List ;
66
77import com .etheller .warsmash .util .ParseUtils ;
8+ import com .etheller .warsmash .util .War3ID ;
89import com .google .common .io .LittleEndianDataInputStream ;
910import com .google .common .io .LittleEndianDataOutputStream ;
1011
1112/**
1213 * war3map.w3i - the general map information file.
14+ * https://github.com/ChiefOfGxBxL/WC3MapSpecification/blob/master/Info/0-33.md
1315 */
1416public class War3MapW3i {
1517 private int version ;
@@ -33,7 +35,7 @@ public class War3MapW3i {
3335 private String loadingScreenText ;
3436 private String loadingScreenTitle ;
3537 private String loadingScreenSubtitle ;
36- private int gameDataSet ;
38+ private int gameDataSet = 0 ;
3739 private String prologueScreenModel ;
3840 private String prologueScreenText ;
3941 private String prologueScreenTitle ;
@@ -42,13 +44,16 @@ public class War3MapW3i {
4244 private final float [] fogHeight = new float [2 ];
4345 private float fogDensity ;
4446 private final short [] fogColor = new short [4 ];
45- private int globalWeather ;
47+ private War3ID globalWeather ;
4648 private String soundEnvironment ;
4749 private char lightEnvironmentTileset ;
4850 private final short [] waterVertexColor = new short [4 ];
49- private final short [] unknown2ProbablyLua = new short [4 ];
50- private long supportedModes ;
51- private long gameDataVersion ;
51+ private int scriptLanguage = 0 ; // 0 = JASS, 1 = Lua
52+ private long supportedModes ; // 1=SD, 2=HD, 3=SD+HD
53+ private long gameDataVersion = 0 ; // 0=ROC, 1=TFT
54+ private int forceDefaultCameraZoom ;
55+ private int forceMaxCameraZoom ;
56+ private int forceMinCameraZoom ;
5257 private final List <Player > players = new ArrayList <>();
5358 private final List <Force > forces = new ArrayList <>();
5459 private final List <UpgradeAvailabilityChange > upgradeAvailabilityChanges = new ArrayList <>();
@@ -83,45 +88,78 @@ private void load(final LittleEndianDataInputStream stream) throws IOException {
8388 ParseUtils .readInt32Array (stream , this .playableSize );
8489 this .flags = ParseUtils .readUInt32 (stream );
8590 this .tileset = (char ) stream .read ();
86- this .campaignBackground = stream .readInt ();
8791
88- if (this .version > 24 ) {
92+ if (this .version >= 17 ) {
93+ this .campaignBackground = stream .readInt ();
94+ }
95+
96+ if (this .version >= 10 && this .version != 18 && this .version != 19 ) {
8997 this .loadingScreenModel = ParseUtils .readUntilNull (stream );
9098 }
9199
92- this .loadingScreenText = ParseUtils .readUntilNull (stream );
93- this .loadingScreenTitle = ParseUtils .readUntilNull (stream );
94- this .loadingScreenSubtitle = ParseUtils .readUntilNull (stream );
95- this .gameDataSet = stream .readInt ();
100+ if (this .version >= 10 ) {
101+ this .loadingScreenText = ParseUtils .readUntilNull (stream );
102+ }
96103
97- if (this .version > 24 ) {
104+ if (this .version >= 11 ) {
105+ this .loadingScreenTitle = ParseUtils .readUntilNull (stream );
106+ this .loadingScreenSubtitle = ParseUtils .readUntilNull (stream );
107+ }
108+
109+ if (this .version >= 17 ) {
110+ this .gameDataSet = stream .readInt ();
111+ }
112+
113+ if (this .version >= 13 && this .version != 18 && this .version != 19 ) {
98114 this .prologueScreenModel = ParseUtils .readUntilNull (stream );
99115 }
100116
101- this .prologueScreenText = ParseUtils .readUntilNull (stream );
102- this .prologueScreenTitle = ParseUtils .readUntilNull (stream );
103- this .prologueScreenSubtitle = ParseUtils .readUntilNull (stream );
117+ if (this .version >= 13 ) {
118+ this .prologueScreenText = ParseUtils .readUntilNull (stream );
119+ this .prologueScreenTitle = ParseUtils .readUntilNull (stream );
120+ this .prologueScreenSubtitle = ParseUtils .readUntilNull (stream );
121+ }
104122
105- if (this .version > 24 ) {
123+ if (this .version >= 19 ) {
106124 this .useTerrainFog = stream .readInt ();
107125 ParseUtils .readFloatArray (stream , this .fogHeight );
108126 this .fogDensity = stream .readFloat ();
109127 ParseUtils .readUInt8Array (stream , this .fogColor );
110- this .globalWeather = stream .readInt (); // TODO probably war3id, right?
128+ }
129+
130+ if (this .version >= 21 ) {
131+ this .globalWeather = ParseUtils .readWar3ID (stream );
132+ }
133+
134+ if (this .version >= 22 ) {
111135 this .soundEnvironment = ParseUtils .readUntilNull (stream );
136+ }
137+
138+ if (this .version >= 23 ) {
112139 this .lightEnvironmentTileset = (char ) stream .read ();
140+ }
141+
142+ if (this .version >= 25 ) {
113143 ParseUtils .readUInt8Array (stream , this .waterVertexColor );
114144 }
115145
116- if (this .version > 27 ) {
117- ParseUtils . readUInt8Array ( stream , this . unknown2ProbablyLua );
146+ if (this .version >= 28 ) {
147+ this . scriptLanguage = stream . readInt ( );
118148 }
119- if (this .version > 30 ) {
149+ if (this .version >= 29 ) {
120150 this .supportedModes = ParseUtils .readUInt32 (stream );
151+ }
152+ if (this .version >= 30 ) {
121153 this .gameDataVersion = ParseUtils .readUInt32 (stream );
122154 }
123- else {
124- this .gameDataVersion = -1 ; // indicate to the outside that this was unspecified
155+
156+ if (this .version >= 32 ) {
157+ this .forceDefaultCameraZoom = stream .readInt ();
158+ this .forceMaxCameraZoom = stream .readInt ();
159+ }
160+
161+ if (this .version >= 33 ) {
162+ this .forceMinCameraZoom = stream .readInt ();
125163 }
126164
127165 for (int i = 0 , l = stream .readInt (); i < l ; i ++) {
@@ -144,6 +182,7 @@ private void load(final LittleEndianDataInputStream stream) throws IOException {
144182 // some kind of really stupid protected map???
145183 return ;
146184 }
185+
147186 if (stream .available () > 0 ) {
148187 for (int i = 0 , l = stream .readInt (); i < l ; i ++) {
149188 final UpgradeAvailabilityChange upgradeAvailabilityChange = new UpgradeAvailabilityChange ();
@@ -208,49 +247,86 @@ public void save(final LittleEndianDataOutputStream stream) throws IOException {
208247 ParseUtils .writeInt32Array (stream , this .playableSize );
209248 ParseUtils .writeUInt32 (stream , this .flags );
210249 stream .write ((byte ) this .tileset );
211- stream .writeInt (this .campaignBackground );
212250
213- if (this .version > 24 ) {
251+ if (this .version >= 17 ) {
252+ stream .writeInt (this .campaignBackground );
253+ }
254+
255+ if (this .version >= 10 && this .version != 18 && this .version != 19 ) {
214256 ParseUtils .writeWithNullTerminator (stream , this .loadingScreenModel );
215257 }
216258
217- ParseUtils .writeWithNullTerminator (stream , this .loadingScreenText );
218- ParseUtils .writeWithNullTerminator (stream , this .loadingScreenTitle );
219- ParseUtils .writeWithNullTerminator (stream , this .loadingScreenSubtitle );
220- stream .writeInt (this .gameDataSet );
259+ if (this .version >= 10 ) {
260+ ParseUtils .writeWithNullTerminator (stream , this .loadingScreenText );
261+ }
221262
222- if (this .version > 24 ) {
263+ if (this .version >= 11 ) {
264+ ParseUtils .writeWithNullTerminator (stream , this .loadingScreenTitle );
265+ ParseUtils .writeWithNullTerminator (stream , this .loadingScreenSubtitle );
266+ }
267+
268+ if (this .version >= 17 ) {
269+ stream .writeInt (this .gameDataSet );
270+ }
271+
272+ if (this .version >= 13 && this .version != 18 && this .version != 19 ) {
223273 ParseUtils .writeWithNullTerminator (stream , this .prologueScreenModel );
224274 }
225275
226- ParseUtils .writeWithNullTerminator (stream , this .prologueScreenText );
227- ParseUtils .writeWithNullTerminator (stream , this .prologueScreenTitle );
228- ParseUtils .writeWithNullTerminator (stream , this .prologueScreenSubtitle );
276+ if (this .version >= 13 ) {
277+ ParseUtils .writeWithNullTerminator (stream , this .prologueScreenText );
278+ ParseUtils .writeWithNullTerminator (stream , this .prologueScreenTitle );
279+ ParseUtils .writeWithNullTerminator (stream , this .prologueScreenSubtitle );
280+ }
229281
230- if (this .version > 24 ) {
282+ if (this .version >= 19 ) {
231283 stream .writeInt (this .useTerrainFog );
232284 ParseUtils .writeFloatArray (stream , this .fogHeight );
233285 stream .writeFloat (this .fogDensity );
234286 ParseUtils .writeUInt8Array (stream , this .fogColor );
235- stream .writeInt (this .globalWeather ); // TODO War3ID???
287+ }
288+
289+ if (this .version >= 21 ) {
290+ ParseUtils .writeWar3ID (stream , this .globalWeather );
291+ }
292+
293+ if (this .version >= 22 ) {
236294 ParseUtils .writeWithNullTerminator (stream , this .soundEnvironment );
295+ }
296+
297+ if (this .version >= 23 ) {
237298 stream .write ((byte ) this .lightEnvironmentTileset );
299+ }
300+
301+ if (this .version >= 25 ) {
238302 ParseUtils .writeUInt8Array (stream , this .waterVertexColor );
239303 }
240304
241- if (this .version > 27 ) {
242- ParseUtils .writeUInt8Array (stream , this .unknown2ProbablyLua );
305+ if (this .version >= 28 ) {
306+ ParseUtils .writeUInt32 (stream , this .scriptLanguage );
243307 }
244308
245- if (this .version > 30 ) {
309+ if (this .version >= 29 ) {
246310 ParseUtils .writeUInt32 (stream , this .supportedModes );
311+ }
312+
313+ if (this .version >= 30 ) {
247314 ParseUtils .writeUInt32 (stream , this .gameDataVersion );
248315 }
249316
317+ if (this .version >= 32 ) {
318+ ParseUtils .writeUInt32 (stream , this .forceDefaultCameraZoom );
319+ ParseUtils .writeUInt32 (stream , this .forceMaxCameraZoom );
320+ }
321+
322+ if (this .version >= 33 ) {
323+ ParseUtils .writeUInt32 (stream , this .forceMinCameraZoom );
324+ }
325+
250326 ParseUtils .writeUInt32 (stream , this .players .size ());
251327
252328 for (final Player player : this .players ) {
253- player .save (stream );
329+ player .save (stream , this . version );
254330 }
255331
256332 ParseUtils .writeUInt32 (stream , this .forces .size ());
@@ -284,41 +360,6 @@ public void save(final LittleEndianDataOutputStream stream) throws IOException {
284360 table .save (stream );
285361 }
286362 }
287-
288- }
289-
290- public int getByteLength () {
291- int size = 111 + this .name .length () + this .author .length () + this .description .length ()
292- + this .recommendedPlayers .length () + this .loadingScreenText .length () + this .loadingScreenTitle .length ()
293- + this .loadingScreenSubtitle .length () + this .prologueScreenText .length ()
294- + this .prologueScreenTitle .length () + this .prologueScreenSubtitle .length ();
295-
296- for (final Player player : this .players ) {
297- size += player .getByteLength ();
298- }
299-
300- for (final Force force : this .forces ) {
301- size += force .getByteLength ();
302- }
303-
304- size += this .upgradeAvailabilityChanges .size () * 16 ;
305-
306- size += this .techAvailabilityChanges .size () * 8 ;
307-
308- for (final RandomUnitTable table : this .randomUnitTables ) {
309- size += table .getByteLength ();
310- }
311-
312- if (this .version > 24 ) {
313- size += 36 + this .loadingScreenModel .length () + this .prologueScreenModel .length ()
314- + this .soundEnvironment .length ();
315-
316- for (final RandomItemTable table : this .randomItemTables ) {
317- size += table .getByteLength ();
318- }
319- }
320-
321- return size ;
322363 }
323364
324365 public int getVersion () {
@@ -429,7 +470,7 @@ public short[] getFogColor() {
429470 return this .fogColor ;
430471 }
431472
432- public int getGlobalWeather () {
473+ public War3ID getGlobalWeather () {
433474 return this .globalWeather ;
434475 }
435476
@@ -445,8 +486,8 @@ public short[] getWaterVertexColor() {
445486 return this .waterVertexColor ;
446487 }
447488
448- public short [] getUnknown2 () {
449- return this .unknown2ProbablyLua ;
489+ public int getScriptLanguage () {
490+ return this .scriptLanguage ;
450491 }
451492
452493 public long getSupportedModes () {
0 commit comments