wc3maptranslator 3.0.3 → 4.0.1

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.
Files changed (100) hide show
  1. package/.codeclimate.yml +0 -1
  2. package/.eslintignore +0 -1
  3. package/.github/workflows/codeql-analysis.yml +54 -0
  4. package/.nycrc +1 -2
  5. package/.travis.yml +1 -2
  6. package/CHANGELOG.md +78 -0
  7. package/LICENSE.md +23 -0
  8. package/README.md +68 -75
  9. package/index.js +11 -15
  10. package/index.ts +12 -30
  11. package/lib/CommonInterfaces.ts +22 -0
  12. package/lib/HexBuffer.ts +11 -14
  13. package/lib/W3Buffer.ts +7 -3
  14. package/lib/translators/CamerasTranslator.ts +36 -41
  15. package/lib/translators/DoodadsTranslator.ts +57 -55
  16. package/lib/translators/ImportsTranslator.ts +29 -31
  17. package/lib/translators/InfoTranslator.ts +252 -204
  18. package/lib/translators/{object/ObjectsTranslator.ts → ObjectsTranslator.ts} +84 -82
  19. package/lib/translators/RegionsTranslator.ts +40 -58
  20. package/lib/translators/SoundsTranslator.ts +112 -96
  21. package/lib/translators/StringsTranslator.ts +23 -49
  22. package/lib/translators/TerrainTranslator.ts +166 -97
  23. package/lib/translators/UnitsTranslator.ts +98 -97
  24. package/lib/translators/index.ts +0 -1
  25. package/package.json +23 -16
  26. package/test/.mocharc.json +4 -0
  27. package/test/HexBufferTest.ts +11 -15
  28. package/test/TranslatorReversion.ts +104 -115
  29. package/test/W3BufferTest.ts +19 -13
  30. package/test/data/cameras.json +16 -0
  31. package/test/data/doodads.json +2730 -0
  32. package/test/data/imports.json +386 -0
  33. package/test/data/info.json +250 -0
  34. package/test/data/obj-abilities.json +4892 -0
  35. package/test/data/obj-buffs.json +38 -0
  36. package/test/data/obj-destructables.json +31 -0
  37. package/test/data/obj-doodads.json +38 -0
  38. package/test/data/obj-items.json +31 -0
  39. package/test/data/obj-units.json +40 -0
  40. package/test/data/obj-upgrades.json +38 -0
  41. package/test/data/regions.json +206 -0
  42. package/test/data/sounds.json +50 -0
  43. package/test/data/strings.json +115 -0
  44. package/test/data/terrain.json +1 -0
  45. package/test/data/units.json +452 -0
  46. package/test/data/war3map.doo +0 -0
  47. package/test/data/war3map.imp +0 -0
  48. package/test/data/war3map.j +3442 -0
  49. package/test/data/war3map.shd +0 -0
  50. package/test/data/war3map.w3a +0 -0
  51. package/test/data/war3map.w3b +0 -0
  52. package/test/data/war3map.w3c +0 -0
  53. package/test/data/war3map.w3d +0 -0
  54. package/test/data/war3map.w3e +0 -0
  55. package/test/data/war3map.w3h +0 -0
  56. package/test/data/war3map.w3i +0 -0
  57. package/test/data/war3map.w3q +0 -0
  58. package/test/data/war3map.w3r +0 -0
  59. package/test/data/war3map.w3s +0 -0
  60. package/test/data/war3map.w3t +0 -0
  61. package/test/data/war3map.w3u +0 -0
  62. package/test/data/war3map.wts +631 -0
  63. package/test/data/war3mapUnits.doo +0 -0
  64. package/examples/index.js +0 -123
  65. package/examples/index.ts +0 -134
  66. package/examples/json/cameras.json +0 -16
  67. package/examples/json/doodads.json +0 -28499
  68. package/examples/json/imports.json +0 -10
  69. package/examples/json/info.json +0 -111
  70. package/examples/json/object-abilities.json +0 -31
  71. package/examples/json/object-buffs.json +0 -24
  72. package/examples/json/object-destructables.json +0 -31
  73. package/examples/json/object-doodads.json +0 -24
  74. package/examples/json/object-items.json +0 -45
  75. package/examples/json/object-units.json +0 -45
  76. package/examples/json/object-upgrades.json +0 -31
  77. package/examples/json/regions.json +0 -36
  78. package/examples/json/sounds.json +0 -46
  79. package/examples/json/strings.json +0 -83
  80. package/examples/json/terrain.json +0 -46633
  81. package/examples/json/units.json +0 -332
  82. package/examples/package.json +0 -17
  83. package/examples/tsconfig.json +0 -27
  84. package/examples/war/war3map.doo +0 -0
  85. package/examples/war/war3map.imp +0 -0
  86. package/examples/war/war3map.w3a +0 -0
  87. package/examples/war/war3map.w3b +0 -0
  88. package/examples/war/war3map.w3c +0 -0
  89. package/examples/war/war3map.w3d +0 -0
  90. package/examples/war/war3map.w3e +0 -0
  91. package/examples/war/war3map.w3h +0 -0
  92. package/examples/war/war3map.w3i +0 -0
  93. package/examples/war/war3map.w3q +0 -0
  94. package/examples/war/war3map.w3r +0 -0
  95. package/examples/war/war3map.w3s +0 -0
  96. package/examples/war/war3map.w3t +0 -0
  97. package/examples/war/war3map.w3u +0 -0
  98. package/examples/war/war3map.wts +0 -99
  99. package/lib/translators/index.js +0 -16
  100. package/test/mocha.opts +0 -4
@@ -1,5 +1,6 @@
1
1
  import { HexBuffer } from '../HexBuffer';
2
2
  import { W3Buffer } from '../W3Buffer';
3
+ import { WarResult, JsonResult } from '../CommonInterfaces'
3
4
 
