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,13 +1,23 @@
1
1
  import { HexBuffer } from '../HexBuffer';
2
2
  import { W3Buffer } from '../W3Buffer';
3
+ import { WarResult, JsonResult } from '../CommonInterfaces'
3
4
 
4
5
  interface Terrain {
5
6
  tileset: string;
6
- customtileset: boolean;
7
- tilepalette: string[];
8
- clifftilepalette: string[];
7
+ customTileset: boolean;
8
+ tilePalette: string[];
9
+ cliffTilePalette: string[];
9
10
  map: Map;
10
- tiles: any;
11
+ // "Masks"
12
+ groundHeight: number[],
13
+ waterHeight: number[],
14
+ boundaryFlag: boolean[],
15
+ flags: number[],
16
+ groundTexture: number[],
17
+ groundVariation: number[],
18
+ cliffVariation: number[],
19
+ cliffTexture: number[],
20
+ layerHeight: number[]
11
21
  }
12
22
 
13
23
  interface Map {
@@ -21,83 +31,118 @@ interface Offset {
21
31
  y: number;
22
32
  }
23
33
 
24
- export class TerrainTranslator {
25
-
26
- private _outBufferToWar: HexBuffer;
27
- private _outBufferToJSON: W3Buffer;
34
+ function splitLargeArrayIntoWidthArrays(array: any[], width: number) {
35
+ const rows = [];
36
+ for(let i = 0; i < array.length / width; i++) {
37
+ rows.push(array.slice(i * width, (i+1) * width));
38
+ }
39
+ return rows;
40
+ }
28
41
 
29
- constructor() { }
42
+ export abstract class TerrainTranslator {
30
43
 
31
- public jsonToWar(terrainJson: Terrain) {
32
- this._outBufferToWar = new HexBuffer();
44
+ public static jsonToWar(terrainJson: Terrain): WarResult {
45
+ const outBufferToWar = new HexBuffer();
33
46
 
34
47
  /*
35
48
  * Header
36
49
  */
37
- this._outBufferToWar.addString('W3E!'); // file id
38
- this._outBufferToWar.addInt(11); // file version
39
- this._outBufferToWar.addChar(terrainJson.tileset); // base tileset
40
- this._outBufferToWar.addInt(+terrainJson.customtileset); // 1 = using custom tileset, 0 = not
50
+ outBufferToWar.addChars('W3E!'); // file id
51
+ outBufferToWar.addInt(11); // file version
52
+ outBufferToWar.addChar(terrainJson.tileset); // base tileset
53
+ outBufferToWar.addInt(+terrainJson.customTileset); // 1 = using custom tileset, 0 = not
41
54
 
42
55
  /*
43
56
  * Tiles
44
57
  */
45
- this._outBufferToWar.addInt(terrainJson.tilepalette.length);
46
- terrainJson.tilepalette.forEach((tile) => {
47
- this._outBufferToWar.addString(tile);
58
+ outBufferToWar.addInt(terrainJson.tilePalette.length);
59
+ terrainJson.tilePalette.forEach((tile) => {
60
+ outBufferToWar.addChars(tile);
48
61
  });
49
62
 
50
63
  /*
51
64
  * Cliffs
52
65
  */
53
- this._outBufferToWar.addInt(terrainJson.clifftilepalette.length);
54
- terrainJson.clifftilepalette.forEach((clifftile) => {
55
- this._outBufferToWar.addString(clifftile);
66
+ outBufferToWar.addInt(terrainJson.cliffTilePalette.length);
67
+ terrainJson.cliffTilePalette.forEach((cliffTile) => {
68
+ outBufferToWar.addChars(cliffTile);
56
69
  });
57
70
 
58
71
  /*
59
72
  * Map size data
60
73
  */
61
- this._outBufferToWar.addInt(terrainJson.map.width + 1);
62
- this._outBufferToWar.addInt(terrainJson.map.height + 1);
74
+ outBufferToWar.addInt(terrainJson.map.width + 1);
75
+ outBufferToWar.addInt(terrainJson.map.height + 1);
63
76
 
64
- // map offset
65
- this._outBufferToWar.addFloat(terrainJson.map.offset.x);
66
- this._outBufferToWar.addFloat(terrainJson.map.offset.y);
77
+ /*
78
+ * Map offset
79
+ */
80
+ outBufferToWar.addFloat(terrainJson.map.offset.x);
81
+ outBufferToWar.addFloat(terrainJson.map.offset.y);
67
82
 
68
83
  /*
69
84
  * Tile points
70
85
  */
71
- for (let i = terrainJson.tiles.length - 1; i >= 0; i--) {
72
- // write each for of tiles
73
- // tslint:disable-next-line: prefer-for-of
74
- for (let width = 0; width < terrainJson.tiles[i].length; width++) {
75
- const currTile = terrainJson.tiles[i][width];
86
+ // Partition the terrainJson masks into "chunks" (i.e. rows) of (width+1) length,
87
+ // reverse that list of rows (due to vertical flipping), and then write the rows out
88
+ const rows = {
89
+ groundHeight: splitLargeArrayIntoWidthArrays(terrainJson.groundHeight, terrainJson.map.width + 1),
90
+ waterHeight: splitLargeArrayIntoWidthArrays(terrainJson.waterHeight, terrainJson.map.width + 1),
91
+ boundaryFlag: splitLargeArrayIntoWidthArrays(terrainJson.boundaryFlag, terrainJson.map.width + 1),
92
+ flags: splitLargeArrayIntoWidthArrays(terrainJson.flags, terrainJson.map.width + 1),
93
+ groundTexture: splitLargeArrayIntoWidthArrays(terrainJson.groundTexture, terrainJson.map.width + 1),
94
+ groundVariation: splitLargeArrayIntoWidthArrays(terrainJson.groundVariation, terrainJson.map.width + 1),
95
+ cliffVariation: splitLargeArrayIntoWidthArrays(terrainJson.cliffVariation, terrainJson.map.width + 1),
96
+ cliffTexture: splitLargeArrayIntoWidthArrays(terrainJson.cliffTexture, terrainJson.map.width + 1),
97
+ layerHeight: splitLargeArrayIntoWidthArrays(terrainJson.layerHeight, terrainJson.map.width + 1)
98
+ };
76
99
 
77
- const boundaryFlag = currTile.boundaryFlag ? 0x4000 : 0;
100
+ rows.groundHeight.reverse();
101
+ rows.waterHeight.reverse();
102
+ rows.boundaryFlag.reverse();
103
+ rows.flags.reverse();
104
+ rows.groundTexture.reverse();
105
+ rows.groundVariation.reverse();
106
+ rows.cliffVariation.reverse();
107
+ rows.cliffTexture.reverse();
108
+ rows.layerHeight.reverse();
78
109
 
110
+ for(let i = 0; i < rows.groundHeight.length; i++) {
111
+ for(let j = 0; j < rows.groundHeight[i].length; j++) {
79
112
  // these bit operations are based off documentation from https://github.com/stijnherfst/HiveWE/wiki/war3map.w3e-Terrain
80
- this._outBufferToWar.addShort(currTile.groundHeight); // height
81
- this._outBufferToWar.addShort(currTile.waterHeight | boundaryFlag); // water
82
- this._outBufferToWar.addByte(currTile.flags | currTile.groundTexture);
83
- this._outBufferToWar.addByte(currTile.groundVariation | currTile.cliffVariation);
84
- this._outBufferToWar.addByte(currTile.cliffTexture | currTile.layerHeight);
113
+ const groundHeight = rows.groundHeight[i][j];
114
+ const waterHeight = rows.waterHeight[i][j];
115
+ const boundaryFlag = rows.boundaryFlag[i][j];
116
+ const flags = rows.flags[i][j];
117
+ const groundTexture = rows.groundTexture[i][j];
118
+ const groundVariation = rows.groundVariation[i][j];
119
+ const cliffVariation = rows.cliffVariation[i][j];
120
+ const cliffTexture = rows.cliffTexture[i][j];
121
+ const layerHeight = rows.layerHeight[i][j];
122
+
123
+ const hasBoundaryFlag = boundaryFlag ? 0x4000 : 0;
124
+
125
+ outBufferToWar.addShort(groundHeight);
126
+ outBufferToWar.addShort(waterHeight | hasBoundaryFlag);
127
+ outBufferToWar.addByte(flags | groundTexture);
128
+ outBufferToWar.addByte(groundVariation | cliffVariation);
129
+ outBufferToWar.addByte(cliffTexture | layerHeight);
85
130
  }
86
131
  }
87
132
 
88
133
  return {
89
134
  errors: [],
90
- buffer: this._outBufferToWar.getBuffer()
135
+ buffer: outBufferToWar.getBuffer()
91
136
  };
92
137
  }
93
138
 
94
- public warToJson(buffer: Buffer) {
139
+ public static warToJson(buffer: Buffer): JsonResult<Terrain> {
95
140
  // create buffer
96
141
  const result: Terrain = {
97
142
  tileset: '',
98
- customtileset: false,
99
- tilepalette: [],
100
- clifftilepalette: [],
143
+ customTileset: false,
144
+ tilePalette: [],
145
+ cliffTilePalette: [],
101
146
  map: {
102
147
  width: 1,
103
148
  height: 1,
@@ -106,98 +151,122 @@ export class TerrainTranslator {
106
151
  y: 0
107
152
  }
108
153
  },
109
- tiles: {}
154
+ groundHeight: [],
155
+ waterHeight: [],
156
+ boundaryFlag: [],
157
+ flags: [],
158
+ groundTexture: [],
159
+ groundVariation: [],
160
+ cliffVariation: [],
161
+ cliffTexture: [],
162
+ layerHeight: []
110
163
  };
111
- this._outBufferToJSON = new W3Buffer(buffer);
164
+ const outBufferToJSON = new W3Buffer(buffer);
112
165
 
113
166
  /**
114
167
  * Header
115
168
  */
116
- const w3eHeader = this._outBufferToJSON.readChars(4); // W3E!
117
- const version = this._outBufferToJSON.readInt(); // 0B 00 00 00
118
- const tileset = this._outBufferToJSON.readChars(1); // tileset
119
- const customtileset = (this._outBufferToJSON.readInt() === 1);
169
+ const w3eHeader = outBufferToJSON.readChars(4); // W3E!
170
+ const version = outBufferToJSON.readInt(); // 0B 00 00 00
171
+ const tileset = outBufferToJSON.readChars(1); // tileset
172
+ const customTileset = (outBufferToJSON.readInt() === 1);
120
173
 
121
174
  result.tileset = tileset;
122
- result.customtileset = customtileset;
175
+ result.customTileset = customTileset;
123
176
 
124
177
  /**
125
178
  * Tiles
126
179
  */
127
- const numTilePalettes = this._outBufferToJSON.readInt();
180
+ const numTilePalettes = outBufferToJSON.readInt();
128
181
  const tilePalettes = [];
129
182
  for (let i = 0; i < numTilePalettes; i++) {
130
- tilePalettes.push(this._outBufferToJSON.readChars(4));
183
+ tilePalettes.push(outBufferToJSON.readChars(4));
131
184
  }
132
185
 
133
- result.tilepalette = tilePalettes;
186
+ result.tilePalette = tilePalettes;
134
187
 
135
188
  /**
136
189
  * Cliffs
137
190
  */
138
- const numCliffTilePalettes = this._outBufferToJSON.readInt();
191
+ const numCliffTilePalettes = outBufferToJSON.readInt();
139
192
  const cliffPalettes = [];
140
193
  for (let i = 0; i < numCliffTilePalettes; i++) {
141
- const cliffPalette = this._outBufferToJSON.readChars(4);
194
+ const cliffPalette = outBufferToJSON.readChars(4);
142
195
  cliffPalettes.push(cliffPalette);
143
196
  }
144
197
 
145
- result.clifftilepalette = cliffPalettes;
198
+ result.cliffTilePalette = cliffPalettes;
146
199
 
147
200
  /**
148
201
  * map dimensions
149
202
  */
150
- const width = this._outBufferToJSON.readInt() - 1;
151
- const height = this._outBufferToJSON.readInt() - 1;
203
+ const width = outBufferToJSON.readInt() - 1;
204
+ const height = outBufferToJSON.readInt() - 1;
152
205
  result.map = { width, height, offset: { x: 0, y: 0 } };
153
206
 
154
- const offsetX = this._outBufferToJSON.readFloat();
155
- const offsetY = this._outBufferToJSON.readFloat();
207
+ const offsetX = outBufferToJSON.readFloat();
208
+ const offsetY = outBufferToJSON.readFloat();
156
209
  result.map.offset = { x: offsetX, y: offsetY };
157
210
 
158
211
  /**
159
212
  * map tiles
160
213
  */
161
- result.tiles = [];
162
- for (let h = 0; h < height + 1; h++) {
163
- const currRow = [];
164
-
165
- for (let w = 0; w < width + 1; w++) {
166
- // get the bytes from the buffer
167
- const groundHeight = this._outBufferToJSON.readShort();
168
- const waterHeightAndBoundary = this._outBufferToJSON.readShort();
169
- const flagsAndGroundTexture = this._outBufferToJSON.readByte();
170
- const groundAndCliffVariation = this._outBufferToJSON.readByte();
171
- const cliffTextureAndLayerHeight = this._outBufferToJSON.readByte();
172
-
173
- // parse out different bits (based on documentation from https://github.com/stijnherfst/HiveWE/wiki/war3map.w3e-Terrain)
174
- const waterHeight = waterHeightAndBoundary & 32767;
175
- const boundaryFlag = (waterHeightAndBoundary & 0x4000) === 0x4000;
176
- const flags = flagsAndGroundTexture & 240;
177
- const groundTexture = flagsAndGroundTexture & 15;
178
- const groundVariation = groundAndCliffVariation & 248;
179
- const cliffVariation = groundAndCliffVariation & 7;
180
- const cliffTexture = cliffTextureAndLayerHeight & 240;
181
- const layerHeight = cliffTextureAndLayerHeight & 15;
182
-
183
- // add tile
184
- currRow.push({
185
- groundHeight,
186
- waterHeight,
187
- boundaryFlag,
188
- flags,
189
- groundTexture,
190
- groundVariation,
191
- cliffVariation,
192
- cliffTexture,
193
- layerHeight
194
- });
195
- }
196
- result.tiles.unshift(currRow);
214
+ const arr_groundHeight = [];
215
+ const arr_waterHeight = [];
216
+ const arr_boundaryFlag = [];
217
+ const arr_flags = [];
218
+ const arr_groundTexture = [];
219
+ const arr_groundVariation = [];
220
+ const arr_cliffVariation = [];
221
+ const arr_cliffTexture = [];
222
+ const arr_layerHeight = [];
223
+
224
+ while(!outBufferToJSON.isExhausted()) {
225
+ const groundHeight = outBufferToJSON.readShort();
226
+ const waterHeightAndBoundary = outBufferToJSON.readShort();
227
+ const flagsAndGroundTexture = outBufferToJSON.readByte();
228
+ const groundAndCliffVariation = outBufferToJSON.readByte();
229
+ const cliffTextureAndLayerHeight = outBufferToJSON.readByte();
230
+
231
+ // parse out different bits (based on documentation from https://github.com/stijnherfst/HiveWE/wiki/war3map.w3e-Terrain)
232
+ const waterHeight = waterHeightAndBoundary & 32767;
233
+ const boundaryFlag = (waterHeightAndBoundary & 0x4000) === 0x4000;
234
+ const flags = flagsAndGroundTexture & 240;
235
+ const groundTexture = flagsAndGroundTexture & 15;
236
+ const groundVariation = groundAndCliffVariation & 248;
237
+ const cliffVariation = groundAndCliffVariation & 7;
238
+ const cliffTexture = cliffTextureAndLayerHeight & 240;
239
+ const layerHeight = cliffTextureAndLayerHeight & 15;
240
+
241
+ arr_groundHeight.push(groundHeight);
242
+ arr_waterHeight.push(waterHeight);
243
+ arr_boundaryFlag.push(boundaryFlag);
244
+ arr_flags.push(flags);
245
+ arr_groundTexture.push(groundTexture);
246
+ arr_groundVariation.push(groundVariation);
247
+ arr_cliffVariation.push(cliffVariation);
248
+ arr_cliffTexture.push(cliffTexture);
249
+ arr_layerHeight.push(layerHeight);
250
+ }
251
+
252
+ function convertArrayOfArraysIntoFlatArray(arr) {
253
+ return arr.reduce((a, b) => {
254
+ return [...a, ...b]
255
+ });
197
256
  }
198
257
 
199
- // tiles
200
- // [0, 0, 0, 0, 0, 0, 0]
258
+ // The map was read in "backwards" because wc3 maps have origin (0,0)
259
+ // at the bottom left instead of top left as we desire. Flip the rows
260
+ // vertically to fix this.
261
+ result.groundHeight = convertArrayOfArraysIntoFlatArray(splitLargeArrayIntoWidthArrays(arr_groundHeight, result.map.width + 1).reverse())
262
+ result.waterHeight = convertArrayOfArraysIntoFlatArray(splitLargeArrayIntoWidthArrays(arr_waterHeight, result.map.width + 1).reverse())
263
+ result.boundaryFlag = convertArrayOfArraysIntoFlatArray(splitLargeArrayIntoWidthArrays(arr_boundaryFlag, result.map.width + 1).reverse())
264
+ result.flags = convertArrayOfArraysIntoFlatArray(splitLargeArrayIntoWidthArrays(arr_flags, result.map.width + 1).reverse())
265
+ result.groundTexture = convertArrayOfArraysIntoFlatArray(splitLargeArrayIntoWidthArrays(arr_groundTexture, result.map.width + 1).reverse())
266
+ result.groundVariation = convertArrayOfArraysIntoFlatArray(splitLargeArrayIntoWidthArrays(arr_groundVariation, result.map.width + 1).reverse())
267
+ result.cliffVariation = convertArrayOfArraysIntoFlatArray(splitLargeArrayIntoWidthArrays(arr_cliffVariation, result.map.width + 1).reverse())
268
+ result.cliffTexture = convertArrayOfArraysIntoFlatArray(splitLargeArrayIntoWidthArrays(arr_cliffTexture, result.map.width + 1).reverse())
269
+ result.layerHeight = convertArrayOfArraysIntoFlatArray(splitLargeArrayIntoWidthArrays(arr_layerHeight, result.map.width + 1).reverse())
201
270
 
202
271
  return {
203
272
  errors: [],