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.
- package/.codeclimate.yml +0 -1
- package/.eslintignore +0 -1
- package/.github/workflows/codeql-analysis.yml +54 -0
- package/.nycrc +1 -2
- package/.travis.yml +1 -2
- package/CHANGELOG.md +78 -0
- package/LICENSE.md +23 -0
- package/README.md +68 -75
- package/index.js +11 -15
- package/index.ts +12 -30
- package/lib/CommonInterfaces.ts +22 -0
- package/lib/HexBuffer.ts +11 -14
- package/lib/W3Buffer.ts +7 -3
- package/lib/translators/CamerasTranslator.ts +36 -41
- package/lib/translators/DoodadsTranslator.ts +57 -55
- package/lib/translators/ImportsTranslator.ts +29 -31
- package/lib/translators/InfoTranslator.ts +252 -204
- package/lib/translators/{object/ObjectsTranslator.ts → ObjectsTranslator.ts} +84 -82
- package/lib/translators/RegionsTranslator.ts +40 -58
- package/lib/translators/SoundsTranslator.ts +112 -96
- package/lib/translators/StringsTranslator.ts +23 -49
- package/lib/translators/TerrainTranslator.ts +166 -97
- package/lib/translators/UnitsTranslator.ts +98 -97
- package/lib/translators/index.ts +0 -1
- package/package.json +23 -16
- package/test/.mocharc.json +4 -0
- package/test/HexBufferTest.ts +11 -15
- package/test/TranslatorReversion.ts +104 -115
- package/test/W3BufferTest.ts +19 -13
- package/test/data/cameras.json +16 -0
- package/test/data/doodads.json +2730 -0
- package/test/data/imports.json +386 -0
- package/test/data/info.json +250 -0
- package/test/data/obj-abilities.json +4892 -0
- package/test/data/obj-buffs.json +38 -0
- package/test/data/obj-destructables.json +31 -0
- package/test/data/obj-doodads.json +38 -0
- package/test/data/obj-items.json +31 -0
- package/test/data/obj-units.json +40 -0
- package/test/data/obj-upgrades.json +38 -0
- package/test/data/regions.json +206 -0
- package/test/data/sounds.json +50 -0
- package/test/data/strings.json +115 -0
- package/test/data/terrain.json +1 -0
- package/test/data/units.json +452 -0
- package/test/data/war3map.doo +0 -0
- package/test/data/war3map.imp +0 -0
- package/test/data/war3map.j +3442 -0
- package/test/data/war3map.shd +0 -0
- package/test/data/war3map.w3a +0 -0
- package/test/data/war3map.w3b +0 -0
- package/test/data/war3map.w3c +0 -0
- package/test/data/war3map.w3d +0 -0
- package/test/data/war3map.w3e +0 -0
- package/test/data/war3map.w3h +0 -0
- package/test/data/war3map.w3i +0 -0
- package/test/data/war3map.w3q +0 -0
- package/test/data/war3map.w3r +0 -0
- package/test/data/war3map.w3s +0 -0
- package/test/data/war3map.w3t +0 -0
- package/test/data/war3map.w3u +0 -0
- package/test/data/war3map.wts +631 -0
- package/test/data/war3mapUnits.doo +0 -0
- package/examples/index.js +0 -123
- package/examples/index.ts +0 -134
- package/examples/json/cameras.json +0 -16
- package/examples/json/doodads.json +0 -28499
- package/examples/json/imports.json +0 -10
- package/examples/json/info.json +0 -111
- package/examples/json/object-abilities.json +0 -31
- package/examples/json/object-buffs.json +0 -24
- package/examples/json/object-destructables.json +0 -31
- package/examples/json/object-doodads.json +0 -24
- package/examples/json/object-items.json +0 -45
- package/examples/json/object-units.json +0 -45
- package/examples/json/object-upgrades.json +0 -31
- package/examples/json/regions.json +0 -36
- package/examples/json/sounds.json +0 -46
- package/examples/json/strings.json +0 -83
- package/examples/json/terrain.json +0 -46633
- package/examples/json/units.json +0 -332
- package/examples/package.json +0 -17
- package/examples/tsconfig.json +0 -27
- package/examples/war/war3map.doo +0 -0
- package/examples/war/war3map.imp +0 -0
- package/examples/war/war3map.w3a +0 -0
- package/examples/war/war3map.w3b +0 -0
- package/examples/war/war3map.w3c +0 -0
- package/examples/war/war3map.w3d +0 -0
- package/examples/war/war3map.w3e +0 -0
- package/examples/war/war3map.w3h +0 -0
- package/examples/war/war3map.w3i +0 -0
- package/examples/war/war3map.w3q +0 -0
- package/examples/war/war3map.w3r +0 -0
- package/examples/war/war3map.w3s +0 -0
- package/examples/war/war3map.w3t +0 -0
- package/examples/war/war3map.w3u +0 -0
- package/examples/war/war3map.wts +0 -99
- package/lib/translators/index.js +0 -16
- package/test/mocha.opts +0 -4
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { HexBuffer } from '../HexBuffer';
|
|
2
2
|
import { W3Buffer } from '../W3Buffer';
|
|
3
|
+
import { WarResult, JsonResult } from '../CommonInterfaces'
|
|
3
4
|
|
|
4
5
|
interface Sound {
|
|
5
6
|
name: string;
|
|
7
|
+
variableName: string;
|
|
6
8
|
path: string;
|
|
7
|
-
eax
|
|
9
|
+
eax: string;
|
|
8
10
|
flags: SoundFlags;
|
|
9
11
|
fadeRate: FadeRate;
|
|
10
12
|
volume: number;
|
|
11
13
|
pitch: number;
|
|
12
|
-
channel:
|
|
14
|
+
channel: number;
|
|
13
15
|
distance: Distance;
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -31,65 +33,35 @@ interface Distance {
|
|
|
31
33
|
cutoff: number;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
Default = 'DefaultEAXON',
|
|
36
|
-
Combat = 'CombatSoundsEAX',
|
|
37
|
-
Drums = 'KotoDrumsEAX',
|
|
38
|
-
Spells = 'SpellsEAX',
|
|
39
|
-
Missiles = 'MissilesEAX',
|
|
40
|
-
HeroSpeech = 'HeroAcksEAX',
|
|
41
|
-
Doodads = 'DoodadsEAX'
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
enum SoundChannel {
|
|
45
|
-
General = 0,
|
|
46
|
-
UnitSelection,
|
|
47
|
-
UnitAcknowledgement,
|
|
48
|
-
UnitMovement,
|
|
49
|
-
UnitReady,
|
|
50
|
-
Combat,
|
|
51
|
-
Error,
|
|
52
|
-
Music,
|
|
53
|
-
UserInterface,
|
|
54
|
-
LoopingMovement,
|
|
55
|
-
LoopingAmbient,
|
|
56
|
-
Animations,
|
|
57
|
-
Constructions,
|
|
58
|
-
Birth,
|
|
59
|
-
Fire
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export class SoundsTranslator {
|
|
63
|
-
|
|
64
|
-
private _outBufferToWar: HexBuffer;
|
|
65
|
-
private _outBufferToJSON: W3Buffer;
|
|
66
|
-
|
|
67
|
-
constructor() { }
|
|
36
|
+
export abstract class SoundsTranslator {
|
|
68
37
|
|
|
69
|
-
public jsonToWar(soundsJson: Sound[]) {
|
|
70
|
-
|
|
38
|
+
public static jsonToWar(soundsJson: Sound[]): WarResult {
|
|
39
|
+
const outBufferToWar = new HexBuffer();
|
|
71
40
|
|
|
72
41
|
/*
|
|
73
42
|
* Header
|
|
74
43
|
*/
|
|
75
|
-
|
|
76
|
-
|
|
44
|
+
outBufferToWar.addInt(3); // file version
|
|
45
|
+
outBufferToWar.addInt(soundsJson.length); // number of sounds
|
|
77
46
|
|
|
78
47
|
/*
|
|
79
48
|
* Body
|
|
80
49
|
*/
|
|
81
50
|
soundsJson.forEach((sound) => {
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
51
|
+
outBufferToWar.addString(sound.name); // e.g. gg_snd_HumanGlueScreenLoop1
|
|
52
|
+
outBufferToWar.addString(sound.path); // e.g. Sound\Ambient\HumanGlueScreenLoop1.wav
|
|
53
|
+
|
|
54
|
+
// EAX effects enum (e.g. missiles, speech, etc)
|
|
55
|
+
/*
|
|
56
|
+
default = DefaultEAXON
|
|
57
|
+
combat = CombatSoundsEAX
|
|
58
|
+
drums = KotoDrumsEAX
|
|
59
|
+
spells = SpellsEAX
|
|
60
|
+
missiles = MissilesEAX
|
|
61
|
+
hero speech = HeroAcksEAX
|
|
62
|
+
doodads = DoodadsEAX
|
|
63
|
+
*/
|
|
64
|
+
outBufferToWar.addString(sound.eax || 'DefaultEAXON'); // defaults to "DefaultEAXON"
|
|
93
65
|
|
|
94
66
|
// Flags, if present (optional)
|
|
95
67
|
let flags = 0;
|
|
@@ -99,57 +71,88 @@ export class SoundsTranslator {
|
|
|
99
71
|
if (sound.flags.stopOutOfRange) flags |= 0x4;
|
|
100
72
|
if (sound.flags.music) flags |= 0x8;
|
|
101
73
|
}
|
|
102
|
-
|
|
74
|
+
outBufferToWar.addInt(flags);
|
|
103
75
|
|
|
104
76
|
// Fade in and out rate (optional)
|
|
105
|
-
|
|
106
|
-
|
|
77
|
+
outBufferToWar.addInt(sound.fadeRate ? sound.fadeRate.in || 10 : 10); // default to 10
|
|
78
|
+
outBufferToWar.addInt(sound.fadeRate ? sound.fadeRate.out || 10 : 10); // default to 10
|
|
107
79
|
|
|
108
80
|
// Volume (optional)
|
|
109
|
-
|
|
81
|
+
outBufferToWar.addInt(sound.volume || -1); // default to -1 (for normal volume)
|
|
110
82
|
|
|
111
83
|
// Pitch (optional)
|
|
112
|
-
|
|
84
|
+
outBufferToWar.addFloat(sound.pitch || 1.0); // default to 1.0 for normal pitch
|
|
113
85
|
|
|
114
86
|
// Mystery numbers... their use is unknown by the w3x documentation, but they must be present
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
//
|
|
119
|
-
|
|
87
|
+
outBufferToWar.addFloat(0);
|
|
88
|
+
outBufferToWar.addInt(8); // or -1?
|
|
89
|
+
|
|
90
|
+
// Which channel to use? Use the lookup table for more details (optional)
|
|
91
|
+
/*
|
|
92
|
+
0=General
|
|
93
|
+
1=Unit Selection
|
|
94
|
+
2=Unit Acknowledgement
|
|
95
|
+
3=Unit Movement
|
|
96
|
+
4=Unit Ready
|
|
97
|
+
5=Combat
|
|
98
|
+
6=Error
|
|
99
|
+
7=Music
|
|
100
|
+
8=User Interface
|
|
101
|
+
9=Looping Movement
|
|
102
|
+
10=Looping Ambient
|
|
103
|
+
11=Animations
|
|
104
|
+
12=Constructions
|
|
105
|
+
13=Birth
|
|
106
|
+
14=Fire
|
|
107
|
+
*/
|
|
108
|
+
outBufferToWar.addInt(sound.channel || 0); // default to 0
|
|
120
109
|
|
|
121
110
|
// Distance fields
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
111
|
+
outBufferToWar.addFloat(sound.distance.min);
|
|
112
|
+
outBufferToWar.addFloat(sound.distance.max);
|
|
113
|
+
outBufferToWar.addFloat(sound.distance.cutoff);
|
|
125
114
|
|
|
126
115
|
// More mystery numbers...
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
116
|
+
outBufferToWar.addFloat(0);
|
|
117
|
+
outBufferToWar.addFloat(0);
|
|
118
|
+
outBufferToWar.addFloat(127); // or -1?
|
|
119
|
+
outBufferToWar.addFloat(0);
|
|
120
|
+
outBufferToWar.addFloat(0);
|
|
121
|
+
outBufferToWar.addFloat(0);
|
|
122
|
+
|
|
123
|
+
outBufferToWar.addString(sound.variableName);
|
|
124
|
+
outBufferToWar.addString('');
|
|
125
|
+
outBufferToWar.addString(sound.path);
|
|
126
|
+
|
|
127
|
+
// More unknowns
|
|
128
|
+
outBufferToWar.addFloat(0);
|
|
129
|
+
outBufferToWar.addByte(0);
|
|
130
|
+
outBufferToWar.addFloat(0);
|
|
131
|
+
outBufferToWar.addFloat(0);
|
|
132
|
+
outBufferToWar.addFloat(0);
|
|
133
|
+
outBufferToWar.addByte(0);
|
|
134
|
+
outBufferToWar.addFloat(0);
|
|
133
135
|
});
|
|
134
136
|
|
|
135
137
|
return {
|
|
136
138
|
errors: [],
|
|
137
|
-
buffer:
|
|
139
|
+
buffer: outBufferToWar.getBuffer()
|
|
138
140
|
};
|
|
139
141
|
}
|
|
140
142
|
|
|
141
|
-
public warToJson(buffer: Buffer) {
|
|
143
|
+
public static warToJson(buffer: Buffer): JsonResult<Sound[]> {
|
|
142
144
|
const result = [];
|
|
143
|
-
|
|
145
|
+
const outBufferToJSON = new W3Buffer(buffer);
|
|
144
146
|
|
|
145
|
-
const fileVersion =
|
|
146
|
-
numSounds =
|
|
147
|
+
const fileVersion = outBufferToJSON.readInt(), // File version
|
|
148
|
+
numSounds = outBufferToJSON.readInt(); // # of sounds
|
|
147
149
|
|
|
148
150
|
for (let i = 0; i < numSounds; i++) {
|
|
149
151
|
const sound: Sound = {
|
|
150
152
|
name: '',
|
|
153
|
+
variableName: '',
|
|
151
154
|
path: '',
|
|
152
|
-
eax:
|
|
155
|
+
eax: '',
|
|
153
156
|
volume: 0,
|
|
154
157
|
pitch: 0,
|
|
155
158
|
channel: 0,
|
|
@@ -170,11 +173,11 @@ export class SoundsTranslator {
|
|
|
170
173
|
}
|
|
171
174
|
};
|
|
172
175
|
|
|
173
|
-
sound.name =
|
|
174
|
-
sound.path =
|
|
175
|
-
sound.eax =
|
|
176
|
+
sound.name = outBufferToJSON.readString();
|
|
177
|
+
sound.path = outBufferToJSON.readString();
|
|
178
|
+
sound.eax = outBufferToJSON.readString();
|
|
176
179
|
|
|
177
|
-
const flags =
|
|
180
|
+
const flags = outBufferToJSON.readInt();
|
|
178
181
|
sound.flags = {
|
|
179
182
|
'looping': !!(flags & 0b1), // 0x00000001=looping
|
|
180
183
|
'3dSound': !!(flags & 0b10), // 0x00000002=3D sound
|
|
@@ -183,32 +186,45 @@ export class SoundsTranslator {
|
|
|
183
186
|
};
|
|
184
187
|
|
|
185
188
|
sound.fadeRate = {
|
|
186
|
-
in:
|
|
187
|
-
out:
|
|
189
|
+
in: outBufferToJSON.readInt(),
|
|
190
|
+
out: outBufferToJSON.readInt()
|
|
188
191
|
};
|
|
189
192
|
|
|
190
|
-
sound.volume =
|
|
191
|
-
sound.pitch =
|
|
193
|
+
sound.volume = outBufferToJSON.readInt();
|
|
194
|
+
sound.pitch = outBufferToJSON.readFloat();
|
|
192
195
|
|
|
193
196
|
// Unknown values
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
outBufferToJSON.readFloat();
|
|
198
|
+
outBufferToJSON.readInt();
|
|
196
199
|
|
|
197
|
-
sound.channel =
|
|
200
|
+
sound.channel = outBufferToJSON.readInt();
|
|
198
201
|
|
|
199
202
|
sound.distance = {
|
|
200
|
-
min:
|
|
201
|
-
max:
|
|
202
|
-
cutoff:
|
|
203
|
+
min: outBufferToJSON.readFloat(),
|
|
204
|
+
max: outBufferToJSON.readFloat(),
|
|
205
|
+
cutoff: outBufferToJSON.readFloat()
|
|
203
206
|
};
|
|
204
207
|
|
|
205
208
|
// Unknown values
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
209
|
+
outBufferToJSON.readFloat();
|
|
210
|
+
outBufferToJSON.readFloat();
|
|
211
|
+
outBufferToJSON.readFloat();
|
|
212
|
+
outBufferToJSON.readFloat();
|
|
213
|
+
outBufferToJSON.readFloat();
|
|
214
|
+
outBufferToJSON.readFloat();
|
|
215
|
+
|
|
216
|
+
sound.variableName = outBufferToJSON.readString();
|
|
217
|
+
|
|
218
|
+
// Unknown values
|
|
219
|
+
outBufferToJSON.readString();
|
|
220
|
+
outBufferToJSON.readString();
|
|
221
|
+
outBufferToJSON.readChars(4);
|
|
222
|
+
outBufferToJSON.readChars(1);
|
|
223
|
+
outBufferToJSON.readChars(4);
|
|
224
|
+
outBufferToJSON.readChars(4);
|
|
225
|
+
outBufferToJSON.readChars(4);
|
|
226
|
+
outBufferToJSON.readChars(1);
|
|
227
|
+
outBufferToJSON.readChars(4);
|
|
212
228
|
|
|
213
229
|
result.push(sound);
|
|
214
230
|
}
|
|
@@ -1,70 +1,44 @@
|
|
|
1
1
|
import { HexBuffer } from '../HexBuffer';
|
|
2
|
+
import { WarResult, JsonResult } from '../CommonInterfaces'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
id: number;
|
|
5
|
-
text: string;
|
|
6
|
-
comment?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export class StringsTranslator {
|
|
10
|
-
private _outBufferToWar: HexBuffer;
|
|
11
|
-
|
|
12
|
-
constructor() { }
|
|
4
|
+
export abstract class StringsTranslator {
|
|
13
5
|
|
|
14
|
-
public jsonToWar(stringsJson:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// Add UTF8 byte-order mark (BOM), which is in the .wts file generated by World Editor
|
|
18
|
-
// You can see the BOM when printing the buffer of the .wts file
|
|
19
|
-
this._outBufferToWar.addBytes([0xef, 0xbb, 0xbf]); // see: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8
|
|
6
|
+
public static jsonToWar(stringsJson: object): WarResult {
|
|
7
|
+
const outBufferToWar = new HexBuffer();
|
|
20
8
|
|
|
21
9
|
/*
|
|
22
10
|
* Strings
|
|
23
11
|
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
12
|
+
Object.keys(stringsJson).forEach((key) => {
|
|
13
|
+
outBufferToWar.addChars('STRING ' + key);
|
|
14
|
+
outBufferToWar.addNewLine();
|
|
15
|
+
outBufferToWar.addChars('{');
|
|
16
|
+
outBufferToWar.addNewLine();
|
|
17
|
+
outBufferToWar.addChars(stringsJson[key]);
|
|
18
|
+
outBufferToWar.addNewLine();
|
|
19
|
+
outBufferToWar.addChars('}');
|
|
20
|
+
outBufferToWar.addNewLine();
|
|
21
|
+
outBufferToWar.addNewLine();
|
|
22
|
+
});
|
|
32
23
|
|
|
33
|
-
this._outBufferToWar.addString('{');
|
|
34
|
-
this._outBufferToWar.addNewLine();
|
|
35
|
-
|
|
36
|
-
this._outBufferToWar.addString(strDef.text);
|
|
37
|
-
this._outBufferToWar.addNewLine();
|
|
38
|
-
|
|
39
|
-
this._outBufferToWar.addString('}');
|
|
40
|
-
this._outBufferToWar.addNewLine();
|
|
41
|
-
|
|
42
|
-
this._outBufferToWar.addNewLine();
|
|
43
|
-
}
|
|
44
24
|
return {
|
|
45
25
|
errors: [],
|
|
46
|
-
buffer:
|
|
26
|
+
buffer: outBufferToWar.getBuffer()
|
|
47
27
|
};
|
|
48
28
|
}
|
|
49
29
|
|
|
50
|
-
public warToJson(buffer: Buffer) {
|
|
30
|
+
public static warToJson(buffer: Buffer): JsonResult<object> {
|
|
51
31
|
const wts = buffer.toString().replace(/\r\n/g, '\n'), // may contain Windows linebreaks (\r\n), but below regex just assumes \n
|
|
52
|
-
matchStringDefinitionBlock = new RegExp('STRING ([0-9]+)\n?(
|
|
32
|
+
matchStringDefinitionBlock = new RegExp('STRING ([0-9]+)\n?(?:.*\n)?\{\n((?:.|\n)*?)\n}', 'g'); // see: https://regexr.com/3r572
|
|
53
33
|
|
|
54
|
-
const result
|
|
55
|
-
let match
|
|
34
|
+
const result = {}; // stores the json form of strings file
|
|
35
|
+
let match; // stores individual matches as input is read
|
|
56
36
|
|
|
57
37
|
// tslint:disable-next-line: no-conditional-assignment
|
|
58
38
|
while ((match = matchStringDefinitionBlock.exec(wts)) !== null) {
|
|
59
|
-
const num =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
result.push({
|
|
64
|
-
id: num,
|
|
65
|
-
text: body,
|
|
66
|
-
comment
|
|
67
|
-
});
|
|
39
|
+
const num = match[1],
|
|
40
|
+
body = match[2];
|
|
41
|
+
result[num] = body;
|
|
68
42
|
}
|
|
69
43
|
|
|
70
44
|
return {
|