4
5
  interface Map {
5
6
  name: string;
@@ -11,28 +12,38 @@ interface Map {
11
12
  mainTileType: string;
12
13
  }
13
14
 
15
+ interface GameVersion {
16
+ major: number;
17
+ minor: number;
18
+ patch: number;
19
+ build: number;
20
+ }
21
+
14
22
  interface Camera {
15
23
  bounds: number[];
16
24
  complements: number[];
17
25
  }
18
26
 
19
27
  interface MapFlags {
20
- hideMinimapInPreview: boolean; // 0x0001: 1=hide minimap in preview screens
21
- modifyAllyPriorities: boolean; // 0x0002: 1=modify ally priorities
22
- isMeleeMap: boolean; // 0x0004: 1=melee map
23
- unknown1: boolean; // 0x0008: 1=playable map size was large and has never been reduced to medium (?)
28
+ hideMinimapInPreview: boolean; // 0x0001: 1=hide minimap in preview screens
29
+ modifyAllyPriorities: boolean; // 0x0002: 1=modify ally priorities
30
+ isMeleeMap: boolean; // 0x0004: 1=melee map
31
+ // 0x0008: 1=playable map size was large and has never been reduced to medium (?)
24
32
  maskedPartiallyVisible: boolean; // 0x0010: 1=masked area are partially visible
25
- fixedPlayerSetting: boolean; // 0x0020: 1=fixed player setting for custom forces
26
- useCustomForces: boolean; // 0x0040: 1=use custom forces
27
- useCustomTechtree: boolean; // 0x0080: 1=use custom techtree
28
- useCustomAbilities: boolean; // 0x0100: 1=use custom abilities
29
- useCustomUpgrades: boolean; // 0x0200: 1=use custom upgrades
30
- unknown2: boolean; // 0x0400: 1=map properties menu opened at least once since map creation (?)
33
+ fixedPlayerSetting: boolean; // 0x0020: 1=fixed player setting for custom forces
34
+ useCustomForces: boolean; // 0x0040: 1=use custom forces
35
+ useCustomTechtree: boolean; // 0x0080: 1=use custom techtree
36
+ useCustomAbilities: boolean; // 0x0100: 1=use custom abilities
37
+ useCustomUpgrades: boolean; // 0x0200: 1=use custom upgrades
38
+ // 0x0400: 1=map properties menu opened at least once since map creation (?)
31
39
  waterWavesOnCliffShores: boolean; // 0x0800: 1=show water waves on cliff shores
32
40
  waterWavesOnRollingShores: boolean; // 0x1000: 1=show water waves on rolling shores
33
- unknown3: boolean; // 0x2000: 1=unknown
34
- unknown4: boolean; // 0x4000: 1=unknown
35
- unknown5: boolean; // 0x8000: 1=unknown
41
+ // 0x2000: 1=unknown
42
+ // 0x4000: 1=unknown
43
+ useItemClassificationSystem: boolean; // 0x8000: 1=use item classification system
44
+ enableWaterTinting: boolean; // 0x10000
45
+ useAccurateProbabilityForCalculations: boolean; // 0x20000
46
+ useCustomAbilitySkins: boolean; // 0x40000
36
47
  }
37
48
 
38
49
  interface LoadingScreen {
@@ -43,8 +54,14 @@ interface LoadingScreen {
43
54
  subtitle: string;
44
55
  }
45
56
 
57
+ enum FogType {
58
+ Linear = 0,
59
+ Exponential1 = 1,
60
+ Exponential2 = 2
61
+ }
62
+
46
63
  interface Fog {
47
- type: number;
64
+ type: FogType;
48
65
  startHeight: number;
49
66
  endHeight: number;
50
67
  density: number;
@@ -65,7 +82,10 @@ interface Prologue {
65
82
 
66
83
  interface Info {
67
84
  saves: number;
85
+ gameVersion: GameVersion;
68
86
  editorVersion: number;
87
+ scriptLanguage: ScriptLanguage;
88
+ supportedModes: SupportedModes;
69
89
  map: Map;
70
90
  camera: Camera;
71
91
  prologue: Prologue;
@@ -85,26 +105,10 @@ interface PlayerStartingPosition {
85
105
  fixed: boolean;
86
106
  }
87
107
 
88
- enum PlayerType {
89
- // 1=Human, 2=Computer, 3=Neutral, 4=Rescuable
90
- 'Human' = 1,
91
- 'Computer',
92
- 'Neutral',
93
- 'Rescuable'
94
- }
95
-
96
- enum PlayerRace {
97
- // 1=Human, 2=Orc, 3=Undead, 4=Night Elf
98
- 'Human' = 1,
99
- 'Orc',
100
- 'Undead',
101
- 'NightElf'
102
- }
103
-
104
108
  interface Player {
105
109
  playerNum: number;
106
- type: PlayerType;
107
- race: PlayerRace;
110
+ type: number; // 1=Human, 2=Computer, 3=Neutral, 4=Rescuable
111
+ race: number; // 1=Human, 2=Orc, 3=Undead, 4=Night Elf
108
112
 
109
113
  name: string;
110
114
  startingPos: PlayerStartingPosition;
@@ -125,39 +129,50 @@ interface Force {
125
129
  name: string;
126
130
  }
127
131
 
128
- export class InfoTranslator {
132
+ enum ScriptLanguage {
133
+ JASS = 0,
134
+ Lua = 1
135
+ }
136
+
137
+ enum SupportedModes {
138
+ SD = 1,
139
+ HD = 2,
140
+ Both = 3
141
+ }
129
142
 
130
- private _outBufferToWar: HexBuffer;
131
- private _outBufferToJSON: W3Buffer;
143
+ export abstract class InfoTranslator {
132
144
 
133
- constructor() { }
145
+ public static jsonToWar(infoJson: Info): WarResult {
146
+ const outBufferToWar = new HexBuffer();
134
147
 
135
- public jsonToWar(infoJson: Info) {
136
- this._outBufferToWar = new HexBuffer();
148
+ outBufferToWar.addInt(31); // file version, 0x1F
149
+ outBufferToWar.addInt(infoJson.saves || 0);
150
+ outBufferToWar.addInt(infoJson.editorVersion || 0);
137
151
 
138
- this._outBufferToWar.addInt(25); // file version, 0x19
139
- this._outBufferToWar.addInt(infoJson.saves || 0);
140
- this._outBufferToWar.addInt(infoJson.editorVersion || 0);
152
+ outBufferToWar.addInt(infoJson.gameVersion.major);
153
+ outBufferToWar.addInt(infoJson.gameVersion.minor);
154
+ outBufferToWar.addInt(infoJson.gameVersion.patch);
155
+ outBufferToWar.addInt(infoJson.gameVersion.build);
141
156
 
142
157
  // Map information
143
- this._outBufferToWar.addString(infoJson.map.name, true);
144
- this._outBufferToWar.addString(infoJson.map.author, true);
145
- this._outBufferToWar.addString(infoJson.map.description, true);
146
- this._outBufferToWar.addString(infoJson.map.recommendedPlayers, true);
158
+ outBufferToWar.addString(infoJson.map.name);
159
+ outBufferToWar.addString(infoJson.map.author);
160
+ outBufferToWar.addString(infoJson.map.description);
161
+ outBufferToWar.addString(infoJson.map.recommendedPlayers);
147
162
 
148
163
  // Camera bounds (8 floats total)
149
164
  for (let cbIndex = 0; cbIndex < 8; cbIndex++) {
150
- this._outBufferToWar.addFloat(infoJson.camera.bounds[cbIndex]);
165
+ outBufferToWar.addFloat(infoJson.camera.bounds[cbIndex]);
151
166
  }
152
167
 
153
168
  // Camera complements (4 floats total)
154
169
  for (let ccIndex = 0; ccIndex < 4; ccIndex++) {
155
- this._outBufferToWar.addInt(infoJson.camera.complements[ccIndex]);
170
+ outBufferToWar.addInt(infoJson.camera.complements[ccIndex]);
156
171
  }
157
172
 
158
173
  // Playable area
159
- this._outBufferToWar.addInt(infoJson.map.playableArea.width);
160
- this._outBufferToWar.addInt(infoJson.map.playableArea.height);
174
+ outBufferToWar.addInt(infoJson.map.playableArea.width);
175
+ outBufferToWar.addInt(infoJson.map.playableArea.height);
161
176
 
162
177
  /*
163
178
  * Flags
@@ -167,119 +182,132 @@ export class InfoTranslator {
167
182
  if (infoJson.map.flags.hideMinimapInPreview) flags |= 0x0001; // hide minimap in preview screens
168
183
  if (infoJson.map.flags.modifyAllyPriorities) flags |= 0x0002; // modify ally priorities
169
184
  if (infoJson.map.flags.isMeleeMap) flags |= 0x0004; // melee map
170
- if (infoJson.map.flags.unknown1) flags |= 0x0008; // unknown flag: playable map size was large and never reduced to medium (?)
185
+ // 0x0008 - unknown; // playable map size was large and never reduced to medium (?)
171
186
  if (infoJson.map.flags.maskedPartiallyVisible) flags |= 0x0010; // masked area are partially visible
172
187
  if (infoJson.map.flags.fixedPlayerSetting) flags |= 0x0020; // fixed player setting for custom forces
173
188
  if (infoJson.map.flags.useCustomForces) flags |= 0x0040; // use custom forces
174
189
  if (infoJson.map.flags.useCustomTechtree) flags |= 0x0080; // use custom techtree
175
190
  if (infoJson.map.flags.useCustomAbilities) flags |= 0x0100; // use custom abilities
176
191
  if (infoJson.map.flags.useCustomUpgrades) flags |= 0x0200; // use custom upgrades
177
- if (infoJson.map.flags.unknown2) flags |= 0x0400; // unknown flag: map properties menu opened at least once since map creation (?)
192
+ // 0x0400 - unknown; // map properties menu opened at least once since map creation (?)
178
193
  if (infoJson.map.flags.waterWavesOnCliffShores) flags |= 0x0800; // show water waves on cliff shores
179
194
  if (infoJson.map.flags.waterWavesOnRollingShores) flags |= 0x1000; // show water waves on rolling shores
180
- if (infoJson.map.flags.unknown3) flags |= 0x2000; // unknown flag
181
- if (infoJson.map.flags.unknown4) flags |= 0x4000; // unknown flag
182
- if (infoJson.map.flags.unknown5) flags |= 0x8000; // unknown flag
195
+ // 0x2000: 1=unknown
196
+ // 0x4000: 1=unknown
197
+ if (infoJson.map.flags.useItemClassificationSystem) flags |= 0x8000
198
+ if (infoJson.map.flags.enableWaterTinting) flags |= 0x10000
199
+ if (infoJson.map.flags.useAccurateProbabilityForCalculations) flags |= 0x20000
200
+ if (infoJson.map.flags.useCustomAbilitySkins) flags |= 0x40000
183
201
  }
184
202
 
185
- this._outBufferToWar.addInt(flags); // Add flags
203
+ // Unknown, but these seem to always be on, at least for default maps
204
+ flags |= 0x8000;
205
+ flags |= 0x4000;
206
+ flags |= 0x0400;
207
+
208
+ outBufferToWar.addInt(flags); // Add flags
186
209
 
187
210
  // Map main ground type
188
- this._outBufferToWar.addChar(infoJson.map.mainTileType);
211
+ outBufferToWar.addChar(infoJson.map.mainTileType);
189
212
 
190
213
  // Loading screen
191
- this._outBufferToWar.addInt(infoJson.loadingScreen.background);
192
- this._outBufferToWar.addString(infoJson.loadingScreen.path, true);
193
- this._outBufferToWar.addString(infoJson.loadingScreen.text, true);
194
- this._outBufferToWar.addString(infoJson.loadingScreen.title, true);
195
- this._outBufferToWar.addString(infoJson.loadingScreen.subtitle, true);
214
+ outBufferToWar.addInt(infoJson.loadingScreen.background);
215
+ outBufferToWar.addString(infoJson.loadingScreen.path);
216
+ outBufferToWar.addString(infoJson.loadingScreen.text);
217
+ outBufferToWar.addString(infoJson.loadingScreen.title);
218
+ outBufferToWar.addString(infoJson.loadingScreen.subtitle);
196
219
 
197
220
  // Use game data set (Unsupported)
198
- this._outBufferToWar.addInt(0);
221
+ outBufferToWar.addInt(0);
199
222
 
200
223
  // Prologue
201
- this._outBufferToWar.addString(infoJson.prologue.path, true);
202
- this._outBufferToWar.addString(infoJson.prologue.text, true);
203
- this._outBufferToWar.addString(infoJson.prologue.title, true);
204
- this._outBufferToWar.addString(infoJson.prologue.subtitle, true);
224
+ outBufferToWar.addString(infoJson.prologue.path);
225
+ outBufferToWar.addString(infoJson.prologue.text);
226
+ outBufferToWar.addString(infoJson.prologue.title);
227
+ outBufferToWar.addString(infoJson.prologue.subtitle);
205
228
 
206
229
  // Fog
207
- this._outBufferToWar.addInt(infoJson.fog.type);
208
- this._outBufferToWar.addFloat(infoJson.fog.startHeight);
209
- this._outBufferToWar.addFloat(infoJson.fog.endHeight);
210
- this._outBufferToWar.addFloat(infoJson.fog.density);
211
- this._outBufferToWar.addByte(infoJson.fog.color[0]);
212
- this._outBufferToWar.addByte(infoJson.fog.color[1]);
213
- this._outBufferToWar.addByte(infoJson.fog.color[2]);
214
- this._outBufferToWar.addByte(255); // Fog alpha - unsupported
230
+ outBufferToWar.addInt(infoJson.fog.type);
231
+ outBufferToWar.addFloat(infoJson.fog.startHeight);
232
+ outBufferToWar.addFloat(infoJson.fog.endHeight);
233
+ outBufferToWar.addFloat(infoJson.fog.density);
234
+ outBufferToWar.addByte(infoJson.fog.color[0]);
235
+ outBufferToWar.addByte(infoJson.fog.color[1]);
236
+ outBufferToWar.addByte(infoJson.fog.color[2]);
237
+ outBufferToWar.addByte(255); // Fog alpha - unsupported
215
238
 
216
239
  // Misc.
217
240
  // If globalWeather is not defined or is set to 'none', use 0 sentinel value, else add char[4]
218
241
  if (!infoJson.globalWeather || infoJson.globalWeather.toLowerCase() === 'none') {
219
- this._outBufferToWar.addInt(0);
242
+ outBufferToWar.addInt(0);
220
243
  } else {
221
- this._outBufferToWar.addString(infoJson.globalWeather, false); // char[4] - lookup table
244
+ outBufferToWar.addChars(infoJson.globalWeather); // char[4] - lookup table
222
245
  }
223
- this._outBufferToWar.addString(infoJson.customSoundEnvironment || '', true);
224
- this._outBufferToWar.addChar(infoJson.customLightEnv || 'L');
246
+ outBufferToWar.addString(infoJson.customSoundEnvironment || '');
247
+ outBufferToWar.addChar(infoJson.customLightEnv || 'L');
225
248
 
226
249
  // Custom water tinting
227
- this._outBufferToWar.addByte(infoJson.water[0]);
228
- this._outBufferToWar.addByte(infoJson.water[1]);
229
- this._outBufferToWar.addByte(infoJson.water[2]);
230
- this._outBufferToWar.addByte(255); // Water alpha - unsupported
250
+ outBufferToWar.addByte(infoJson.water[0]);
251
+ outBufferToWar.addByte(infoJson.water[1]);
252
+ outBufferToWar.addByte(infoJson.water[2]);
253
+ outBufferToWar.addByte(255); // Water alpha - unsupported
254
+
255
+ outBufferToWar.addInt(infoJson.scriptLanguage);
256
+ outBufferToWar.addInt(infoJson.supportedModes);
257
+ outBufferToWar.addInt(0); // unknown
231
258
 
232
259
  // Players
233
- this._outBufferToWar.addInt(infoJson.players.length);
260
+ outBufferToWar.addInt(infoJson.players.length);
234
261
  infoJson.players.forEach((player) => {
235
- this._outBufferToWar.addInt(player.playerNum);
236
- this._outBufferToWar.addInt(player.type);
237
- this._outBufferToWar.addInt(player.race);
238
- this._outBufferToWar.addInt(player.startingPos.fixed ? 1 : 0);
239
- this._outBufferToWar.addString(player.name, true);
240
- this._outBufferToWar.addFloat(player.startingPos.x);
241
- this._outBufferToWar.addFloat(player.startingPos.y);
242
- this._outBufferToWar.addInt(0); // ally low prio flags - unsupported
243
- this._outBufferToWar.addInt(0); // ally high prio flags - unsupported
262
+ outBufferToWar.addInt(player.playerNum);
263
+ outBufferToWar.addInt(player.type);
264
+ outBufferToWar.addInt(player.race);
265
+ outBufferToWar.addInt(player.startingPos.fixed ? 1 : 0);
266
+ outBufferToWar.addString(player.name);
267
+ outBufferToWar.addFloat(player.startingPos.x);
268
+ outBufferToWar.addFloat(player.startingPos.y);
269
+ outBufferToWar.addInt(0); // ally low prio flags - unsupported
270
+ outBufferToWar.addInt(0); // ally high prio flags - unsupported
271
+ outBufferToWar.addInt(0); // enemy low prio flags - unsupported
272
+ outBufferToWar.addInt(0); // enemy high prio flags - unsupported
244
273
  });
245
274
 
246
275
  // Forces
247
- this._outBufferToWar.addInt(infoJson.forces.length);
276
+ outBufferToWar.addInt(infoJson.forces.length);
248
277
  infoJson.forces.forEach((force) => {
249
278
  // Calculate flags
250
279
  let forceFlags = 0;
251
280
  if (force.flags.allied) forceFlags |= 0x0001;
252
281
  if (force.flags.alliedVictory) forceFlags |= 0x0002;
253
- if (force.flags.shareVision) forceFlags |= 0x0004;
282
+ // Skip 0x0004
283
+ if (force.flags.shareVision) forceFlags |= 0x0008;
254
284
  if (force.flags.shareUnitControl) forceFlags |= 0x0010;
255
285
  if (force.flags.shareAdvUnitControl) forceFlags |= 0x0020;
256
286
 
257
- this._outBufferToWar.addInt(forceFlags);
258
- this._outBufferToWar.addByte(255); // force players - unsupported
259
- this._outBufferToWar.addByte(255); // force players - unsupported
260
- this._outBufferToWar.addByte(255); // force players - unsupported
261
- this._outBufferToWar.addByte(255); // force players - unsupported
262
- this._outBufferToWar.addString(force.name, true);
287
+ outBufferToWar.addInt(forceFlags);
288
+ outBufferToWar.addInt(force.players);
289
+ outBufferToWar.addString(force.name);
263
290
  });
264
291
 
265
292
  // Upgrades - unsupported
266
- this._outBufferToWar.addInt(0);
293
+ outBufferToWar.addInt(0);
267
294
 
268
295
  // Tech availability - unsupported
269
- this._outBufferToWar.addInt(0);
296
+ outBufferToWar.addInt(0);
270
297
 
271
298
  // Unit table (random) - unsupported
272
- this._outBufferToWar.addInt(0);
299
+ outBufferToWar.addInt(0);
273
300
 
274
301
  // Item table (random) - unsupported
275
- this._outBufferToWar.addInt(0);
302
+ outBufferToWar.addInt(0);
276
303
 
277
304
  return {
278
305
  errors: [],
279
- buffer: this._outBufferToWar.getBuffer()
306
+ buffer: outBufferToWar.getBuffer()
280
307
  };
281
308
  }
282
- public warToJson(buffer: Buffer) {
309
+
310
+ public static warToJson(buffer: Buffer): JsonResult<Info> {
283
311
  const result: Info = {
284
312
  map: {
285
313
  name: '',
@@ -293,21 +321,22 @@ export class InfoTranslator {
293
321
  mainTileType: '',
294
322
  flags: {
295
323
  hideMinimapInPreview: false, // 0x0001: 1=hide minimap in preview screens
296
- modifyAllyPriorities: false, // 0x0002: 1=modify ally priorities
324
+ modifyAllyPriorities: true, // 0x0002: 1=modify ally priorities
297
325
  isMeleeMap: false, // 0x0004: 1=melee map
298
- unknown1: false, // 0x0008: 1=playable map size was large and has never been reduced to medium (?)
326
+ // 0x0008: 1=playable map size was large and has never been reduced to medium (?)
299
327
  maskedPartiallyVisible: false, // 0x0010: 1=masked area are partially visible
300
328
  fixedPlayerSetting: false, // 0x0020: 1=fixed player setting for custom forces
301
329
  useCustomForces: false, // 0x0040: 1=use custom forces
302
330
  useCustomTechtree: false, // 0x0080: 1=use custom techtree
303
331
  useCustomAbilities: false, // 0x0100: 1=use custom abilities
304
332
  useCustomUpgrades: false, // 0x0200: 1=use custom upgrades
305
- unknown2: false, // 0x0400: 1=map properties menu opened at least once since map creation (?)
333
+ // 0x0400: 1=map properties menu opened at least once since map creation (?)
306
334
  waterWavesOnCliffShores: false, // 0x0800: 1=show water waves on cliff shores
307
335
  waterWavesOnRollingShores: false, // 0x1000: 1=show water waves on rolling shores
308
- unknown3: false,
309
- unknown4: false,
310
- unknown5: false
336
+ useItemClassificationSystem: false, // 0x8000: 1=use item classification system
337
+ enableWaterTinting: false, // 0x10000
338
+ useAccurateProbabilityForCalculations: false, // 0x20000
339
+ useCustomAbilitySkins: false // 0x40000
311
340
  }
312
341
  },
313
342
  loadingScreen: {
@@ -322,7 +351,7 @@ export class InfoTranslator {
322
351
  title: '',
323
352
  subtitle: ''
324
353
  }, fog: {
325
- type: 0,
354
+ type: FogType.Linear,
326
355
  startHeight: 0,
327
356
  endHeight: 0,
328
357
  density: 0,
@@ -337,93 +366,110 @@ export class InfoTranslator {
337
366
  ],
338
367
  saves: 0,
339
368
  editorVersion: 0,
369
+ scriptLanguage: ScriptLanguage.JASS,
370
+ supportedModes: SupportedModes.Both,
371
+ gameVersion: {
372
+ major: 0,
373
+ minor: 0,
374
+ patch: 0,
375
+ build: 0
376
+ },
340
377
  globalWeather: '',
341
378
  customSoundEnvironment: '',
342
379
  customLightEnv: '',
343
380
  water: []
344
381
  };
345
- this._outBufferToJSON = new W3Buffer(buffer);
382
+ const outBufferToJSON = new W3Buffer(buffer);
383
+
384
+ const fileVersion = outBufferToJSON.readInt();
346
385
 
347
- const fileVersion = this._outBufferToJSON.readInt(), // File version
348
- numOfSaves = this._outBufferToJSON.readInt(), // # of times saved
349
- editorVersion = this._outBufferToJSON.readInt(); // editor version
386
+ result.saves = outBufferToJSON.readInt(),
387
+ result.editorVersion = outBufferToJSON.readInt();
350
388
 
351
- result.saves = numOfSaves;
352
- result.editorVersion = editorVersion;
389
+ result.gameVersion = {
390
+ major: outBufferToJSON.readInt(),
391
+ minor: outBufferToJSON.readInt(),
392
+ patch: outBufferToJSON.readInt(),
393
+ build: outBufferToJSON.readInt()
394
+ };
353
395
 
354
- result.map.name = this._outBufferToJSON.readString();
355
- result.map.author = this._outBufferToJSON.readString();
356
- result.map.description = this._outBufferToJSON.readString();
357
- result.map.recommendedPlayers = this._outBufferToJSON.readString();
396
+ result.map.name = outBufferToJSON.readString();
397
+ result.map.author = outBufferToJSON.readString();
398
+ result.map.description = outBufferToJSON.readString();
399
+ result.map.recommendedPlayers = outBufferToJSON.readString();
358
400
 
359
401
  result.camera.bounds = [
360
- this._outBufferToJSON.readFloat(), this._outBufferToJSON.readFloat(), this._outBufferToJSON.readFloat(), this._outBufferToJSON.readFloat(),
361
- this._outBufferToJSON.readFloat(), this._outBufferToJSON.readFloat(), this._outBufferToJSON.readFloat(), this._outBufferToJSON.readFloat()
402
+ outBufferToJSON.readFloat(), outBufferToJSON.readFloat(), outBufferToJSON.readFloat(), outBufferToJSON.readFloat(),
403
+ outBufferToJSON.readFloat(), outBufferToJSON.readFloat(), outBufferToJSON.readFloat(), outBufferToJSON.readFloat()
362
404
  ];
363
405
 
364
406
  result.camera.complements = [
365
- this._outBufferToJSON.readInt(), this._outBufferToJSON.readInt(), this._outBufferToJSON.readInt(), this._outBufferToJSON.readInt()
407
+ outBufferToJSON.readInt(), outBufferToJSON.readInt(), outBufferToJSON.readInt(), outBufferToJSON.readInt()
366
408
  ];
367
409
 
368
410
  result.map.playableArea = {
369
- width: this._outBufferToJSON.readInt(),
370
- height: this._outBufferToJSON.readInt()
411
+ width: outBufferToJSON.readInt(),
412
+ height: outBufferToJSON.readInt()
371
413
  };
372
414
 
373
- const flags = this._outBufferToJSON.readInt();
415
+ const flags = outBufferToJSON.readInt();
374
416
  result.map.flags = {
375
- hideMinimapInPreview: !!(flags & 0b1),
376
- modifyAllyPriorities: !!(flags & 0b10),
377
- isMeleeMap: !!(flags & 0b100),
378
- unknown1: !!(flags & 0b1000),
379
- maskedPartiallyVisible: !!(flags & 0b10000),
380
- fixedPlayerSetting: !!(flags & 0b100000),
381
- useCustomForces: !!(flags & 0b1000000),
382
- useCustomTechtree: !!(flags & 0b10000000),
383
- useCustomAbilities: !!(flags & 0b100000000),
384
- useCustomUpgrades: !!(flags & 0b1000000000),
385
- unknown2: !!(flags & 0b10000000000),
386
- waterWavesOnCliffShores: !!(flags & 0b100000000000),
387
- waterWavesOnRollingShores: !!(flags & 0b1000000000000),
388
- unknown3: !!(flags & 0b10000000000000),
389
- unknown4: !!(flags & 0b100000000000000),
390
- unknown5: !!(flags & 0b1000000000000000),
417
+ hideMinimapInPreview: !!(flags & 0x0001),
418
+ modifyAllyPriorities: !!(flags & 0x0002),
419
+ isMeleeMap: !!(flags & 0x0004),
420
+ // skip 0x008
421
+ maskedPartiallyVisible: !!(flags & 0x0010),
422
+ fixedPlayerSetting: !!(flags & 0x0020),
423
+ useCustomForces: !!(flags & 0x0040),
424
+ useCustomTechtree: !!(flags & 0x0080),
425
+ useCustomAbilities: !!(flags & 0x0100),
426
+ useCustomUpgrades: !!(flags & 0x0200),
427
+ waterWavesOnCliffShores: !!(flags & 0x0800),
428
+ waterWavesOnRollingShores: !!(flags & 0x1000),
429
+ // skip 0x2000
430
+ // skip 0x4000
431
+ useItemClassificationSystem: !!(flags & 0x8000),
432
+ enableWaterTinting: !!(flags & 0x10000),
433
+ useAccurateProbabilityForCalculations: !!(flags & 0x20000),
434
+ useCustomAbilitySkins: !!(flags & 0x40000)
391
435
  };
392
436
 
393
- result.map.mainTileType = this._outBufferToJSON.readChars();
437
+ result.map.mainTileType = outBufferToJSON.readChars();
394
438
 
395
- result.loadingScreen = {
396
- background: this._outBufferToJSON.readInt(),
397
- path: this._outBufferToJSON.readString(),
398
- text: this._outBufferToJSON.readString(),
399
- title: this._outBufferToJSON.readString(),
400
- subtitle: this._outBufferToJSON.readString()
401
- };
439
+ result.loadingScreen.background = outBufferToJSON.readInt();
440
+ result.loadingScreen.path = outBufferToJSON.readString();
441
+ result.loadingScreen.text = outBufferToJSON.readString();
442
+ result.loadingScreen.title = outBufferToJSON.readString();
443
+ result.loadingScreen.subtitle = outBufferToJSON.readString();
402
444
 
403
- const gameDataSet = this._outBufferToJSON.readInt(); // 0 = standard
445
+ const gameDataSet = outBufferToJSON.readInt(); // 0 = standard
404
446
 
405
447
  result.prologue = {
406
- path: this._outBufferToJSON.readString(),
407
- text: this._outBufferToJSON.readString(),
408
- title: this._outBufferToJSON.readString(),
409
- subtitle: this._outBufferToJSON.readString()
448
+ path: outBufferToJSON.readString(),
449
+ text: outBufferToJSON.readString(),
450
+ title: outBufferToJSON.readString(),
451
+ subtitle: outBufferToJSON.readString()
410
452
  };
411
453
 
412
454
  result.fog = {
413
- type: this._outBufferToJSON.readInt(),
414
- startHeight: this._outBufferToJSON.readFloat(),
415
- endHeight: this._outBufferToJSON.readFloat(),
416
- density: this._outBufferToJSON.readFloat(),
417
- color: [this._outBufferToJSON.readByte(), this._outBufferToJSON.readByte(), this._outBufferToJSON.readByte(), this._outBufferToJSON.readByte()] // R G B A
455
+ type: outBufferToJSON.readInt(),
456
+ startHeight: outBufferToJSON.readFloat(),
457
+ endHeight: outBufferToJSON.readFloat(),
458
+ density: outBufferToJSON.readFloat(),
459
+ color: [outBufferToJSON.readByte(), outBufferToJSON.readByte(), outBufferToJSON.readByte(), outBufferToJSON.readByte()] // R G B A
418
460
  };
419
461
 
420
- result.globalWeather = this._outBufferToJSON.readChars(4);
421
- result.customSoundEnvironment = this._outBufferToJSON.readString();
422
- result.customLightEnv = this._outBufferToJSON.readChars();
423
- result.water = [this._outBufferToJSON.readByte(), this._outBufferToJSON.readByte(), this._outBufferToJSON.readByte(), this._outBufferToJSON.readByte()]; // R G B A
462
+ result.globalWeather = outBufferToJSON.readChars(4);
463
+ result.customSoundEnvironment = outBufferToJSON.readString();
464
+ result.customLightEnv = outBufferToJSON.readChars();
465
+ result.water = [outBufferToJSON.readByte(), outBufferToJSON.readByte(), outBufferToJSON.readByte(), outBufferToJSON.readByte()]; // R G B A
466
+
467
+ result.scriptLanguage = outBufferToJSON.readInt();
468
+ result.supportedModes = outBufferToJSON.readInt();
469
+ outBufferToJSON.readInt(); // unknown
424
470
 
425
471
  // Struct: players
426
- const numPlayers = this._outBufferToJSON.readInt();
472
+ const numPlayers = outBufferToJSON.readInt();
427
473
  for (let i = 0; i < numPlayers; i++) {
428
474
  const player: Player = {
429
475
  name: '',
@@ -433,27 +479,29 @@ export class InfoTranslator {
433
479
  race: 0
434
480
  };
435
481
 
436
- player.playerNum = this._outBufferToJSON.readInt();
437
- player.type = this._outBufferToJSON.readInt(); // 1=Human, 2=Computer, 3=Neutral, 4=Rescuable
438
- player.race = this._outBufferToJSON.readInt(); // 1=Human, 2=Orc, 3=Undead, 4=Night Elf
482
+ player.playerNum = outBufferToJSON.readInt();
483
+ player.type = outBufferToJSON.readInt(); // 1=Human, 2=Computer, 3=Neutral, 4=Rescuable
484
+ player.race = outBufferToJSON.readInt(); // 1=Human, 2=Orc, 3=Undead, 4=Night Elf
439
485
 
440
- const isPlayerStartPositionFixed: boolean = this._outBufferToJSON.readInt() === 1; // 00000001 = fixed start position
486
+ const isPlayerStartPositionFixed: boolean = outBufferToJSON.readInt() === 1; // 00000001 = fixed start position
441
487
 
442
- player.name = this._outBufferToJSON.readString();
488
+ player.name = outBufferToJSON.readString();
443
489
  player.startingPos = {
444
- x: this._outBufferToJSON.readFloat(),
445
- y: this._outBufferToJSON.readFloat(),
490
+ x: outBufferToJSON.readFloat(),
491
+ y: outBufferToJSON.readFloat(),
446
492
  fixed: isPlayerStartPositionFixed
447
493
  };
448
494
 
449
- this._outBufferToJSON.readInt(); // ally low priorities flags (bit "x"=1 --> set for player "x")
450
- this._outBufferToJSON.readInt(); // ally high priorities flags (bit "x"=1 --> set for player "x")
495
+ outBufferToJSON.readInt(); // ally low priorities flags (bit "x"=1 --> set for player "x")
496
+ outBufferToJSON.readInt(); // ally high priorities flags (bit "x"=1 --> set for player "x")
497
+ outBufferToJSON.readInt(); // enemy low priorities flags
498
+ outBufferToJSON.readInt(); // enemy high priorities flags
451
499
 
452
500
  result.players.push(player);
453
501
  }
454
502
 
455
503
  // Struct: forces
456
- const numForces = this._outBufferToJSON.readInt();
504
+ const numForces = outBufferToJSON.readInt();
457
505
  for (let i = 0; i < numForces; i++) {
458
506
  const force: Force = {
459
507
  flags: { allied: false, alliedVictory: true, shareVision: true, shareUnitControl: false, shareAdvUnitControl: false },
@@ -461,7 +509,7 @@ export class InfoTranslator {
461
509
  name: ''
462
510
  };
463
511
 
464
- const forceFlag = this._outBufferToJSON.readInt();
512
+ const forceFlag = outBufferToJSON.readInt();
465
513
  force.flags = {
466
514
  allied: !!(forceFlag & 0b1), // 0x00000001: allied (force 1)
467
515
  alliedVictory: !!(forceFlag & 0b10), // 0x00000002: allied victory
@@ -470,59 +518,59 @@ export class InfoTranslator {
470
518
  shareUnitControl: !!(forceFlag & 0b10000), // 0x00000010: share unit control
471
519
  shareAdvUnitControl: !!(forceFlag & 0b100000) // 0x00000020: share advanced unit control
472
520
  };
473
- force.players = this._outBufferToJSON.readInt(); // UNSUPPORTED: (bit "x"=1 --> player "x" is in this force)
474
- force.name = this._outBufferToJSON.readString();
521
+ force.players = outBufferToJSON.readInt(); // UNSUPPORTED: (bit "x"=1 --> player "x" is in this force; but carried over for accurate translation
522
+ force.name = outBufferToJSON.readString();
475
523
 
476
524
  result.forces.push(force);
477
525
  }
478
526
 
479
527
  // UNSUPPORTED: Struct: upgrade avail.
480
- const numUpgrades = this._outBufferToJSON.readInt();
528
+ const numUpgrades = outBufferToJSON.readInt();
481
529
  for (let i = 0; i < numUpgrades; i++) {
482
- this._outBufferToJSON.readInt(); // Player Flags (bit "x"=1 if this change applies for player "x")
483
- this._outBufferToJSON.readChars(4); // upgrade id (as in UpgradeData.slk)
484
- this._outBufferToJSON.readInt(); // Level of the upgrade for which the availability is changed (this is actually the level - 1, so 1 => 0)
485
- this._outBufferToJSON.readInt(); // Availability (0 = unavailable, 1 = available, 2 = researched)
530
+ outBufferToJSON.readInt(); // Player Flags (bit "x"=1 if this change applies for player "x")
531
+ outBufferToJSON.readChars(4); // upgrade id (as in UpgradeData.slk)
532
+ outBufferToJSON.readInt(); // Level of the upgrade for which the availability is changed (this is actually the level - 1, so 1 => 0)
533
+ outBufferToJSON.readInt(); // Availability (0 = unavailable, 1 = available, 2 = researched)
486
534
  }
487
535
 
488
536
  // UNSUPPORTED: Struct: tech avail.
489
- const numTech = this._outBufferToJSON.readInt();
537
+ const numTech = outBufferToJSON.readInt();
490
538
  for (let i = 0; i < numTech; i++) {
491
- this._outBufferToJSON.readInt(); // Player Flags (bit "x"=1 if this change applies for player "x")
492
- this._outBufferToJSON.readChars(4); // tech id (this can be an item, unit or ability)
539
+ outBufferToJSON.readInt(); // Player Flags (bit "x"=1 if this change applies for player "x")
540
+ outBufferToJSON.readChars(4); // tech id (this can be an item, unit or ability)
493
541
  }
494
542
 
495
543
  // UNSUPPORTED: Struct: random unit table
496
- const numUnitTable = this._outBufferToJSON.readInt();
544
+ const numUnitTable = outBufferToJSON.readInt();
497
545
  for (let i = 0; i < numUnitTable; i++) {
498
- this._outBufferToJSON.readInt(); // Group number
499
- this._outBufferToJSON.readString(); // Group name
546
+ outBufferToJSON.readInt(); // Group number
547
+ outBufferToJSON.readString(); // Group name
500
548
 
501
- const numPositions = this._outBufferToJSON.readInt(); // Number "m" of positions
549
+ const numPositions = outBufferToJSON.readInt(); // Number "m" of positions
502
550
  for (let j = 0; j < numPositions; j++) {
503
- this._outBufferToJSON.readInt(); // unit table (=0), a building table (=1) or an item table (=2)
551
+ outBufferToJSON.readInt(); // unit table (=0), a building table (=1) or an item table (=2)
504
552
 
505
- const numLinesInTable = this._outBufferToJSON.readInt();
553
+ const numLinesInTable = outBufferToJSON.readInt();
506
554
  for (let k = 0; k < numLinesInTable; k++) {
507
- this._outBufferToJSON.readInt(); // Chance of the unit/item (percentage)
508
- this._outBufferToJSON.readChars(); // unit/item id's for this line specified
555
+ outBufferToJSON.readInt(); // Chance of the unit/item (percentage)
556
+ outBufferToJSON.readChars(4); // unit/item id's for this line specified
509
557
  }
510
558
  }
511
559
  }
512
560
 
513
561
  // UNSUPPORTED: Struct: random item table
514
- const numItemTable = this._outBufferToJSON.readInt();
562
+ const numItemTable = outBufferToJSON.readInt();
515
563
  for (let i = 0; i < numItemTable; i++) {
516
- this._outBufferToJSON.readInt(); // Table number
517
- this._outBufferToJSON.readString(); // Table name
564
+ outBufferToJSON.readInt(); // Table number
565
+ outBufferToJSON.readString(); // Table name
518
566
 
519
- const itemSetsCurrentTable = this._outBufferToJSON.readInt(); // Number "m" of item sets on the current item table
567
+ const itemSetsCurrentTable = outBufferToJSON.readInt(); // Number "m" of item sets on the current item table
520
568
  for (let j = 0; j < itemSetsCurrentTable; j++) {
521
569
 
522
- const itemsInItemSet = this._outBufferToJSON.readInt(); // Number "i" of items on the current item set
570
+ const itemsInItemSet = outBufferToJSON.readInt(); // Number "i" of items on the current item set
523
571
  for (let k = 0; k < itemsInItemSet; k++) {
524
- this._outBufferToJSON.readInt(); // Percentual chance
525
- this._outBufferToJSON.readChars(4); // Item id (as in ItemData.slk)
572
+ outBufferToJSON.readInt(); // Percentual chance
573
+ outBufferToJSON.readChars(4); // Item id (as in ItemData.slk)
526
574
  }
527
575
 
528
576
  }