miijs 2.0.1 → 2.1.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/Enums.js +164 -0
- package/README.md +65 -22
- package/defaultMii.json +188 -0
- package/ideal.jsonc +91 -0
- package/index.js +1780 -1480
- package/out.txt +178 -0
- package/package.json +8 -3
- package/stuff.js +208 -0
- package/types.d.ts +156 -0
- package/FFLShaderMaterial.js +0 -859
- package/ffl-emscripten-single-file.js +0 -21
- package/ffl.js +0 -5051
- package/struct-fu.js +0 -1140
package/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//Imports
|
|
1
2
|
const fs = require('fs');
|
|
2
3
|
const nodeCanvas = require('canvas');
|
|
3
4
|
const { createCanvas, loadImage, ImageData } = nodeCanvas;
|
|
@@ -10,47 +11,73 @@ const httpsLib = require('https');
|
|
|
10
11
|
const asmCrypto=require("./asmCrypto.js");
|
|
11
12
|
const path=require("path");
|
|
12
13
|
const createGL = require('gl');
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
|
|
15
|
+
const req=require("require-esm-in-cjs");
|
|
16
|
+
const {
|
|
17
|
+
createCharModel, initCharModelTextures,
|
|
18
|
+
initializeFFL, exitFFL, parseHexOrB64ToUint8Array,
|
|
19
|
+
setIsWebGL1State, getCameraForViewType, ViewType
|
|
20
|
+
} = req("ffl.js/ffl.js");
|
|
21
|
+
const ModuleFFL = require("ffl.js/examples/ffl-emscripten-single-file.js");
|
|
22
|
+
const FFLShaderMaterial = require("ffl.js/FFLShaderMaterial.js");
|
|
23
|
+
|
|
24
|
+
// Typedefs for intellisence
|
|
25
|
+
/** @typedef {import('./types').WiiMii} WiiMii */
|
|
26
|
+
|
|
27
|
+
//Tools
|
|
28
|
+
function Uint8Cat(){
|
|
29
|
+
var destLength = 0
|
|
30
|
+
for(var i = 0;i < arguments.length;i++){
|
|
31
|
+
destLength += arguments[i].length;
|
|
32
|
+
}
|
|
33
|
+
var dest = new Uint8Array(destLength);
|
|
34
|
+
var index = 0;
|
|
35
|
+
for(var i=0;i<arguments.length;i++){
|
|
36
|
+
dest.set(arguments[i],index);
|
|
37
|
+
index += arguments[i].length;
|
|
21
38
|
}
|
|
39
|
+
return dest;
|
|
22
40
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if(
|
|
27
|
-
|
|
41
|
+
async function downloadImage(url) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
httpsLib.get(url, (res) => {
|
|
44
|
+
if (res.statusCode === 200) {
|
|
45
|
+
const data = [];
|
|
46
|
+
res.on('data', chunk => data.push(chunk));
|
|
47
|
+
res.on('end', () => resolve(Buffer.concat(data)));
|
|
48
|
+
res.on('error', reject);
|
|
49
|
+
} else {
|
|
50
|
+
res.resume();
|
|
51
|
+
reject(new Error(`Request Failed With a Status Code: ${res.statusCode}`));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function byteToString(int){
|
|
57
|
+
var str = int.toString(16);
|
|
58
|
+
if(str.length < 2)str = '0' + str;
|
|
59
|
+
return str;
|
|
28
60
|
}
|
|
29
61
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
62
|
+
//If FFLResHigh.dat is in the same directory as Node.js is calling the library from, use it by default
|
|
63
|
+
let _fflRes; // undefined initially
|
|
64
|
+
function getFFLRes() {
|
|
65
|
+
// If we've already tried loading, just return the result
|
|
66
|
+
if (_fflRes !== undefined) return _fflRes;
|
|
67
|
+
for (const path of [ "./FFLResHigh.dat", "./ffl/FFLResHigh.dat" ]) {
|
|
68
|
+
if (fs.existsSync(path))
|
|
69
|
+
return _fflRes = new Uint8Array(fs.readFileSync(path));
|
|
35
70
|
}
|
|
36
|
-
|
|
71
|
+
// If no file found, mark as null
|
|
72
|
+
return _fflRes = null;
|
|
37
73
|
}
|
|
74
|
+
|
|
75
|
+
//3DS QR Code (En|De)cryption
|
|
38
76
|
var NONCE_OFFSET = 0xC;
|
|
39
77
|
var NONCE_LENGTH = 8;
|
|
40
78
|
var TAG_LENGTH = 0x10;
|
|
41
79
|
var aes_key = new Uint8Array([0x59, 0xFC, 0x81, 0x7E, 0x64, 0x46, 0xEA, 0x61, 0x90, 0x34, 0x7B, 0x20, 0xE9, 0xBD, 0xCE, 0x52]);
|
|
42
80
|
var pad = new Uint8Array([0,0,0,0]);
|
|
43
|
-
function Uint8Cat(){
|
|
44
|
-
var destLength = 0
|
|
45
|
-
for(var i = 0;i < arguments.length;i++)destLength += arguments[i].length;
|
|
46
|
-
var dest = new Uint8Array(destLength);
|
|
47
|
-
var index = 0;
|
|
48
|
-
for(i = 0;i < arguments.length;i++){
|
|
49
|
-
dest.set(arguments[i],index);
|
|
50
|
-
index += arguments[i].length;
|
|
51
|
-
}
|
|
52
|
-
return dest;
|
|
53
|
-
}
|
|
54
81
|
function decodeAesCcm(data){
|
|
55
82
|
var nonce = Uint8Cat(data.subarray(0,NONCE_LENGTH),pad);
|
|
56
83
|
var ciphertext = data.subarray(NONCE_LENGTH,0x70);
|
|
@@ -79,331 +106,457 @@ function encodeAesCcm(data){
|
|
|
79
106
|
var ciphertext = asmCrypto.AES_CCM.encrypt(plaintext,aes_key,nonce,undefined,TAG_LENGTH);
|
|
80
107
|
return Uint8Cat(cfsd.subarray(NONCE_OFFSET,NONCE_OFFSET + NONCE_LENGTH),ciphertext.subarray(0,ciphertext.length - 24),ciphertext.subarray(ciphertext.length - TAG_LENGTH,ciphertext.length))
|
|
81
108
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
109
|
+
|
|
110
|
+
//Miscellaneous Tables
|
|
111
|
+
const lookupTables = {
|
|
112
|
+
favCols: ["Red", "Orange", "Yellow", "Lime", "Green", "Blue", "Cyan", "Pink", "Purple", "Brown", "White", "Black"],
|
|
113
|
+
skinCols: ["White", "Tanned White", "Darker White", "Tanned Darker", "Mostly Black", "Black"],
|
|
114
|
+
hairCols: ["Black", "Brown", "Red", "Reddish Brown", "Grey", "Light Brown", "Dark Blonde", "Blonde"],
|
|
115
|
+
eyeCols: ["Black", "Grey", "Brown", "Lime", "Blue", "Green"],
|
|
116
|
+
wiiFaceFeatures: ["None", "Blush", "Makeup and Blush", "Freckles", "Bags", "Wrinkles on Cheeks", "Wrinkles near Eyes", "Chin Wrinkle", "Makeup", "Stubble", "Wrinkles near Mouth", "Wrinkles"],
|
|
117
|
+
wiiMouthColors: ["Peach", "Red", "Pink"],
|
|
118
|
+
wiiGlassesCols: ["Grey", "Brown", "Red", "Blue", "Yellow", "White"],
|
|
119
|
+
wiiNoses: {
|
|
120
|
+
"1": 0,
|
|
121
|
+
"10": 1,
|
|
122
|
+
"2": 2,
|
|
123
|
+
"3": 3,
|
|
124
|
+
"6": 4,
|
|
125
|
+
"0": 5,
|
|
126
|
+
"5": 6,
|
|
127
|
+
"4": 7,
|
|
128
|
+
"8": 8,
|
|
129
|
+
"9": 9,
|
|
130
|
+
"7": 10,
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
pages:{
|
|
134
|
+
mouths: {
|
|
135
|
+
'0': '1',
|
|
136
|
+
'1': '1',
|
|
137
|
+
'2': '2',
|
|
138
|
+
'3': '2',
|
|
139
|
+
'4': '2',
|
|
140
|
+
'5': '1',
|
|
141
|
+
'6': '1',
|
|
142
|
+
'7': '2',
|
|
143
|
+
'8': '1',
|
|
144
|
+
'9': '2',
|
|
145
|
+
'10': '1',
|
|
146
|
+
'11': '2',
|
|
147
|
+
'12': '2',
|
|
148
|
+
'13': '1',
|
|
149
|
+
'14': '2',
|
|
150
|
+
'15': '2',
|
|
151
|
+
'16': '1',
|
|
152
|
+
'17': '2',
|
|
153
|
+
'18': '2',
|
|
154
|
+
'19': '1',
|
|
155
|
+
'20': '2',
|
|
156
|
+
'21': '1',
|
|
157
|
+
'22': '1',
|
|
158
|
+
'23': '1'
|
|
159
|
+
},
|
|
160
|
+
eyebrows:{
|
|
161
|
+
'0': '1',
|
|
162
|
+
'1': '1',
|
|
163
|
+
'2': '2',
|
|
164
|
+
'3': '2',
|
|
165
|
+
'4': '1',
|
|
166
|
+
'5': '1',
|
|
167
|
+
'6': '1',
|
|
168
|
+
'7': '1',
|
|
169
|
+
'8': '1',
|
|
170
|
+
'9': '1',
|
|
171
|
+
'10': '2',
|
|
172
|
+
'11': '2',
|
|
173
|
+
'12': '1',
|
|
174
|
+
'13': '2',
|
|
175
|
+
'14': '2',
|
|
176
|
+
'15': '2',
|
|
177
|
+
'16': '2',
|
|
178
|
+
'17': '1',
|
|
179
|
+
'18': '2',
|
|
180
|
+
'19': '1',
|
|
181
|
+
'20': '2',
|
|
182
|
+
'21': '1',
|
|
183
|
+
'22': '2',
|
|
184
|
+
'23': '2'
|
|
185
|
+
},
|
|
186
|
+
eyes:{
|
|
187
|
+
'0': '1',
|
|
188
|
+
'1': '1',
|
|
189
|
+
'2': '1',
|
|
190
|
+
'3': '4',
|
|
191
|
+
'4': '1',
|
|
192
|
+
'5': '3',
|
|
193
|
+
'6': '3',
|
|
194
|
+
'7': '4',
|
|
195
|
+
'8': '1',
|
|
196
|
+
'9': '2',
|
|
197
|
+
'10': '4',
|
|
198
|
+
'11': '2',
|
|
199
|
+
'12': '2',
|
|
200
|
+
'13': '3',
|
|
201
|
+
'14': '4',
|
|
202
|
+
'15': '1',
|
|
203
|
+
'16': '1',
|
|
204
|
+
'17': '1',
|
|
205
|
+
'18': '3',
|
|
206
|
+
'19': '2',
|
|
207
|
+
'20': '1',
|
|
208
|
+
'21': '2',
|
|
209
|
+
'22': '4',
|
|
210
|
+
'23': '2',
|
|
211
|
+
'24': '3',
|
|
212
|
+
'25': '2',
|
|
213
|
+
'26': '1',
|
|
214
|
+
'27': '1',
|
|
215
|
+
'28': '3',
|
|
216
|
+
'29': '4',
|
|
217
|
+
'30': '3',
|
|
218
|
+
'31': '3',
|
|
219
|
+
'32': '2',
|
|
220
|
+
'33': '2',
|
|
221
|
+
'34': '2',
|
|
222
|
+
'35': '2',
|
|
223
|
+
'36': '3',
|
|
224
|
+
'37': '3',
|
|
225
|
+
'38': '4',
|
|
226
|
+
'39': '1',
|
|
227
|
+
'40': '2',
|
|
228
|
+
'41': '3',
|
|
229
|
+
'42': '4',
|
|
230
|
+
'43': '4',
|
|
231
|
+
'44': '4',
|
|
232
|
+
'45': '4',
|
|
233
|
+
'46': '3',
|
|
234
|
+
'47': '4'
|
|
235
|
+
},
|
|
236
|
+
hairs:{
|
|
237
|
+
'0': '5',
|
|
238
|
+
'1': '4',
|
|
239
|
+
'2': '6',
|
|
240
|
+
'3': '5',
|
|
241
|
+
'4': '4',
|
|
242
|
+
'5': '4',
|
|
243
|
+
'6': '5',
|
|
244
|
+
'7': '4',
|
|
245
|
+
'8': '4',
|
|
246
|
+
'9': '6',
|
|
247
|
+
'10': '5',
|
|
248
|
+
'11': '5',
|
|
249
|
+
'12': '4',
|
|
250
|
+
'13': '4',
|
|
251
|
+
'14': '5',
|
|
252
|
+
'15': '6',
|
|
253
|
+
'16': '6',
|
|
254
|
+
'17': '5',
|
|
255
|
+
'18': '6',
|
|
256
|
+
'19': '4',
|
|
257
|
+
'20': '5',
|
|
258
|
+
'21': '5',
|
|
259
|
+
'22': '5',
|
|
260
|
+
'23': '3',
|
|
261
|
+
'24': '6',
|
|
262
|
+
'25': '4',
|
|
263
|
+
'26': '4',
|
|
264
|
+
'27': '4',
|
|
265
|
+
'28': '6',
|
|
266
|
+
'29': '6',
|
|
267
|
+
'30': '3',
|
|
268
|
+
'31': '1',
|
|
269
|
+
'32': '2',
|
|
270
|
+
'33': '1',
|
|
271
|
+
'34': '3',
|
|
272
|
+
'35': '5',
|
|
273
|
+
'36': '3',
|
|
274
|
+
'37': '2',
|
|
275
|
+
'38': '3',
|
|
276
|
+
'39': '1',
|
|
277
|
+
'40': '1',
|
|
278
|
+
'41': '3',
|
|
279
|
+
'42': '3',
|
|
280
|
+
'43': '3',
|
|
281
|
+
'44': '1',
|
|
282
|
+
'45': '1',
|
|
283
|
+
'46': '6',
|
|
284
|
+
'47': '2',
|
|
285
|
+
'48': '2',
|
|
286
|
+
'49': '1',
|
|
287
|
+
'50': '2',
|
|
288
|
+
'51': '1',
|
|
289
|
+
'52': '2',
|
|
290
|
+
'53': '6',
|
|
291
|
+
'54': '3',
|
|
292
|
+
'55': '2',
|
|
293
|
+
'56': '1',
|
|
294
|
+
'57': '3',
|
|
295
|
+
'58': '2',
|
|
296
|
+
'59': '1',
|
|
297
|
+
'60': '2',
|
|
298
|
+
'61': '6',
|
|
299
|
+
'62': '2',
|
|
300
|
+
'63': '5',
|
|
301
|
+
'64': '2',
|
|
302
|
+
'65': '3',
|
|
303
|
+
'66': '2',
|
|
304
|
+
'67': '3',
|
|
305
|
+
'68': '1',
|
|
306
|
+
'69': '4',
|
|
307
|
+
'70': '1',
|
|
308
|
+
'71': '6'
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
types:{
|
|
312
|
+
"mouths": {
|
|
313
|
+
"0": 6,
|
|
314
|
+
"1": 1,
|
|
315
|
+
"2": 2,
|
|
316
|
+
"3": 4,
|
|
317
|
+
"4": 5,
|
|
318
|
+
"5": 5,
|
|
319
|
+
"6": 10,
|
|
320
|
+
"7": 0,
|
|
321
|
+
"8": 7,
|
|
322
|
+
"9": 1,
|
|
323
|
+
"10": 8,
|
|
324
|
+
"11": 7,
|
|
325
|
+
"12": 11,
|
|
326
|
+
"13": 11,
|
|
327
|
+
"14": 10,
|
|
328
|
+
"15": 6,
|
|
329
|
+
"16": 9,
|
|
330
|
+
"17": 3,
|
|
331
|
+
"18": 9,
|
|
332
|
+
"19": 2,
|
|
333
|
+
"20": 8,
|
|
334
|
+
"21": 3,
|
|
335
|
+
"22": 4,
|
|
336
|
+
"23": 0
|
|
337
|
+
},
|
|
338
|
+
"eyebrows": {
|
|
339
|
+
"0": 1,
|
|
340
|
+
"1": 3,
|
|
341
|
+
"2": 2,
|
|
342
|
+
"3": 3,
|
|
343
|
+
"4": 11,
|
|
344
|
+
"5": 10,
|
|
345
|
+
"6": 0,
|
|
346
|
+
"7": 6,
|
|
347
|
+
"8": 8,
|
|
348
|
+
"9": 4,
|
|
349
|
+
"10": 1,
|
|
350
|
+
"11": 0,
|
|
351
|
+
"12": 2,
|
|
352
|
+
"13": 7,
|
|
353
|
+
"14": 4,
|
|
354
|
+
"15": 6,
|
|
355
|
+
"16": 10,
|
|
356
|
+
"17": 9,
|
|
357
|
+
"18": 9,
|
|
358
|
+
"19": 5,
|
|
359
|
+
"20": 5,
|
|
360
|
+
"21": 7,
|
|
361
|
+
"22": 8,
|
|
362
|
+
"23": 11
|
|
363
|
+
},
|
|
364
|
+
"eyes": {
|
|
365
|
+
"0": 2,
|
|
366
|
+
"1": 6,
|
|
367
|
+
"2": 0,
|
|
368
|
+
"3": 6,
|
|
369
|
+
"4": 1,
|
|
370
|
+
"5": 0,
|
|
371
|
+
"6": 5,
|
|
372
|
+
"7": 0,
|
|
373
|
+
"8": 3,
|
|
374
|
+
"9": 4,
|
|
375
|
+
"10": 9,
|
|
376
|
+
"11": 1,
|
|
377
|
+
"12": 5,
|
|
378
|
+
"13": 2,
|
|
379
|
+
"14": 10,
|
|
380
|
+
"15": 9,
|
|
381
|
+
"16": 8,
|
|
382
|
+
"17": 5,
|
|
383
|
+
"18": 9,
|
|
384
|
+
"19": 2,
|
|
385
|
+
"20": 11,
|
|
386
|
+
"21": 8,
|
|
387
|
+
"22": 8,
|
|
388
|
+
"23": 6,
|
|
389
|
+
"24": 6,
|
|
390
|
+
"25": 9,
|
|
391
|
+
"26": 7,
|
|
392
|
+
"27": 10,
|
|
393
|
+
"28": 10,
|
|
394
|
+
"29": 5,
|
|
395
|
+
"30": 7,
|
|
396
|
+
"31": 8,
|
|
397
|
+
"32": 3,
|
|
398
|
+
"33": 0,
|
|
399
|
+
"34": 7,
|
|
400
|
+
"35": 11,
|
|
401
|
+
"36": 3,
|
|
402
|
+
"37": 4,
|
|
403
|
+
"38": 2,
|
|
404
|
+
"39": 4,
|
|
405
|
+
"40": 10,
|
|
406
|
+
"41": 1,
|
|
407
|
+
"42": 3,
|
|
408
|
+
"43": 7,
|
|
409
|
+
"44": 1,
|
|
410
|
+
"45": 4,
|
|
411
|
+
"46": 11,
|
|
412
|
+
"47": 11
|
|
413
|
+
},
|
|
414
|
+
"hairs": {
|
|
415
|
+
"0": 11,
|
|
416
|
+
"1": 6,
|
|
417
|
+
"2": 5,
|
|
418
|
+
"3": 1,
|
|
419
|
+
"4": 4,
|
|
420
|
+
"5": 8,
|
|
421
|
+
"6": 4,
|
|
422
|
+
"7": 11,
|
|
423
|
+
"8": 9,
|
|
424
|
+
"9": 3,
|
|
425
|
+
"10": 3,
|
|
426
|
+
"11": 6,
|
|
427
|
+
"12": 0,
|
|
428
|
+
"13": 1,
|
|
429
|
+
"14": 0,
|
|
430
|
+
"15": 10,
|
|
431
|
+
"16": 1,
|
|
432
|
+
"17": 8,
|
|
433
|
+
"18": 4,
|
|
434
|
+
"19": 7,
|
|
435
|
+
"20": 5,
|
|
436
|
+
"21": 10,
|
|
437
|
+
"22": 2,
|
|
438
|
+
"23": 3,
|
|
439
|
+
"24": 9,
|
|
440
|
+
"25": 5,
|
|
441
|
+
"26": 3,
|
|
442
|
+
"27": 10,
|
|
443
|
+
"28": 6,
|
|
444
|
+
"29": 11,
|
|
445
|
+
"30": 9,
|
|
446
|
+
"31": 11,
|
|
447
|
+
"32": 0,
|
|
448
|
+
"33": 0,
|
|
449
|
+
"34": 11,
|
|
450
|
+
"35": 9,
|
|
451
|
+
"36": 6,
|
|
452
|
+
"37": 2,
|
|
453
|
+
"38": 1,
|
|
454
|
+
"39": 4,
|
|
455
|
+
"40": 1,
|
|
456
|
+
"41": 7,
|
|
457
|
+
"42": 2,
|
|
458
|
+
"43": 0,
|
|
459
|
+
"44": 3,
|
|
460
|
+
"45": 6,
|
|
461
|
+
"46": 2,
|
|
462
|
+
"47": 1,
|
|
463
|
+
"48": 3,
|
|
464
|
+
"49": 7,
|
|
465
|
+
"50": 7,
|
|
466
|
+
"51": 2,
|
|
467
|
+
"52": 5,
|
|
468
|
+
"53": 7,
|
|
469
|
+
"54": 5,
|
|
470
|
+
"55": 8,
|
|
471
|
+
"56": 9,
|
|
472
|
+
"57": 10,
|
|
473
|
+
"58": 6,
|
|
474
|
+
"59": 8,
|
|
475
|
+
"60": 10,
|
|
476
|
+
"61": 0,
|
|
477
|
+
"62": 11,
|
|
478
|
+
"63": 7,
|
|
479
|
+
"64": 9,
|
|
480
|
+
"65": 8,
|
|
481
|
+
"66": 4,
|
|
482
|
+
"67": 4,
|
|
483
|
+
"68": 10,
|
|
484
|
+
"69": 2,
|
|
485
|
+
"70": 5,
|
|
486
|
+
"71": 8
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
// 3DS fields
|
|
491
|
+
faceFeatures3DS: ["None", "Near Eye Creases", "Cheek Creases", "Far Eye Creases", "Near Nose Creases", "Giant Bags", "Cleft Chin", "Chin Crease", "Sunken Eyes", "Far Cheek Creases", "Lines Near Eyes", "Wrinkles"],
|
|
492
|
+
makeups3DS: ["None", "Blush", "Orange Blush", "Blue Eyes", "Blush 2", "Orange Blush 2", "Blue Eyes and Blush", "Orange Eyes and Blush", "Purple Eyes and Blush 2", "Freckles", "Beard Stubble", "Beard and Mustache Stubble"],
|
|
493
|
+
mouthCols3DS: ["Orange", "Red", "Pink", "Peach", "Black"],
|
|
494
|
+
glassesCols3DS: ["Black", "Brown", "Red", "Blue", "Yellow", "Grey"],
|
|
495
|
+
|
|
496
|
+
faces: {
|
|
497
|
+
indexLookup: true,
|
|
498
|
+
values: [
|
|
499
|
+
0x00, 0x01, 0x08,
|
|
500
|
+
0x02, 0x03, 0x09,
|
|
501
|
+
0x04, 0x05, 0x0a,
|
|
502
|
+
0x06, 0x07, 0x0b
|
|
503
|
+
]
|
|
504
|
+
},
|
|
505
|
+
hairs: {
|
|
506
|
+
paginated: true,
|
|
507
|
+
indexLookup: true,
|
|
508
|
+
values: [
|
|
509
|
+
[0x21, 0x2f, 0x28, 0x25, 0x20, 0x6b, 0x30, 0x33, 0x37, 0x46, 0x2c, 0x42],
|
|
510
|
+
[0x34, 0x32, 0x26, 0x31, 0x2b, 0x1f, 0x38, 0x44, 0x3e, 0x73, 0x4c, 0x77],
|
|
511
|
+
[0x40, 0x51, 0x74, 0x79, 0x16, 0x3a, 0x3c, 0x57, 0x7d, 0x75, 0x49, 0x4b],
|
|
512
|
+
[0x2a, 0x59, 0x39, 0x36, 0x50, 0x22, 0x17, 0x56, 0x58, 0x76, 0x27, 0x24],
|
|
513
|
+
[0x2d, 0x43, 0x3b, 0x41, 0x29, 0x1e, 0x0c, 0x10, 0x0a, 0x52, 0x80, 0x81],
|
|
514
|
+
[0x0e, 0x5f, 0x69, 0x64, 0x06, 0x14, 0x5d, 0x66, 0x1b, 0x04, 0x11, 0x6e],
|
|
515
|
+
[0x7b, 0x08, 0x6a, 0x48, 0x03, 0x15, 0x00, 0x62, 0x3f, 0x5a, 0x0b, 0x78],
|
|
516
|
+
[0x05, 0x4a, 0x6c, 0x5e, 0x7c, 0x19, 0x63, 0x45, 0x23, 0x0d, 0x7a, 0x71],
|
|
517
|
+
[0x35, 0x18, 0x55, 0x53, 0x47, 0x83, 0x60, 0x65, 0x1d, 0x07, 0x0f, 0x70],
|
|
518
|
+
[0x4f, 0x01, 0x6d, 0x7f, 0x5b, 0x1a, 0x3d, 0x67, 0x02, 0x4d, 0x12, 0x5c],
|
|
519
|
+
[0x54, 0x09, 0x13, 0x82, 0x61, 0x68, 0x2e, 0x4e, 0x1c, 0x72, 0x7e, 0x6f]
|
|
520
|
+
]
|
|
521
|
+
},
|
|
522
|
+
eyebrows: {
|
|
523
|
+
indexLookup: true,
|
|
524
|
+
paginated: true,
|
|
525
|
+
values: [
|
|
526
|
+
[0x06, 0x00, 0x0c, 0x01, 0x09, 0x13, 0x07, 0x15, 0x08, 0x11, 0x05, 0x04],
|
|
527
|
+
[0x0b, 0x0a, 0x02, 0x03, 0x0e, 0x14, 0x0f, 0x0d, 0x16, 0x12, 0x10, 0x17]
|
|
528
|
+
]
|
|
529
|
+
},
|
|
530
|
+
eyes: {
|
|
531
|
+
indexLookup: true,
|
|
532
|
+
paginated: true,
|
|
533
|
+
values: [
|
|
534
|
+
[0x02, 0x04, 0x00, 0x08, 0x27, 0x11, 0x01, 0x1a, 0x10, 0x0f, 0x1b, 0x14],
|
|
535
|
+
[0x21, 0x0b, 0x13, 0x20, 0x09, 0x0c, 0x17, 0x22, 0x15, 0x19, 0x28, 0x23],
|
|
536
|
+
[0x05, 0x29, 0x0d, 0x24, 0x25, 0x06, 0x18, 0x1e, 0x1f, 0x12, 0x1c, 0x2e],
|
|
537
|
+
[0x07, 0x2c, 0x26, 0x2a, 0x2d, 0x1d, 0x03, 0x2b, 0x16, 0x0a, 0x0e, 0x2f],
|
|
538
|
+
[0x30, 0x31, 0x32, 0x35, 0x3b, 0x38, 0x36, 0x3a, 0x39, 0x37, 0x33, 0x34]
|
|
539
|
+
]
|
|
540
|
+
},
|
|
541
|
+
noses: {
|
|
542
|
+
indexLookup: true,
|
|
543
|
+
paginated: true,
|
|
544
|
+
values: [
|
|
545
|
+
[0x01, 0x0a, 0x02, 0x03, 0x06, 0x00, 0x05, 0x04, 0x08, 0x09, 0x07, 0x0B],
|
|
546
|
+
[0x0d, 0x0e, 0x0c, 0x11, 0x10, 0x0f]
|
|
547
|
+
]
|
|
548
|
+
},
|
|
549
|
+
mouths: {
|
|
550
|
+
indexLookup: true,
|
|
551
|
+
paginated: true,
|
|
552
|
+
values: [
|
|
553
|
+
[0x17, 0x01, 0x13, 0x15, 0x16, 0x05, 0x00, 0x08, 0x0a, 0x10, 0x06, 0x0d],
|
|
554
|
+
[0x07, 0x09, 0x02, 0x11, 0x03, 0x04, 0x0f, 0x0b, 0x14, 0x12, 0x0e, 0x0c],
|
|
555
|
+
[0x1b, 0x1e, 0x18, 0x19, 0x1d, 0x1c, 0x1a, 0x23, 0x1f, 0x22, 0x21, 0x20]
|
|
556
|
+
]
|
|
557
|
+
}
|
|
406
558
|
};
|
|
559
|
+
|
|
407
560
|
var convTables={
|
|
408
561
|
face3DSToWii:[0,1,2,2,3,1,4,5,4,6,7,6],
|
|
409
562
|
features3DSToWii:["0","6",5,6,"6",4,7,7,8,10,"6",11],//If typeof===String, choose a makeup in that field's place - there is no suitable replacement. Read the discrepancies in the README for more information.
|
|
@@ -582,26 +735,7 @@ var convTables={
|
|
|
582
735
|
"10",9,11
|
|
583
736
|
]
|
|
584
737
|
};
|
|
585
|
-
|
|
586
|
-
if(paginated){
|
|
587
|
-
for(var i=0;i<tables[table].length;i++){
|
|
588
|
-
for(var j=0;j<tables[table][i].length;j++){
|
|
589
|
-
if(tables[table][i][j]===value){
|
|
590
|
-
return [i,j];
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
else{
|
|
596
|
-
for(var i=0;i<tables[table].length;i++){
|
|
597
|
-
if(tables[table][i]===value){
|
|
598
|
-
return i;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
return undefined;
|
|
603
|
-
}
|
|
604
|
-
var kidNames={
|
|
738
|
+
const kidNames={
|
|
605
739
|
"Male":[
|
|
606
740
|
"Aaron",
|
|
607
741
|
"Adam",
|
|
@@ -890,7 +1024,9 @@ var kidNames={
|
|
|
890
1024
|
"Taylor"
|
|
891
1025
|
]
|
|
892
1026
|
};
|
|
893
|
-
|
|
1027
|
+
|
|
1028
|
+
//Defaults
|
|
1029
|
+
const defaultInstrs={
|
|
894
1030
|
wii:{
|
|
895
1031
|
male:{
|
|
896
1032
|
"col": "On the info page (first tab), set the Favorite Color to Red (1 from the left, top row).",
|
|
@@ -1073,1148 +1209,1068 @@ var defaultInstrs={
|
|
|
1073
1209
|
}
|
|
1074
1210
|
};
|
|
1075
1211
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1212
|
+
const defaultMii={
|
|
1213
|
+
"male":{
|
|
1214
|
+
"general": {
|
|
1215
|
+
"type":3,
|
|
1216
|
+
"birthday": 17,
|
|
1217
|
+
"birthMonth": 4,
|
|
1218
|
+
"height": 0,
|
|
1219
|
+
"weight": 0,
|
|
1220
|
+
"gender": 1,
|
|
1221
|
+
"favoriteColor": 7
|
|
1222
|
+
},
|
|
1223
|
+
"meta":{
|
|
1224
|
+
"name": "Madison",
|
|
1225
|
+
"creatorName": "",
|
|
1226
|
+
"console":"3ds"
|
|
1227
|
+
},
|
|
1228
|
+
"perms": {
|
|
1229
|
+
"sharing": false,
|
|
1230
|
+
"copying": true,
|
|
1231
|
+
"fromCheckMiiOut": false,
|
|
1232
|
+
"mingle": true
|
|
1233
|
+
},
|
|
1234
|
+
"hair": {
|
|
1235
|
+
"page":0,
|
|
1236
|
+
"type":7,
|
|
1237
|
+
"color": 7,
|
|
1238
|
+
"flipped": false
|
|
1239
|
+
},
|
|
1240
|
+
"face": {
|
|
1241
|
+
"type": 5,
|
|
1242
|
+
"color": 0,
|
|
1243
|
+
"feature": 0,
|
|
1244
|
+
"makeup": 0
|
|
1245
|
+
},
|
|
1246
|
+
"eyes": {
|
|
1247
|
+
"page":0,
|
|
1248
|
+
"type": 9,
|
|
1249
|
+
"col": 4,
|
|
1250
|
+
"size": 1,
|
|
1251
|
+
"squash": 3,
|
|
1252
|
+
"rotation": 4,
|
|
1253
|
+
"distanceApart": 3,
|
|
1254
|
+
"yPosition": 11
|
|
1255
|
+
},
|
|
1256
|
+
"eyebrows": {
|
|
1257
|
+
"page":0,
|
|
1258
|
+
"type":5,
|
|
1259
|
+
"color":7,
|
|
1260
|
+
"size": 2,
|
|
1261
|
+
"squash": 4,
|
|
1262
|
+
"rotation": 4,
|
|
1263
|
+
"distanceApart": 4,
|
|
1264
|
+
"yPosition": 6
|
|
1265
|
+
},
|
|
1266
|
+
"nose": {
|
|
1267
|
+
"page":1,
|
|
1268
|
+
"type":0,
|
|
1269
|
+
"size": 0,
|
|
1270
|
+
"yPosition": 5
|
|
1271
|
+
},
|
|
1272
|
+
"mouth": {
|
|
1273
|
+
"page":1,
|
|
1274
|
+
"type":6,
|
|
1275
|
+
"color": 0,
|
|
1276
|
+
"size": 2,
|
|
1277
|
+
"squash": 3,
|
|
1278
|
+
"yPosition": 10
|
|
1279
|
+
},
|
|
1280
|
+
"beard": {
|
|
1281
|
+
"mustache":{
|
|
1282
|
+
"type": 0,
|
|
1283
|
+
"size": 4,
|
|
1284
|
+
"yPosition": 10
|
|
1285
|
+
},
|
|
1286
|
+
"col": 0,
|
|
1287
|
+
"type": 0
|
|
1288
|
+
},
|
|
1289
|
+
"glasses": {
|
|
1290
|
+
"type": 0,
|
|
1291
|
+
"color":0,
|
|
1292
|
+
"size": 4,
|
|
1293
|
+
"yPosition": 10
|
|
1294
|
+
},
|
|
1295
|
+
"mole": {
|
|
1296
|
+
"on": false,
|
|
1297
|
+
"size": 4,
|
|
1298
|
+
"xPosition": 2,
|
|
1299
|
+
"yPosition": 20
|
|
1300
|
+
},
|
|
1301
|
+
"name": "",
|
|
1302
|
+
"creatorName": ""
|
|
1303
|
+
},
|
|
1304
|
+
"female":{
|
|
1305
|
+
"general": {
|
|
1306
|
+
"type":3,
|
|
1307
|
+
"birthday": 17,
|
|
1308
|
+
"birthMonth": 4,
|
|
1309
|
+
"height": 0,
|
|
1310
|
+
"weight": 0,
|
|
1311
|
+
"gender": 1,
|
|
1312
|
+
"favoriteColor": 7
|
|
1313
|
+
},
|
|
1314
|
+
"meta":{
|
|
1315
|
+
"name": "Madison",
|
|
1316
|
+
"creatorName": "",
|
|
1317
|
+
"console":"3ds"
|
|
1318
|
+
},
|
|
1319
|
+
"perms": {
|
|
1320
|
+
"sharing": false,
|
|
1321
|
+
"copying": true,
|
|
1322
|
+
"fromCheckMiiOut": false,
|
|
1323
|
+
"mingle": true
|
|
1324
|
+
},
|
|
1325
|
+
"hair": {
|
|
1326
|
+
"page":0,
|
|
1327
|
+
"type":7,
|
|
1328
|
+
"color": 7,
|
|
1329
|
+
"flipped": false
|
|
1330
|
+
},
|
|
1331
|
+
"face": {
|
|
1332
|
+
"type": 5,
|
|
1333
|
+
"color": 0,
|
|
1334
|
+
"feature": 0,
|
|
1335
|
+
"makeup": 0
|
|
1336
|
+
},
|
|
1337
|
+
"eyes": {
|
|
1338
|
+
"page":0,
|
|
1339
|
+
"type": 9,
|
|
1340
|
+
"col": 4,
|
|
1341
|
+
"size": 1,
|
|
1342
|
+
"squash": 3,
|
|
1343
|
+
"rotation": 4,
|
|
1344
|
+
"distanceApart": 3,
|
|
1345
|
+
"yPosition": 11
|
|
1346
|
+
},
|
|
1347
|
+
"eyebrows": {
|
|
1348
|
+
"page":0,
|
|
1349
|
+
"type":5,
|
|
1350
|
+
"color":7,
|
|
1351
|
+
"size": 2,
|
|
1352
|
+
"squash": 4,
|
|
1353
|
+
"rotation": 4,
|
|
1354
|
+
"distanceApart": 4,
|
|
1355
|
+
"yPosition": 6
|
|
1356
|
+
},
|
|
1357
|
+
"nose": {
|
|
1358
|
+
"page":1,
|
|
1359
|
+
"type":0,
|
|
1360
|
+
"size": 0,
|
|
1361
|
+
"yPosition": 5
|
|
1362
|
+
},
|
|
1363
|
+
"mouth": {
|
|
1364
|
+
"page":1,
|
|
1365
|
+
"type":6,
|
|
1366
|
+
"color": 0,
|
|
1367
|
+
"size": 2,
|
|
1368
|
+
"squash": 3,
|
|
1369
|
+
"yPosition": 10
|
|
1370
|
+
},
|
|
1371
|
+
"beard": {
|
|
1372
|
+
"mustache":{
|
|
1373
|
+
"type": 0,
|
|
1374
|
+
"size": 4,
|
|
1375
|
+
"yPosition": 10
|
|
1376
|
+
},
|
|
1377
|
+
"col": 0,
|
|
1378
|
+
"type": 0
|
|
1379
|
+
},
|
|
1380
|
+
"glasses": {
|
|
1381
|
+
"type": 0,
|
|
1382
|
+
"color":0,
|
|
1383
|
+
"size": 4,
|
|
1384
|
+
"yPosition": 10
|
|
1385
|
+
},
|
|
1386
|
+
"mole": {
|
|
1387
|
+
"on": false,
|
|
1388
|
+
"size": 4,
|
|
1389
|
+
"xPosition": 2,
|
|
1390
|
+
"yPosition": 20
|
|
1391
|
+
},
|
|
1392
|
+
"name": "",
|
|
1393
|
+
"creatorName": ""
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1128
1396
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1397
|
+
// Mii binary helpers
|
|
1398
|
+
const decoders = {
|
|
1399
|
+
number: (value, field) => value + (field.offset || 0),
|
|
1400
|
+
boolean: (value, field) => field.invert ? value === 0 : value === 1,
|
|
1401
|
+
enum: (value, field) => field.values[value],
|
|
1402
|
+
lookup: (value, field, tables) => {
|
|
1403
|
+
const table = getNestedProperty(tables, field.lookupTable)
|
|
1404
|
+
if (!table) return "ERROR: could not find requested lookup table";
|
|
1136
1405
|
|
|
1137
|
-
|
|
1406
|
+
if (table.indexLookup) {
|
|
1407
|
+
if (table.paginated) {
|
|
1408
|
+
// Handle paginated (2D array) lookup
|
|
1409
|
+
for (let page = 0; page < table.values.length; page++) {
|
|
1410
|
+
for (let index = 0; index < table.values[page].length; index++) {
|
|
1411
|
+
if (table.values[page][index] === value) {
|
|
1412
|
+
return [page, index];
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return undefined;
|
|
1417
|
+
} else {
|
|
1418
|
+
// Handle non-paginated index lookup
|
|
1419
|
+
return table.values.indexOf(value);
|
|
1420
|
+
}
|
|
1421
|
+
} else if (Array.isArray(table)) {
|
|
1422
|
+
return table[value];
|
|
1423
|
+
} else {
|
|
1424
|
+
return table[value.toString()];
|
|
1425
|
+
}
|
|
1426
|
+
},
|
|
1427
|
+
lookupPage: (value, field, tables, type) => {
|
|
1428
|
+
const table = getNestedProperty(tables, field.lookupTable)
|
|
1429
|
+
if (!table) return "ERROR: could not find requested lookup table";
|
|
1138
1430
|
|
|
1139
|
-
|
|
1431
|
+
if (table.indexLookup) {
|
|
1432
|
+
if (table.paginated) {
|
|
1433
|
+
// Handle paginated (2D array) lookup
|
|
1434
|
+
for (let page = 0; page < table.values.length; page++) {
|
|
1435
|
+
for (let index = 0; index < table.values[page].length; index++) {
|
|
1436
|
+
if (table.values[page][index] === value) {
|
|
1437
|
+
return [page, index][0];
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
return undefined;
|
|
1442
|
+
} else {
|
|
1443
|
+
// Handle non-paginated index lookup
|
|
1444
|
+
return table.values.indexOf(value);
|
|
1445
|
+
}
|
|
1446
|
+
} else if (Array.isArray(table)) {
|
|
1447
|
+
return table[value];
|
|
1448
|
+
} else {
|
|
1449
|
+
return table[value.toString()];
|
|
1450
|
+
}
|
|
1451
|
+
},
|
|
1452
|
+
lookupType: (value, field, tables, type) => {
|
|
1453
|
+
const table = getNestedProperty(tables, field.lookupTable)
|
|
1454
|
+
if (!table) return "ERROR: could not find requested lookup table";
|
|
1140
1455
|
|
|
1456
|
+
if (table.indexLookup) {
|
|
1457
|
+
if (table.paginated) {
|
|
1458
|
+
// Handle paginated (2D array) lookup
|
|
1459
|
+
for (let page = 0; page < table.values.length; page++) {
|
|
1460
|
+
for (let index = 0; index < table.values[page].length; index++) {
|
|
1461
|
+
if (table.values[page][index] === value) {
|
|
1462
|
+
return [page, index][1];
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
return undefined;
|
|
1467
|
+
} else {
|
|
1468
|
+
// Handle non-paginated index lookup
|
|
1469
|
+
return table.values.indexOf(value);
|
|
1470
|
+
}
|
|
1471
|
+
} else if (Array.isArray(table)) {
|
|
1472
|
+
return table[value];
|
|
1473
|
+
} else {
|
|
1474
|
+
return table[value.toString()];
|
|
1475
|
+
}
|
|
1476
|
+
},
|
|
1477
|
+
color: (value, field, tables) => tables[field.colorArray]?.[value] || value
|
|
1478
|
+
};
|
|
1141
1479
|
|
|
1480
|
+
const encoders = {
|
|
1481
|
+
number: (value, field) => value - (field.offset || 0),
|
|
1482
|
+
boolean: (value, field) => field.invert ? (value ? 0 : 1) : (value ? 1 : 0),
|
|
1483
|
+
enum: (value, field) => field.values.indexOf(value),
|
|
1484
|
+
lookup: (decodedValue, field, tables) => {
|
|
1485
|
+
const table = getNestedProperty(tables, field.lookupTable)
|
|
1486
|
+
if (!table) return "ERROR: could not find requested lookup table";
|
|
1142
1487
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1488
|
+
if (table.indexLookup){
|
|
1489
|
+
if (table.paginated) {
|
|
1490
|
+
if (!Array.isArray(decodedValue) || decodedValue.length !== 2) {
|
|
1491
|
+
return undefined;
|
|
1492
|
+
}
|
|
1493
|
+
const [page, index] = decodedValue;
|
|
1494
|
+
if (page >= 0 && page < table.values.length && index >= 0 && index < table.values[page].length) {
|
|
1495
|
+
return table.values[page][index];
|
|
1496
|
+
}
|
|
1497
|
+
return undefined;
|
|
1498
|
+
} else {
|
|
1499
|
+
return table.values[decodedValue];
|
|
1500
|
+
}
|
|
1501
|
+
} else if (Array.isArray(table)) {
|
|
1502
|
+
const index = table.indexOf(decodedValue);
|
|
1503
|
+
return index !== -1 ? index : undefined;
|
|
1504
|
+
} else {
|
|
1505
|
+
// Handle object lookup
|
|
1506
|
+
for (const [key, val] of Object.entries(table)) {
|
|
1507
|
+
if (val === decodedValue) return parseInt(key);
|
|
1508
|
+
}
|
|
1509
|
+
return undefined;
|
|
1510
|
+
}
|
|
1511
|
+
},
|
|
1512
|
+
color: (value, field, T) => {
|
|
1513
|
+
const arr = T[field.colorArray];
|
|
1514
|
+
return arr?.indexOf(value) ?? value;
|
|
1515
|
+
},
|
|
1516
|
+
};
|
|
1146
1517
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1518
|
+
// Decoding system
|
|
1519
|
+
function decodeString(data, field) {
|
|
1520
|
+
let result = "";
|
|
1521
|
+
const maxLength = field.maxLength || 10;
|
|
1522
|
+
|
|
1523
|
+
for (let i = 0; i < maxLength; i++) {
|
|
1524
|
+
const charOffset = field.byteOffset + (i * 2);
|
|
1525
|
+
if (charOffset + 1 < data.length) {
|
|
1526
|
+
const char1 = data[charOffset];
|
|
1527
|
+
const char2 = data[charOffset + 1];
|
|
1528
|
+
if (char1 === 0 && char2 === 0) break;
|
|
1529
|
+
result += String.fromCharCode(field.endianness == "little" ? char1 : char2);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
return result.replace(/\x00/g, "");
|
|
1533
|
+
}
|
|
1150
1534
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
const
|
|
1154
|
-
const dstStart = (height - y - 1) * rowBytes;
|
|
1155
|
-
src.copy(flipped, dstStart, srcStart, srcStart + rowBytes);
|
|
1156
|
-
}
|
|
1535
|
+
function encodeString(str, field) {
|
|
1536
|
+
const result = [];
|
|
1537
|
+
const maxLength = field.maxLength || 10;
|
|
1157
1538
|
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
const ctx = canvas.getContext('2d');
|
|
1161
|
-
const img = new ImageData(new Uint8ClampedArray(flipped.buffer), width, height);
|
|
1162
|
-
ctx.putImageData(img, 0, 0);
|
|
1539
|
+
for (let i = 0; i < maxLength; i++) {
|
|
1540
|
+
const code = i < str.length ? str.charCodeAt(i) : 0;
|
|
1163
1541
|
|
|
1164
|
-
|
|
1542
|
+
if (field.endianness == "little") {
|
|
1543
|
+
result.push(code); // Low byte
|
|
1544
|
+
result.push(0); // High byte
|
|
1545
|
+
} else {
|
|
1546
|
+
result.push(0); // High byte
|
|
1547
|
+
result.push(code); // Low byte
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
return result;
|
|
1165
1551
|
}
|
|
1166
1552
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
info:{},
|
|
1171
|
-
face:{},
|
|
1172
|
-
nose:{},
|
|
1173
|
-
mouth:{},
|
|
1174
|
-
mole:{},
|
|
1175
|
-
hair:{},
|
|
1176
|
-
eyebrows:{},
|
|
1177
|
-
eyes:{},
|
|
1178
|
-
glasses:{},
|
|
1179
|
-
facialHair:{}
|
|
1180
|
-
};
|
|
1553
|
+
function extractMultiBits(data, bitSpecs, isBigEndian = true) {
|
|
1554
|
+
let result = 0;
|
|
1555
|
+
let totalBitsProcessed = 0;
|
|
1181
1556
|
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1557
|
+
// Process bit specs in order (they should be ordered from most significant to least significant)
|
|
1558
|
+
for (const spec of bitSpecs) {
|
|
1559
|
+
const bits = extractBits(data, spec.byteOffset, spec.bitOffset, spec.bitLength, isBigEndian);
|
|
1560
|
+
result = (result << spec.bitLength) | bits;
|
|
1561
|
+
totalBitsProcessed += spec.bitLength;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
return result;
|
|
1565
|
+
}
|
|
1189
1566
|
|
|
1190
|
-
|
|
1567
|
+
function setMultiBits(buffer, bitSpecs, value) {
|
|
1568
|
+
let remainingValue = value;
|
|
1569
|
+
|
|
1570
|
+
// Process specs in reverse order (from least significant to most significant)
|
|
1571
|
+
for (let i = bitSpecs.length - 1; i >= 0; i--) {
|
|
1572
|
+
const spec = bitSpecs[i];
|
|
1573
|
+
const mask = (1 << spec.bitLength) - 1;
|
|
1574
|
+
const bitsToSet = remainingValue & mask;
|
|
1575
|
+
|
|
1576
|
+
setBits(buffer, spec.byteOffset, spec.bitOffset, spec.bitLength, bitsToSet);
|
|
1577
|
+
remainingValue >>>= spec.bitLength;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1191
1580
|
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
thisMii.info.gender=get(0x00)[1]==="1"?"Female":"Male";//0 for Male, 1 for Female
|
|
1205
|
-
thisMii.info.miiId=parseInt(get(0x18),2).toString(16)+parseInt(get(0x19),2).toString(16)+parseInt(get(0x1A),2).toString(16)+parseInt(get(0x1B),2).toString(16);
|
|
1206
|
-
thisMii.info.systemId=parseInt(get(0x1C),2).toString(16)+parseInt(get(0x1D),2).toString(16)+parseInt(get(0x1E),2).toString(16)+parseInt(get(0x1F),2).toString(16);
|
|
1207
|
-
var temp=get(0x20);
|
|
1208
|
-
thisMii.face.shape=parseInt(temp.slice(0,3),2);//0-7
|
|
1209
|
-
thisMii.face.col=skinCols[parseInt(temp.slice(3,6),2)];//0-5
|
|
1210
|
-
temp=get(0x21);
|
|
1211
|
-
thisMii.face.feature=wiiFaceFeatures[parseInt(get(0x20).slice(6,8)+temp.slice(0,2),2)];//0-11
|
|
1212
|
-
thisMii.info.mingle=temp[5]==="0";//0 for Mingle, 1 for Don't Mingle
|
|
1213
|
-
temp=get(0x2C);
|
|
1214
|
-
for(var i=0;i<12;i++){
|
|
1215
|
-
if(wiiNoses[i]===parseInt(temp.slice(0,4),2)){
|
|
1216
|
-
thisMii.nose.type=i;
|
|
1581
|
+
function extractBits(data, byteOffset, bitOffset, bitLength, isBigEndian = true) {
|
|
1582
|
+
const totalBitOffset = byteOffset * 8 + bitOffset;
|
|
1583
|
+
const startByte = Math.floor(totalBitOffset / 8);
|
|
1584
|
+
const endByte = Math.floor((totalBitOffset + bitLength - 1) / 8);
|
|
1585
|
+
|
|
1586
|
+
let value = 0;
|
|
1587
|
+
|
|
1588
|
+
if (isBigEndian) {
|
|
1589
|
+
// Big endian: process bytes left to right (original behavior)
|
|
1590
|
+
for (let i = startByte; i <= endByte; i++) {
|
|
1591
|
+
if (i < data.length) {
|
|
1592
|
+
value = (value << 8) | data[i];
|
|
1217
1593
|
}
|
|
1218
1594
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
temp2=get(0x2F);
|
|
1225
|
-
thisMii.mouth.size=parseInt(temp[7]+temp2.slice(0,3),2);//0-8, default 4
|
|
1226
|
-
thisMii.mouth.yPos=parseInt(temp2.slice(3,8),2);//0-18, default 9, from top to bottom
|
|
1227
|
-
temp=get(0x00);
|
|
1228
|
-
var temp2=get(0x01);
|
|
1229
|
-
thisMii.info.birthMonth=parseInt(temp.slice(2,6),2);
|
|
1230
|
-
thisMii.info.birthday=parseInt(temp.slice(6,8)+temp2.slice(0,3),2);
|
|
1231
|
-
thisMii.info.favColor=favCols[parseInt(temp2.slice(3,7),2)];//0-11, refer to cols array
|
|
1232
|
-
thisMii.info.favorited=temp2[7]==="0"?false:true;
|
|
1233
|
-
thisMii.info.height=parseInt(get(0x16),2);//0-127
|
|
1234
|
-
thisMii.info.weight=parseInt(get(0x17),2);//0-127
|
|
1235
|
-
thisMii.info.downloadedFromCheckMiiOut=get(0x21)[7]==="0"?false:true;
|
|
1236
|
-
temp=get(0x34);
|
|
1237
|
-
temp2=get(0x35);
|
|
1238
|
-
thisMii.mole.on=temp[0]==="0"?false:true;//0 for Off, 1 for On
|
|
1239
|
-
thisMii.mole.size=parseInt(temp.slice(1,5),2);//0-8, default 4
|
|
1240
|
-
thisMii.mole.xPos=parseInt(temp2.slice(2,7),2);//0-16, Default 2
|
|
1241
|
-
thisMii.mole.yPos=parseInt(temp.slice(5,8)+temp2.slice(0,2),2);//Top to bottom
|
|
1242
|
-
temp=get(0x22);
|
|
1243
|
-
temp2=get(0x23);
|
|
1244
|
-
thisMii.hair.type=hairTable[""+parseInt(temp.slice(0,7),2)];//0-71, Needs lookup table
|
|
1245
|
-
thisMii.hair.col=hairCols[parseInt(temp[7]+temp2.slice(0,2),2)];//0-7, refer to hairCols array
|
|
1246
|
-
thisMii.hair.flipped=temp2[2]==="0"?false:true;
|
|
1247
|
-
temp=get(0x24);
|
|
1248
|
-
temp2=get(0x25);
|
|
1249
|
-
thisMii.eyebrows.type=eyebrowTable[""+parseInt(temp.slice(0,5),2)];//0-23, Needs lookup table
|
|
1250
|
-
thisMii.eyebrows.rotation=parseInt(temp.slice(6,8)+temp2.slice(0,2),2);//0-11, default varies based on eyebrow type
|
|
1251
|
-
temp=get(0x26);
|
|
1252
|
-
temp2=get(0x27);
|
|
1253
|
-
thisMii.eyebrows.col=hairCols[parseInt(temp.slice(0,3),2)];
|
|
1254
|
-
thisMii.eyebrows.size=parseInt(temp.slice(3,7),2);//0-8, default 4
|
|
1255
|
-
thisMii.eyebrows.yPos=(parseInt(temp[7]+temp2.slice(0,4),2))-3;//0-15, default 10
|
|
1256
|
-
thisMii.eyebrows.distApart=parseInt(temp2.slice(4,8),2);//0-12, default 2
|
|
1257
|
-
thisMii.eyes.type=eyeTable[parseInt(get(0x28).slice(0,6),2)];//0-47, needs lookup table
|
|
1258
|
-
temp=get(0x29);
|
|
1259
|
-
thisMii.eyes.rotation=parseInt(temp.slice(0,3),2);//0-7, default varies based on eye type
|
|
1260
|
-
thisMii.eyes.yPos=parseInt(temp.slice(3,8),2);//0-18, default 12, top to bottom
|
|
1261
|
-
temp=get(0x2A);
|
|
1262
|
-
thisMii.eyes.col=eyeCols[parseInt(temp.slice(0,3),2)];//0-5
|
|
1263
|
-
thisMii.eyes.size=parseInt(temp.slice(4,7),2);//0-7, default 4
|
|
1264
|
-
temp2=get(0x2B);
|
|
1265
|
-
thisMii.eyes.distApart=parseInt(temp[7]+temp2.slice(0,3),2);//0-12, default 2
|
|
1266
|
-
temp=get(0x30);
|
|
1267
|
-
thisMii.glasses.type=parseInt(temp.slice(0,4),2);//0-8
|
|
1268
|
-
thisMii.glasses.col=wiiGlassesCols[parseInt(temp.slice(4,7),2)];//0-5
|
|
1269
|
-
temp=get(0x31);
|
|
1270
|
-
thisMii.glasses.size=parseInt(temp.slice(0,3),2);//0-7, default 4
|
|
1271
|
-
thisMii.glasses.yPos=parseInt(temp.slice(3,8),2);//0-20, default 10
|
|
1272
|
-
temp=get(0x32);
|
|
1273
|
-
temp2=get(0x33);
|
|
1274
|
-
thisMii.facialHair.mustacheType=parseInt(temp.slice(0,2),2);//0-3
|
|
1275
|
-
thisMii.facialHair.beardType=parseInt(temp.slice(2,4),2);//0-3
|
|
1276
|
-
thisMii.facialHair.col=hairCols[parseInt(temp.slice(4,7),2)];//0-7
|
|
1277
|
-
thisMii.facialHair.mustacheSize=parseInt(temp[7]+temp2.slice(0,3),2);//0-30, default 20
|
|
1278
|
-
thisMii.facialHair.mustacheYPos=parseInt(temp2.slice(3,8),2);//0-16, default 2
|
|
1279
|
-
thisMii.console="wii";
|
|
1280
|
-
return thisMii;
|
|
1281
|
-
},
|
|
1282
|
-
read3DSQR:async function(binOrPath){
|
|
1283
|
-
function readMii(data){
|
|
1284
|
-
var miiJson={
|
|
1285
|
-
info:{},
|
|
1286
|
-
perms:{},
|
|
1287
|
-
hair:{},
|
|
1288
|
-
face:{},
|
|
1289
|
-
eyes:{},
|
|
1290
|
-
eyebrows:{},
|
|
1291
|
-
nose:{},
|
|
1292
|
-
mouth:{},
|
|
1293
|
-
facialHair:{},
|
|
1294
|
-
glasses:{},
|
|
1295
|
-
mole:{}
|
|
1296
|
-
};
|
|
1297
|
-
const get = address => getBinaryFromAddress(address, data);
|
|
1298
|
-
var temp=get(0x18);
|
|
1299
|
-
var temp2=get(0x19);
|
|
1300
|
-
miiJson.info.birthday=parseInt(temp2.slice(6,8)+temp.slice(0,3),2);
|
|
1301
|
-
miiJson.info.birthMonth=parseInt(temp.slice(3,7),2);
|
|
1302
|
-
var name="";
|
|
1303
|
-
for(var i=0x1A;i<0x2E;i+=2){
|
|
1304
|
-
if(get(i)==="00000000"){
|
|
1305
|
-
break;
|
|
1306
|
-
}
|
|
1307
|
-
name+=data.slice(i,i+1);
|
|
1595
|
+
} else {
|
|
1596
|
+
// Little endian: process bytes right to left
|
|
1597
|
+
for (let i = endByte; i >= startByte; i--) {
|
|
1598
|
+
if (i < data.length) {
|
|
1599
|
+
value = (value << 8) | data[i];
|
|
1308
1600
|
}
|
|
1309
|
-
miiJson.name=name.replaceAll("\x00","");
|
|
1310
|
-
var cname="";
|
|
1311
|
-
for(var i=0x48;i<0x5C;i+=2){
|
|
1312
|
-
if(get(i)==="00000000"){
|
|
1313
|
-
break;
|
|
1314
|
-
}
|
|
1315
|
-
cname+=data.slice(i,i+1);
|
|
1316
|
-
}
|
|
1317
|
-
miiJson.creatorName=cname.replaceAll("\x00","");
|
|
1318
|
-
miiJson.info.name=miiJson.name;
|
|
1319
|
-
miiJson.info.creatorName=miiJson.creatorName;
|
|
1320
|
-
miiJson.info.height=parseInt(get(0x2E),2);
|
|
1321
|
-
miiJson.info.weight=parseInt(get(0x2F),2);
|
|
1322
|
-
miiJson.info.gender=temp[7]==="1"?"Female":"Male";
|
|
1323
|
-
temp=get(0x30);
|
|
1324
|
-
miiJson.perms.sharing=temp[7]==="1"?false:true;
|
|
1325
|
-
miiJson.info.favColor=favCols[parseInt(temp2.slice(2,6),2)];
|
|
1326
|
-
miiJson.perms.copying=get(0x01)[7]==="1"?true:false;
|
|
1327
|
-
miiJson.hair.style=lookupTable("hairs",parseInt(get(0x32),2),true);
|
|
1328
|
-
miiJson.face.shape=lookupTable("faces",parseInt(temp.slice(3,7),2),false);
|
|
1329
|
-
miiJson.face.col=skinCols[parseInt(temp.slice(0,3),2)];
|
|
1330
|
-
temp=get(0x31);
|
|
1331
|
-
miiJson.face.feature=faceFeatures3DS[parseInt(temp.slice(4,8),2)];
|
|
1332
|
-
miiJson.face.makeup=makeups3DS[parseInt(temp.slice(0,4),2)];
|
|
1333
|
-
temp=get(0x34);
|
|
1334
|
-
miiJson.eyes.type=lookupTable("eyes",parseInt(temp.slice(2,8),2),true);
|
|
1335
|
-
temp2=get(0x33);
|
|
1336
|
-
miiJson.hair.col=hairCols[parseInt(temp2.slice(5,8),2)];
|
|
1337
|
-
miiJson.hair.flipped=temp2[4]==="0"?false:true;
|
|
1338
|
-
miiJson.eyes.col=eyeCols[parseInt(get(0x35)[7]+temp.slice(0,2),2)];
|
|
1339
|
-
temp=get(0x35);
|
|
1340
|
-
miiJson.eyes.size=parseInt(temp.slice(3,7),2);
|
|
1341
|
-
miiJson.eyes.squash=parseInt(temp.slice(0,3),2);
|
|
1342
|
-
temp=get(0x36);
|
|
1343
|
-
temp2=get(0x37);
|
|
1344
|
-
miiJson.eyes.rot=parseInt(temp.slice(3,8),2);
|
|
1345
|
-
miiJson.eyes.distApart=parseInt(temp2[7]+temp.slice(0,3),2);
|
|
1346
|
-
miiJson.eyes.yPos=parseInt(temp2.slice(2,7),2);
|
|
1347
|
-
temp=get(0x38);
|
|
1348
|
-
miiJson.eyebrows.style=lookupTable("eyebrows",parseInt(temp.slice(3,8),2),true);
|
|
1349
|
-
miiJson.eyebrows.col=hairCols[parseInt(temp.slice(0,3),2)];
|
|
1350
|
-
temp=get(0x39);
|
|
1351
|
-
miiJson.eyebrows.size=parseInt(temp.slice(4,8),2);
|
|
1352
|
-
miiJson.eyebrows.squash=parseInt(temp.slice(1,4),2);
|
|
1353
|
-
temp=get(0x3A);
|
|
1354
|
-
miiJson.eyebrows.rot=parseInt(temp.slice(4,8),2);
|
|
1355
|
-
temp2=get(0x3B);
|
|
1356
|
-
miiJson.eyebrows.distApart=parseInt(temp2[7]+temp.slice(0,3),2);
|
|
1357
|
-
miiJson.eyebrows.yPos=parseInt(temp2.slice(2,7),2)-3;
|
|
1358
|
-
temp=get(0x3C);
|
|
1359
|
-
miiJson.nose.type=lookupTable("noses",parseInt(temp.slice(3,8),2),true);
|
|
1360
|
-
temp2=get(0x3D);
|
|
1361
|
-
miiJson.nose.size=parseInt(temp2[7]+temp.slice(0,3),2);
|
|
1362
|
-
miiJson.nose.yPos=parseInt(temp2.slice(2,7),2);
|
|
1363
|
-
temp=get(0x3E);
|
|
1364
|
-
miiJson.mouth.type=lookupTable("mouths",parseInt(temp.slice(2,8),2),true);
|
|
1365
|
-
temp2=get(0x3F);
|
|
1366
|
-
miiJson.mouth.col=mouthCols3DS[parseInt(temp2[7]+temp.slice(0,2),2)];
|
|
1367
|
-
miiJson.mouth.size=parseInt(temp2.slice(3,7),2);
|
|
1368
|
-
miiJson.mouth.squash=parseInt(temp2.slice(0,3),2);
|
|
1369
|
-
temp=get(0x40);
|
|
1370
|
-
miiJson.mouth.yPos=parseInt(temp.slice(3,8),2);
|
|
1371
|
-
miiJson.facialHair.mustacheType=parseInt(temp.slice(0,3),2);
|
|
1372
|
-
temp=get(0x42);
|
|
1373
|
-
miiJson.facialHair.beardType=parseInt(temp.slice(5,8),2);
|
|
1374
|
-
miiJson.facialHair.col=hairCols[parseInt(temp.slice(2,5),2)];
|
|
1375
|
-
temp2=get(0x43);
|
|
1376
|
-
miiJson.facialHair.mustacheSize=parseInt(temp2.slice(6,8)+temp.slice(0,2),2);
|
|
1377
|
-
miiJson.facialHair.mustacheYPos=parseInt(temp2.slice(1,6),2);
|
|
1378
|
-
temp=get(0x44);
|
|
1379
|
-
miiJson.glasses.type=parseInt(temp.slice(4,8),2);
|
|
1380
|
-
miiJson.glasses.col=glassesCols3DS[parseInt(temp.slice(1,4),2)];
|
|
1381
|
-
temp2=get(0x45);
|
|
1382
|
-
miiJson.glasses.size=parseInt(temp2.slice(5,8)+temp[0],2);
|
|
1383
|
-
miiJson.glasses.yPos=parseInt(temp2.slice(0,5),2);
|
|
1384
|
-
temp=get(0x46);
|
|
1385
|
-
miiJson.mole.on=temp[7]==="0"?false:true;
|
|
1386
|
-
miiJson.mole.size=parseInt(temp.slice(3,7),2);
|
|
1387
|
-
temp2=get(0x47);
|
|
1388
|
-
miiJson.mole.xPos=parseInt(temp2.slice(6,8)+temp.slice(0,3),2);
|
|
1389
|
-
miiJson.mole.yPos=parseInt(temp2.slice(1,6),2);
|
|
1390
|
-
miiJson.console="3ds";
|
|
1391
|
-
return miiJson;
|
|
1392
|
-
}
|
|
1393
|
-
let qrCode;
|
|
1394
|
-
if(/[^01]/ig.test(binOrPath)){
|
|
1395
|
-
var data=fs.readFileSync(binOrPath);
|
|
1396
|
-
var img=await loadImage(data);
|
|
1397
|
-
const canvas = createCanvas(img.width, img.height);
|
|
1398
|
-
const ctx = canvas.getContext('2d');
|
|
1399
|
-
ctx.drawImage(img, 0, 0);
|
|
1400
|
-
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
1401
|
-
qrCode = jsQR(imageData.data, imageData.width, imageData.height).binaryData;
|
|
1402
1601
|
}
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
const rightShift = (endByte - startByte + 1) * 8 - (totalBitOffset % 8) - bitLength;
|
|
1605
|
+
value >>>= rightShift;
|
|
1606
|
+
|
|
1607
|
+
const mask = (1 << bitLength) - 1;
|
|
1608
|
+
return value & mask;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
function setBits(buffer, byteOffset, bitOffset, bitLength, value) {
|
|
1612
|
+
// Calculate the absolute bit position from the start
|
|
1613
|
+
const absoluteBitPos = byteOffset * 8 + bitOffset;
|
|
1614
|
+
|
|
1615
|
+
// Process each bit of the value
|
|
1616
|
+
for (let i = 0; i < bitLength; i++) {
|
|
1617
|
+
const currentBitPos = absoluteBitPos + i;
|
|
1618
|
+
const currentByteIndex = Math.floor(currentBitPos / 8);
|
|
1619
|
+
const currentBitInByte = currentBitPos % 8;
|
|
1620
|
+
|
|
1621
|
+
// Extract the bit from the value (MSB first)
|
|
1622
|
+
const bitValue = (value >> (bitLength - 1 - i)) & 1;
|
|
1623
|
+
|
|
1624
|
+
// Create mask for this specific bit position
|
|
1625
|
+
const mask = 1 << (7 - currentBitInByte);
|
|
1626
|
+
|
|
1627
|
+
if (bitValue) {
|
|
1628
|
+
// Set the bit
|
|
1629
|
+
buffer[currentByteIndex] |= mask;
|
|
1413
1630
|
} else {
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
},
|
|
1417
|
-
writeWiiBin:function(jsonIn, outPath){
|
|
1418
|
-
if(jsonIn.console?.toLowerCase() !== "wii"){
|
|
1419
|
-
this.convertMii(jsonIn);
|
|
1631
|
+
// Clear the bit
|
|
1632
|
+
buffer[currentByteIndex] &= ~mask;
|
|
1420
1633
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
}
|
|
1433
|
-
else{
|
|
1434
|
-
miiBin+="00000000";
|
|
1435
|
-
}
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
function setNestedProperty(obj, path, value) {
|
|
1638
|
+
// Allows to reference nested properties in extraction schemas with "name.subcategory.suboption"
|
|
1639
|
+
const keys = path.split('.');
|
|
1640
|
+
let current = obj;
|
|
1641
|
+
|
|
1642
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
1643
|
+
if (!(keys[i] in current)) {
|
|
1644
|
+
current[keys[i]] = {};
|
|
1436
1645
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1646
|
+
current = current[keys[i]];
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
current[keys[keys.length - 1]] = value;
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
function getNestedProperty(obj, path) {
|
|
1653
|
+
// See `setNestedProperty` comment
|
|
1654
|
+
return path.split('.').reduce((current, key) => current?.[key], obj);
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
function miiBufferToJson(data, schema, lookupTables = {}, isBigEndian = true) {
|
|
1658
|
+
const result = {};
|
|
1659
|
+
|
|
1660
|
+
for (const [fieldPath, fieldDef] of Object.entries(schema)) {
|
|
1661
|
+
let value;
|
|
1662
|
+
|
|
1663
|
+
if (fieldDef.type === 'string') {
|
|
1664
|
+
value = decodeString(data, fieldDef);
|
|
1665
|
+
} else if (fieldDef.bitSpecs) {
|
|
1666
|
+
// Handle multi-byte fields with non-contiguous bits
|
|
1667
|
+
value = extractMultiBits(data, fieldDef.bitSpecs, isBigEndian);
|
|
1668
|
+
} else {
|
|
1669
|
+
// Handle standard contiguous bit fields
|
|
1670
|
+
value = extractBits(data, fieldDef.byteOffset, fieldDef.bitOffset, fieldDef.bitLength, isBigEndian);
|
|
1450
1671
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1672
|
+
|
|
1673
|
+
// Apply decoder
|
|
1674
|
+
if (fieldDef.decoder && typeof decoders !== 'undefined' && decoders[fieldDef.decoder]) {
|
|
1675
|
+
value = decoders[fieldDef.decoder](value, fieldDef, lookupTables);
|
|
1453
1676
|
}
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1677
|
+
|
|
1678
|
+
setNestedProperty(result, fieldPath, value);
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
return result;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
function jsonToMiiBuffer(miiData, schema, lookupTables = {}, totalBytes = 74) {
|
|
1685
|
+
const buffer = new Array(totalBytes).fill(0);
|
|
1686
|
+
|
|
1687
|
+
for (const [fieldPath, fieldDef] of Object.entries(schema)) {
|
|
1688
|
+
let raw = getNestedProperty(miiData, fieldPath);
|
|
1689
|
+
|
|
1690
|
+
// Run encoders
|
|
1691
|
+
if (fieldDef.decoder && typeof encoders !== 'undefined' && encoders[fieldDef.decoder]) {
|
|
1692
|
+
raw = encoders[fieldDef.decoder](raw, fieldDef, lookupTables);
|
|
1463
1693
|
}
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
miiBin+=mii.hair.flipped?"1":"0";
|
|
1470
|
-
miiBin+="00000";
|
|
1471
|
-
miiBin+=(+getKeyByValue(eyebrowTable,mii.eyebrows.type)).toString(2).padStart(5,"0");
|
|
1472
|
-
miiBin+="0";
|
|
1473
|
-
miiBin+=mii.eyebrows.rotation.toString(2).padStart(4,"0");
|
|
1474
|
-
miiBin+="000000";
|
|
1475
|
-
miiBin+=hairCols.indexOf(mii.eyebrows.col).toString(2).padStart(3,"0");
|
|
1476
|
-
miiBin+=mii.eyebrows.size.toString(2).padStart(4,"0");
|
|
1477
|
-
miiBin+=(mii.eyebrows.yPos+3).toString(2).padStart(5,"0");
|
|
1478
|
-
miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0");
|
|
1479
|
-
miiBin+=(+getKeyByValue(eyeTable,mii.eyes.type)).toString(2).padStart(6,"0");
|
|
1480
|
-
miiBin+="00";
|
|
1481
|
-
miiBin+=mii.eyes.rotation.toString(2).padStart(3,"0");
|
|
1482
|
-
miiBin+=mii.eyes.yPos.toString(2).padStart(5,"0");
|
|
1483
|
-
miiBin+=eyeCols.indexOf(mii.eyes.col).toString(2).padStart(3,"0");
|
|
1484
|
-
miiBin+="0";
|
|
1485
|
-
miiBin+=mii.eyes.size.toString(2).padStart(3,"0");
|
|
1486
|
-
miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0");
|
|
1487
|
-
miiBin+="00000";
|
|
1488
|
-
miiBin+=wiiNoses[mii.nose.type].toString(2).padStart(4,"0");
|
|
1489
|
-
miiBin+=mii.nose.size.toString(2).padStart(4,"0");
|
|
1490
|
-
miiBin+=mii.nose.yPos.toString(2).padStart(5,"0");
|
|
1491
|
-
miiBin+="000";
|
|
1492
|
-
miiBin+=(+getKeyByValue(mouthTable,mii.mouth.type)).toString(2).padStart(5,"0");
|
|
1493
|
-
miiBin+=wiiMouthColors.indexOf(mii.mouth.col).toString(2).padStart(2,"0");
|
|
1494
|
-
miiBin+=mii.mouth.size.toString(2).padStart(4,"0");
|
|
1495
|
-
miiBin+=mii.mouth.yPos.toString(2).padStart(5,"0");
|
|
1496
|
-
miiBin+=mii.glasses.type.toString(2).padStart(4,"0");
|
|
1497
|
-
miiBin+=wiiGlassesCols.indexOf(mii.glasses.col).toString(2).padStart(3,"0");
|
|
1498
|
-
miiBin+="0";
|
|
1499
|
-
miiBin+=mii.glasses.size.toString(2).padStart(3,"0");
|
|
1500
|
-
miiBin+=mii.glasses.yPos.toString(2).padStart(5,"0");
|
|
1501
|
-
miiBin+=mii.facialHair.mustacheType.toString(2).padStart(2,"0");
|
|
1502
|
-
miiBin+=mii.facialHair.beardType.toString(2).padStart(2,"0");
|
|
1503
|
-
miiBin+=hairCols.indexOf(mii.facialHair.col).toString(2).padStart(3,"0");
|
|
1504
|
-
miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0");
|
|
1505
|
-
miiBin+=mii.facialHair.mustacheYPos.toString(2).padStart(5,"0");
|
|
1506
|
-
miiBin+=mii.mole.on?"1":"0";
|
|
1507
|
-
miiBin+=mii.mole.size.toString(2).padStart(4,"0");
|
|
1508
|
-
miiBin+=mii.mole.yPos.toString(2).padStart(5,"0");
|
|
1509
|
-
miiBin+=mii.mole.xPos.toString(2).padStart(5,"0");
|
|
1510
|
-
miiBin+="0";
|
|
1511
|
-
for(var i=0;i<10;i++){
|
|
1512
|
-
miiBin+="00000000";
|
|
1513
|
-
if(i<mii.creatorName.length){
|
|
1514
|
-
miiBin+=mii.creatorName.charCodeAt(i).toString(2).padStart(8,"0");
|
|
1515
|
-
}
|
|
1516
|
-
else{
|
|
1517
|
-
miiBin+="00000000";
|
|
1694
|
+
|
|
1695
|
+
if (fieldDef.type === 'string') {
|
|
1696
|
+
const bytes = encodeString(raw, fieldDef);
|
|
1697
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1698
|
+
buffer[fieldDef.byteOffset + i] = bytes[i];
|
|
1518
1699
|
}
|
|
1700
|
+
} else if (fieldDef.bitSpecs) {
|
|
1701
|
+
// Handle multi-byte fields with non-contiguous bits
|
|
1702
|
+
setMultiBits(buffer, fieldDef.bitSpecs, raw);
|
|
1703
|
+
} else {
|
|
1704
|
+
// Handle standard contiguous bit fields
|
|
1705
|
+
setBits(buffer, fieldDef.byteOffset, fieldDef.bitOffset, fieldDef.bitLength, raw);
|
|
1519
1706
|
}
|
|
1520
|
-
|
|
1521
|
-
//Writing based on miiBin
|
|
1522
|
-
var toWrite=miiBin.match(/.{1,8}/g);
|
|
1523
|
-
var buffers=[];
|
|
1524
|
-
for(var i=0;i<toWrite.length;i++){
|
|
1525
|
-
buffers.push(parseInt(toWrite[i],2));
|
|
1526
|
-
}
|
|
1527
|
-
fs.writeFileSync(outPath, Buffer.from(buffers));
|
|
1528
|
-
},
|
|
1529
|
-
write3DSQR:async function(jsonIn,outPath,fflRes=_fflRes){
|
|
1530
|
-
if(!["3ds","wii u"].includes(jsonIn.console?.toLowerCase())){
|
|
1531
|
-
jsonIn=this.convertMii(jsonIn);
|
|
1532
|
-
}
|
|
1533
|
-
return new Promise(async (resolve, reject) => {
|
|
1534
|
-
var mii=jsonIn;
|
|
1535
|
-
function makeMiiBinary(mii){
|
|
1536
|
-
if(mii.perms.sharing&&mii.info.type==="Special"){
|
|
1537
|
-
mii.perms.sharing=false;
|
|
1538
|
-
console.log("Cannot have Sharing enabled for Special Miis. Disabled Sharing.");
|
|
1539
|
-
}
|
|
1540
|
-
var miiBin="00000011";
|
|
1541
|
-
miiBin+="0000000";
|
|
1542
|
-
miiBin+=mii.perms.copying?"1":"0";
|
|
1543
|
-
miiBin+="00000000";
|
|
1544
|
-
miiBin+="00110000";
|
|
1545
|
-
miiBin+="1000101011010010000001101000011100011000110001100100011001100110010101100111111110111100000001110101110001000101011101100000001110100100010000000000000000000000".slice(0,8*8);
|
|
1546
|
-
miiBin+=mii.info.type==="Special"?"0":"1";
|
|
1547
|
-
miiBin+="0000000";
|
|
1548
|
-
for(var i=0;i<3;i++){
|
|
1549
|
-
miiBin+=Math.floor(Math.random()*255).toString(2).padStart(8,"0");
|
|
1550
|
-
}
|
|
1551
|
-
miiBin+="0000000001000101011101100000001110100100010000000000000000000000";
|
|
1552
|
-
miiBin+=mii.info.birthday.toString(2).padStart(5,"0").slice(2,5);
|
|
1553
|
-
miiBin+=mii.info.birthMonth.toString(2).padStart(4,"0");
|
|
1554
|
-
miiBin+=mii.info.gender==="Male"?"0":"1";
|
|
1555
|
-
miiBin+="00";
|
|
1556
|
-
miiBin+=favCols.indexOf(mii.info.favColor).toString(2).padStart(4,"0");
|
|
1557
|
-
miiBin+=mii.info.birthday.toString(2).padStart(5,"0").slice(0,2);
|
|
1558
|
-
for(var i=0;i<10;i++){
|
|
1559
|
-
if(i<mii.name.length){
|
|
1560
|
-
miiBin+=mii.name.charCodeAt(i).toString(2).padStart(8,"0");
|
|
1561
|
-
}
|
|
1562
|
-
else{
|
|
1563
|
-
miiBin+="00000000";
|
|
1564
|
-
}
|
|
1565
|
-
miiBin+="00000000";
|
|
1566
|
-
}
|
|
1567
|
-
miiBin+=mii.info.height.toString(2).padStart(8,"0");
|
|
1568
|
-
miiBin+=mii.info.weight.toString(2).padStart(8,"0");
|
|
1569
|
-
miiBin+=skinCols.indexOf(mii.face.col).toString(2).padStart(3,"0");
|
|
1570
|
-
miiBin+=tables.faces[mii.face.shape].toString(2).padStart(4,"0");
|
|
1571
|
-
miiBin+=mii.perms.sharing?"0":"1";
|
|
1572
|
-
miiBin+=makeups3DS.indexOf(mii.face.makeup).toString(2).padStart(4,"0");
|
|
1573
|
-
miiBin+=faceFeatures3DS.indexOf(mii.face.feature).toString(2).padStart(4,"0");
|
|
1574
|
-
miiBin+=tables.hairs[mii.hair.style[0]][mii.hair.style[1]].toString(2).padStart(8,"0");
|
|
1575
|
-
miiBin+="0000";
|
|
1576
|
-
miiBin+=mii.hair.flipped?"1":"0";
|
|
1577
|
-
miiBin+=hairCols.indexOf(mii.hair.col).toString(2).padStart(3,"0");
|
|
1578
|
-
miiBin+=eyeCols.indexOf(mii.eyes.col).toString(2).padStart(3,"0").slice(1,3);
|
|
1579
|
-
miiBin+=tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]].toString(2).padStart(6,"0");
|
|
1580
|
-
miiBin+=mii.eyes.squash.toString(2).padStart(3,"0");
|
|
1581
|
-
miiBin+=mii.eyes.size.toString(2).padStart(4,"0");
|
|
1582
|
-
miiBin+=eyeCols.indexOf(mii.eyes.col).toString(2).padStart(3,"0")[0];
|
|
1583
|
-
miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0").slice(1,4);
|
|
1584
|
-
miiBin+=mii.eyes.rot.toString(2).padStart(5,"0");
|
|
1585
|
-
miiBin+="00";
|
|
1586
|
-
miiBin+=mii.eyes.yPos.toString(2).padStart(5,"0");
|
|
1587
|
-
miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0")[0];
|
|
1588
|
-
miiBin+=hairCols.indexOf(mii.eyebrows.col).toString(2).padStart(3,"0");
|
|
1589
|
-
miiBin+=tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]].toString(2).padStart(5,"0");
|
|
1590
|
-
miiBin+="0";
|
|
1591
|
-
miiBin+=mii.eyebrows.squash.toString(2).padStart(3,"0");
|
|
1592
|
-
miiBin+=mii.eyebrows.size.toString(2).padStart(4,"0");
|
|
1593
|
-
miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0").slice(1,4);
|
|
1594
|
-
miiBin+="0";
|
|
1595
|
-
miiBin+=mii.eyebrows.rot.toString(2).padStart(4,"0");
|
|
1596
|
-
miiBin+="00";
|
|
1597
|
-
miiBin+=(mii.eyebrows.yPos+3).toString(2).padStart(5,"0");
|
|
1598
|
-
miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0")[0];
|
|
1599
|
-
miiBin+=mii.nose.size.toString(2).padStart(4,"0").slice(1,4);
|
|
1600
|
-
miiBin+=tables.noses[mii.nose.type[0]][mii.nose.type[1]].toString(2).padStart(5,"0");
|
|
1601
|
-
miiBin+="00";
|
|
1602
|
-
miiBin+=mii.nose.yPos.toString(2).padStart(5,"0");
|
|
1603
|
-
miiBin+=mii.nose.size.toString(2).padStart(4,"0")[0];
|
|
1604
|
-
miiBin+=mouthCols3DS.indexOf(mii.mouth.col).toString(2).padStart(3,"0").slice(1,3);
|
|
1605
|
-
miiBin+=tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]].toString(2).padStart(6,"0");
|
|
1606
|
-
miiBin+=mii.mouth.squash.toString(2).padStart(3,"0");
|
|
1607
|
-
miiBin+=mii.mouth.size.toString(2).padStart(4,"0");
|
|
1608
|
-
miiBin+=mouthCols3DS.indexOf(mii.mouth.col).toString(2).padStart(3,"0")[0];
|
|
1609
|
-
miiBin+=mii.facialHair.mustacheType.toString(2).padStart(3,"0");
|
|
1610
|
-
miiBin+=mii.mouth.yPos.toString(2).padStart(5,"0");
|
|
1611
|
-
miiBin+="00000000";
|
|
1612
|
-
miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0").slice(2,4);
|
|
1613
|
-
miiBin+=hairCols.indexOf(mii.facialHair.col).toString(2).padStart(3,"0");
|
|
1614
|
-
miiBin+=mii.facialHair.beardType.toString(2).padStart(3,"0");
|
|
1615
|
-
miiBin+="0";
|
|
1616
|
-
miiBin+=mii.facialHair.mustacheYPos.toString(2).padStart(5,"0");
|
|
1617
|
-
miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0").slice(0,2);
|
|
1618
|
-
miiBin+=mii.glasses.size.toString(2).padStart(4,"0")[3];
|
|
1619
|
-
miiBin+=glassesCols3DS.indexOf(mii.glasses.col).toString(2).padStart(3,"0");
|
|
1620
|
-
miiBin+=mii.glasses.type.toString(2).padStart(4,"0");
|
|
1621
|
-
miiBin+="0";
|
|
1622
|
-
miiBin+=mii.glasses.yPos.toString(2).padStart(4,"0");
|
|
1623
|
-
miiBin+=mii.glasses.size.toString(2).padStart(4,"0").slice(0,3);
|
|
1624
|
-
miiBin+=mii.mole.xPos.toString(2).padStart(5,"0").slice(2,5);
|
|
1625
|
-
miiBin+=mii.mole.size.toString(2).padStart(4,"0");
|
|
1626
|
-
miiBin+=mii.mole.on?"1":"0";
|
|
1627
|
-
miiBin+="0";
|
|
1628
|
-
miiBin+=mii.mole.yPos.toString(2).padStart(5,"0");
|
|
1629
|
-
miiBin+=mii.mole.xPos.toString(2).padStart(5,"0").slice(0,2);
|
|
1630
|
-
for(var i=0;i<10;i++){
|
|
1631
|
-
if(i<mii.creatorName.length){
|
|
1632
|
-
miiBin+=mii.creatorName.charCodeAt(i).toString(2).padStart(8,"0");
|
|
1633
|
-
}
|
|
1634
|
-
else{
|
|
1635
|
-
miiBin+="00000000";
|
|
1636
|
-
}
|
|
1637
|
-
miiBin+="00000000";
|
|
1638
|
-
}
|
|
1639
|
-
//Writing based on miiBin
|
|
1640
|
-
var toWrite=miiBin.match(/.{1,8}/g);
|
|
1641
|
-
var buffers=[];
|
|
1642
|
-
for(var i=0;i<toWrite.length;i++){
|
|
1643
|
-
buffers.push(parseInt(toWrite[i],2));
|
|
1644
|
-
}
|
|
1645
|
-
const buffer = Buffer.from(buffers);
|
|
1646
|
-
return buffer;
|
|
1647
|
-
}
|
|
1648
|
-
const miiBinary = makeMiiBinary(mii);
|
|
1649
|
-
var encryptedData = Buffer.from(encodeAesCcm(new Uint8Array(miiBinary)));
|
|
1650
|
-
|
|
1651
|
-
const options = {
|
|
1652
|
-
width: 300,
|
|
1653
|
-
height: 300,
|
|
1654
|
-
data: encryptedData.toString("latin1"),
|
|
1655
|
-
image: "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", // 1x1 gif
|
|
1656
|
-
dotsOptions: {
|
|
1657
|
-
color: "#000000",
|
|
1658
|
-
type: "square"
|
|
1659
|
-
},
|
|
1660
|
-
backgroundOptions: {
|
|
1661
|
-
color: "#ffffff",
|
|
1662
|
-
},
|
|
1663
|
-
imageOptions: {
|
|
1664
|
-
crossOrigin: "anonymous",
|
|
1665
|
-
imageSize: 0.4 // Changes how large center area is
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1668
|
-
const qrCodeImage = new QRCodeStyling({
|
|
1669
|
-
jsdom: JSDOM,
|
|
1670
|
-
nodeCanvas,
|
|
1671
|
-
...options
|
|
1672
|
-
});
|
|
1673
|
-
const qrBuffer = Buffer.from( await qrCodeImage.getRawData("png") )
|
|
1674
|
-
|
|
1675
|
-
var studioMii=new Uint8Array([0x08, 0x00, 0x40, 0x03, 0x08, 0x04, 0x04, 0x02, 0x02, 0x0c, 0x03, 0x01, 0x06, 0x04, 0x06, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x21, 0x40, 0x04, 0x00, 0x02, 0x14, 0x03, 0x13, 0x04, 0x17, 0x0d, 0x04, 0x00, 0x0a, 0x04, 0x01, 0x09]);
|
|
1676
|
-
studioMii[0x16] = mii.info.gender==="Male"?0:1;
|
|
1677
|
-
studioMii[0x15] = favCols.indexOf(mii.info.favColor);
|
|
1678
|
-
studioMii[0x1E] = mii.info.height;
|
|
1679
|
-
studioMii[2] = mii.info.weight;
|
|
1680
|
-
studioMii[0x13] = tables.faces[mii.face.shape];
|
|
1681
|
-
studioMii[0x11] = skinCols.indexOf(mii.face.col);
|
|
1682
|
-
studioMii[0x14] = faceFeatures3DS.indexOf(mii.face.feature);
|
|
1683
|
-
studioMii[0x12] = makeups3DS.indexOf(mii.face.makeup);
|
|
1684
|
-
studioMii[0x1D] = tables.hairs[mii.hair.style[0]][mii.hair.style[1]];
|
|
1685
|
-
studioMii[0x1B] = hairCols.indexOf(mii.hair.col);
|
|
1686
|
-
if (!studioMii[0x1B]) studioMii[0x1B] = 8;
|
|
1687
|
-
studioMii[0x1C] = mii.hair.flipped?1:0;
|
|
1688
|
-
studioMii[7] = tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]];
|
|
1689
|
-
studioMii[4] = eyeCols.indexOf(mii.eyes.col) + 8;
|
|
1690
|
-
studioMii[6] = mii.eyes.size;
|
|
1691
|
-
studioMii[3] = mii.eyes.squash;
|
|
1692
|
-
studioMii[5] = mii.eyes.rot;
|
|
1693
|
-
studioMii[8] = mii.eyes.distApart;
|
|
1694
|
-
studioMii[9] = mii.eyes.yPos;
|
|
1695
|
-
studioMii[0xE] = tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]];
|
|
1696
|
-
studioMii[0xB] = hairCols.indexOf(mii.eyebrows.col);
|
|
1697
|
-
if (!studioMii[0xB]) studioMii[0xB] = 8;
|
|
1698
|
-
studioMii[0xD] = mii.eyebrows.size;
|
|
1699
|
-
studioMii[0xA] = mii.eyebrows.squash;
|
|
1700
|
-
studioMii[0xC] = mii.eyebrows.rot;
|
|
1701
|
-
studioMii[0xF] = mii.eyebrows.distApart;
|
|
1702
|
-
studioMii[0x10] = mii.eyebrows.yPos+3;
|
|
1703
|
-
studioMii[0x2C] = tables.noses[mii.nose.type[0]][mii.nose.type[1]];
|
|
1704
|
-
studioMii[0x2B] = mii.nose.size;
|
|
1705
|
-
studioMii[0x2D] = mii.nose.yPos;
|
|
1706
|
-
studioMii[0x26] = tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]];
|
|
1707
|
-
studioMii[0x24] = mouthCols3DS.indexOf(mii.mouth.col);
|
|
1708
|
-
if (studioMii[0x24] < 4) {
|
|
1709
|
-
studioMii[0x24] += 19;
|
|
1710
|
-
} else {
|
|
1711
|
-
studioMii[0x24] = 0;
|
|
1712
|
-
}
|
|
1713
|
-
studioMii[0x25] = mii.mouth.size;
|
|
1714
|
-
studioMii[0x23] = mii.mouth.squash;
|
|
1715
|
-
studioMii[0x27] = mii.mouth.yPos;
|
|
1716
|
-
studioMii[0x29] = mii.facialHair.mustacheType;
|
|
1717
|
-
studioMii[1] = mii.facialHair.beardType;
|
|
1718
|
-
studioMii[0] = hairCols.indexOf(mii.facialHair.col);
|
|
1719
|
-
if (!studioMii[0]) studioMii[0] = 8;
|
|
1720
|
-
studioMii[0x28] = mii.facialHair.mustacheSize;
|
|
1721
|
-
studioMii[0x2A] = mii.facialHair.mustacheYPos;
|
|
1722
|
-
studioMii[0x19] = mii.glasses.type;
|
|
1723
|
-
studioMii[0x17] = mii.glasses.col;
|
|
1724
|
-
if (!studioMii[0x17]) {
|
|
1725
|
-
studioMii[0x17] = 8;
|
|
1726
|
-
} else if (studioMii[0x17] < 6) {
|
|
1727
|
-
studioMii[0x17] += 13;
|
|
1728
|
-
} else {
|
|
1729
|
-
studioMii[0x17] = 0;
|
|
1730
|
-
}
|
|
1731
|
-
studioMii[0x18] = mii.glasses.size;
|
|
1732
|
-
studioMii[0x1A] = mii.glasses.yPos;
|
|
1733
|
-
studioMii[0x20] = mii.mole.on?1:0;
|
|
1734
|
-
studioMii[0x1F] = mii.mole.size;
|
|
1735
|
-
studioMii[0x21] = mii.mole.xPos;
|
|
1736
|
-
studioMii[0x22] = mii.mole.yPos;
|
|
1737
|
-
let miiPNGBuf = null;
|
|
1738
|
-
let renderedWithStudio = fflRes===null || fflRes===undefined;
|
|
1739
|
-
if(renderedWithStudio){
|
|
1740
|
-
miiPNGBuf = await this.render3DSMiiWithStudio(jsonIn);
|
|
1741
|
-
}
|
|
1742
|
-
else{
|
|
1743
|
-
miiPNGBuf = await this.render3DSMii(jsonIn,fflRes);
|
|
1744
|
-
}
|
|
1745
|
-
const main_img = await Jimp.read(qrBuffer);
|
|
1746
|
-
main_img.resize(424, 424, Jimp.RESIZE_NEAREST_NEIGHBOR); // Don't anti-alias the QR code
|
|
1747
|
-
|
|
1748
|
-
let miiSize, miiZoomFactor, miiYOffset;
|
|
1749
|
-
if (renderedWithStudio) {
|
|
1750
|
-
miiSize = 100;
|
|
1751
|
-
miiZoomFactor = 1;
|
|
1752
|
-
miiYOffset = -15;
|
|
1707
|
+
}
|
|
1753
1708
|
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
miiZoomFactor = 1.25;
|
|
1757
|
-
miiYOffset = -5;
|
|
1758
|
-
}
|
|
1759
|
-
const mii_img = await Jimp.read(miiPNGBuf);
|
|
1760
|
-
mii_img.resize(miiSize*miiZoomFactor, miiSize*miiZoomFactor, Jimp.RESIZE_BICUBIC);
|
|
1761
|
-
mii_img.crop(
|
|
1762
|
-
(miiSize*miiZoomFactor - 100) / 2,
|
|
1763
|
-
(miiSize*miiZoomFactor - 100) / 2,
|
|
1764
|
-
miiSize,
|
|
1765
|
-
miiSize
|
|
1766
|
-
);
|
|
1767
|
-
|
|
1768
|
-
const canvas = new Jimp(mii_img.bitmap.width, mii_img.bitmap.height, 0xFFFFFFFF);
|
|
1769
|
-
canvas.composite(mii_img, 0, miiYOffset);
|
|
1770
|
-
main_img.blit(canvas, 212-100/2, 212-100/2);
|
|
1771
|
-
const font = await Jimp.loadFont(Jimp.FONT_SANS_16_BLACK)
|
|
1772
|
-
|
|
1773
|
-
main_img.print(font, 0, 55, {
|
|
1774
|
-
text: mii.name,
|
|
1775
|
-
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
|
|
1776
|
-
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
|
|
1777
|
-
}, 424, 395);
|
|
1778
|
-
|
|
1779
|
-
if(mii.info.type==="Special"){
|
|
1780
|
-
const crown_img = await Jimp.read(path.join(__dirname, 'crown.jpg'));
|
|
1781
|
-
crown_img.resize(40,20);
|
|
1782
|
-
main_img.blit(crown_img,225,160);
|
|
1783
|
-
}
|
|
1709
|
+
return Buffer.from(buffer);
|
|
1710
|
+
}
|
|
1784
1711
|
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1712
|
+
const WII_MII_SCHEMA = {
|
|
1713
|
+
'general.gender': { byteOffset: 0x00, bitOffset: 1, bitLength: 1, decoder: 'number' },
|
|
1714
|
+
'general.birthMonth': { byteOffset: 0x00, bitOffset: 2, bitLength: 4, decoder: 'number' },
|
|
1715
|
+
'general.birthday': { byteOffset: 0x00, bitOffset: 6, bitLength: 5, decoder: 'number' },
|
|
1716
|
+
'general.favoriteColor': { byteOffset: 0x01, bitOffset: 3, bitLength: 4, decoder: 'number' },
|
|
1717
|
+
'meta.name': { type: 'string', byteOffset: 0x03, maxLength: 10, endianness: "little" },
|
|
1718
|
+
'meta.creatorName': { type: 'string', byteOffset: 0x37, maxLength: 10, endianness: "little" },
|
|
1719
|
+
'general.height': { byteOffset: 0x16, bitOffset: 0, bitLength: 8, decoder: 'number' },
|
|
1720
|
+
'general.weight': { byteOffset: 0x17, bitOffset: 0, bitLength: 8, decoder: 'number' },
|
|
1721
|
+
'perms.mingle': { byteOffset: 0x21, bitOffset: 5, bitLength: 1, decoder: 'boolean', invert: true },
|
|
1722
|
+
'perms.fromCheckMiiOut': { byteOffset: 0x21, bitOffset: 7, bitLength: 1, decoder: 'boolean' },
|
|
1723
|
+
'face.type': { byteOffset: 0x20, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1724
|
+
'face.color': { byteOffset: 0x20, bitOffset: 3, bitLength: 3, decoder: 'number' },
|
|
1725
|
+
'face.feature': { byteOffset: 0x20, bitOffset: 6, bitLength: 4, decoder: 'number' },
|
|
1726
|
+
'hair.page': { byteOffset: 0x22, bitOffset: 0, bitLength: 7, decoder: 'lookup', lookupTable: 'hairs' },
|
|
1727
|
+
'hair.type': { byteOffset: 0x22, bitOffset: 0, bitLength: 7, decoder: 'lookup', lookupTable: 'types.hairs' },
|
|
1728
|
+
'hair.color': { byteOffset: 0x22, bitOffset: 7, bitLength: 3, decoder: 'number' },
|
|
1729
|
+
'hair.flipped': { byteOffset: 0x23, bitOffset: 2, bitLength: 1, decoder: 'boolean' },
|
|
1730
|
+
'eyebrows.page': { byteOffset: 0x24, bitOffset: 0, bitLength: 5, decoder: 'lookup', lookupTable: 'pages.eyebrows' },
|
|
1731
|
+
'eyebrows.type': { byteOffset: 0x24, bitOffset: 0, bitLength: 5, decoder: 'lookup', lookupTable: 'types.eyebrows' },
|
|
1732
|
+
'eyebrows.rotation': { byteOffset: 0x24, bitOffset: 6, bitLength: 4, decoder: 'number' },
|
|
1733
|
+
'eyebrows.color': { byteOffset: 0x26, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1734
|
+
'eyebrows.size': { byteOffset: 0x26, bitOffset: 3, bitLength: 4, decoder: 'number' },
|
|
1735
|
+
'eyebrows.yPosition': { byteOffset: 0x26, bitOffset: 7, bitLength: 5, decoder: 'number', offset: -3 },
|
|
1736
|
+
'eyebrows.distanceApart': { byteOffset: 0x27, bitOffset: 4, bitLength: 4, decoder: 'number' },
|
|
1737
|
+
'eyes.page': { byteOffset: 0x28, bitOffset: 0, bitLength: 6, decoder: 'lookup', lookupTable: 'pages.eyes' },
|
|
1738
|
+
'eyes.type': { byteOffset: 0x28, bitOffset: 0, bitLength: 6, decoder: 'lookup', lookupTable: 'types.eyes' },
|
|
1739
|
+
'eyes.rotation': { byteOffset: 0x29, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1740
|
+
'eyes.yPosition': { byteOffset: 0x29, bitOffset: 3, bitLength: 5, decoder: 'number' },
|
|
1741
|
+
'eyes.color': { byteOffset: 0x2A, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1742
|
+
'eyes.size': { byteOffset: 0x2A, bitOffset: 4, bitLength: 3 },
|
|
1743
|
+
'eyes.distanceApart': { byteOffset: 0x2A, bitOffset: 7, bitLength: 4, decoder: 'number' },
|
|
1744
|
+
'nose.type': { byteOffset: 0x2C, bitOffset: 0, bitLength: 4, decoder: 'lookup', lookupTable: 'wiiNoses' },
|
|
1745
|
+
'nose.size': { byteOffset: 0x2C, bitOffset: 4, bitLength: 4, decoder: 'number' },
|
|
1746
|
+
'nose.yPosition': { byteOffset: 0x2D, bitOffset: 0, bitLength: 5, decoder: 'number' },
|
|
1747
|
+
'mouth.page': { byteOffset: 0x2E, bitOffset: 0, bitLength: 5, decoder: 'lookup', lookupTable: 'pages.mouths' },
|
|
1748
|
+
'mouth.type': { byteOffset: 0x2E, bitOffset: 0, bitLength: 5, decoder: 'lookup', lookupTable: 'types.mouths' },
|
|
1749
|
+
'mouth.color': { byteOffset: 0x2E, bitOffset: 5, bitLength: 2, decoder: 'number' },
|
|
1750
|
+
'mouth.size': { byteOffset: 0x2E, bitOffset: 7, bitLength: 4, decoder: 'number' },
|
|
1751
|
+
'mouth.yPosition': { byteOffset: 0x2F, bitOffset: 3, bitLength: 5, decoder: 'number' },
|
|
1752
|
+
'glasses.type': { byteOffset: 0x30, bitOffset: 0, bitLength: 4, decoder: 'number' },
|
|
1753
|
+
'glasses.color': { byteOffset: 0x30, bitOffset: 4, bitLength: 3, decoder: 'number' },
|
|
1754
|
+
'glasses.size': { byteOffset: 0x31, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1755
|
+
'glasses.yPosition': { byteOffset: 0x31, bitOffset: 3, bitLength: 5, decoder: 'number' },
|
|
1756
|
+
'beard.mustache.type': { byteOffset: 0x32, bitOffset: 0, bitLength: 2, decoder: 'number' },
|
|
1757
|
+
'beard.type': { byteOffset: 0x32, bitOffset: 2, bitLength: 2, decoder: 'number' },
|
|
1758
|
+
'beard.color': { byteOffset: 0x32, bitOffset: 4, bitLength: 3, decoder: 'number' },
|
|
1759
|
+
'beard.mustache.size': { byteOffset: 0x32, bitOffset: 7, bitLength: 4, decoder: 'number' },
|
|
1760
|
+
'beard.mustache.yPosition': { byteOffset: 0x33, bitOffset: 3, bitLength: 5, decoder: 'number' },
|
|
1761
|
+
'mole.on': { byteOffset: 0x34, bitOffset: 0, bitLength: 1, decoder: 'boolean' },
|
|
1762
|
+
'mole.size': { byteOffset: 0x34, bitOffset: 1, bitLength: 4, decoder: 'number' },
|
|
1763
|
+
'mole.yPosition': { byteOffset: 0x34, bitOffset: 5, bitLength: 5, decoder: 'number' },
|
|
1764
|
+
'mole.xPosition': { byteOffset: 0x35, bitOffset: 2, bitLength: 5, decoder: 'number' }
|
|
1765
|
+
};
|
|
1766
|
+
|
|
1767
|
+
const THREEDS_MII_SCHEMA = {
|
|
1768
|
+
'general.birthday': {
|
|
1769
|
+
bitSpecs: [
|
|
1770
|
+
{ byteOffset: 0x19, bitOffset: 6, bitLength: 2 },
|
|
1771
|
+
{ byteOffset: 0x18, bitOffset: 0, bitLength: 3 }
|
|
1772
|
+
],
|
|
1773
|
+
decoder: 'number'
|
|
1789
1774
|
},
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1775
|
+
'general.birthMonth': { byteOffset: 0x18, bitOffset: 3, bitLength: 4, decoder: 'number' },
|
|
1776
|
+
'general.gender': { byteOffset: 0x18, bitOffset: 7, bitLength: 1, decoder: 'number' },
|
|
1777
|
+
'general.favoriteColor': { byteOffset: 0x19, bitOffset: 2, bitLength: 4, decoder: 'number' },
|
|
1778
|
+
'meta.name': { type: 'string', byteOffset: 0x1A, maxLength: 10, endianness: "little" },
|
|
1779
|
+
'meta.creatorName': { type: 'string', byteOffset: 0x48, maxLength: 10, endianness: "little" },
|
|
1780
|
+
'general.height': { byteOffset: 0x2E, bitOffset: 0, bitLength: 8, decoder: 'number' },
|
|
1781
|
+
'general.weight': { byteOffset: 0x2F, bitOffset: 0, bitLength: 8, decoder: 'number' },
|
|
1782
|
+
'perms.sharing': { byteOffset: 0x30, bitOffset: 7, bitLength: 1, decoder: 'boolean', invert: true },
|
|
1783
|
+
'perms.copying': { byteOffset: 0x01, bitOffset: 7, bitLength: 1, decoder: 'boolean' },
|
|
1784
|
+
'face.type': { byteOffset: 0x30, bitOffset: 3, bitLength: 4, decoder: 'lookup', lookupTable: 'faces' },
|
|
1785
|
+
'face.color': { byteOffset: 0x30, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1786
|
+
'face.feature': { byteOffset: 0x31, bitOffset: 4, bitLength: 4, decoder: 'number' },
|
|
1787
|
+
'face.makeup': { byteOffset: 0x31, bitOffset: 0, bitLength: 4, decoder: 'number' },
|
|
1788
|
+
'hair.page': { byteOffset: 0x32, bitOffset: 0, bitLength: 8, decoder: 'lookupPage', lookupTable: 'hairs' },//qk
|
|
1789
|
+
'hair.type': { byteOffset: 0x32, bitOffset: 0, bitLength: 8, decoder: 'lookupType', lookupTable: 'hairs' },//qk
|
|
1790
|
+
'hair.color': { byteOffset: 0x33, bitOffset: 5, bitLength: 3, decoder: 'number' },
|
|
1791
|
+
'hair.flipped': { byteOffset: 0x33, bitOffset: 4, bitLength: 1, decoder: 'boolean' },
|
|
1792
|
+
'eyes.page': { byteOffset: 0x34, bitOffset: 2, bitLength: 6, decoder: 'lookupPage', lookupTable: 'eyes' },//qk
|
|
1793
|
+
'eyes.type': { byteOffset: 0x34, bitOffset: 2, bitLength: 6, decoder: 'lookupType', lookupTable: 'eyes' },//qk
|
|
1794
|
+
'eyes.color': {
|
|
1795
|
+
bitSpecs: [
|
|
1796
|
+
{ byteOffset: 0x35, bitOffset: 7, bitLength: 1 },
|
|
1797
|
+
{ byteOffset: 0x34, bitOffset: 0, bitLength: 2 }
|
|
1798
|
+
],
|
|
1799
|
+
decoder: 'number'
|
|
1800
|
+
},
|
|
1801
|
+
'eyes.size': { byteOffset: 0x35, bitOffset: 3, bitLength: 4, decoder: 'number' },
|
|
1802
|
+
'eyes.squash': { byteOffset: 0x35, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1803
|
+
'eyes.rotation': { byteOffset: 0x36, bitOffset: 3, bitLength: 5, decoder: 'number' },
|
|
1804
|
+
'eyes.distanceApart': {
|
|
1805
|
+
bitSpecs: [
|
|
1806
|
+
{ byteOffset: 0x37, bitOffset: 7, bitLength: 1 },
|
|
1807
|
+
{ byteOffset: 0x36, bitOffset: 0, bitLength: 3 }
|
|
1808
|
+
],
|
|
1809
|
+
decoder: 'number'
|
|
1810
|
+
},
|
|
1811
|
+
'eyes.yPosition': { byteOffset: 0x37, bitOffset: 2, bitLength: 5, decoder: 'number' },
|
|
1812
|
+
'eyebrows.page': { byteOffset: 0x38, bitOffset: 3, bitLength: 5, decoder: 'lookupPage', lookupTable: 'eyebrows' },//qk
|
|
1813
|
+
'eyebrows.type': { byteOffset: 0x38, bitOffset: 3, bitLength: 5, decoder: 'lookupType', lookupTable: 'eyebrows' },//qk
|
|
1814
|
+
'eyebrows.color': { byteOffset: 0x38, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1815
|
+
'eyebrows.size': { byteOffset: 0x39, bitOffset: 4, bitLength: 4, decoder: 'number' },
|
|
1816
|
+
'eyebrows.squash': { byteOffset: 0x39, bitOffset: 1, bitLength: 3, decoder: 'number' },
|
|
1817
|
+
'eyebrows.rotation': { byteOffset: 0x3A, bitOffset: 4, bitLength: 4, decoder: 'number' },
|
|
1818
|
+
'eyebrows.distanceApart': {
|
|
1819
|
+
bitSpecs: [
|
|
1820
|
+
{ byteOffset: 0x3B, bitOffset: 7, bitLength: 1 },
|
|
1821
|
+
{ byteOffset: 0x3A, bitOffset: 0, bitLength: 3 }
|
|
1822
|
+
],
|
|
1823
|
+
decoder: 'number'
|
|
1824
|
+
},
|
|
1825
|
+
'eyebrows.yPosition': { byteOffset: 0x3B, bitOffset: 2, bitLength: 5, decoder: 'number', offset: -3 },
|
|
1826
|
+
'nose.page': { byteOffset: 0x3C, bitOffset: 3, bitLength: 5, decoder: 'lookupPage', lookupTable: 'noses' },//qk
|
|
1827
|
+
'nose.type': { byteOffset: 0x3C, bitOffset: 3, bitLength: 5, decoder: 'lookupType', lookupTable: 'noses' },//qk
|
|
1828
|
+
'nose.size': {
|
|
1829
|
+
bitSpecs: [
|
|
1830
|
+
{ byteOffset: 0x3D, bitOffset: 7, bitLength: 1 },
|
|
1831
|
+
{ byteOffset: 0x3C, bitOffset: 0, bitLength: 3 }
|
|
1832
|
+
],
|
|
1833
|
+
decoder: 'number'
|
|
1834
|
+
},
|
|
1835
|
+
'nose.yPosition': { byteOffset: 0x3D, bitOffset: 2, bitLength: 5, decoder: 'number' },
|
|
1836
|
+
'mouth.page': { byteOffset: 0x3E, bitOffset: 2, bitLength: 6, decoder: 'lookupPage', lookupTable: 'mouths' },//qk
|
|
1837
|
+
'mouth.type': { byteOffset: 0x3E, bitOffset: 2, bitLength: 6, decoder: 'lookupType', lookupTable: 'mouths' },//qk
|
|
1838
|
+
'mouth.color': {
|
|
1839
|
+
bitSpecs: [
|
|
1840
|
+
{ byteOffset: 0x3F, bitOffset: 7, bitLength: 1 },
|
|
1841
|
+
{ byteOffset: 0x3E, bitOffset: 0, bitLength: 2 }
|
|
1842
|
+
],
|
|
1843
|
+
decoder: 'number'
|
|
1844
|
+
},
|
|
1845
|
+
'mouth.size': { byteOffset: 0x3F, bitOffset: 3, bitLength: 4, decoder: 'number' },
|
|
1846
|
+
'mouth.squash': { byteOffset: 0x3F, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1847
|
+
'mouth.yPosition': { byteOffset: 0x40, bitOffset: 3, bitLength: 5, decoder: 'number' },
|
|
1848
|
+
'beard.mustache.type': { byteOffset: 0x40, bitOffset: 0, bitLength: 3, decoder: 'number' },
|
|
1849
|
+
'beard.type': { byteOffset: 0x42, bitOffset: 5, bitLength: 3, decoder: 'number' },
|
|
1850
|
+
'beard.color': { byteOffset: 0x42, bitOffset: 2, bitLength: 3, decoder: 'number' },
|
|
1851
|
+
'beard.mustache.size': {
|
|
1852
|
+
bitSpecs: [
|
|
1853
|
+
{ byteOffset: 0x43, bitOffset: 6, bitLength: 2 },
|
|
1854
|
+
{ byteOffset: 0x42, bitOffset: 0, bitLength: 2 }
|
|
1855
|
+
],
|
|
1856
|
+
decoder: 'number'
|
|
1857
|
+
},
|
|
1858
|
+
'beard.mustache.yPosition': { byteOffset: 0x43, bitOffset: 1, bitLength: 5, decoder: 'number' },
|
|
1859
|
+
'glasses.type': { byteOffset: 0x44, bitOffset: 4, bitLength: 4, decoder: 'number' },
|
|
1860
|
+
'glasses.color': { byteOffset: 0x44, bitOffset: 1, bitLength: 3, decoder: 'number' },
|
|
1861
|
+
'glasses.size': {
|
|
1862
|
+
bitSpecs: [
|
|
1863
|
+
{ byteOffset: 0x45, bitOffset: 5, bitLength: 3 },
|
|
1864
|
+
{ byteOffset: 0x44, bitOffset: 0, bitLength: 1 }
|
|
1865
|
+
],
|
|
1866
|
+
decoder: 'number'
|
|
1796
1867
|
},
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1868
|
+
'glasses.yPosition': { byteOffset: 0x45, bitOffset: 0, bitLength: 5, decoder: 'number' },
|
|
1869
|
+
'mole.on': { byteOffset: 0x46, bitOffset: 7, bitLength: 1, decoder: 'boolean' },
|
|
1870
|
+
'mole.size': { byteOffset: 0x46, bitOffset: 3, bitLength: 4, decoder: 'number' },
|
|
1871
|
+
'mole.xPosition': {
|
|
1872
|
+
bitSpecs: [
|
|
1873
|
+
{ byteOffset: 0x47, bitOffset: 6, bitLength: 2 },
|
|
1874
|
+
{ byteOffset: 0x46, bitOffset: 0, bitLength: 3 }
|
|
1875
|
+
],
|
|
1876
|
+
decoder: 'number'
|
|
1877
|
+
},
|
|
1878
|
+
'mole.yPosition': { byteOffset: 0x47, bitOffset: 1, bitLength: 5, decoder: 'number' },
|
|
1879
|
+
};
|
|
1880
|
+
|
|
1881
|
+
//Functions for working with the Miis
|
|
1882
|
+
function encodeStudio(mii) {
|
|
1883
|
+
var n = 0;
|
|
1884
|
+
var eo;
|
|
1885
|
+
var dest = byteToString(n);
|
|
1886
|
+
for (var i = 0; i < mii.length; i++) {
|
|
1887
|
+
eo = (7 + (mii[i] ^ n)) & 0xFF;
|
|
1888
|
+
n = eo;
|
|
1889
|
+
dest += byteToString(eo);
|
|
1890
|
+
}
|
|
1891
|
+
return dest;
|
|
1892
|
+
}
|
|
1893
|
+
function convertMii(jsonIn,typeTo){
|
|
1894
|
+
typeFrom=jsonIn.console?.toLowerCase();
|
|
1895
|
+
if(typeFrom==null||typeTo===typeFrom){
|
|
1896
|
+
return jsonIn;
|
|
1897
|
+
}
|
|
1898
|
+
let mii=jsonIn;
|
|
1899
|
+
var miiTo=structuredClone(mii);
|
|
1900
|
+
if(["wii u","3ds"].includes(typeFrom)){
|
|
1901
|
+
miiTo.perms.mingle=mii.perms.sharing;
|
|
1902
|
+
miiTo.perms.fromCheckMiiOut=false;
|
|
1903
|
+
miiTo.face.type=convTables.face3DSToWii[mii.face.type];
|
|
1904
|
+
//We prioritize Facial Features here because the Wii supports more of those than they do Makeup types, and is more likely to apply. The 3DS has two separate fields, so you can have makeup and wrinkles applied at the same time. The Wii only has one that covers both.
|
|
1905
|
+
if(typeof(convTables.features3DSToWii[mii.face.feature])==='string'){
|
|
1906
|
+
miiTo.face.feature=convTables.makeup3DSToWii[mii.face.makeup];
|
|
1801
1907
|
}
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
if(["wii u","3ds"].includes(typeFrom)){
|
|
1805
|
-
miiTo={
|
|
1806
|
-
info:{},
|
|
1807
|
-
face:{},
|
|
1808
|
-
nose:{},
|
|
1809
|
-
mouth:{},
|
|
1810
|
-
mole:{},
|
|
1811
|
-
hair:{},
|
|
1812
|
-
eyebrows:{},
|
|
1813
|
-
eyes:{},
|
|
1814
|
-
glasses:{},
|
|
1815
|
-
facialHair:{}
|
|
1816
|
-
};
|
|
1817
|
-
miiTo.creatorName=mii.creatorName;
|
|
1818
|
-
miiTo.info.creatorName=miiTo.creatorName;
|
|
1819
|
-
miiTo.name=mii.name;
|
|
1820
|
-
miiTo.info.name=miiTo.name;
|
|
1821
|
-
miiTo.info.gender=mii.info.gender;
|
|
1822
|
-
miiTo.info.systemId="ffffffff";
|
|
1823
|
-
let miiId;
|
|
1824
|
-
switch(mii.info.type){
|
|
1825
|
-
case "Special":
|
|
1826
|
-
miiId="01000110";
|
|
1827
|
-
break;
|
|
1828
|
-
case "Foreign":
|
|
1829
|
-
miiId="11000110";
|
|
1830
|
-
break;
|
|
1831
|
-
default:
|
|
1832
|
-
miiId="10001001";
|
|
1833
|
-
break;
|
|
1834
|
-
}
|
|
1835
|
-
for(var i=0;i<3;i++){
|
|
1836
|
-
miiId+=Math.floor(Math.random()*255).toString(2).padStart(8,"0");
|
|
1837
|
-
}
|
|
1838
|
-
miiTo.info.miiId+=miiId;
|
|
1839
|
-
miiTo.info.mingle=mii.perms.copying;
|
|
1840
|
-
miiTo.info.birthMonth=mii.info.birthMonth;
|
|
1841
|
-
miiTo.info.birthday=mii.info.birthday;
|
|
1842
|
-
miiTo.info.favColor=mii.info.favColor;
|
|
1843
|
-
miiTo.info.favorited=false;
|
|
1844
|
-
miiTo.info.height=mii.info.height;
|
|
1845
|
-
miiTo.info.weight=mii.info.weight;
|
|
1846
|
-
miiTo.info.downloadedFromCheckMiiOut=false;
|
|
1847
|
-
miiTo.face.shape=convTables.face3DSToWii[mii.face.shape];
|
|
1848
|
-
miiTo.face.col=mii.face.col;
|
|
1849
|
-
//We prioritize Facial Features here because the Wii supports more of those than they do Makeup types, and is more likely to apply. The 3DS has two separate fields, so you can have makeup and wrinkles applied at the same time. The Wii only has one that covers both.
|
|
1850
|
-
if(typeof(convTables.features3DSToWii[faceFeatures3DS.indexOf(mii.face.feature)])==='string'){
|
|
1851
|
-
miiTo.face.feature=wiiFaceFeatures[convTables.makeup3DSToWii[makeups3DS.indexOf(mii.face.makeup)]];
|
|
1852
|
-
}
|
|
1853
|
-
else{
|
|
1854
|
-
miiTo.face.feature=wiiFaceFeatures[convTables.features3DSToWii[features3DS.indexOf(mii.face.feature)]];
|
|
1855
|
-
}
|
|
1856
|
-
miiTo.nose.type=convTables.nose3DSToWii[mii.nose.type[0]][mii.nose.type[1]];
|
|
1857
|
-
miiTo.nose.size=mii.nose.size;
|
|
1858
|
-
miiTo.nose.yPos=mii.nose.yPos;
|
|
1859
|
-
miiTo.mouth.type=convTables.mouth3DSToWii[mii.mouth.type[0]][mii.mouth.type[1]];
|
|
1860
|
-
miiTo.mouth.col=wiiMouthColors[mouthCols3DS.indexOf(mii.mouth.col)>2?0:mouthCols3DS.indexOf(mii.mouth.col)];
|
|
1861
|
-
miiTo.mouth.size=mii.mouth.size;
|
|
1862
|
-
miiTo.mouth.yPos=mii.mouth.yPos;
|
|
1863
|
-
miiTo.mole=mii.mole;
|
|
1864
|
-
miiTo.hair.col=mii.hair.col;
|
|
1865
|
-
miiTo.hair.flipped=mii.hair.flipped;
|
|
1866
|
-
miiTo.hair.type=convTables.hair3DSToWii[mii.hair.style[0]][mii.hair.style[1]];
|
|
1867
|
-
miiTo.eyebrows.type=convTables.eyebrows3DSToWii[mii.eyebrows.style[0]][mii.eyebrows.style[1]];
|
|
1868
|
-
miiTo.eyebrows.col=mii.eyebrows.col;
|
|
1869
|
-
miiTo.eyebrows.rotation=mii.eyebrows.rot;
|
|
1870
|
-
miiTo.eyebrows.size=mii.eyebrows.size;
|
|
1871
|
-
miiTo.eyebrows.yPos=mii.eyebrows.yPos;
|
|
1872
|
-
miiTo.eyebrows.distApart=mii.eyebrows.distApart;
|
|
1873
|
-
miiTo.eyes.type=convTables.eyes3DSToWii[mii.eyes.type[0]][mii.eyes.type[1]];
|
|
1874
|
-
miiTo.eyes.rotation=mii.eyes.rot;
|
|
1875
|
-
miiTo.eyes.yPos=mii.eyes.yPos;
|
|
1876
|
-
miiTo.eyes.col=mii.eyes.col;
|
|
1877
|
-
miiTo.eyes.size=mii.eyes.size;
|
|
1878
|
-
miiTo.eyes.distApart=mii.eyes.distApart;
|
|
1879
|
-
miiTo.glasses=mii.glasses;
|
|
1880
|
-
miiTo.glasses.col=wiiGlassesCols[glassesCols3DS.indexOf(mii.glasses.col)];
|
|
1881
|
-
miiTo.facialHair=mii.facialHair;
|
|
1882
|
-
if(miiTo.facialHair.mustacheType===4){
|
|
1883
|
-
miiTo.facialHair.mustacheType=2;
|
|
1884
|
-
}
|
|
1885
|
-
else if(miiTo.facialHair.mustacheType===5){
|
|
1886
|
-
miiTo.facialHair.mustacheType=0;
|
|
1887
|
-
miiTo.facialHair.beardType=1;
|
|
1888
|
-
}
|
|
1889
|
-
if(mii.facialHair.beardType>3){
|
|
1890
|
-
mii.facialHair.beardType=3;
|
|
1891
|
-
}
|
|
1892
|
-
miiTo.console="wii";
|
|
1908
|
+
else{
|
|
1909
|
+
miiTo.face.feature=convTables.features3DSToWii[mii.face.feature];
|
|
1893
1910
|
}
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
mouth:{},
|
|
1904
|
-
facialHair:{},
|
|
1905
|
-
glasses:{},
|
|
1906
|
-
mole:{}
|
|
1907
|
-
};
|
|
1908
|
-
miiTo.info.birthday=mii.info.birthday;
|
|
1909
|
-
miiTo.info.birthMonth=mii.info.birthMonth;
|
|
1910
|
-
miiTo.name=mii.name;
|
|
1911
|
-
miiTo.info.name=miiTo.name;
|
|
1912
|
-
miiTo.creatorName=mii.creatorName;
|
|
1913
|
-
miiTo.info.creatorName=mii.creatorName;
|
|
1914
|
-
miiTo.info.height=mii.info.height;
|
|
1915
|
-
miiTo.info.weight=mii.info.weight;
|
|
1916
|
-
miiTo.info.favColor=mii.info.favColor;
|
|
1917
|
-
miiTo.info.gender=mii.info.gender;
|
|
1918
|
-
miiTo.perms.sharing=mii.info.mingle;
|
|
1919
|
-
miiTo.perms.copying=mii.info.mingle;
|
|
1920
|
-
miiTo.hair.col=hairCols[hairCols.indexOf(mii.hair.col)];
|
|
1921
|
-
miiTo.hair.flipped=mii.hair.flipped;
|
|
1922
|
-
miiTo.hair.style=convTables.hairWiiTo3DS[+mii.hair.type[0]-1][0+(3*(+mii.hair.type[2]-1))+(+mii.hair.type[1]-1)];
|
|
1923
|
-
miiTo.face.shape=convTables.faceWiiTo3DS[mii.face.shape];
|
|
1924
|
-
miiTo.face.col=skinCols[skinCols.indexOf(mii.face.col)];
|
|
1925
|
-
miiTo.face.makeup="None";
|
|
1926
|
-
miiTo.face.feature="None";
|
|
1927
|
-
if(typeof(convTables.featureWiiTo3DS[wiiFaceFeatures.indexOf(mii.face.feature)])==='string'){
|
|
1928
|
-
miiTo.face.makeup=makeups3DS[+convTables.featureWiiTo3DS[wiiFaceFeatures.indexOf(mii.face.feature)]];
|
|
1929
|
-
}
|
|
1930
|
-
else{
|
|
1931
|
-
miiTo.face.feature=faceFeatures3DS[convTables.featureWiiTo3DS[wiiFaceFeatures.indexOf(mii.face.feature)]];
|
|
1932
|
-
}
|
|
1933
|
-
miiTo.eyes.col=eyeCols[eyeCols.indexOf(mii.eyes.col)];
|
|
1934
|
-
miiTo.eyes.type=[+mii.eyes.type[0]-1,(+mii.eyes.type[1]-1)+(3*(+mii.eyes.type[2]-1))];
|
|
1935
|
-
miiTo.eyes.size=mii.eyes.size;
|
|
1936
|
-
miiTo.eyes.squash=3;
|
|
1937
|
-
miiTo.eyes.rot=mii.eyes.rotation;
|
|
1938
|
-
miiTo.eyes.distApart=mii.eyes.distApart;
|
|
1939
|
-
miiTo.eyes.yPos=mii.eyes.yPos;
|
|
1940
|
-
miiTo.eyebrows.style=[+mii.eyebrows.type[0]-1,(+mii.eyebrows.type[1]-1)+(3*(+mii.eyebrows.type[2]-1))];
|
|
1941
|
-
miiTo.eyebrows.col=hairCols[hairCols.indexOf(mii.eyebrows.col)];
|
|
1942
|
-
miiTo.eyebrows.size=mii.eyebrows.size;
|
|
1943
|
-
miiTo.eyebrows.squash=3;
|
|
1944
|
-
miiTo.eyebrows.rot=mii.eyebrows.rotation;
|
|
1945
|
-
miiTo.eyebrows.distApart=mii.eyebrows.distApart;
|
|
1946
|
-
miiTo.eyebrows.yPos=mii.eyebrows.yPos;
|
|
1947
|
-
miiTo.nose.type=[0,mii.nose.type];
|
|
1948
|
-
miiTo.nose.size=mii.nose.size;
|
|
1949
|
-
miiTo.nose.yPos=mii.nose.yPos;
|
|
1950
|
-
miiTo.mouth.type=[+mii.mouth.type[0]-1,(+mii.mouth.type[1]-1)+(3*(+mii.mouth.type[2]-1))];
|
|
1951
|
-
miiTo.mouth.col=mouthCols3DS[wiiMouthColors.indexOf(mii.mouth.col)];
|
|
1952
|
-
miiTo.mouth.size=mii.mouth.size;
|
|
1953
|
-
miiTo.mouth.squash=3;
|
|
1954
|
-
miiTo.mouth.yPos=mii.mouth.yPos;
|
|
1955
|
-
miiTo.facialHair.mustacheType=mii.facialHair.mustacheType;
|
|
1956
|
-
miiTo.facialHair.beardType=mii.facialHair.beardType;
|
|
1957
|
-
miiTo.facialHair.col=hairCols[hairCols.indexOf(mii.facialHair.col)];
|
|
1958
|
-
miiTo.facialHair.mustacheSize=mii.facialHair.mustacheSize;
|
|
1959
|
-
miiTo.facialHair.mustacheYPos=mii.facialHair.mustacheYPos;
|
|
1960
|
-
miiTo.glasses.type=mii.glasses.type;
|
|
1961
|
-
miiTo.glasses.col=glassesCols3DS[["Grey","Brown","Red","Blue","Yellow","White"].indexOf(mii.glasses.col)];
|
|
1962
|
-
miiTo.glasses.size=mii.glasses.size;
|
|
1963
|
-
miiTo.glasses.yPos=mii.glasses.yPos;
|
|
1964
|
-
miiTo.mole.on=mii.mole.on;
|
|
1965
|
-
miiTo.mole.size=mii.mole.size;
|
|
1966
|
-
miiTo.mole.xPos=mii.mole.xPos;
|
|
1967
|
-
miiTo.mole.yPos=mii.mole.yPos;
|
|
1968
|
-
miiTo.console="3ds";
|
|
1911
|
+
miiTo.nose.type=convTables.nose3DSToWii[mii.nose.page][mii.nose.type];
|
|
1912
|
+
miiTo.mouth.type=convTables.mouth3DSToWii[mii.mouth.page][mii.mouth.type];
|
|
1913
|
+
miiTo.mouth.color=mii.mouth.col>2?0:mii.mouth.col;
|
|
1914
|
+
miiTo.hair.type=convTables.hair3DSToWii[mii.hair.page][mii.hair.type];
|
|
1915
|
+
miiTo.eyebrows.type=convTables.eyebrows3DSToWii[mii.eyebrows.page][mii.eyebrows.type];
|
|
1916
|
+
miiTo.eyes.type=convTables.eyes3DSToWii[mii.eyes.page][mii.eyes.type];
|
|
1917
|
+
miiTo.glasses.col=mii.glasses.col;
|
|
1918
|
+
if(miiTo.beard.mustache.type===4){
|
|
1919
|
+
miiTo.beard.mustache.type=2;
|
|
1969
1920
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
if(!["3ds","wii u"].includes(dad.console?.toLowerCase())){
|
|
1974
|
-
dad=this.convertMii(dad,"wii");
|
|
1921
|
+
else if(miiTo.beard.mustache.type===5){
|
|
1922
|
+
miiTo.beard.mustache.type=0;
|
|
1923
|
+
miiTo.beard.type=1;
|
|
1975
1924
|
}
|
|
1976
|
-
if(
|
|
1977
|
-
|
|
1925
|
+
if(mii.beard.type>3){
|
|
1926
|
+
mii.beard.type=3;
|
|
1978
1927
|
}
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
},
|
|
1991
|
-
"perms":{
|
|
1992
|
-
"sharing":true,
|
|
1993
|
-
"copying":true
|
|
1994
|
-
},
|
|
1995
|
-
"hair":{
|
|
1996
|
-
"style":[8,3],//Hardcoded
|
|
1997
|
-
"col":Math.floor(Math.random()*2)===1?dad.hair.col:mom.hair.col,
|
|
1998
|
-
"flipped":Math.floor(Math.random()*2)===0?true:false
|
|
1999
|
-
},
|
|
2000
|
-
"face":{
|
|
2001
|
-
"shape":Math.floor(Math.random()*2)===1?dad.face.shape:mom.face.shape,
|
|
2002
|
-
"feature":Math.floor(Math.random()*2)===1?dad.face.feature:mom.face.feature,
|
|
2003
|
-
"makeup":g==="Male"?"None":Math.floor(Math.random()*2)===1?dad.face.makeup:mom.face.makeup
|
|
2004
|
-
},
|
|
2005
|
-
"eyes":Math.floor(Math.random()*2)===1?dad.eyes:mom.eyes,
|
|
2006
|
-
"eyebrows":Math.floor(Math.random()*2)===1?dad.eyebrows:mom.eyebrows,
|
|
2007
|
-
"nose":Math.floor(Math.random()*2)===1?dad.nose:mom.nose,
|
|
2008
|
-
"mouth":Math.floor(Math.random()*2)===1?dad.mouth:mom.mouth,
|
|
2009
|
-
"facialHair":g==="Female"?{
|
|
2010
|
-
"mustacheType": 0,
|
|
2011
|
-
"beardType": 0,
|
|
2012
|
-
"col": "Black",
|
|
2013
|
-
"mustacheSize": 4,
|
|
2014
|
-
"mustacheYPos": 10
|
|
2015
|
-
}:Math.floor(Math.random()*2)===0?dad.facialHair:mom.facialHair,
|
|
2016
|
-
"glasses":Math.floor(Math.random()*2)===1?dad.glasses:mom.glasses,
|
|
2017
|
-
"mole":Math.floor(Math.random()*2)===1?dad.mole:mom.mole,
|
|
2018
|
-
"creatorName":""
|
|
2019
|
-
};
|
|
2020
|
-
child.eyebrows.col=child.hair.col;
|
|
2021
|
-
var c=[skinCols.indexOf(mom.face.col),skinCols.indexOf(dad.face.col)];
|
|
2022
|
-
if(c[0]>c[1]){
|
|
2023
|
-
c[1]=c[0];
|
|
2024
|
-
c[0]=skinCols.indexOf(dad.face.col);
|
|
2025
|
-
}
|
|
2026
|
-
child.face.col=skinCols[c[0]+Math.round((c[1]-c[0])/2)];
|
|
2027
|
-
child.name=child.info.name;
|
|
2028
|
-
child.type="3DS";
|
|
2029
|
-
return child;
|
|
2030
|
-
},
|
|
2031
|
-
generateInstructions:function(mii,full){
|
|
2032
|
-
let type=mii.console?.toLowerCase();
|
|
2033
|
-
if(type.toLowerCase()==="wii"){
|
|
2034
|
-
var instrs={
|
|
2035
|
-
"base":`Select "${mii.info.gender}", and then "Start from Scratch".`,
|
|
2036
|
-
"col":`On the info page (first tab), set the Favorite Color to ${mii.info.favColor} (${favCols.indexOf(mii.info.favColor)<=5?favCols.indexOf(mii.info.favColor)+1:favCols.indexOf(mii.info.favColor)-5} from the left, ${favCols.indexOf(mii.info.favColor)>5?"bottom":"top"} row).`,
|
|
2037
|
-
"heightWeight":`On the build page (second tab), set the height to ${Math.round((100/128)*mii.info.height)}%, and the weight to ${Math.round((100/128)*mii.info.weight)}%.`,
|
|
2038
|
-
"faceShape":`On the face page (third tab), set the shape to the one ${Math.floor(mii.face.shape/2)+1} from the top, in the ${mii.face.shape%2===0?"left":"right"} column.`,
|
|
2039
|
-
"skinCol":`On the face page (third tab), set the color to the one ${skinCols.indexOf(mii.face.col)+skinCols.indexOf(mii.face.col)>2?-2:1} from the left, on the ${skinCols.indexOf(mii.face.col)>2?`bottom`:`top`} row.`,
|
|
2040
|
-
"makeup":`On the face page's makeup tab, set the makeup to \"${mii.face.feature}\" (the one ${Math.ceil((wiiFaceFeatures.indexOf(mii.face.feature)+1)/3)} from the top, and ${[1,2,3,1,2,3,1,2,3,1,2,3][wiiFaceFeatures.indexOf(mii.face.feature)]} from the left).`,
|
|
2041
|
-
"hairStyle":`On the hair page (fourth tab), set the hair style to the one ${mii.hair.type[1]} from the left, ${mii.hair.type[2]} from the top, on page ${mii.hair.type[0]}.`,
|
|
2042
|
-
"hairFlipped":`${mii.hair.flipped?`On the hair page (fourth tab), press the button to flip the hair.`:``}`,
|
|
2043
|
-
"hairColor":`On the hair page (fourth tab), set the hair color to the one ${hairCols.indexOf(mii.hair.col)+(hairCols.indexOf(mii.hair.col)>3?-3:1)} from the left, on the ${hairCols.indexOf(mii.hair.col)>3?`bottom`:`top`} row.`,
|
|
2044
|
-
"eyebrowStyle":`On the eyebrow page (fifth tab), set the eyebrow style to the one ${mii.eyebrows.type[1]} from the left, ${mii.eyebrows.type[2]} from the top, on page ${mii.eyebrows.type[0]}.`,
|
|
2045
|
-
"eyebrowColor":`On the eyebrow page (fifth tab), set the eyebrow color to the one ${hairCols.indexOf(mii.eyebrows.col)+(hairCols.indexOf(mii.eyebrows.col)>3?-3:1)} from the left, on the ${hairCols.indexOf(mii.eyebrows.col)>3?`bottom`:`top`} row.`,
|
|
2046
|
-
"eyebrowY":`${mii.eyebrows.yPos!==7?`On the eyebrow page (fifth tab), `:``}${mii.eyebrows.yPos<7?`press the up button ${7-mii.eyebrows.yPos} times.`:mii.eyebrows.yPos>7?`press the down button ${mii.eyebrows.yPos-7} times.`:``}`,
|
|
2047
|
-
"eyebrowSize":`${mii.eyebrows.size!==4?`On the eyebrow page (fifth tab), `:``}${mii.eyebrows.size<4?`press the shrink button ${4-mii.eyebrows.size} times.`:mii.eyebrows.size>4?`press the enlarge button ${mii.eyebrows.size-4} times.`:``}`,
|
|
2048
|
-
"eyebrowRot":`${mii.eyebrows.rotation!==6?`On the eyebrow page (fifth tab), `:``}${mii.eyebrows.rotation<6?`press the rotate clockwise button ${6-mii.eyebrows.rotation} times.`:mii.eyebrows.rotation>6?`press the rotate counter-clockwise button ${mii.eyebrows.rotation-6} times.`:``}`,
|
|
2049
|
-
"eyebrowDist":`${mii.eyebrows.distApart!==2?`On the eyebrow page (fifth tab), `:``}${mii.eyebrows.distApart<2?`press the closer-together button ${2-mii.eyebrows.distApart} times.`:mii.eyebrows.distApart>2?`press the further-apart button ${mii.eyebrows.distApart-2} times.`:``}`,
|
|
2050
|
-
"eyeType":`On the eye page (sixth tab), set the eye type to the one ${mii.eyes.type[1]} from the left, ${mii.eyes.type[2]} from the top, on page ${mii.eyes.type[0]}.`,
|
|
2051
|
-
"eyeColor":`On the eye page (sixth tab), set the color to the one ${eyeCols.indexOf(mii.eyes.col)+(eyeCols.indexOf(mii.eyes.col)>2?-2:1)} from the left, on the ${eyeCols.indexOf(mii.eyes.col)>2?`bottom`:`top`} row.`,
|
|
2052
|
-
"eyeY":`${mii.eyes.yPos!==12?`On the eye page (sixth tab), `:``}${mii.eyes.yPos<12?`press the up button ${12-mii.eyes.yPos} times.`:mii.eyes.yPos>12?`press the down button ${mii.eyes.yPos-12} times.`:``}`,
|
|
2053
|
-
"eyeSize":`${mii.eyes.size!==4?`On the eye page (sixth tab), `:``}${mii.eyes.size<4?`press the shrink button ${4-mii.eyes.size} times.`:mii.eyes.size>4?`press the enlarge button ${mii.eyes.size-4} times.`:``}`,
|
|
2054
|
-
"eyeRot":`${mii.eyes.rotation!==(mii.info.gender==="Female"?3:4)?`On the eye page (sixth tab), `:``}${mii.eyes.rotation<(mii.info.gender==="Female"?3:4)?`press the rotate clockwise button ${(mii.info.gender==="Female"?3:4)-mii.eyes.rotation} times.`:mii.eyes.rotation>(mii.info.gender==="Female"?3:4)?`press the rotate counter-clockwise button ${mii.eyes.rotation-(mii.info.gender==="Female"?3:4)} times.`:``}`,
|
|
2055
|
-
"eyeDist":`${mii.eyes.distApart!==2?`On the eye page (sixth tab), `:``}${mii.eyes.distApart<2?`press the closer-together button ${2-mii.eyes.distApart} times.`:mii.eyes.distApart>2?`press the further-apart button ${mii.eyes.distApart-2} times.`:``}`,
|
|
2056
|
-
"noseType":`On the nose page (seventh tab), set the nose to the one ${Math.ceil((mii.nose.type+1)/3)} from the top, and ${[1,2,3,1,2,3,1,2,3,1,2,3][mii.nose.type]} from the left.`,
|
|
2057
|
-
"noseY":`${mii.nose.yPos!==9?`On the nose page (seventh tab), `:``}${mii.nose.yPos<9?`press the up button ${9-mii.nose.yPos} times.`:mii.nose.yPos>9?`press the down button ${mii.nose.yPos-9} times.`:``}`,
|
|
2058
|
-
"noseSize":`${mii.nose.size!==4?`On the nose page (seventh tab), `:``}${mii.nose.size<4?`press the shrink button ${4-mii.nose.size} times.`:mii.nose.size>4?`press the enlarge button ${mii.nose.size-4} times.`:``}`,
|
|
2059
|
-
"mouthType":`On the mouth page (eighth tab), set the mouth type to the one ${mii.mouth.type[1]} from the left, ${mii.mouth.type[2]} from the top, on page ${mii.mouth.type[0]}.`,
|
|
2060
|
-
"mouthCol":`On the mouth page (eighth tab), set the color to the one ${wiiMouthColors.indexOf(mii.mouth.col)+1} from the left.`,
|
|
2061
|
-
"mouthY":`${mii.mouth.yPos!==13?`On the mouth page (eighth tab), `:``}${mii.mouth.yPos<13?`press the up button ${13-mii.mouth.yPos} times.`:mii.mouth.yPos>13?`press the down button ${mii.mouth.yPos-13} times.`:``}`,
|
|
2062
|
-
"mouthSize":`${mii.mouth.size!==4?`On the mouth page (eighth tab), `:``}${mii.mouth.size<4?`press the shrink button ${4-mii.mouth.size} times.`:mii.mouth.size>4?`press the enlarge button ${mii.mouth.size-4} times.`:``}`,
|
|
2063
|
-
"glasses":`On the glasses page (within the ninth tab), set the glasses to the one ${Math.ceil((mii.glasses.type+1)/3)} from the top, and ${[1,2,3,1,2,3,1,2,3,1,2,3][mii.glasses.type]} from the left.`,
|
|
2064
|
-
"glassesCol":`On the glasses page (within the ninth tab), set the color to the one ${wiiGlassesCols.indexOf(mii.glasses.col)+(wiiGlassesCols.indexOf(mii.glasses.col)>2?-2:1)} from the left, on the ${wiiGlassesCols.indexOf(mii.glasses.col)>2?`bottom`:`top`} row.`,
|
|
2065
|
-
"glassesY":`${mii.glasses.yPos!==10?`On the glasses page (within the ninth tab), `:``}${mii.glasses.yPos<10?`press the up button ${10-mii.glasses.yPos} times.`:mii.glasses.yPos>10?`press the down button ${mii.glasses.yPos-10} times.`:``}`,
|
|
2066
|
-
"glassesSize":`${mii.glasses.size!==4?`On the glasses page (within the ninth tab), `:``}${mii.glasses.size<4?`press the shrink button ${4-mii.glasses.size} times.`:mii.glasses.size>4?`press the enlarge button ${mii.glasses.size-4} times.`:``}`,
|
|
2067
|
-
"stache":`On the mustache page (within the ninth tab), set the mustache to the one on the ${[0,1].includes(mii.facialHair.mustacheType)?`top`:`bottom`}-${[0,2].includes(mii.facialHair.mustacheType)?`left`:`right`}.`,
|
|
2068
|
-
"stacheY":`${mii.facialHair.mustacheYPos!==10?`On the mustache page (within the ninth tab), press the `:``}${mii.facialHair.mustacheYPos>10?`down button ${mii.facialHair.mustacheYPos-10} times.`:mii.facialHair.mustacheYPos<10?`up button ${10-mii.facialHair.mustacheYPos} times.`:``}`,
|
|
2069
|
-
"stacheSize":`${mii.facialHair.mustacheSize!==4?`On the mustache page (within the ninth tab), `:``}${mii.facialHair.mustacheSize<4?`press the shrink button ${4-mii.facialHair.mustacheSize} times.`:mii.facialHair.mustacheSize>4?`press the enlarge button ${mii.facialHair.mustacheSize-4} times.`:``}`,
|
|
2070
|
-
"mole":`${mii.mole.on?`On the mole page (within the ninth tab), turn the mole on.`:``}`,
|
|
2071
|
-
"moleX":`${mii.mole.xPos!==2?`On the mole page (within the ninth tab), press the `:``}${mii.mole.xPos>2?`right button ${mii.mole.xPos-2} times.`:mii.mole.xPos<2?`left button ${2-mii.mole.xPos} times.`:``}`,
|
|
2072
|
-
"moleY":`${mii.mole.yPos!==20?`On the mole page (within the ninth tab), press the `:``}${mii.mole.yPos>20?`down button ${mii.mole.yPos-20} times.`:mii.mole.yPos<20?`up button ${20-mii.mole.yPos} times.`:``}`,
|
|
2073
|
-
"moleSize":`${mii.mole.size!==4?`On the mole page (within the ninth tab), `:``}${mii.mole.size<4?`press the shrink button ${4-mii.mole.size} times.`:mii.mole.size>4?`press the enlarge button ${mii.mole.size-4} times.`:``}`,
|
|
2074
|
-
"beard":`On the beard page (within the ninth tab), set the beard to the one on the ${[0,1].includes(mii.facialHair.beardType)?`top`:`bottom`}-${[0,2].includes(mii.facialHair.beardType)?`left`:`right`}.`,
|
|
2075
|
-
"beardCol":`On the mustache OR beard pages (within the ninth tab), set the color to the one ${hairCols.indexOf(mii.facialHair.col)+(hairCols.indexOf(mii.facialHair.col)>3?-3:1)} from the left, on the ${hairCols.indexOf(mii.facialHair.col)>3?`bottom`:`top`} row.`,
|
|
2076
|
-
"other":`The Nickname of this Mii is ${mii.info.name}.${mii.info.creatorName?` The creator was ${mii.info.creatorName}.`:``} Mingle was turned ${mii.info.mingle?`on`:`off`}.${mii.info.birthday!==0?` Its birthday is ${["","January","February","March","April","May","June","July","August","September","October","November","December"][mii.info.birthMonth]} ${mii.info.birthday}.`:``}`
|
|
2077
|
-
};
|
|
2078
|
-
if(!full){
|
|
2079
|
-
var defaultMiiInstrs=structuredClone(mii.info.gender==="Male"?defaultInstrs.wii.male:defaultInstrs.wii.female);
|
|
2080
|
-
Object.keys(instrs).forEach(instr=>{
|
|
2081
|
-
if(instrs[instr]===defaultMiiInstrs[instr]){
|
|
2082
|
-
delete instrs[instr];
|
|
2083
|
-
}
|
|
2084
|
-
});
|
|
2085
|
-
}
|
|
2086
|
-
return instrs;
|
|
1928
|
+
miiTo.console="wii";
|
|
1929
|
+
}
|
|
1930
|
+
else if(typeFrom==="wii"){
|
|
1931
|
+
miiTo.perms.sharing=mii.info.mingle;
|
|
1932
|
+
miiTo.perms.copying=mii.info.mingle;
|
|
1933
|
+
miiTo.hair.style=convTables.hairWiiTo3DS[mii.hair.page][mii.hair.type];
|
|
1934
|
+
miiTo.face.shape=convTables.faceWiiTo3DS[mii.face.shape];
|
|
1935
|
+
miiTo.face.makeup=0;
|
|
1936
|
+
miiTo.face.feature=0;
|
|
1937
|
+
if(typeof(convTables.featureWiiTo3DS[mii.face.feature])==='string'){
|
|
1938
|
+
miiTo.face.makeup=makeups3DS[+convTables.featureWiiTo3DS[mii.face.feature]];
|
|
2087
1939
|
}
|
|
2088
1940
|
else{
|
|
2089
|
-
|
|
2090
|
-
"base":`Select "Start from Scratch", and then "${mii.info.gender}".`,
|
|
2091
|
-
"faceShape":`On the face page (first tab), set the face shape to the one ${Math.ceil((mii.face.shape+1)/3)} from the top, and ${[1,2,3,1,2,3,1,2,3,1,2,3][mii.face.shape]} from the left.`,
|
|
2092
|
-
"skinCol":`On the face page (first tab), set the color to the one ${skinCols.indexOf(mii.face.col)+1} from the top.`,
|
|
2093
|
-
"makeup":`On the face page's makeup tab, set the makeup to \"${mii.face.makeup}\" (the one ${Math.ceil((makeups3DS.indexOf(mii.face.makeup)+1)/3)} from the top, and ${[1,2,3,1,2,3,1,2,3,1,2,3][makeups3DS.indexOf(mii.face.makeup)]} from the left).`,
|
|
2094
|
-
"feature":`On the face page's wrinkles tab, set the facial feature to \"${mii.face.feature}\" (the one ${Math.ceil((faceFeatures3DS.indexOf(mii.face.feature)+1)/3)+1} from the top, and ${[1,2,3,1,2,3,1,2,3,1,2,3][makeups3DS.indexOf(mii.face.makeup)]} from the left).`,
|
|
2095
|
-
"hairStyle":`On the hair page (second tab), set the hair style to the one ${Math.ceil((mii.hair.style[1]+1)/3)} from the top, and ${[1,2,3,1,2,3,1,2,3,1,2,3][mii.hair.style[1]]} from the left, on page ${mii.hair.style[0]+1}.`,
|
|
2096
|
-
"hairFlipped":`${mii.hair.flipped?`On the hair page (second tab), press the button to flip the hair.`:``}`,
|
|
2097
|
-
"hairColor":`On the hair page (second tab), set the hair color to the one ${hairCols.indexOf(mii.hair.col)+1} from the top.`,
|
|
2098
|
-
"eyebrowStyle":`On the eyebrow page (third tab), set the eyebrow style to the one ${[1,2,3,1,2,3,1,2,3,1,2,3][mii.eyebrows.style[1]]} from the left, ${Math.ceil((mii.eyebrows.style[1]+1)/3)} from the top, on page ${mii.eyebrows.style[0]+1}.`,
|
|
2099
|
-
"eyebrowColor":`On the eyebrow page (third tab), set the eyebrow color to the one ${hairCols.indexOf(mii.eyebrows.col)+1} from the top.`,
|
|
2100
|
-
"eyebrowY":`${mii.eyebrows.yPos!==7?`On the eyebrow page (third tab), `:``}${mii.eyebrows.yPos<7?`press the up button ${7-mii.eyebrows.yPos} times.`:mii.eyebrows.yPos>7?`press the down button ${mii.eyebrows.yPos-7} times.`:``}`,
|
|
2101
|
-
"eyebrowSize":`${mii.eyebrows.size!==4?`On the eyebrow page (third tab), `:``}${mii.eyebrows.size<4?`press the shrink button ${4-mii.eyebrows.size} times.`:mii.eyebrows.size>4?`press the enlarge button ${mii.eyebrows.size-4} times.`:``}`,
|
|
2102
|
-
"eyebrowRot":`${mii.eyebrows.rot!==6?`On the eyebrow page (third tab), `:``}${mii.eyebrows.rot<6?`press the rotate clockwise button ${6-mii.eyebrows.rot} times.`:mii.eyebrows.rot>6?`press the rotate counter-clockwise button ${mii.eyebrows.rot-6} times.`:``}`,
|
|
2103
|
-
"eyebrowDist":`${mii.eyebrows.distApart!==2?`On the eyebrow page (third tab), `:``}${mii.eyebrows.distApart<2?`press the closer-together button ${2-mii.eyebrows.distApart} times.`:mii.eyebrows.distApart>2?`press the further-apart button ${mii.eyebrows.distApart-2} times.`:``}`,
|
|
2104
|
-
"eyebrowSquash":`${mii.eyebrows.squash!==3?`On the eyebrow page (third tab), `:``}${mii.eyebrows.squash<3?`press the squish button ${3-mii.eyebrows.squash} times.`:mii.eyebrows.squash>3?`press the un-squish button ${mii.eyebrows.squash-3} times.`:``}`,
|
|
2105
|
-
"eyeType":`On the eye page (fourth tab), set the eye type to the one ${[1,2,3,1,2,3,1,2,3,1,2,3][mii.eyes.type[1]]} from the left, ${Math.ceil((mii.eyes.type[1]+1)/3)} from the top, on page ${mii.eyes.type[0]+1}.`,
|
|
2106
|
-
"eyeColor":`On the eye page (fourth tab), set the color to the one ${eyeCols.indexOf(mii.eyes.col)+1} from the top.`,
|
|
2107
|
-
"eyeY":`${mii.eyes.yPos!==12?`On the eye page (fourth tab), `:``}${mii.eyes.yPos<12?`press the up button ${12-mii.eyes.yPos} times.`:mii.eyes.yPos>12?`press the down button ${mii.eyes.yPos-12} times.`:``}`,
|
|
2108
|
-
"eyeSize":`${mii.eyes.size!==4?`On the eye page (fourth tab), `:``}${mii.eyes.size<4?`press the shrink button ${4-mii.eyes.size} times.`:mii.eyes.size>4?`press the enlarge button ${mii.eyes.size-4} times.`:``}`,
|
|
2109
|
-
"eyeRot":`${mii.eyes.rot!==(mii.info.gender==="Female"?3:4)?`On the eye page (fourth tab), `:``}${mii.eyes.rot<(mii.info.gender==="Female"?3:4)?`press the rotate clockwise button ${(mii.info.gender==="Female"?3:4)-mii.eyes.rot} times.`:mii.eyes.rot>(mii.info.gender==="Female"?3:4)?`press the rotate counter-clockwise button ${mii.eyes.rot-(mii.info.gender==="Female"?3:4)} times.`:``}`,
|
|
2110
|
-
"eyeDist":`${mii.eyes.distApart!==2?`On the eye page (fourth tab), `:``}${mii.eyes.distApart<2?`press the closer-together button ${2-mii.eyes.distApart} times.`:mii.eyes.distApart>2?`press the further-apart button ${mii.eyes.distApart-2} times.`:``}`,
|
|
2111
|
-
"eyeSquash":`${mii.eyes.squash!==3?`On the eye page (fourth tab), `:``}${mii.eyes.squash<3?`press the squish button ${3-mii.eyes.squash} times.`:mii.eyes.squash>3?`press the un-squish button ${mii.eyes.squash-3} times.`:``}`,
|
|
2112
|
-
"noseType":`On the nose page (fifth tab), set the nose to the one ${Math.ceil((mii.nose.type[1]+1)/3)} from the top, and ${[1,2,3,1,2,3,1,2,3,1,2,3][mii.nose.type[1]]} from the left, on page ${mii.nose.type[0]}.`,
|
|
2113
|
-
"noseY":`${mii.nose.yPos!==9?`On the nose page (fifth tab), `:``}${mii.nose.yPos<9?`press the up button ${9-mii.nose.yPos} times.`:mii.nose.yPos>9?`press the down button ${mii.nose.yPos-9} times.`:``}`,
|
|
2114
|
-
"noseSize":`${mii.nose.size!==4?`On the nose page (fifth tab), `:``}${mii.nose.size<4?`press the shrink button ${4-mii.nose.size} times.`:mii.nose.size>4?`press the enlarge button ${mii.nose.size-4} times.`:``}`,
|
|
2115
|
-
"mouthType":`On the mouth page (sixth tab), set the mouth type to the one ${[1,2,3,1,2,3,1,2,3,1,2,3][mii.mouth.type[1]]} from the left, ${Math.ceil((mii.mouth.type[1]+1)/3)} from the top, on page ${mii.mouth.type[0]+1}.`,
|
|
2116
|
-
"mouthCol":`On the mouth page (sixth tab), set the color to the one ${mouthCols3DS.indexOf(mii.mouth.col)+1} from the top.`,
|
|
2117
|
-
"mouthY":`${mii.mouth.yPos!==13?`On the mouth page (sixth tab), `:``}${mii.mouth.yPos<13?`press the up button ${13-mii.mouth.yPos} times.`:mii.mouth.yPos>13?`press the down button ${mii.mouth.yPos-13} times.`:``}`,
|
|
2118
|
-
"mouthSize":`${mii.mouth.size!==4?`On the mouth page (sixth tab), `:``}${mii.mouth.size<4?`press the shrink button ${4-mii.mouth.size} times.`:mii.mouth.size>4?`press the enlarge button ${mii.mouth.size-4} times.`:``}`,
|
|
2119
|
-
"mouthSquash":`${mii.mouth.squash!==3?`On the mouth page (sixth tab), `:``}${mii.mouth.squash<3?`press the squish button ${3-mii.mouth.squash} times.`:mii.mouth.squash>3?`press the un-squish button ${mii.mouth.squash-3} times.`:``}`,
|
|
2120
|
-
"glasses":`On the glasses page (within the seventh tab), set the glasses to the one ${Math.ceil((mii.glasses.type+1)/3)} from the top, and ${[1,2,3,1,2,3,1,2,3,1,2,3][mii.glasses.type]} from the left.`,
|
|
2121
|
-
"glassesCol":`On the glasses page (within the seventh tab), set the color to the one ${glassesCols3DS.indexOf(mii.glasses.col)+1} from the top.`,
|
|
2122
|
-
"glassesY":`${mii.glasses.yPos!==10?`On the glasses page (within the seventh tab), `:``}${mii.glasses.yPos<10?`press the up button ${10-mii.glasses.yPos} times.`:mii.glasses.yPos>10?`press the down button ${mii.glasses.yPos-10} times.`:``}`,
|
|
2123
|
-
"glassesSize":`${mii.glasses.size!==4?`On the glasses page (within the seventh tab), `:``}${mii.glasses.size<4?`press the shrink button ${4-mii.glasses.size} times.`:mii.glasses.size>4?`press the enlarge button ${mii.glasses.size-4} times.`:``}`,
|
|
2124
|
-
"stache":`On the mustache page (within the seventh tab), set the mustache to the one on the ${[0,1].includes(mii.facialHair.mustacheType)?`top`:[2,3].includes(mii.facialHair.mustacheType)?`middle`:`bottom`}-${[0,2,4].includes(mii.facialHair.mustacheType)?`left`:`right`}.`,
|
|
2125
|
-
"stacheY":`${mii.facialHair.mustacheYPos!==10?`On the mustache page (within the seventh tab), press the `:``}${mii.facialHair.mustacheYPos>10?`down button ${mii.facialHair.mustacheYPos-10} times.`:mii.facialHair.mustacheYPos<10?`up button ${10-mii.facialHair.mustacheYPos} times.`:``}`,
|
|
2126
|
-
"stacheSize":`${mii.facialHair.mustacheSize!==4?`On the mustache page (within the seventh tab), `:``}${mii.facialHair.mustacheSize<4?`press the shrink button ${4-mii.facialHair.mustacheSize} times.`:mii.facialHair.mustacheSize>4?`press the enlarge button ${mii.facialHair.mustacheSize-4} times.`:``}`,
|
|
2127
|
-
"mole":`${mii.mole.on?`On the mole page (within the seventh tab), turn the mole on.`:``}`,
|
|
2128
|
-
"moleX":`${mii.mole.xPos!==2?`On the mole page (within the seventh tab), press the `:``}${mii.mole.xPos>2?`right button ${mii.mole.xPos-2} times.`:mii.mole.xPos<2?`left button ${2-mii.mole.xPos} times.`:``}`,
|
|
2129
|
-
"moleY":`${mii.mole.yPos!==20?`On the mole page (within the seventh tab), press the `:``}${mii.mole.yPos>20?`down button ${mii.mole.yPos-20} times.`:mii.mole.yPos<20?`up button ${20-mii.mole.yPos} times.`:``}`,
|
|
2130
|
-
"moleSize":`${mii.mole.size!==4?`On the mole page (within the seventh tab), `:``}${mii.mole.size<4?`press the shrink button ${4-mii.mole.size} times.`:mii.mole.size>4?`press the enlarge button ${mii.mole.size-4} times.`:``}`,
|
|
2131
|
-
"beard":`On the beard page (within the seventh tab), set the beard to the one on the ${[0,1].includes(mii.facialHair.beardType)?`top`:[2,3].includes(mii.facialHair.beardType)?`middle`:`bottom`}-${[0,2].includes(mii.facialHair.beardType)?`left`:`right`}.`,
|
|
2132
|
-
"beardCol":`On the mustache OR beard pages (within the seventh tab), set the color to the one ${hairCols.indexOf(mii.facialHair.col)+1} from the top.`,
|
|
2133
|
-
"heightWeight":`On the build page (eighth tab), set the height to ${Math.round((100/128)*mii.info.height)}%, and the weight to ${Math.round((100/128)*mii.info.weight)}%.`,
|
|
2134
|
-
"col":`On the info page (after pressing "Next"), set the Favorite Color to ${mii.info.favColor} (${favCols.indexOf(mii.info.favColor)<=5?favCols.indexOf(mii.info.favColor)+1:favCols.indexOf(mii.info.favColor)-5} from the left, ${favCols.indexOf(mii.info.favColor)>5?"bottom":"top"} row).`,
|
|
2135
|
-
"other":`The Nickname of this Mii is ${mii.info.name}.${mii.info.creatorName?` The creator was ${mii.info.creatorName}.`:``} ${mii.info.birthday!==0?` Its birthday is ${["","January","February","March","April","May","June","July","August","September","October","November","December"][mii.info.birthMonth]} ${mii.info.birthday}.`:``}`
|
|
2136
|
-
};
|
|
2137
|
-
if(!full){
|
|
2138
|
-
var defaultMiiInstrs=structuredClone(mii.info.gender==="Male"?defaultInstrs["3ds"].male:defaultInstrs["3ds"].female);
|
|
2139
|
-
Object.keys(instrs).forEach(instr=>{
|
|
2140
|
-
if(instrs[instr]===defaultMiiInstrs[instr]){
|
|
2141
|
-
delete instrs[instr];
|
|
2142
|
-
}
|
|
2143
|
-
});
|
|
2144
|
-
}
|
|
2145
|
-
return instrs;
|
|
1941
|
+
miiTo.face.feature=faceFeatures3DS[convTables.featureWiiTo3DS[mii.face.feature]];
|
|
2146
1942
|
}
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
1943
|
+
miiTo.eyes.squash=3;
|
|
1944
|
+
miiTo.eyebrows.squash=3;
|
|
1945
|
+
miiTo.mouth.col=mouthCols3DS[mii.mouth.col];//qk
|
|
1946
|
+
miiTo.mouth.squash=3;
|
|
1947
|
+
miiTo.console="3ds";
|
|
1948
|
+
}
|
|
1949
|
+
return miiTo;
|
|
1950
|
+
}
|
|
1951
|
+
function convertMiiToStudio(jsonIn) {
|
|
1952
|
+
if (!["3ds", "wii u"].includes(jsonIn.console?.toLowerCase())) {
|
|
1953
|
+
jsonIn = convertMii(jsonIn);
|
|
1954
|
+
}
|
|
1955
|
+
var mii = jsonIn;
|
|
1956
|
+
var studioMii = new Uint8Array([0x08, 0x00, 0x40, 0x03, 0x08, 0x04, 0x04, 0x02, 0x02, 0x0c, 0x03, 0x01, 0x06, 0x04, 0x06, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x21, 0x40, 0x04, 0x00, 0x02, 0x14, 0x03, 0x13, 0x04, 0x17, 0x0d, 0x04, 0x00, 0x0a, 0x04, 0x01, 0x09]);
|
|
1957
|
+
studioMii[0x16] = mii.general.gender;
|
|
1958
|
+
studioMii[0x15] = mii.info.favoriteColor;
|
|
1959
|
+
studioMii[0x1E] = mii.info.height;
|
|
1960
|
+
studioMii[2] = mii.info.weight;
|
|
1961
|
+
studioMii[0x13] = lookupTables.faces.values[mii.face.type];
|
|
1962
|
+
studioMii[0x11] = mii.face.color;
|
|
1963
|
+
studioMii[0x14] = mii.face.feature;
|
|
1964
|
+
studioMii[0x12] = mii.face.makeup;
|
|
1965
|
+
studioMii[0x1D] = lookupTables.hairs.values[mii.hair.page][mii.hair.type];
|
|
1966
|
+
studioMii[0x1B] = mii.hair.color;
|
|
1967
|
+
if (!studioMii[0x1B]) studioMii[0x1B] = 8;
|
|
1968
|
+
studioMii[0x1C] = mii.hair.flipped ? 1 : 0;
|
|
1969
|
+
studioMii[7] = lookupTables.eyes.values[mii.eyes.page][mii.eyes.type];
|
|
1970
|
+
studioMii[4] = mii.eyes.color + 8;
|
|
1971
|
+
studioMii[6] = mii.eyes.size;
|
|
1972
|
+
studioMii[3] = mii.eyes.squash;
|
|
1973
|
+
studioMii[5] = mii.eyes.rotation;
|
|
1974
|
+
studioMii[8] = mii.eyes.distanceApart;
|
|
1975
|
+
studioMii[9] = mii.eyes.yPosition;
|
|
1976
|
+
studioMii[0xE] = lookupTables.eyebrows.values[mii.eyebrows.page][mii.eyebrows.type];
|
|
1977
|
+
studioMii[0xB] = mii.eyebrows.color;
|
|
1978
|
+
if (!studioMii[0xB]) studioMii[0xB] = 8;
|
|
1979
|
+
studioMii[0xD] = mii.eyebrows.size;
|
|
1980
|
+
studioMii[0xA] = mii.eyebrows.squash;
|
|
1981
|
+
studioMii[0xC] = mii.eyebrows.rotation;
|
|
1982
|
+
studioMii[0xF] = mii.eyebrows.distanceApart;
|
|
1983
|
+
studioMii[0x10] = mii.eyebrows.yPosition + 3;
|
|
1984
|
+
studioMii[0x2C] = lookupTables.noses.values[mii.nose.page][mii.nose.type];
|
|
1985
|
+
studioMii[0x2B] = mii.nose.size;
|
|
1986
|
+
studioMii[0x2D] = mii.nose.yPosition;
|
|
1987
|
+
studioMii[0x26] = lookupTables.mouths.values[mii.mouth.page][mii.mouth.type];
|
|
1988
|
+
studioMii[0x24] = mii.mouth.col;
|
|
1989
|
+
if (studioMii[0x24] < 4) {
|
|
1990
|
+
studioMii[0x24] += 19;
|
|
1991
|
+
} else {
|
|
1992
|
+
studioMii[0x24] = 0;
|
|
1993
|
+
}
|
|
1994
|
+
studioMii[0x25] = mii.mouth.size;
|
|
1995
|
+
studioMii[0x23] = mii.mouth.squash;
|
|
1996
|
+
studioMii[0x27] = mii.mouth.yPos;
|
|
1997
|
+
studioMii[0x29] = mii.facialHair.mustacheType;
|
|
1998
|
+
studioMii[1] = mii.facialHair.beardType;
|
|
1999
|
+
studioMii[0] = lookupTables.hairCols.indexOf(mii.facialHair.col);
|
|
2000
|
+
if (!studioMii[0]) studioMii[0] = 8;
|
|
2001
|
+
studioMii[0x28] = mii.facialHair.mustacheSize;
|
|
2002
|
+
studioMii[0x2A] = mii.facialHair.mustacheYPos;
|
|
2003
|
+
studioMii[0x19] = mii.glasses.type;
|
|
2004
|
+
studioMii[0x17] = lookupTables.glassesCols3DS.indexOf(mii.glasses.col);
|
|
2005
|
+
if (!studioMii[0x17]) {
|
|
2006
|
+
studioMii[0x17] = 8;
|
|
2007
|
+
} else if (studioMii[0x17] < 6) {
|
|
2008
|
+
studioMii[0x17] += 13;
|
|
2009
|
+
} else {
|
|
2010
|
+
studioMii[0x17] = 0;
|
|
2011
|
+
}
|
|
2012
|
+
studioMii[0x18] = mii.glasses.size;
|
|
2013
|
+
studioMii[0x1A] = mii.glasses.yPosition;
|
|
2014
|
+
studioMii[0x20] = mii.mole.on ? 1 : 0;
|
|
2015
|
+
studioMii[0x1F] = mii.mole.size;
|
|
2016
|
+
studioMii[0x21] = mii.mole.xPosition;
|
|
2017
|
+
studioMii[0x22] = mii.mole.yPosition;
|
|
2018
|
+
return encodeStudio(studioMii);
|
|
2019
|
+
}
|
|
2020
|
+
async function readWiiBin(binOrPath) {
|
|
2021
|
+
let data;
|
|
2022
|
+
if (/[^01]/ig.test(binOrPath)) {
|
|
2023
|
+
data = await fs.promises.readFile(binOrPath);
|
|
2024
|
+
} else {
|
|
2025
|
+
data = Buffer.from(binOrPath);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
const thisMii = miiBufferToJson(data, WII_MII_SCHEMA, lookupTables, true);
|
|
2029
|
+
thisMii.console = 'wii';
|
|
2030
|
+
|
|
2031
|
+
return thisMii;
|
|
2032
|
+
}
|
|
2033
|
+
async function read3DSQR(binOrPath,returnDecryptedBin) {
|
|
2034
|
+
let qrCode;
|
|
2035
|
+
if (/[^01]/ig.test(binOrPath)) {
|
|
2036
|
+
var data = await fs.promises.readFile(binOrPath);
|
|
2037
|
+
var img = await loadImage(data);
|
|
2038
|
+
const canvas = createCanvas(img.width, img.height);
|
|
2039
|
+
const ctx = canvas.getContext('2d');
|
|
2040
|
+
ctx.drawImage(img, 0, 0);
|
|
2041
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
2042
|
+
qrCode = jsQR(imageData.data, imageData.width, imageData.height).binaryData;
|
|
2043
|
+
}
|
|
2044
|
+
else {
|
|
2045
|
+
var d = binOrPath.match(/(0|1){1,8}/g);
|
|
2046
|
+
qrCode = [];
|
|
2047
|
+
d.forEach(byte => {
|
|
2048
|
+
qrCode.push(parseInt(byte, 2));
|
|
2049
|
+
});
|
|
2050
|
+
}
|
|
2051
|
+
if (qrCode) {
|
|
2052
|
+
var data = Buffer.from(decodeAesCcm(new Uint8Array(qrCode)));
|
|
2053
|
+
if(returnDecryptedBin){
|
|
2054
|
+
return data;
|
|
2151
2055
|
}
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2056
|
+
const miiJson = miiBufferToJson(data, THREEDS_MII_SCHEMA, lookupTables, false);
|
|
2057
|
+
miiJson.console = '3ds';
|
|
2058
|
+
return miiJson;
|
|
2059
|
+
} else {
|
|
2060
|
+
console.error('Failed to decode QR code');
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
async function renderMiiWithStudio(jsonIn){
|
|
2064
|
+
if(!["3ds","wii u"].includes(jsonIn.console?.toLowerCase())){
|
|
2065
|
+
jsonIn=convertMii(jsonIn);
|
|
2066
|
+
}
|
|
2067
|
+
var studioMii=convertMiiToStudio(jsonIn);
|
|
2068
|
+
return await downloadImage('https://studio.mii.nintendo.com/miis/image.png?data=' + studioMii + "&width=270&type=face");
|
|
2069
|
+
}
|
|
2070
|
+
async function createFFLMiiIcon(data, width, height, fflRes) {
|
|
2071
|
+
/**
|
|
2072
|
+
* Creates a Mii face render using FFL.js/Three.js/gl-headless.
|
|
2073
|
+
* @example
|
|
2074
|
+
* const fs = require('fs');
|
|
2075
|
+
* // NOTE: ASSUMES that this function IS EXPORTED in index.js.
|
|
2076
|
+
* const createFFLMiiIcon = require('./index.js').createFFLMiiIcon;
|
|
2077
|
+
* const miiData = '000d142a303f434b717a7b84939ba6b2bbbec5cbc9d0e2ea010d15252b3250535960736f726870757f8289a0a7aeb1';
|
|
2078
|
+
* const outFilePath = 'mii-render.png';
|
|
2079
|
+
* const fflRes = fs.readFileSync('./FFLResHigh.dat');
|
|
2080
|
+
* createFFLMiiIcon(miiData, 512, 512, fflRes)
|
|
2081
|
+
* .then(pngBytes => fs.writeFileSync(outFilePath, pngBytes));
|
|
2082
|
+
*/
|
|
2083
|
+
|
|
2084
|
+
// Create WebGL context.
|
|
2085
|
+
const gl = createGL(width, height);
|
|
2086
|
+
if (!gl) {
|
|
2087
|
+
throw new Error('Failed to create WebGL 1 context');
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
// Create a dummy canvas for Three.js to use.
|
|
2091
|
+
const canvas = {
|
|
2092
|
+
width, height, style: {},
|
|
2093
|
+
addEventListener() {},
|
|
2094
|
+
removeEventListener() {},
|
|
2095
|
+
// Return the context for 'webgl' (not webgl2)
|
|
2096
|
+
getContext: (type, _) => type === 'webgl' ? gl : null,
|
|
2097
|
+
};
|
|
2098
|
+
|
|
2099
|
+
// WebGLRenderer constructor sets "self" as the context.
|
|
2100
|
+
// As of r162, it only tries to call cancelAnimationFrame frame on it.
|
|
2101
|
+
globalThis.self ??= {
|
|
2102
|
+
// Mock window functions called by Three.js.
|
|
2103
|
+
cancelAnimationFrame: () => { },
|
|
2104
|
+
};
|
|
2105
|
+
// Create the Three.js renderer and scene.
|
|
2106
|
+
const renderer = new THREE.WebGLRenderer({ canvas, context: gl, alpha: true });
|
|
2107
|
+
setIsWebGL1State(!renderer.capabilities.isWebGL2); // Tell FFL.js we are WebGL1
|
|
2108
|
+
|
|
2109
|
+
const scene = new THREE.Scene();
|
|
2110
|
+
// scene.background = null; // Transparent background.
|
|
2111
|
+
scene.background = new THREE.Color('white');
|
|
2112
|
+
// (You DO NOT need to add any lights to the scene,
|
|
2113
|
+
// unless you are using a Three.js built-in material.
|
|
2114
|
+
// If you are, look at demo-basic.js "addLightsToScene".)
|
|
2115
|
+
|
|
2116
|
+
let ffl, currentCharModel;
|
|
2117
|
+
|
|
2118
|
+
//const _realConsoleDebug = console.debug;
|
|
2119
|
+
//console.debug = () => { };
|
|
2120
|
+
try {
|
|
2121
|
+
// Initialize FFL
|
|
2122
|
+
ffl = await initializeFFL(fflRes, ModuleFFL);
|
|
2123
|
+
|
|
2124
|
+
// Create Mii model and add to the scene.
|
|
2125
|
+
const studioRaw = parseHexOrB64ToUint8Array(data); // Parse studio data
|
|
2126
|
+
currentCharModel = createCharModel(studioRaw, null,
|
|
2127
|
+
FFLShaderMaterial, ffl.module);
|
|
2128
|
+
initCharModelTextures(currentCharModel, renderer); // Initialize fully
|
|
2129
|
+
scene.add(currentCharModel.meshes); // Add to scene
|
|
2130
|
+
|
|
2131
|
+
// Use the camera for an icon pose.
|
|
2132
|
+
const camera = getCameraForViewType(ViewType.MakeIcon);
|
|
2133
|
+
|
|
2134
|
+
// The pixels coming from WebGL are upside down.
|
|
2135
|
+
camera.projectionMatrix.elements[5] *= -1; // Flip the camera Y axis.
|
|
2136
|
+
// When flipping the camera, the triangles are in the wrong direction.
|
|
2137
|
+
scene.traverse(mesh => {
|
|
2138
|
+
if (mesh.isMesh && mesh.material.side === THREE.FrontSide)
|
|
2139
|
+
// Fix triangle winding by changing the culling (side).
|
|
2140
|
+
mesh.material.side = THREE.BackSide;
|
|
2141
|
+
});
|
|
2142
|
+
|
|
2143
|
+
// Render the scene, and read the pixels into a buffer.
|
|
2144
|
+
renderer.render(scene, camera);
|
|
2145
|
+
const pixels = new Uint8Array(width * height * 4);
|
|
2146
|
+
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
2147
|
+
|
|
2148
|
+
// Draw the pixels to a new canvas.
|
|
2149
|
+
const canvas = createCanvas(width, height);
|
|
2150
|
+
const img = new ImageData(new Uint8ClampedArray(pixels), width, height);
|
|
2151
|
+
canvas.getContext('2d').putImageData(img, 0, 0);
|
|
2152
|
+
|
|
2153
|
+
return canvas.toBuffer('image/png'); // Encode image to PNG
|
|
2154
|
+
|
|
2155
|
+
} catch (error) {
|
|
2156
|
+
console.error('Error during rendering:', error);
|
|
2157
|
+
throw error;
|
|
2158
|
+
} finally {
|
|
2159
|
+
// Clean up.
|
|
2160
|
+
try {
|
|
2161
|
+
(currentCharModel) && currentCharModel.dispose(); // Mii model
|
|
2162
|
+
exitFFL(ffl.module, ffl.resourceDesc); // Free fflRes from memory.
|
|
2163
|
+
renderer.dispose(); // Dispose Three.js renderer.
|
|
2164
|
+
gl.finish();
|
|
2165
|
+
} catch (error) {
|
|
2166
|
+
console.warn('Error disposing Mii and renderer:', error);
|
|
2167
|
+
}// finally {
|
|
2168
|
+
// console.debug = _realConsoleDebug;
|
|
2169
|
+
//}
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
async function renderMii(jsonIn, fflRes=getFFLRes()){
|
|
2173
|
+
if(!["3ds","wii u"].includes(jsonIn.console?.toLowerCase())){
|
|
2174
|
+
jsonIn=convertMii(jsonIn);
|
|
2175
|
+
}
|
|
2176
|
+
const studioMii = convertMiiToStudio(jsonIn);
|
|
2177
|
+
const width = height = 600;
|
|
2178
|
+
|
|
2179
|
+
return createFFLMiiIcon(studioMii, width, height, fflRes);
|
|
2180
|
+
}
|
|
2181
|
+
async function writeWiiBin(jsonIn, outPath) {
|
|
2182
|
+
if (jsonIn.console?.toLowerCase() !== "wii") {
|
|
2183
|
+
convertMii(jsonIn);
|
|
2184
|
+
}
|
|
2185
|
+
const miiBuffer = jsonToMiiBuffer(jsonIn, WII_MII_SCHEMA, lookupTables, 74);
|
|
2186
|
+
if(outPath){
|
|
2187
|
+
await fs.promises.writeFile(outPath, miiBuffer);
|
|
2188
|
+
}
|
|
2189
|
+
else{
|
|
2190
|
+
return miiBuffer;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
async function write3DSQR(miiJson, outPath, fflRes = getFFLRes()) {
|
|
2194
|
+
if (!["3ds", "wii u"].includes(miiJson.console?.toLowerCase())) {
|
|
2195
|
+
miiJson = convertMii(miiJson);
|
|
2196
|
+
}
|
|
2197
|
+
return new Promise(async (resolve, reject) => {
|
|
2198
|
+
const miiBinary = jsonToMiiBuffer(miiJson, THREEDS_MII_SCHEMA, lookupTables, 74);
|
|
2199
|
+
var encryptedData = Buffer.from(encodeAesCcm(new Uint8Array(miiBinary)));
|
|
2200
|
+
|
|
2201
|
+
const options = {
|
|
2202
|
+
width: 300,
|
|
2203
|
+
height: 300,
|
|
2204
|
+
data: encryptedData.toString("latin1"),
|
|
2205
|
+
image: "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", // 1x1 gif
|
|
2206
|
+
dotsOptions: {
|
|
2207
|
+
color: "#000000",
|
|
2208
|
+
type: "square"
|
|
2209
|
+
},
|
|
2210
|
+
backgroundOptions: {
|
|
2211
|
+
color: "#ffffff",
|
|
2212
|
+
},
|
|
2213
|
+
imageOptions: {
|
|
2214
|
+
crossOrigin: "anonymous",
|
|
2215
|
+
imageSize: 0.4 // Changes how large center area is
|
|
2167
2216
|
}
|
|
2168
|
-
return dest;
|
|
2169
2217
|
}
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
studioMii
|
|
2178
|
-
studioMii[
|
|
2179
|
-
studioMii[
|
|
2218
|
+
const qrCodeImage = new QRCodeStyling({
|
|
2219
|
+
jsdom: JSDOM,
|
|
2220
|
+
nodeCanvas,
|
|
2221
|
+
...options
|
|
2222
|
+
});
|
|
2223
|
+
const qrBuffer = Buffer.from(await qrCodeImage.getRawData("png"))
|
|
2224
|
+
|
|
2225
|
+
var studioMii = new Uint8Array([0x08, 0x00, 0x40, 0x03, 0x08, 0x04, 0x04, 0x02, 0x02, 0x0c, 0x03, 0x01, 0x06, 0x04, 0x06, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x21, 0x40, 0x04, 0x00, 0x02, 0x14, 0x03, 0x13, 0x04, 0x17, 0x0d, 0x04, 0x00, 0x0a, 0x04, 0x01, 0x09]);
|
|
2226
|
+
studioMii[0x16] = miiJson.info.gender === "Male" ? 0 : 1;
|
|
2227
|
+
studioMii[0x15] = lookupTables.favCols.indexOf(miiJson.info.favColor);
|
|
2228
|
+
studioMii[0x1E] = miiJson.info.height;
|
|
2229
|
+
studioMii[2] = miiJson.info.weight;
|
|
2230
|
+
studioMii[0x13] = lookupTables.faces.values[miiJson.face.shape];
|
|
2231
|
+
studioMii[0x11] = lookupTables.skinCols.indexOf(miiJson.face.col);
|
|
2232
|
+
studioMii[0x14] = lookupTables.faceFeatures3DS.indexOf(miiJson.face.feature);
|
|
2233
|
+
studioMii[0x12] = lookupTables.makeups3DS.indexOf(miiJson.face.makeup);
|
|
2234
|
+
studioMii[0x1D] = lookupTables.hairs.values[miiJson.hair.style[0]][miiJson.hair.style[1]];
|
|
2235
|
+
studioMii[0x1B] = lookupTables.hairCols.indexOf(miiJson.hair.col);
|
|
2180
2236
|
if (!studioMii[0x1B]) studioMii[0x1B] = 8;
|
|
2181
|
-
studioMii[0x1C] =
|
|
2182
|
-
studioMii[7] =
|
|
2183
|
-
studioMii[4] = eyeCols.indexOf(
|
|
2184
|
-
studioMii[6] =
|
|
2185
|
-
studioMii[3] =
|
|
2186
|
-
studioMii[5] =
|
|
2187
|
-
studioMii[8] =
|
|
2188
|
-
studioMii[9] =
|
|
2189
|
-
studioMii[0xE] =
|
|
2190
|
-
studioMii[0xB] = hairCols.indexOf(
|
|
2237
|
+
studioMii[0x1C] = miiJson.hair.flipped ? 1 : 0;
|
|
2238
|
+
studioMii[7] = lookupTables.eyes.values[miiJson.eyes.type[0]][miiJson.eyes.type[1]];
|
|
2239
|
+
studioMii[4] = lookupTables.eyeCols.indexOf(miiJson.eyes.col) + 8;
|
|
2240
|
+
studioMii[6] = miiJson.eyes.size;
|
|
2241
|
+
studioMii[3] = miiJson.eyes.squash;
|
|
2242
|
+
studioMii[5] = miiJson.eyes.rot;
|
|
2243
|
+
studioMii[8] = miiJson.eyes.distApart;
|
|
2244
|
+
studioMii[9] = miiJson.eyes.yPos;
|
|
2245
|
+
studioMii[0xE] = lookupTables.eyebrows.values[miiJson.eyebrows.style[0]][miiJson.eyebrows.style[1]];
|
|
2246
|
+
studioMii[0xB] = lookupTables.hairCols.indexOf(miiJson.eyebrows.col);
|
|
2191
2247
|
if (!studioMii[0xB]) studioMii[0xB] = 8;
|
|
2192
|
-
studioMii[0xD] =
|
|
2193
|
-
studioMii[0xA] =
|
|
2194
|
-
studioMii[0xC] =
|
|
2195
|
-
studioMii[0xF] =
|
|
2196
|
-
studioMii[0x10] =
|
|
2197
|
-
studioMii[0x2C] =
|
|
2198
|
-
studioMii[0x2B] =
|
|
2199
|
-
studioMii[0x2D] =
|
|
2200
|
-
studioMii[0x26] =
|
|
2201
|
-
studioMii[0x24] = mouthCols3DS.indexOf(
|
|
2248
|
+
studioMii[0xD] = miiJson.eyebrows.size;
|
|
2249
|
+
studioMii[0xA] = miiJson.eyebrows.squash;
|
|
2250
|
+
studioMii[0xC] = miiJson.eyebrows.rot;
|
|
2251
|
+
studioMii[0xF] = miiJson.eyebrows.distApart;
|
|
2252
|
+
studioMii[0x10] = miiJson.eyebrows.yPos + 3;
|
|
2253
|
+
studioMii[0x2C] = lookupTables.noses.values[miiJson.nose.type[0]][miiJson.nose.type[1]];
|
|
2254
|
+
studioMii[0x2B] = miiJson.nose.size;
|
|
2255
|
+
studioMii[0x2D] = miiJson.nose.yPos;
|
|
2256
|
+
studioMii[0x26] = lookupTables.mouths.values[miiJson.mouth.type[0]][miiJson.mouth.type[1]];
|
|
2257
|
+
studioMii[0x24] = lookupTables.mouthCols3DS.indexOf(miiJson.mouth.col);
|
|
2202
2258
|
if (studioMii[0x24] < 4) {
|
|
2203
2259
|
studioMii[0x24] += 19;
|
|
2204
2260
|
} else {
|
|
2205
2261
|
studioMii[0x24] = 0;
|
|
2206
2262
|
}
|
|
2207
|
-
studioMii[0x25] =
|
|
2208
|
-
studioMii[0x23] =
|
|
2209
|
-
studioMii[0x27] =
|
|
2210
|
-
studioMii[0x29] =
|
|
2211
|
-
studioMii[1] =
|
|
2212
|
-
studioMii[0] = hairCols.indexOf(
|
|
2263
|
+
studioMii[0x25] = miiJson.mouth.size;
|
|
2264
|
+
studioMii[0x23] = miiJson.mouth.squash;
|
|
2265
|
+
studioMii[0x27] = miiJson.mouth.yPos;
|
|
2266
|
+
studioMii[0x29] = miiJson.facialHair.mustacheType;
|
|
2267
|
+
studioMii[1] = miiJson.facialHair.beardType;
|
|
2268
|
+
studioMii[0] = lookupTables.hairCols.indexOf(miiJson.facialHair.col);
|
|
2213
2269
|
if (!studioMii[0]) studioMii[0] = 8;
|
|
2214
|
-
studioMii[0x28] =
|
|
2215
|
-
studioMii[0x2A] =
|
|
2216
|
-
studioMii[0x19] =
|
|
2217
|
-
studioMii[0x17] =
|
|
2270
|
+
studioMii[0x28] = miiJson.facialHair.mustacheSize;
|
|
2271
|
+
studioMii[0x2A] = miiJson.facialHair.mustacheYPos;
|
|
2272
|
+
studioMii[0x19] = miiJson.glasses.type;
|
|
2273
|
+
studioMii[0x17] = miiJson.glasses.col;
|
|
2218
2274
|
if (!studioMii[0x17]) {
|
|
2219
2275
|
studioMii[0x17] = 8;
|
|
2220
2276
|
} else if (studioMii[0x17] < 6) {
|
|
@@ -2222,19 +2278,263 @@ var exports={
|
|
|
2222
2278
|
} else {
|
|
2223
2279
|
studioMii[0x17] = 0;
|
|
2224
2280
|
}
|
|
2225
|
-
studioMii[0x18] =
|
|
2226
|
-
studioMii[0x1A] =
|
|
2227
|
-
studioMii[0x20] =
|
|
2228
|
-
studioMii[0x1F] =
|
|
2229
|
-
studioMii[0x21] =
|
|
2230
|
-
studioMii[0x22] =
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2281
|
+
studioMii[0x18] = miiJson.glasses.size;
|
|
2282
|
+
studioMii[0x1A] = miiJson.glasses.yPos;
|
|
2283
|
+
studioMii[0x20] = miiJson.mole.on ? 1 : 0;
|
|
2284
|
+
studioMii[0x1F] = miiJson.mole.size;
|
|
2285
|
+
studioMii[0x21] = miiJson.mole.xPos;
|
|
2286
|
+
studioMii[0x22] = miiJson.mole.yPos;
|
|
2287
|
+
let miiPNGBuf = null;
|
|
2288
|
+
let renderedWithStudio = fflRes === null || fflRes === undefined;
|
|
2289
|
+
if (renderedWithStudio) {
|
|
2290
|
+
miiPNGBuf = await renderMiiWithStudio(miiJson);
|
|
2291
|
+
}
|
|
2292
|
+
else {
|
|
2293
|
+
miiPNGBuf = await renderMii(miiJson, fflRes);
|
|
2294
|
+
}
|
|
2295
|
+
const main_img = await Jimp.read(qrBuffer);
|
|
2296
|
+
main_img.resize(424, 424, Jimp.RESIZE_NEAREST_NEIGHBOR); // Don't anti-alias the QR code
|
|
2297
|
+
|
|
2298
|
+
let miiSize, miiZoomFactor, miiYOffset;
|
|
2299
|
+
if (renderedWithStudio) {
|
|
2300
|
+
miiSize = 100;
|
|
2301
|
+
miiZoomFactor = 1;
|
|
2302
|
+
miiYOffset = -15;
|
|
2303
|
+
|
|
2304
|
+
} else {
|
|
2305
|
+
miiSize = 100;
|
|
2306
|
+
miiZoomFactor = 1.25;
|
|
2307
|
+
miiYOffset = -5;
|
|
2308
|
+
}
|
|
2309
|
+
const mii_img = await Jimp.read(miiPNGBuf);
|
|
2310
|
+
mii_img.resize(miiSize * miiZoomFactor, miiSize * miiZoomFactor, Jimp.RESIZE_BICUBIC);
|
|
2311
|
+
mii_img.crop(
|
|
2312
|
+
(miiSize * miiZoomFactor - 100) / 2,
|
|
2313
|
+
(miiSize * miiZoomFactor - 100) / 2,
|
|
2314
|
+
miiSize,
|
|
2315
|
+
miiSize
|
|
2316
|
+
);
|
|
2317
|
+
|
|
2318
|
+
const canvas = new Jimp(mii_img.bitmap.width, mii_img.bitmap.height, 0xFFFFFFFF);
|
|
2319
|
+
canvas.composite(mii_img, 0, miiYOffset);
|
|
2320
|
+
main_img.blit(canvas, 212 - 100 / 2, 212 - 100 / 2);
|
|
2321
|
+
const font = await Jimp.loadFont(Jimp.FONT_SANS_16_BLACK)
|
|
2322
|
+
|
|
2323
|
+
main_img.print(font, 0, 55, {
|
|
2324
|
+
text: miiJson.name,
|
|
2325
|
+
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
|
|
2326
|
+
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
|
|
2327
|
+
}, 424, 395);
|
|
2328
|
+
|
|
2329
|
+
if (miiJson.info.type === "Special") {
|
|
2330
|
+
const crown_img = await Jimp.read(path.join(__dirname, 'crown.jpg'));
|
|
2331
|
+
crown_img.resize(40, 20);
|
|
2332
|
+
main_img.blit(crown_img, 225, 160);
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
main_img.write(outPath, (err, img) =>
|
|
2336
|
+
resolve(img)
|
|
2337
|
+
);
|
|
2338
|
+
})
|
|
2339
|
+
}
|
|
2340
|
+
function make3DSChild(dad,mom,options={}){
|
|
2341
|
+
if(!["3ds","wii u"].includes(dad.console?.toLowerCase())){
|
|
2342
|
+
dad=convertMii(dad,"wii");
|
|
2343
|
+
}
|
|
2344
|
+
if(!["3ds","wii u"].includes(mom.console?.toLowerCase())){
|
|
2345
|
+
mom=convertMii(dad,"wii");
|
|
2346
|
+
}
|
|
2347
|
+
var g=options.gender||Math.floor(Math.random()*2)===1?"Male":"Female";
|
|
2348
|
+
var child={
|
|
2349
|
+
"info":{
|
|
2350
|
+
"birthMonth":new Date().getMonth()+1,
|
|
2351
|
+
"birthday":new Date().getDay(),
|
|
2352
|
+
"height":64,
|
|
2353
|
+
"weight":64,
|
|
2354
|
+
"creatorName":"",
|
|
2355
|
+
"gender":g,
|
|
2356
|
+
"name":options.name||kidNames[g][Math.floor(Math.random()*kidNames[g].length)],
|
|
2357
|
+
"favColor":options.favColor||favCols[Math.floor(Math.random()*favCols.length)]
|
|
2358
|
+
},
|
|
2359
|
+
"perms":{
|
|
2360
|
+
"sharing":true,
|
|
2361
|
+
"copying":true
|
|
2362
|
+
},
|
|
2363
|
+
"hair":{
|
|
2364
|
+
"style":[8,3],//Hardcoded
|
|
2365
|
+
"col":Math.floor(Math.random()*2)===1?dad.hair.col:mom.hair.col,
|
|
2366
|
+
"flipped":Math.floor(Math.random()*2)===0?true:false
|
|
2367
|
+
},
|
|
2368
|
+
"face":{
|
|
2369
|
+
"shape":Math.floor(Math.random()*2)===1?dad.face.shape:mom.face.shape,
|
|
2370
|
+
"feature":Math.floor(Math.random()*2)===1?dad.face.feature:mom.face.feature,
|
|
2371
|
+
"makeup":g==="Male"?"None":Math.floor(Math.random()*2)===1?dad.face.makeup:mom.face.makeup
|
|
2372
|
+
},
|
|
2373
|
+
"eyes":Math.floor(Math.random()*2)===1?dad.eyes:mom.eyes,
|
|
2374
|
+
"eyebrows":Math.floor(Math.random()*2)===1?dad.eyebrows:mom.eyebrows,
|
|
2375
|
+
"nose":Math.floor(Math.random()*2)===1?dad.nose:mom.nose,
|
|
2376
|
+
"mouth":Math.floor(Math.random()*2)===1?dad.mouth:mom.mouth,
|
|
2377
|
+
"facialHair":g==="Female"?{
|
|
2378
|
+
"mustacheType": 0,
|
|
2379
|
+
"beardType": 0,
|
|
2380
|
+
"col": "Black",
|
|
2381
|
+
"mustacheSize": 4,
|
|
2382
|
+
"mustacheYPos": 10
|
|
2383
|
+
}:Math.floor(Math.random()*2)===0?dad.facialHair:mom.facialHair,
|
|
2384
|
+
"glasses":Math.floor(Math.random()*2)===1?dad.glasses:mom.glasses,
|
|
2385
|
+
"mole":Math.floor(Math.random()*2)===1?dad.mole:mom.mole,
|
|
2386
|
+
"creatorName":""
|
|
2387
|
+
};
|
|
2388
|
+
child.eyebrows.col=child.hair.col;
|
|
2389
|
+
var c=[skinCols.indexOf(mom.face.col),skinCols.indexOf(dad.face.col)];
|
|
2390
|
+
if(c[0]>c[1]){
|
|
2391
|
+
c[1]=c[0];
|
|
2392
|
+
c[0]=skinCols.indexOf(dad.face.col);
|
|
2393
|
+
}
|
|
2394
|
+
child.face.col=skinCols[c[0]+Math.round((c[1]-c[0])/2)];
|
|
2395
|
+
child.name=child.info.name;
|
|
2396
|
+
child.type="3DS";
|
|
2397
|
+
return child;
|
|
2398
|
+
}
|
|
2399
|
+
function generateInstructions(mii,full){
|
|
2400
|
+
let type=mii.console?.toLowerCase();
|
|
2401
|
+
if(type.toLowerCase()==="wii"){
|
|
2402
|
+
var typeCheat=[1,2,3,1,2,3,1,2,3,1,2,3];
|
|
2403
|
+
var instrs={
|
|
2404
|
+
"base":`Select "${mii.general.gender}", and then "Start from Scratch".`,
|
|
2405
|
+
"col":`On the info page (first tab), set the Favorite Color to ${lookupTables.favCols[mii.general.favoriteColor]} (${mii.general.favoriteColor<=5?mii.general.favoriteColor+1:mii.general.favoriteColor-5} from the left, ${mii.general.favoriteColor>5?"bottom":"top"} row).`,
|
|
2406
|
+
"heightWeight":`On the build page (second tab), set the height to ${Math.round((100/128)*mii.general.height)}%, and the weight to ${Math.round((100/128)*mii.general.weight)}%.`,
|
|
2407
|
+
"faceShape":`On the face page (third tab), set the shape to the one ${Math.floor(mii.face.type/2)+1} from the top, in the ${mii.face.type%2===0?"left":"right"} column.`,
|
|
2408
|
+
"skinCol":`On the face page (third tab), set the color to the one ${mii.face.color+mii.face.color>2?-2:1} from the left, on the ${mii.face.color>2?`bottom`:`top`} row.`,
|
|
2409
|
+
"makeup":`On the face page's makeup tab, set the makeup to the one ${Math.ceil((mii.face.feature+1)/3)} from the top, and ${typeCheat[mii.face.feature]} from the left.`,
|
|
2410
|
+
"hairStyle":`On the hair page (fourth tab), set the hair style to the one ${typeCheat[mii.hair.type]} from the left, ${Math.ceil((mii.hair.type+1)/3)} from the top, on page ${mii.hair.page}.`,
|
|
2411
|
+
"hairFlipped":`${mii.hair.flipped?`On the hair page (fourth tab), press the button to flip the hair.`:``}`,
|
|
2412
|
+
"hairColor":`On the hair page (fourth tab), set the hair color to the one ${mii.hair.col+(mii.hair.col>3?-3:1)} from the left, on the ${mii.hair.col>3?`bottom`:`top`} row.`,
|
|
2413
|
+
"eyebrowStyle":`On the eyebrow page (fifth tab), set the eyebrow style to the one ${typeCheat[mii.eyebrows.type]} from the left, ${Math.ceil((mii.eyebrows.type+1)/3)} from the top, on page ${mii.eyebrows.page}.`,
|
|
2414
|
+
"eyebrowColor":`On the eyebrow page (fifth tab), set the eyebrow color to the one ${mii.eyebrows.color+(mii.eyebrows.color>3?-3:1)} from the left, on the ${mii.eyebrows.color>3?`bottom`:`top`} row.`,
|
|
2415
|
+
"eyebrowY":`${mii.eyebrows.yPos!==7?`On the eyebrow page (fifth tab), `:``}${mii.eyebrows.yPosition<7?`press the up button ${7-mii.eyebrows.yPosition} times.`:mii.eyebrows.yPosition>7?`press the down button ${mii.eyebrows.yPosition-7} times.`:``}`,
|
|
2416
|
+
"eyebrowSize":`${mii.eyebrows.size!==4?`On the eyebrow page (fifth tab), `:``}${mii.eyebrows.size<4?`press the shrink button ${4-mii.eyebrows.size} times.`:mii.eyebrows.size>4?`press the enlarge button ${mii.eyebrows.size-4} times.`:``}`,
|
|
2417
|
+
"eyebrowRot":`${mii.eyebrows.rotation!==6?`On the eyebrow page (fifth tab), `:``}${mii.eyebrows.rotation<6?`press the rotate clockwise button ${6-mii.eyebrows.rotation} times.`:mii.eyebrows.rotation>6?`press the rotate counter-clockwise button ${mii.eyebrows.rotation-6} times.`:``}`,
|
|
2418
|
+
"eyebrowDist":`${mii.eyebrows.distApart!==2?`On the eyebrow page (fifth tab), `:``}${mii.eyebrows.distanceApart<2?`press the closer-together button ${2-mii.eyebrows.distanceApart} times.`:mii.eyebrows.distanceApart>2?`press the further-apart button ${mii.eyebrows.distanceApart-2} times.`:``}`,
|
|
2419
|
+
"eyeType":`On the eye page (sixth tab), set the eye type to the one ${typeCheat[mii.eyes.type]} from the left, ${Math.ceil((mii.eyes.type+1)/3)} from the top, on page ${mii.eyes.page}.`,
|
|
2420
|
+
"eyeColor":`On the eye page (sixth tab), set the color to the one ${mii.eyes.color+(mii.eyes.color>2?-2:1)} from the left, on the ${mii.eyes.color>2?`bottom`:`top`} row.`,
|
|
2421
|
+
"eyeY":`${mii.eyes.yPos!==12?`On the eye page (sixth tab), `:``}${mii.eyes.yPosition<12?`press the up button ${12-mii.eyes.yPosition} times.`:mii.eyes.yPosition>12?`press the down button ${mii.eyes.yPosition-12} times.`:``}`,
|
|
2422
|
+
"eyeSize":`${mii.eyes.size!==4?`On the eye page (sixth tab), `:``}${mii.eyes.size<4?`press the shrink button ${4-mii.eyes.size} times.`:mii.eyes.size>4?`press the enlarge button ${mii.eyes.size-4} times.`:``}`,
|
|
2423
|
+
"eyeRot":`${mii.eyes.rotation!==(mii.general.gender==="Female"?3:4)?`On the eye page (sixth tab), `:``}${mii.eyes.rotation<(mii.general.gender==="Female"?3:4)?`press the rotate clockwise button ${(mii.general.gender==="Female"?3:4)-mii.eyes.rotation} times.`:mii.eyes.rotation>(mii.general.gender==="Female"?3:4)?`press the rotate counter-clockwise button ${mii.eyes.rotation-(mii.general.gender==="Female"?3:4)} times.`:``}`,
|
|
2424
|
+
"eyeDist":`${mii.eyes.distanceApart!==2?`On the eye page (sixth tab), `:``}${mii.eyes.distanceApart<2?`press the closer-together button ${2-mii.eyes.distanceApart} times.`:mii.eyes.distanceApart>2?`press the further-apart button ${mii.eyes.distanceApart-2} times.`:``}`,
|
|
2425
|
+
"noseType":`On the nose page (seventh tab), set the nose to the one ${Math.ceil((mii.nose.type+1)/3)} from the top, and ${typeCheat[mii.nose.type]} from the left.`,
|
|
2426
|
+
"noseY":`${mii.nose.yPosition!==9?`On the nose page (seventh tab), `:``}${mii.nose.yPosition<9?`press the up button ${9-mii.nose.yPosition} times.`:mii.nose.yPosition>9?`press the down button ${mii.nose.yPosition-9} times.`:``}`,
|
|
2427
|
+
"noseSize":`${mii.nose.size!==4?`On the nose page (seventh tab), `:``}${mii.nose.size<4?`press the shrink button ${4-mii.nose.size} times.`:mii.nose.size>4?`press the enlarge button ${mii.nose.size-4} times.`:``}`,
|
|
2428
|
+
"mouthType":`On the mouth page (eighth tab), set the mouth type to the one ${typeCheat[mii.mouth.type]} from the left, ${Math.ceil((mii.mouth.type+1)/3)} from the top, on page ${mii.mouth.page}.`,
|
|
2429
|
+
"mouthCol":`On the mouth page (eighth tab), set the color to the one ${mii.mouth.col+1} from the left.`,
|
|
2430
|
+
"mouthY":`${mii.mouth.yPosition!==13?`On the mouth page (eighth tab), `:``}${mii.mouth.yPosition<13?`press the up button ${13-mii.mouth.yPosition} times.`:mii.mouth.yPosition>13?`press the down button ${mii.mouth.yPosition-13} times.`:``}`,
|
|
2431
|
+
"mouthSize":`${mii.mouth.size!==4?`On the mouth page (eighth tab), `:``}${mii.mouth.size<4?`press the shrink button ${4-mii.mouth.size} times.`:mii.mouth.size>4?`press the enlarge button ${mii.mouth.size-4} times.`:``}`,
|
|
2432
|
+
"glasses":`On the glasses page (within the ninth tab), set the glasses to the one ${Math.ceil((mii.glasses.type+1)/3)} from the top, and ${typeCheat[mii.glasses.type]} from the left.`,
|
|
2433
|
+
"glassesCol":`On the glasses page (within the ninth tab), set the color to the one ${mii.glasses.color+(mii.glasses.color>2?-2:1)} from the left, on the ${mii.glasses.color>2?`bottom`:`top`} row.`,
|
|
2434
|
+
"glassesY":`${mii.glasses.yPosition!==10?`On the glasses page (within the ninth tab), `:``}${mii.glasses.yPosition<10?`press the up button ${10-mii.glasses.yPosition} times.`:mii.glasses.yPosition>10?`press the down button ${mii.glasses.yPosition-10} times.`:``}`,
|
|
2435
|
+
"glassesSize":`${mii.glasses.size!==4?`On the glasses page (within the ninth tab), `:``}${mii.glasses.size<4?`press the shrink button ${4-mii.glasses.size} times.`:mii.glasses.size>4?`press the enlarge button ${mii.glasses.size-4} times.`:``}`,
|
|
2436
|
+
"stache":`On the mustache page (within the ninth tab), set the mustache to the one on the ${[0,1].includes(mii.beard.mustache.type)?`top`:`bottom`}-${[0,2].includes(mii.beard.mustache.type)?`left`:`right`}.`,
|
|
2437
|
+
"stacheY":`${mii.beard.mustache.yPosition!==10?`On the mustache page (within the ninth tab), press the `:``}${mii.beard.mustache.yPos>10?`down button ${mii.beard.mustache.yPos-10} times.`:mii.beard.mustache.yPos<10?`up button ${10-mii.beard.mustache.yPos} times.`:``}`,
|
|
2438
|
+
"stacheSize":`${mii.beard.mustache.size!==4?`On the mustache page (within the ninth tab), `:``}${mii.beard.mustache.size<4?`press the shrink button ${4-mii.beard.mustache.size} times.`:mii.beard.mustache.size>4?`press the enlarge button ${mii.beard.mustache.size-4} times.`:``}`,
|
|
2439
|
+
"mole":`${mii.mole.on?`On the mole page (within the ninth tab), turn the mole on.`:``}`,
|
|
2440
|
+
"moleX":`${mii.mole.xPosition!==2?`On the mole page (within the ninth tab), press the `:``}${mii.mole.xPosition>2?`right button ${mii.mole.xPosition-2} times.`:mii.mole.xPosition<2?`left button ${2-mii.mole.xPosition} times.`:``}`,
|
|
2441
|
+
"moleY":`${mii.mole.yPosition!==20?`On the mole page (within the ninth tab), press the `:``}${mii.mole.yPosition>20?`down button ${mii.mole.yPosition-20} times.`:mii.mole.yPosition<20?`up button ${20-mii.mole.yPosition} times.`:``}`,
|
|
2442
|
+
"moleSize":`${mii.mole.size!==4?`On the mole page (within the ninth tab), `:``}${mii.mole.size<4?`press the shrink button ${4-mii.mole.size} times.`:mii.mole.size>4?`press the enlarge button ${mii.mole.size-4} times.`:``}`,
|
|
2443
|
+
"beard":`On the beard page (within the ninth tab), set the beard to the one on the ${[0,1].includes(mii.beard.type)?`top`:`bottom`}-${[0,2].includes(mii.beard.type)?`left`:`right`}.`,
|
|
2444
|
+
"beardCol":`On the mustache OR beard pages (within the ninth tab), set the color to the one ${mii.beard.col+(mii.beard.col>3?-3:1)} from the left, on the ${mii.facialHair.col>3?`bottom`:`top`} row.`,
|
|
2445
|
+
"other":`The Nickname of this Mii is ${mii.info.name}.${mii.info.creatorName?` The creator was ${mii.info.creatorName}.`:``} Mingle was turned ${mii.info.mingle?`on`:`off`}.${mii.info.birthday!==0?` Its birthday is ${["","January","February","March","April","May","June","July","August","September","October","November","December"][mii.info.birthMonth]} ${mii.info.birthday}.`:``}`
|
|
2446
|
+
};
|
|
2447
|
+
if(!full){
|
|
2448
|
+
var defaultMiiInstrs=structuredClone(mii.general.gender==="Male"?defaultInstrs.wii.male:defaultInstrs.wii.female);
|
|
2449
|
+
Object.keys(instrs).forEach(instr=>{
|
|
2450
|
+
if(instrs[instr]===defaultMiiInstrs[instr]){
|
|
2451
|
+
delete instrs[instr];
|
|
2452
|
+
}
|
|
2453
|
+
});
|
|
2236
2454
|
}
|
|
2237
|
-
return
|
|
2455
|
+
return instrs;
|
|
2238
2456
|
}
|
|
2457
|
+
else{
|
|
2458
|
+
var instrs={
|
|
2459
|
+
"base":`Select "Start from Scratch", and then "${mii.general.gender}".`,
|
|
2460
|
+
"faceShape":`On the face page (first tab), set the face shape to the one ${Math.ceil((mii.face.type+1)/3)} from the top, and ${typeCheat[mii.face.type]} from the left.`,
|
|
2461
|
+
"skinCol":`On the face page (first tab), set the color to the one ${mii.face.color+1} from the top.`,
|
|
2462
|
+
"makeup":`On the face page's makeup tab, set the makeup to the one ${Math.ceil((mii.face.makeup+1)/3)} from the top, and ${typeCheat[mii.face.makeup]} from the left.`,
|
|
2463
|
+
"feature":`On the face page's wrinkles tab, set the facial feature to the one ${Math.ceil((mii.face.feature+1)/3)+1} from the top, and ${typeCheat[mii.face.makeup]} from the left.`,
|
|
2464
|
+
"hairStyle":`On the hair page (second tab), set the hair style to the one ${Math.ceil((mii.hair.type+1)/3)} from the top, and ${typeCheat[mii.hair.type]} from the left, on page ${mii.hair.page+1}.`,
|
|
2465
|
+
"hairFlipped":`${mii.hair.flipped?`On the hair page (second tab), press the button to flip the hair.`:``}`,
|
|
2466
|
+
"hairColor":`On the hair page (second tab), set the hair color to the one ${mii.hair.color+1} from the top.`,
|
|
2467
|
+
"eyebrowStyle":`On the eyebrow page (third tab), set the eyebrow style to the one ${typeCheat[mii.eyebrows.type]} from the left, ${Math.ceil((mii.eyebrows.type+1)/3)} from the top, on page ${mii.eyebrows.page+1}.`,
|
|
2468
|
+
"eyebrowColor":`On the eyebrow page (third tab), set the eyebrow color to the one ${mii.eyebrows.color+1} from the top.`,
|
|
2469
|
+
"eyebrowY":`${mii.eyebrows.yPosition!==7?`On the eyebrow page (third tab), `:``}${mii.eyebrows.yPosition<7?`press the up button ${7-mii.eyebrows.yPosition} times.`:mii.eyebrows.yPosition>7?`press the down button ${mii.eyebrows.yPosition-7} times.`:``}`,
|
|
2470
|
+
"eyebrowSize":`${mii.eyebrows.size!==4?`On the eyebrow page (third tab), `:``}${mii.eyebrows.size<4?`press the shrink button ${4-mii.eyebrows.size} times.`:mii.eyebrows.size>4?`press the enlarge button ${mii.eyebrows.size-4} times.`:``}`,
|
|
2471
|
+
"eyebrowRot":`${mii.eyebrows.rotation!==6?`On the eyebrow page (third tab), `:``}${mii.eyebrows.rotation<6?`press the rotate clockwise button ${6-mii.eyebrows.rotation} times.`:mii.eyebrows.rotation>6?`press the rotate counter-clockwise button ${mii.eyebrows.rotation-6} times.`:``}`,
|
|
2472
|
+
"eyebrowDist":`${mii.eyebrows.distanceApart!==2?`On the eyebrow page (third tab), `:``}${mii.eyebrows.distanceApart<2?`press the closer-together button ${2-mii.eyebrows.distanceApart} times.`:mii.eyebrows.distanceApart>2?`press the further-apart button ${mii.eyebrows.distanceApart-2} times.`:``}`,
|
|
2473
|
+
"eyebrowSquash":`${mii.eyebrows.squash!==3?`On the eyebrow page (third tab), `:``}${mii.eyebrows.squash<3?`press the squish button ${3-mii.eyebrows.squash} times.`:mii.eyebrows.squash>3?`press the un-squish button ${mii.eyebrows.squash-3} times.`:``}`,
|
|
2474
|
+
"eyeType":`On the eye page (fourth tab), set the eye type to the one ${typeCheat[mii.eyes.type]} from the left, ${Math.ceil((mii.eyes.type+1)/3)} from the top, on page ${mii.eyes.page+1}.`,
|
|
2475
|
+
"eyeColor":`On the eye page (fourth tab), set the color to the one ${mii.eyes.col+1} from the top.`,
|
|
2476
|
+
"eyeY":`${mii.eyes.yPosition!==12?`On the eye page (fourth tab), `:``}${mii.eyes.yPosition<12?`press the up button ${12-mii.eyes.yPosition} times.`:mii.eyes.yPosition>12?`press the down button ${mii.eyes.yPosition-12} times.`:``}`,
|
|
2477
|
+
"eyeSize":`${mii.eyes.size!==4?`On the eye page (fourth tab), `:``}${mii.eyes.size<4?`press the shrink button ${4-mii.eyes.size} times.`:mii.eyes.size>4?`press the enlarge button ${mii.eyes.size-4} times.`:``}`,
|
|
2478
|
+
"eyeRot":`${mii.eyes.rotation!==(mii.general.gender==="Female"?3:4)?`On the eye page (fourth tab), `:``}${mii.eyes.rotation<(mii.general.gender==="Female"?3:4)?`press the rotate clockwise button ${(mii.general.gender==="Female"?3:4)-mii.eyes.rotation} times.`:mii.eyes.rotation>(mii.general.gender==="Female"?3:4)?`press the rotate counter-clockwise button ${mii.eyes.rotation-(mii.general.gender==="Female"?3:4)} times.`:``}`,
|
|
2479
|
+
"eyeDist":`${mii.eyes.distanceApart!==2?`On the eye page (fourth tab), `:``}${mii.eyes.distanceApart<2?`press the closer-together button ${2-mii.eyes.distanceApart} times.`:mii.eyes.distanceApart>2?`press the further-apart button ${mii.eyes.distanceApart-2} times.`:``}`,
|
|
2480
|
+
"eyeSquash":`${mii.eyes.squash!==3?`On the eye page (fourth tab), `:``}${mii.eyes.squash<3?`press the squish button ${3-mii.eyes.squash} times.`:mii.eyes.squash>3?`press the un-squish button ${mii.eyes.squash-3} times.`:``}`,
|
|
2481
|
+
"noseType":`On the nose page (fifth tab), set the nose to the one ${Math.ceil((mii.nose.type+1)/3)} from the top, and ${typeCheat[mii.nose.type]} from the left, on page ${mii.nose.page}.`,
|
|
2482
|
+
"noseY":`${mii.nose.yPosition!==9?`On the nose page (fifth tab), `:``}${mii.nose.yPosition<9?`press the up button ${9-mii.nose.yPosition} times.`:mii.nose.yPosition>9?`press the down button ${mii.nose.yPosition-9} times.`:``}`,
|
|
2483
|
+
"noseSize":`${mii.nose.size!==4?`On the nose page (fifth tab), `:``}${mii.nose.size<4?`press the shrink button ${4-mii.nose.size} times.`:mii.nose.size>4?`press the enlarge button ${mii.nose.size-4} times.`:``}`,
|
|
2484
|
+
"mouthType":`On the mouth page (sixth tab), set the mouth type to the one ${typeCheat[mii.mouth.type]} from the left, ${Math.ceil((mii.mouth.type+1)/3)} from the top, on page ${mii.mouth.page+1}.`,
|
|
2485
|
+
"mouthCol":`On the mouth page (sixth tab), set the color to the one ${mii.mouth.color+1} from the top.`,
|
|
2486
|
+
"mouthY":`${mii.mouth.yPosition!==13?`On the mouth page (sixth tab), `:``}${mii.mouth.yPosition<13?`press the up button ${13-mii.mouth.yPosition} times.`:mii.mouth.yPosition>13?`press the down button ${mii.mouth.yPosition-13} times.`:``}`,
|
|
2487
|
+
"mouthSize":`${mii.mouth.size!==4?`On the mouth page (sixth tab), `:``}${mii.mouth.size<4?`press the shrink button ${4-mii.mouth.size} times.`:mii.mouth.size>4?`press the enlarge button ${mii.mouth.size-4} times.`:``}`,
|
|
2488
|
+
"mouthSquash":`${mii.mouth.squash!==3?`On the mouth page (sixth tab), `:``}${mii.mouth.squash<3?`press the squish button ${3-mii.mouth.squash} times.`:mii.mouth.squash>3?`press the un-squish button ${mii.mouth.squash-3} times.`:``}`,
|
|
2489
|
+
"glasses":`On the glasses page (within the seventh tab), set the glasses to the one ${Math.ceil((mii.glasses.type+1)/3)} from the top, and ${typeCheat[mii.glasses.type]} from the left.`,
|
|
2490
|
+
"glassesCol":`On the glasses page (within the seventh tab), set the color to the one ${mii.glasses.col+1} from the top.`,
|
|
2491
|
+
"glassesY":`${mii.glasses.yPosition!==10?`On the glasses page (within the seventh tab), `:``}${mii.glasses.yPosition<10?`press the up button ${10-mii.glasses.yPosition} times.`:mii.glasses.yPosition>10?`press the down button ${mii.glasses.yPosition-10} times.`:``}`,
|
|
2492
|
+
"glassesSize":`${mii.glasses.size!==4?`On the glasses page (within the seventh tab), `:``}${mii.glasses.size<4?`press the shrink button ${4-mii.glasses.size} times.`:mii.glasses.size>4?`press the enlarge button ${mii.glasses.size-4} times.`:``}`,
|
|
2493
|
+
"stache":`On the mustache page (within the seventh tab), set the mustache to the one on the ${[0,1].includes(mii.beard.mustache.type)?`top`:[2,3].includes(mii.beard.mustache.type)?`middle`:`bottom`}-${[0,2,4].includes(mii.beard.mustache.type)?`left`:`right`}.`,
|
|
2494
|
+
"stacheY":`${mii.beard.mustache.yPosition!==10?`On the mustache page (within the seventh tab), press the `:``}${mii.beard.mustache.yPosition>10?`down button ${mii.beard.mustache.yPosition-10} times.`:mii.beard.mustache.yPosition<10?`up button ${10-mii.beard.mustache.yPosition} times.`:``}`,
|
|
2495
|
+
"stacheSize":`${mii.beard.mustache.size!==4?`On the mustache page (within the seventh tab), `:``}${mii.beard.mustache.size<4?`press the shrink button ${4-mii.beard.mustache.size} times.`:mii.beard.mustache.size>4?`press the enlarge button ${mii.beard.mustache.size-4} times.`:``}`,
|
|
2496
|
+
"mole":`${mii.mole.on?`On the mole page (within the seventh tab), turn the mole on.`:``}`,
|
|
2497
|
+
"moleX":`${mii.mole.xPosition!==2?`On the mole page (within the seventh tab), press the `:``}${mii.mole.xPosition>2?`right button ${mii.mole.xPosition-2} times.`:mii.mole.xPosition<2?`left button ${2-mii.mole.xPosition} times.`:``}`,
|
|
2498
|
+
"moleY":`${mii.mole.yPosition!==20?`On the mole page (within the seventh tab), press the `:``}${mii.mole.yPosition>20?`down button ${mii.mole.yPosition-20} times.`:mii.mole.yPosition<20?`up button ${20-mii.mole.yPosition} times.`:``}`,
|
|
2499
|
+
"moleSize":`${mii.mole.size!==4?`On the mole page (within the seventh tab), `:``}${mii.mole.size<4?`press the shrink button ${4-mii.mole.size} times.`:mii.mole.size>4?`press the enlarge button ${mii.mole.size-4} times.`:``}`,
|
|
2500
|
+
"beard":`On the beard page (within the seventh tab), set the beard to the one on the ${[0,1].includes(mii.beard.type)?`top`:[2,3].includes(mii.beard.type)?`middle`:`bottom`}-${[0,2].includes(mii.beard.type)?`left`:`right`}.`,
|
|
2501
|
+
"beardCol":`On the mustache OR beard pages (within the seventh tab), set the color to the one ${mii.beard.color+1} from the top.`,
|
|
2502
|
+
"heightWeight":`On the build page (eighth tab), set the height to ${Math.round((100/128)*mii.general.height)}%, and the weight to ${Math.round((100/128)*mii.general.weight)}%.`,
|
|
2503
|
+
"col":`On the info page (after pressing "Next"), set the Favorite Color to ${mii.general.favoriteColor} (${mii.general.favoriteColor<=5?mii.general.favoriteColor+1:mii.general.favoriteColor-5} from the left, ${mii.general.favoriteColor>5?"bottom":"top"} row).`,
|
|
2504
|
+
"other":`The Nickname of this Mii is ${mii.general.name}.${mii.general.creatorName?` The creator was ${mii.general.creatorName}.`:``} ${mii.general.birthday!==0?` Its birthday is ${["","January","February","March","April","May","June","July","August","September","October","November","December"][mii.general.birthMonth]} ${mii.general.birthday}.`:``}`
|
|
2505
|
+
};
|
|
2506
|
+
if(!full){
|
|
2507
|
+
var defaultMiiInstrs=structuredClone(mii.general.gender==="Male"?defaultInstrs["3ds"].male:defaultInstrs["3ds"].female);
|
|
2508
|
+
Object.keys(instrs).forEach(instr=>{
|
|
2509
|
+
if(instrs[instr]===defaultMiiInstrs[instr]){
|
|
2510
|
+
delete instrs[instr];
|
|
2511
|
+
}
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
return instrs;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
|
|
2519
|
+
|
|
2520
|
+
module.exports = {
|
|
2521
|
+
// Data
|
|
2522
|
+
Enums: require("./Enums"),
|
|
2523
|
+
|
|
2524
|
+
//Functions
|
|
2525
|
+
convertMii,
|
|
2526
|
+
convertMiiToStudio,
|
|
2527
|
+
|
|
2528
|
+
readWiiBin,
|
|
2529
|
+
read3DSQR,
|
|
2530
|
+
|
|
2531
|
+
renderMiiWithStudio,
|
|
2532
|
+
renderMii,
|
|
2533
|
+
|
|
2534
|
+
writeWiiBin,
|
|
2535
|
+
write3DSQR,
|
|
2536
|
+
|
|
2537
|
+
//make3DSChild, //WIP
|
|
2538
|
+
|
|
2539
|
+
generateInstructions
|
|
2239
2540
|
}
|
|
2240
|
-
module.exports=exports;
|