Digimon World 3 decomp
The European version, SLES_039.36
Loading...
Searching...
No Matches
vibration_test.c
Go to the documentation of this file.
2
4 {{1, 0}, {1, 0, 0, 0}},
5 {{1, 1}, {2, 3, 6, 7}},
6 {{1, 1}, {4, 5, 8, 9}},
7 {{1, 0}, {10, 0, 11, 0}},
8};
9
10/* The strings of the pattern, time and power windows (setString), in font
11 codes: the label, icon 7 (01 07), then control code 5 (02 05 01), which
12 inserts work buffer 1, where setNumber writes the value */
13char SHOCKTST_numberFormats[3][0x40] = {
14 "\xC3\xB1\xE8\xE3\x01\x07\x02\x05\x01",
15 "\xC7\xDE\xE8\xD2\x01\x07\x02\x05\x01",
16 "\x65\x89\x56\x01\x07\x02\x05\x01",
17};
18
19#define SCENE_TASK Task
20#define SCENE_CHILD Task
21#define SCENE_CREATE OVL_NAME(createLoader)
22#define SCENE_PRIM_BUFFERS 0x5000
23#define SCENE_OT_SHIFT 1
25#include "shared/start.inc.c"
26
27/* Colors the editor's windows: palette 3 for the one under the cursor
28 (highlight 1-5 and 10), 1 for the one being edited (0 and 6-9, 11) */
29void SHOCKTST_highlight(ShockTest *task, ShockTestWindows *win, s32 highlight) {
30 s32 i;
31
33 for (i = 0; i < 2; i++) {
34 win->times[i]->setPalette(win->times[i], PALETTE_WHITE);
35 win->powers[i]->setPalette(win->powers[i], PALETTE_WHITE);
36 }
37 win->play->setPalette(win->play, PALETTE_WHITE);
38 switch (highlight) {
39 default:
41 break;
42 case 2:
43 win->times[0]->setPalette(win->times[0], PALETTE_YELLOW);
44 break;
45 case 3:
46 win->times[1]->setPalette(win->times[1], PALETTE_YELLOW);
47 break;
48 case 4:
49 win->powers[0]->setPalette(win->powers[0], PALETTE_YELLOW);
50 break;
51 case 5:
52 win->powers[1]->setPalette(win->powers[1], PALETTE_YELLOW);
53 break;
54 case 10:
56 break;
57 case 0:
59 break;
60 case 6:
61 win->times[0]->setPalette(win->times[0], PALETTE_BLUE);
62 break;
63 case 7:
64 win->times[1]->setPalette(win->times[1], PALETTE_BLUE);
65 break;
66 case 8:
67 win->powers[0]->setPalette(win->powers[0], PALETTE_BLUE);
68 break;
69 case 9:
70 win->powers[1]->setPalette(win->powers[1], PALETTE_BLUE);
71 break;
72 case 11:
73 win->play->setPalette(win->play, PALETTE_BLUE);
74 break;
75 }
76}
77
78/* Picks the pattern with up and down: 1 on cross, -1 on triangle */
81 if (--task->pattern < 0) {
82 task->pattern = 0;
83 }
84 } else if (PAD_PRESSED(PAD_DOWN) || PAD_REPEATED(PAD_DOWN)) {
85 if (++task->pattern > task->count - 1) {
86 task->pattern = task->count - 1;
87 }
88 }
89 win->pattern->setNumber(win->pattern, 1, task->pattern);
90 SHOCKTST_showPattern(task, win, task->pattern);
92 return 1;
93 }
95 return -1;
96 }
97 return 0;
98}
99
100/* Shows a pattern's number and each motor's time and power */
102 s32 i;
103
104 win->pattern->setNumber(win->pattern, 1, pattern);
105 for (i = 0; i < 2; i++) {
106 win->powers[i]->setNumber(win->powers[i], 1, task->steps[i][pattern].power);
107 win->times[i]->setNumber(win->times[i], 1, task->steps[i][pattern].time);
108 }
109}
110
111/* Shows each motor's power and the time it has left */
113 s32 i;
114
115 for (i = 0; i < 2; i++) {
116 win->powers[i]->setNumber(win->powers[i], 1, task->steps[i][pattern].power);
117 win->times[i]->setNumber(win->times[i], 1, task->timers[i]);
118 }
119}
120
121/* Plays a pattern on both motors, one frame on: 1 once both have stopped
122 or triangle stops them */
124 s32 i;
125
126 for (i = 0; i < 2; i++) {
127 if (task->motors[i] == 0) {
128 if (task->steps[i][pattern].power != 0 && task->steps[i][pattern].time != 0) {
129 PAD.setVibration(0, i, task->steps[i][pattern].time, task->steps[i][pattern].power);
130 task->timers[i] = task->steps[i][pattern].time;
131 task->motors[i] = 1;
132 } else {
133 task->motors[i] = -1;
134 }
135 win->powers[i]->setNumber(win->powers[i], 1, task->steps[i][pattern].power);
136 win->times[i]->setNumber(win->times[i], 1, task->steps[i][pattern].time);
137 } else if (task->motors[i] == 1) {
138 if (--task->timers[i] < 0) {
139 task->timers[i] = 0;
140 task->motors[i] = -1;
141 }
142 }
143 }
144 if ((task->motors[0] == -1 && task->motors[1] == -1) ||
146 for (i = 0; i < 2; i++) {
147 PAD.setVibration(0, i, 0, 0);
148 }
149 SHOCKTST_showPattern(task, win, task->pattern);
150 return 1;
151 }
152 SHOCKTST_showTimers(task, win, task->pattern);
153 return 0;
154}
155
156/*
157 * Plays the patterns from task->playing to task->count in turn, the next one
158 * once a pattern ends or both motors stop, and returns 1 after the last. The
159 * match depends on the reset being written in both branches.
160 */
162 do {
163 SHOCKTST_showPattern(task, win, task->playing);
164 if (SHOCKTST_playPattern(task, win, task->playing) == 0) {
165 if (task->motors[0] != -1 || task->motors[1] != -1) {
166 SHOCKTST_showTimers(task, win, task->playing);
167 return 0;
168 }
169 task->timers[0] = task->timers[1] = 0;
170 task->motors[0] = task->motors[1] = 0;
171 task->playing++;
172 } else {
173 task->timers[0] = task->timers[1] = 0;
174 task->motors[0] = task->motors[1] = 0;
175 task->playing++;
176 }
177 } while (task->playing < task->count);
178 SHOCKTST_showPattern(task, win, task->pattern);
179 return 1;
180}
181
182/* Moves the editor's cursor over its rows and columns, skipping the empty
183 ones: 1 when cross picks a value, -1 when it picks the play row, 2 on circle */
186 do {
187 if (--task->column < 0) {
188 task->column = 1;
189 }
190 } while (SHOCKTST_menuRows[task->row].enabled[task->column] == 0);
192 do {
193 if (++task->column >= 2) {
194 task->column = 0;
195 }
196 } while (SHOCKTST_menuRows[task->row].enabled[task->column] == 0);
197 }
199 do {
200 if (--task->row < 0) {
201 task->row = 3;
202 }
203 } while (SHOCKTST_menuRows[task->row].enabled[task->column] == 0);
204 } else if (PAD_PRESSED(PAD_DOWN) || PAD_REPEATED(PAD_DOWN)) {
205 do {
206 if (++task->row >= 4) {
207 task->row = 0;
208 }
209 } while (SHOCKTST_menuRows[task->row].enabled[task->column] == 0);
210 }
211 if (PAD_PRESSED(PAD_CROSS)) {
212 SHOCKTST_highlight(task, win, SHOCKTST_menuRows[task->row].highlight[task->column + 2]);
213 if (task->row == 3) {
214 return -1;
215 }
216 return 1;
217 }
218 if (PAD_PRESSED(PAD_CIRCLE)) {
219 return 2;
220 }
221 SHOCKTST_highlight(task, win, SHOCKTST_menuRows[task->row].highlight[task->column]);
222 return 0;
223}
224
225/* Changes a time or power with up and down (by 10 when repeating), or flips it
226 between 0 and 1 when toggle is set: 1 on cross, -1 on triangle */
227s32 SHOCKTST_editValue(ShockTest *task, ShockTestWindows *win, TextWindow **windows, u8 *value, u8 toggle) {
228 if (toggle) {
230 *value = 1 - *value;
231 }
232 } else if (PAD_PRESSED(PAD_UP)) {
233 *value += 1;
234 } else if (PAD_REPEATED(PAD_UP)) {
235 *value += 10;
236 } else if (PAD_PRESSED(PAD_DOWN)) {
237 *value -= 1;
238 } else if (PAD_REPEATED(PAD_DOWN)) {
239 *value -= 10;
240 }
241 SHOCKTST_showPattern(task, win, task->pattern);
242 if (PAD_PRESSED(PAD_CROSS)) {
243 return 1;
244 }
246 return -1;
247 }
248 return 0;
249}
250
251/* Edits what the cursor picked: the pattern, or a motor's time or power (the
252 small motor's is only on or off); 1 once done */
254 switch (task->row) {
255 case 0:
256 default:
257 if (SHOCKTST_selectPattern(task, win) != 0) {
258 return 1;
259 }
260 break;
261 case 1:
262 task->step = task->column;
263 if (SHOCKTST_editValue(task, win, win->times, &task->steps[task->step][task->pattern].time, 0) != 0) {
264 return 1;
265 }
266 break;
267 case 2:
268 task->step = task->column;
269 if (task->step != 0) {
270 if (SHOCKTST_editValue(task, win, win->times, &task->steps[task->step][task->pattern].power, 0) != 0) {
271 return 1;
272 }
273 } else if (SHOCKTST_editValue(task, win, win->times, &task->steps[0][task->pattern].power, 1) != 0) {
274 return 1;
275 }
276 break;
277 }
278 return 0;
279}
280
281/* The names of the motors: "こうそく" (fast) and "ていそく" (slow) */
283 "\x82\xB1\x82\xA4\x82\xBB\x82\xAD",
284 "\x82\xC4\x82\xA2\x82\xBB\x82\xAD",
285};
286
287/* The editor's task: creates its windows, then edits and plays the patterns
288 (play with L1 held plays them all, circle checks the memory card); when
289 killed, frees them and stops the motors */
291 s32 i;
292 s32 motor;
293
294 switch (task->state) {
295 case TASK_INIT:
296 default:
297 task->nextState(task);
298 task->windowId = 0x1000;
299 win->pattern = createTextWindow(task->windowId, 1, 0x28, 0x3C);
302 win->pattern->setNumber(win->pattern, 1, task->pattern);
303 for (i = 0; i < 2; i++) {
304 win->motors[i] = createTextWindow(task->windowId, 1, i * 100 + 0x3C, 0x50);
305 win->motors[i]->setText(win->motors[i], SHOCKTST_motorNames[i]);
306 win->times[i] = createTextWindow(task->windowId, 1, i * 100 + 0x3C, 0x64);
307 win->times[i]->setString(win->times[i], SHOCKTST_numberFormats[1], -1);
308 win->times[i]->setNumber(win->times[i], 1, task->steps[i][0].time);
309 win->powers[i] = createTextWindow(task->windowId, 1, i * 100 + 0x3C, 0x78);
310 win->powers[i]->setString(win->powers[i], SHOCKTST_numberFormats[2], -1);
311 win->powers[i]->setNumber(win->powers[i], 1, task->steps[i][0].power);
312 }
313 win->play = createTextWindow(task->windowId, 1, 0x28, 0x8C);
314 win->play->setText(win->play, "\x83\x70\x83\x5E\x81\x5B\x83\x93\x82\xB6\x82\xC1\x82\xB1\x82\xA4"); /* "パターンじっこう" */
315 break;
316 case TASK_RUN:
317 switch (task->substate) {
318 default:
319 task->setSubstate(task, 0);
320 /* fallthrough */
321 case 0:
322 switch (SHOCKTST_moveCursor(task, win)) {
323 case 2:
324 task->setSubstate(task, 4);
325 break;
326 case 1:
327 task->nextSubstate(task);
328 break;
329 case -1:
330 if (PAD_HELD(PAD_L1)) {
331 task->setSubstate(task, 2);
332 } else {
333 task->setSubstate(task, 3);
334 }
335 task->motors[0] = task->motors[1] = task->timers[0] = task->timers[1] = task->playing = 0;
336 break;
337 }
338 break;
339 case 1:
340 if (SHOCKTST_editRow(task, win) != 0) {
341 task->setSubstate(task, 0);
342 }
343 break;
344 case 2:
345 if (SHOCKTST_playAllPatterns(task, win) != 0) {
346 task->setSubstate(task, 0);
347 }
348 break;
349 case 3:
350 if (SHOCKTST_playPattern(task, win, task->pattern) != 0) {
351 task->setSubstate(task, 0);
352 }
353 break;
354 case 4:
355 if (MEMCARD_FUNCS.check(0) != 0) {
356 task->setSubstate(task, 0);
357 }
358 break;
359 }
360 break;
361 case TASK_DONE:
362 break;
363 case TASK_KILL:
364 HEAP.free(task->steps[0]);
365 HEAP.free(task->steps[1]);
366 for (motor = 0; motor < 2; motor++) {
367 PAD.setVibration(0, motor, 0, 0);
368 }
369 break;
370 }
371}
372
373/* Copies the pattern file's times and powers into the editor */
375 s32 i;
376 /* the offsets count bytes from the file's start */
377 u8 *times = (u8 *)file + file->timesOffset;
378 u8 *powers = (u8 *)file + file->powersOffset;
379
380 for (i = 0; i < task->count; i++) {
381 task->steps[0][i].time = times[0];
382 task->steps[1][i].time = times[1];
383 times += 2;
384 task->steps[0][i].power = powers[0];
385 task->steps[1][i].power = powers[1];
386 powers += 2;
387 }
388}
389
390/* Creates the editor, with room for count patterns */
393
394 task->count = count;
395 task->steps[0] = HEAP.allocZeroed(count * sizeof(ShockStep), 2);
396 task->steps[1] = HEAP.allocZeroed(task->count * sizeof(ShockStep), 2);
397 return task;
398}
399
400char *SHOCKTST_textPath = "sim:C:\\DEVELOP\\DLSKDATA.TXT";
401
402/* Turns DLSKDATA.TXT (the count, then a tab-separated row per pattern, of
403 which type 1 holds the motors' times and powers) into the pattern file, and
404 writes it to the PC as DLSKDATA.BIN */
406 u8 *s = task->text;
407 /* the header is written a word at a time, through this pointer */
408 s32 *header = (s32 *)task->file;
409 s32 count;
410 s32 *types;
411 u8 *times;
412 u8 *powers;
413 s32 type;
414 u8 values[4];
415 s32 i;
416 s32 n;
417 s32 fd;
418 s32 k;
419 u8 *t;
420 u8 *p;
421 u8 *nt;
422 u8 *np;
423
424 count = atoi(s);
425 while (*s != '\n') {
426 s++;
427 }
428 *header++ = count;
429 *header++ = sizeof(ShockFile);
430 *header = header[-1] + count * 4;
431 header++;
432 *header = header[-1] + count * 2;
433 s++;
434 /* the offsets count bytes from the file's start. The match depends on
435 times holding the file's start until t and p are copied from it, and
436 on the branch stepping p before t */
437 types = (s32 *)task->file;
438 times = (u8 *)types;
439 types = (s32 *)((u8 *)types + ((ShockFile *)types)->typesOffset);
440 p = t = times;
441 times = t += ((ShockFile *)t)->timesOffset;
442 powers = p += ((ShockFile *)p)->powersOffset;
443 k = 1;
444 while (*s != '/') {
445 s += strcspn(s, "\t");
446 while (*s == '\t') {
447 s++;
448 }
449 s += strcspn(s, "\t");
450 while (*s == '\t') {
451 s++;
452 }
453 n = strcspn(s, "\t");
454 type = atoi(s);
455 s += n;
456 while (*s == '\t') {
457 s++;
458 }
459 if (type == 1) {
460 for (i = 0; i < 4; i++) {
461 n = strcspn(s, "\t\n");
462 values[i] = atoi(s);
463 s += n;
464 while (*s == '\t' || *s == '\n') {
465 s++;
466 }
467 }
468 nt = &times[k * 2];
469 np = &powers[k * 2];
470 *types++ = type;
471 t[0] = values[0];
472 nt[-1] = values[2];
473 p[0] = values[1];
474 np[-1] = values[3];
475 k++;
476 p = np;
477 t = nt;
478 } else {
479 n = strcspn(s, "\n");
480 s += n;
481 while (*s == '\n') {
482 s++;
483 }
484 }
485 }
486 fd = open("sim:C:\\DEVELOP\\DLSKDATA.BIN", 0x200);
487 if (fd != -1) {
488 write(fd, task->file, count * 8 + sizeof(ShockFile));
489 close(fd);
490 }
491}
492
493/* The loader's task: creates the title and help windows, reads DLSKDATA.TXT
494 from the PC and starts the editor on it; START goes back to the stage
495 select (MODE_STAGE_SELECT) */
497 s32 fd;
498
499 switch (task->state) {
500 case TASK_INIT:
501 default:
502 task->nextState(task);
503 win->title = createTextWindow(SCREEN_LAYER, 0, 0x14, 0x1E);
504 win->title->setText(win->title, "\x82\xB5\x82\xF1\x82\xC7\x82\xA4\x83\x65\x83\x58\x83\x67"); /* "しんどうテスト" */
505 win->help[0] = createTextWindow(SCREEN_LAYER, 1, 0xDC, 0xB4);
506 win->help[0]->setText(win->help[0], "\x81\x7E\x81\x46\x82\xB6\x82\xC1\x82\xB1\x82\xA4\x82\xC4\x82\xA2\x82\xB5"); /* "×:じっこうていし" */
507 win->help[1] = createTextWindow(SCREEN_LAYER, 1, 0xDC, 0xC8);
508 win->help[1]->setText(win->help[1], SHOCKTST_STR_START_BACK);
509 task->text = HEAP.allocZeroed(0x4000, 2);
510 task->file = HEAP.allocZeroed(0x4000, 2);
511 if (task->text == NULL || task->file == NULL) {
512 task->setState(task, TASK_KILL);
513 break;
514 }
515 fd = open(SHOCKTST_textPath, 1);
516 if (fd == -1) {
517 task->setState(task, TASK_KILL);
518 break;
519 }
520 read(fd, task->text, 0x4000);
521 close(fd);
523 if (task->file != NULL) {
524 win->test = SHOCKTST_createEditor(task->file->count);
525 SHOCKTST_loadPatterns(win->test, task->file);
526 } else {
527 win->test = SHOCKTST_createEditor(10);
528 }
529 break;
530 case TASK_RUN:
531 if (PAD_PRESSED(PAD_START)) {
532 task->setState(task, TASK_KILL);
533 }
534 break;
535 case TASK_DONE:
536 break;
537 case TASK_KILL:
538 if (task->file != NULL) {
539 HEAP.free(task->file);
540 }
541 if (task->text != NULL) {
542 HEAP.free(task->text);
543 }
545 break;
546 }
547}
548
549/* Creates the loader */
553
554/* "START:もどる" (START: back), padded to a word: the USA file's
555 padding isn't zeros but what the assembler left there; the size leaves
556 out the closing NUL */
558#if VERSION_US
559 "\x82\x72\x82\x73\x82\x60\x82\x71\x82\x73\x81\x46\x82\xE0\x82\xC7\x82\xE9\0\x03";
560#elif VERSION_EU || VERSION_JP
561 "\x82\x72\x82\x73\x82\x60\x82\x71\x82\x73\x81\x46\x82\xE0\x82\xC7\x82\xE9\0\0";
562#endif
#define NULL
Definition common.h:17
signed int s32
Definition common.h:11
unsigned char u8
Definition common.h:8
GameState GAME
The save data, the game mode and the methods.
Definition state.c:64
#define TASK_RUN
Definition task.h:35
#define TASK_KILL
Definition task.h:37
#define TASK_INIT
Tasks: every game object is a task, a heap block that starts with this header and is updated once per...
Definition task.h:34
#define TASK_DONE
Definition task.h:36
FileCache FILE_CACHE
The file cache.
Definition file_cache.c:7
int strcspn(u8 *s, char *reject)
long read(long fd, void *buf, long n)
long write(long fd, void *buf, long n)
int atoi(u8 *s)
stdlib.h's; SHOCKTST parses its text file with these two
long close(long fd)
long open(char *name, unsigned long mode)
The kernel's file functions (libapi.h); the sim: device is the PC's.
#define MODE_STAGE_SELECT
STAGSLCT, the debug stage select.
Definition game_state.h:454
#define SCREEN_LAYER
The layer over the whole screen that most modes create first and draw their menus on (FIELDSTG and ST...
Definition gfx.h:45
Heap HEAP
The functions that return what a call left in v0 (allocMemHigh, findTask) and the ones that take othe...
Definition heap.c:184
MemCardFuncs MEMCARD_FUNCS
Definition memcard.c:468
PadState PAD
Controller input: cleared by initPad, then the methods.
Definition pad.c:168
#define PAD_CROSS
Definition pad.h:31
#define PAD_START
Definition pad.h:21
#define PAD_CIRCLE
Definition pad.h:30
#define PAD_DOWN
Definition pad.h:24
#define PAD_RIGHT
Definition pad.h:23
#define PAD_TRIANGLE
Definition pad.h:32
#define PAD_PRESSED(button)
One button of pad 1: newly pressed, auto-repeated while held, or held.
Definition pad.h:140
#define PAD_UP
Definition pad.h:22
#define PAD_L1
Definition pad.h:28
#define PAD_LEFT
Definition pad.h:25
#define PAD_HELD(button)
Definition pad.h:142
#define PAD_REPEATED(button)
Definition pad.h:141
void *(* load)(u32 file)
Definition file.h:92
void(* requestMode)(s32 mode, s32 arg)
Definition game_state.h:21
GameFuncs funcs
Definition game_state.h:582
void *(* allocZeroed)(s32 size, s32 tag)
Definition heap.h:31
void(* free)(void *ptr)
Definition heap.h:27
s32(* check)(s32 port)
Definition memcard.h:114
s32(* setVibration)(u16 port, s32 motor, s16 time, u8 value)
Definition pad.h:123
DLSKDATA.BIN: a header, then the offsets are from its start.
s32 count
number of patterns
s32 powersOffset
u8 per motor and pattern
s32 timesOffset
u8 per motor and pattern
TextWindow * help[2]
struct ShockTest * test
The patterns loader: the scene's first task.
ShockFile * file
DLSKDATA.BIN being built.
void(* setState)(struct ShockLoader *task, s32 state)
void(* nextState)(struct ShockLoader *task)
u8 * text
DLSKDATA.TXT.
One step of a motor's pattern.
u8 power
the small motor is only on (1) or off (0)
u8 time
frames
One row of the editor's menu.
s32 highlight[4]
per column: selected, then being edited
s32 enabled[2]
per column
The editor's text windows.
TextWindow * times[2]
TextWindow * powers[2]
TextWindow * motors[2]
TextWindow * play
TextWindow * pattern
The pattern editor.
s32 playing
the pattern being played by "play all"
u8 * file
SHOCKTST_FILE, never read.
s32 row
pattern, time, power, play
s32 timers[2]
s32 motors[2]
0: start, 1: vibrating, -1: done
s32 column
the motor
ShockStep * steps[2]
void(* nextState)(struct ShockTest *task)
void(* setSubstate)(struct ShockTest *task, s32 substate)
void(* nextSubstate)(struct ShockTest *task)
Any task, seen through its header.
Definition task.h:62
A text window (createTextWindow): up to six text buffers (0 is shown, 1-5 are "work" buffers that con...
Definition text.h:131
void(* setPalette)(struct TextWindow *obj, u8 arg)
Definition text.h:174
void(* setNumber)()
Definition text.h:166
void(* setText)()
Definition text.h:164
void(* setString)()
Definition text.h:165
void * createTask(void(*update)(), s32 size, s32 childrenSize)
createTaskWithId for a task nothing needs to find
Definition task.c:105
#define PALETTE_BLUE
a light blue: what is highlighted or current
Definition text.h:113
#define PALETTE_WHITE
The text windows' palettes (TextWindow.palette, setPalette): rows of the font's CLUTs,...
Definition text.h:112
#define PALETTE_YELLOW
Definition text.h:115
TextWindow * createTextWindow(s16 layerId, s16 style, s16 x, s16 y)
A text window on a layer, in a font style, at (x, y)
void SHOCKTST_loadPatterns(ShockTest *task, ShockFile *file)
Copies the pattern file's times and powers into the editor.
const char SHOCKTST_STR_START_BACK[20]
"START:もどる" (START: back), padded to a word: the USA file's padding isn't zeros but what the assemble...
s32 SHOCKTST_editValue(ShockTest *task, ShockTestWindows *win, TextWindow **windows, u8 *value, u8 toggle)
Changes a time or power with up and down (by 10 when repeating), or flips it between 0 and 1 when tog...
void SHOCKTST_convertText(ShockLoader *task)
Turns DLSKDATA.TXT (the count, then a tab-separated row per pattern, of which type 1 holds the motors...
char * SHOCKTST_textPath
char * SHOCKTST_motorNames[2]
The names of the motors: "こうそく" (fast) and "ていそく" (slow)
void SHOCKTST_showPattern(ShockTest *task, ShockTestWindows *win, s32 pattern)
Shows a pattern's number and each motor's time and power.
Task * SHOCKTST_createLoader(void)
Creates the loader.
s32 SHOCKTST_moveCursor(ShockTest *task, ShockTestWindows *win)
Moves the editor's cursor over its rows and columns, skipping the empty ones: 1 when cross picks a va...
void SHOCKTST_updateLoader(ShockLoader *task, ShockLoaderWindows *win)
The loader's task: creates the title and help windows, reads DLSKDATA.TXT from the PC and starts the ...
s32 SHOCKTST_editRow(ShockTest *task, ShockTestWindows *win)
Edits what the cursor picked: the pattern, or a motor's time or power (the small motor's is only on o...
s32 SHOCKTST_playPattern(ShockTest *task, ShockTestWindows *win, s32 pattern)
Plays a pattern on both motors, one frame on: 1 once both have stopped or triangle stops them.
void SHOCKTST_showTimers(ShockTest *task, ShockTestWindows *win, s32 pattern)
Shows each motor's power and the time it has left.
ShockTest * SHOCKTST_createEditor(s32 count)
Creates the editor, with room for count patterns.
char SHOCKTST_numberFormats[3][0x40]
The strings of the pattern, time and power windows (setString), in font codes: the label,...
void SHOCKTST_updateEditor(ShockTest *task, ShockTestWindows *win)
The editor's task: creates its windows, then edits and plays the patterns (play with L1 held plays th...
s32 SHOCKTST_selectPattern(ShockTest *task, ShockTestWindows *win)
Picks the pattern with up and down: 1 on cross, -1 on triangle.
s32 SHOCKTST_playAllPatterns(ShockTest *task, ShockTestWindows *win)
Plays the patterns from task->playing to task->count in turn, the next one once a pattern ends or bot...
ShockTestRow SHOCKTST_menuRows[4]
void SHOCKTST_highlight(ShockTest *task, ShockTestWindows *win, s32 highlight)
Colors the editor's windows: palette 3 for the one under the cursor (highlight 1-5 and 10),...
SHOCKTST.PRO: the debug vibration test.
#define SHOCKTST_FILE
A file the editor loads when it starts and never reads (ShockTest.file); the discs number their files...