1 /*---------------------------------------------------------------------------*
2 Project: CARD icon viewer
3 File: listdemo.c
4
5 Copyright 2000-2001 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: listdemo.c,v $
14 Revision 1.2 02/20/2006 04:13:08 mitu
15 changed include path from dolphin/ to revolution/.
16
17 Revision 1.1 01/31/2006 10:48:30 mitu
18 (none)
19
20
21 23 11/21/01 21:41 Shiki
22 Removed obsolete OS function calls
23
24 22 8/23/01 14:21 Shiki
25 Modified to use OSResetSystem for restart.
26
27 21 7/13/01 12:01:00 Shiki
28 Implemented more friendly free space check routines.
29
30 20 7/12/01 21:24:00 Shiki
31 Added support for Japanese menu.
32
33 19 01/06/25 14:38 Shiki
34 Modified ProbeAnimTick() using CARDProbeEx().
35
36 18 01/06/22 11:05 Shiki
37 Removed redundant VIWaitForRetrace().
38
39 17 01/06/19 13:49 Shiki
40 Minor fix.
41
42 16 5/18/01 5:30p Shiki
43 Modified to show progress bar.
44
45 15 5/17/01 8:22p Shiki
46 Revised using new OSResetSystem function.
47
48 14 5/11/01 5:05p Shiki
49 Revised using new DEMO API interface.
50
51 13 01/04/26 10:38 Shiki
52 Set banner background color to black.
53
54 12 01/04/25 14:57 Shiki
55 Merged US console font size setting.
56
57 11 01/04/25 14:35 Shiki
58 Revised using new DEMO API.
59
60 10 01/04/25 11:40 Shiki
61 Modified to load disk banner file.
62
63 9 01/04/23 17:26 Shiki
64 Revised using cardutil.c
65
66 8 01/04/10 16:50 Shiki
67 Added support for icon animation speed.
68
69 7 01/03/06 17:19:00 Shiki
70 Modified InitCont() to support controller recalibration.
71
72 6 01/02/22 13:10 Shiki
73 Added support for multiple sector sizes.
74
75 5 01/01/23 9:35 Shiki
76 Fixed typo.
77
78 4 12/12/00 12:39a Shiki
79 Bug fix.
80
81 3 12/11/00 11:13p Shiki
82 Revised to display icons.
83
84 3 8/10/00 4:39p Shiki
85 Modified CARDStat.length from u8 to u32.
86
87 2 8/08/00 5:23p Shiki
88 Improved the output format.
89
90 1 7/14/00 4:16p Shiki
91 Initial check-in.
92 $NoKeywords: $
93 *---------------------------------------------------------------------------*/
94
95 #include <stdarg.h>
96 #include <string.h>
97 #include <demo.h>
98 #include <revolution.h>
99 #include <revolution/dvd/DVDBanner.h>
100 #include <revolution/os/OSReset.h>
101 #include "cont.h"
102 #include "cardutil.h"
103
104 GXColor Black = { 0, 0, 0, 0 };
105 GXColor Blue = { 0, 0, 192, 0 };
106 GXColor Red = { 255, 0, 0, 0 };
107 GXColor Green = { 0, 224, 0, 0 };
108 GXColor White = { 255, 255, 255, 0 };
109
110 enum
111 {
112 STR_Null,
113 STR_Cancel,
114 STR_Select,
115 STR_Confirm,
116 STR_Finish,
117 STR_Yes,
118 STR_No,
119 STR_Save,
120 STR_Erase,
121
122 STR_Ignore,
123 STR_Menu,
124
125 STR_Mounting,
126
127 STR_Saving,
128 STR_Saved,
129 STR_NotSaved,
130 STR_MayNotSaved,
131
132 STR_Erasing,
133 STR_Erased,
134 STR_MayNotErased,
135
136 STR_Formatting,
137 STR_Formatted,
138 STR_MayNotFormatted,
139
140 STR_Format,
141
142 STR_InsSpace,
143
144 STR_MemoryCard,
145 STR_NotMemoryCard,
146 STR_Nothing,
147 STR_Broken,
148 STR_Open,
149 STR_Stat,
150 STR_End
151 };
152
153 char* StringResource[2][STR_End] =
154 {
155 // US English version
156 {
157 NULL,
158 "Cancel",
159 "Select",
160 "Confirm",
161 "Finish",
162 "Yes",
163 "No",
164 "Save",
165 "Erase",
166
167 "Continue",
168 "Go to GameCube main menu",
169
170 "Loading...",
171
172 "Saving...",
173 "The data was saved.",
174 "The data has not been saved.",
175 "The data may not have been saved.",
176
177 "Erasing...",
178 "The data was erased.",
179 "The data may not have been erased.",
180
181 "Formatting...",
182 "The Memory Card was formatted.",
183 "The Memory Card may not have been formatted.",
184
185 "The Memory Card must be formatted. \n"
186 "If the Memory Card is formatted, all saved \n"
187 "data will be erased. \n"
188 "Format it now?",
189
190 "The Memory Card has no space available or \n"
191 "it has too many files saved to it to play \n"
192 "the game. Game data cannot be saved.",
193
194 "Inserted (%dMbits, %dK sector)",
195 "Inserted (not memory card)",
196 "Nothing is inserted",
197 "The object inserted cannot be used.",
198 "<Open>",
199 "%d blocks free. %d files free.",
200 },
201
202 // Japanese version
203 {
204 NULL,
205 "�߂�",
206 "�I��",
207 "����",
208 "�I��",
209 "�͂�",
210 "������",
211 "�ۑ�",
212 "����",
213
214 "�ۑ����Ȃ��Ői�߂�",
215 "�Q�[���L���[�u ���C�����j���[��",
216
217 "�ǂݍ��ݒ��ł��B",
218
219 "�ۑ����ł��B",
220 "�ۑ����܂����B",
221 "�ۑ��ł��܂���ł����B",
222 "�ۑ��Ɏ��s�����\��������܂��B",
223
224 "�������ł��B",
225 "�������܂����B",
226 "�����Ɏ��s�����\��������܂��B",
227
228 "���������ł��B",
229 "���������܂����B",
230 "�������Ɏ��s�����\��������܂��B",
231
232 "�������[�J�[�h�͏��������K�v�ł��B\n"
233 "����������ƃ������[�J�[�h���̑S�t�@�C����\n"
234 "�����܂��B\n"
235 "���������܂����H",
236
237 "�������[�J�[�h�ɃQ�[���ɕK�v�ȋe�ʂ��Ȃ����A\n"
238 "�t�@�C�����̐������Ă��܂��܂��B\n"
239 "���̂܂n�߂�ƁA�ۑ����邱�Ƃ��ł��܂���B",
240
241 "�������[�J�[�h (%dMbits, %dKB �Z�N�^�[)",
242 "�X���b�g�ɂ������Ă�����͎̂g���܂���B",
243 "�����������Ă��܂���B",
244 "�X���b�g�ɂ������Ă�����͎̂g���܂���B",
245 "<��>",
246 "�e�� %d �u���b�N�B�t�@�C���� %d�B",
247 },
248 };
249
250 #define GetString(str) (StringResource[OSGetFontEncode()][str])
251
252 //
253 // Define save data size of the game in bytes
254 //
255 #define FILE_SIZE (32 * 1024)
256
257 typedef struct Interface
258 {
259 void (*DrawTick)(void);
260 void (*AnimTick)(void);
261 } Interface;
262
263 enum
264 {
265 STATE_PROBE = 0, // State
266 STATE_LIST,
267
268 SUBSTATE_SELECT = 0, // SubState
269 SUBSTATE_COMMAND,
270 SUBSTATE_VERIFY,
271 SUBSTATE_BUSY,
272 SUBSTATE_WAIT,
273
274 YES = 0,
275 NO,
276
277 CARDUTIL_CMD_CHECKSPACE = 0x1000,
278 CARDUTIL_CMD_IGNORE,
279 CARDUTIL_CMD_MAIN_MENU,
280 CARDUTIL_CMD_ERROR
281 };
282
283 #define LIST_ROW 8 // # of rows in the list screen
284
285 // Work area for card threads and card API
286 static u8 CardStack[8192] ATTRIBUTE_ALIGN(32);
287 static u8 CardWorkArea[CARD_WORKAREA_SIZE] ATTRIBUTE_ALIGN(32);
288
289 // Save data template
290 static DVDBanner* Banner;
291 static CARDStat CardStatTemplate; // CARDStat for save file
292 static void* CardData; // Pointer to file save data
293 static TPLPalettePtr TplBanner; // Card banner texture image
294 static TPLPalettePtr TplIcons; // Card icon texture image
295
296 // Program state
297 static int Slot = 0; // Current memory card slot
298 static int State = STATE_PROBE; // Current program state
299 static int SubState; // Current program substate
300 static s32 Command; // Current command
301 static OSTime BeginWaitAt; // Start time of the SUBSTATE_WAIT substate
302 static int YesNo; // 0: Yes, No: 1
303
304 // Directory
305 static CardUtilDirent Directory[CARD_MAX_FILE] ATTRIBUTE_ALIGN(32);
306 static BOOL List; // TRUE if Directory is valid
307 static int Offset; // The first line number in the directory on screen
308 static int Current; // The currently selected entry number
309 static s32 NumEntries; // # of entries in Directory
310
311 static void ProbeDrawTick(void);
312 static void ProbeAnimTick(void);
313 static void ListDrawTick(void);
314 static void ListAnimTick(void);
315
316 static Interface InterfaceTable[] =
317 {
318 ProbeDrawTick, ProbeAnimTick,
319 ListDrawTick, ListAnimTick,
320 };
321
322 static BOOL ForceMenu; // TRUE if goes back to GameCube IPL main menu
323
324 OSFontHeader* FontData; // Pointer to ROM font data
325
326 /*---------------------------------------------------------------------------*
327 Name: DrawRectangle
328
329 Description: Draws rectangle
330 *---------------------------------------------------------------------------*/
DrawRectangle(int x,int y,int cx,int cy,GXColor color)331 static void DrawRectangle(int x, int y, int cx, int cy, GXColor color)
332 {
333 // Set rendering mode
334 GXSetNumChans(1); // # of color channels
335 GXSetChanCtrl(GX_COLOR0,
336 GX_FALSE, // passed through
337 GX_SRC_REG, // amb source
338 GX_SRC_REG, // mat source
339 GX_LIGHT_NULL, // light mask
340 GX_DF_NONE, // diffuse function
341 GX_AF_NONE ); // atten function
342 GXSetChanMatColor(GX_COLOR0, color);
343
344 GXSetNumTexGens(0); // # of Tex gens
345 GXSetNumTevStages(1); // # of Tev Stage
346 GXSetTevOrder(GX_TEVSTAGE0,
347 GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
348 GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
349
350 // Draw rectangle
351 GXClearVtxDesc();
352 GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
353 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0);
354 GXBegin(GX_QUADS, GX_VTXFMT0, 4);
355 GXPosition3s16((s16) (x), (s16) (y), 0);
356 GXPosition3s16((s16) (x + cx), (s16) (y), 0);
357 GXPosition3s16((s16) (x + cx), (s16) (y + cy), 0);
358 GXPosition3s16((s16) (x), (s16) (y + cy), 0);
359 GXEnd( );
360
361 // Restore rendering mode as same as DEMOInitCaption()
362 GXSetNumChans(0);
363 GXSetNumTexGens(0); // # of Tex gens
364 GXSetNumTevStages(1);
365 GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
366 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
367 }
368
369 /*---------------------------------------------------------------------------*
370 Name: DrawMenu
371
372 Description: ex. DrawMenu(x, y, color, current, item0, item1, NULL);
373
374 item must be a character string
375 *---------------------------------------------------------------------------*/
DrawMenu(int x,int y,GXColor color,int current,...)376 static int DrawMenu(int x, int y, GXColor color, int current, ...)
377 {
378 va_list ap;
379 char* item;
380 int cx;
381 s32 width;
382 int i;
383 s16 size;
384 s16 space;
385
386 cx = 0;
387 va_start(ap, current);
388 while ((item = va_arg(ap, char*)) != NULL)
389 {
390 width = DEMOGetRFTextWidth(item);
391 if (cx < width)
392 {
393 cx = width;
394 }
395 }
396 va_end(ap);
397
398 i = 0;
399 DEMOGetROMFontSize(&size, &space);
400 y += FontData->leading * size / FontData->cellWidth;
401 va_start(ap, current);
402 while ((item = va_arg(ap, char*)) != NULL)
403 {
404 DEMOSetFontType(DM_FT_OPQ);
405 DrawRectangle(x, y - FontData->ascent * size / FontData->cellWidth, cx, FontData->leading * size / FontData->cellWidth,
406 (i++ == current) ? color : Black);
407 DEMOSetFontType(DM_FT_XLU);
408 DEMORFPrintf((s16) x, (s16) y, 0, item);
409 y += DEMOGetRFTextHeight(item);
410 }
411 va_end(ap);
412
413 return cx;
414 }
415
416 /*---------------------------------------------------------------------------*
417 Name: DrawMessage
418
419 Description: Draws message
420 *---------------------------------------------------------------------------*/
DrawMessage(int x,int y,GXColor color,char * message)421 static int DrawMessage(int x, int y, GXColor color, char* message)
422 {
423 int cy;
424 int cx;
425 s16 size;
426 s16 space;
427
428 cx = DEMOGetRFTextWidth(message);
429 cy = DEMOGetRFTextHeight(message);
430
431 DEMOSetFontType(DM_FT_OPQ);
432 DrawRectangle(x, y, cx, cy, color);
433
434 DEMOGetROMFontSize(&size, &space);
435 y += FontData->leading * size / FontData->cellWidth;
436 DEMOSetFontType(DM_FT_XLU);
437 DEMORFPrintf((s16) x, (s16) y, 0, message);
438
439 return cx;
440 }
441
442 /*---------------------------------------------------------------------------*
443 Name: DrawUsage
444
445 Description: Draws usages of buttons
446 *---------------------------------------------------------------------------*/
DrawUsage(int slot,char * commandA,char * commandB,char * message)447 static int DrawUsage(int slot, char* commandA, char* commandB, char* message)
448 {
449 int width;
450
451 width = DEMORFPrintf(16, 45, 0, "SLOT-%c: ", "AB"[slot]);
452 if (commandB)
453 {
454 width += DEMORFPrintf((s16) (16 + width), 45, 0, "<B> %s ", commandB);
455 }
456 if (commandA)
457 {
458 width += DEMORFPrintf((s16) (16 + width), 45, 0, "<A> %s ", commandA);
459 }
460 if (message)
461 {
462 width += DEMORFPrintf((s16) (16 + width), 45, 0, message);
463 }
464 return width;
465 }
466
467 /*---------------------------------------------------------------------------*
468 Name: GetBlockSize
469
470 Description: Returns the number of required blocks to save the specified
471 size of data in the current memory card.
472 *---------------------------------------------------------------------------*/
GetBlockSize(s32 size)473 static s32 GetBlockSize(s32 size)
474 {
475 return (size + CardUtilSectorSize() - 1) / CardUtilSectorSize();
476 }
477
478 /*---------------------------------------------------------------------------*
479 Name: IsSpaceAvailable
480
481 Description: Checks if a file of the specified size can be created in
482 the current memory card.
483
484 Note: This function is for reliable file save. It requires the
485 same number of temporary free blocks as the number of saved
486 file will consume as well as one free file directory entry.
487
488 Arguments: size file size in bytes
489
490 Returns: TRUE is space is available. Otherwise FALSE.
491 *---------------------------------------------------------------------------*/
IsSpaceAvailable(s32 size)492 static BOOL IsSpaceAvailable(s32 size)
493 {
494 s32 numFiles;
495 s32 numBlocks;
496
497 numFiles = CardUtilNumFiles();
498 numBlocks = GetBlockSize(size);
499 if (CardUtilFilesNotUsed() == 0 ||
500 numFiles == 0 && CardUtilBlocksNotUsed() < 2 * numBlocks ||
501 0 < numFiles && CardUtilBlocksNotUsed() < numBlocks)
502 {
503 return FALSE;
504 }
505 else
506 {
507 return TRUE;
508 }
509 }
510
511 /*---------------------------------------------------------------------------*
512 Name: ProbeDrawTick
513
514 Description: Draw memory card slot selection screen
515 *---------------------------------------------------------------------------*/
ProbeDrawTick(void)516 static void ProbeDrawTick(void)
517 {
518 GXRenderModeObj* rmp;
519 s32 chan;
520
521 rmp = DEMOGetRenderModeObj();
522 DEMOInitCaption(DM_FT_XLU, (s16) rmp->fbWidth, (s16) rmp->efbHeight);
523
524 DEMOSetFontType(DM_FT_RVS);
525 DrawUsage(Slot, GetString(STR_Select), GetString(STR_Null), NULL);
526
527 for (chan = 0; chan < 2; ++chan)
528 {
529 s32 memSize;
530 s32 sectorSize;
531 int width;
532
533 DEMOSetFontType((Slot == chan) ? DM_FT_RVS : DM_FT_XLU);
534 width = DEMORFPrintf(16, (s16) ((chan == 0) ? 75 : 105), 0, " SLOT-%c: ", "AB"[chan]);
535 switch (CARDProbeEx(chan, &memSize, §orSize))
536 {
537 case CARD_RESULT_READY:
538 DEMORFPrintf((s16) (16 + width), (s16) ((chan == 0) ? 75 : 105), 0, GetString(STR_MemoryCard),
539 memSize, sectorSize / 1024);
540 break;
541 case CARD_RESULT_WRONGDEVICE:
542 DEMORFPrintf((s16) (16 + width), (s16) ((chan == 0) ? 75 : 105), 0, GetString(STR_NotMemoryCard));
543 break;
544 default:
545 DEMORFPrintf((s16) (16 + width), (s16) ((chan == 0) ? 75 : 105), 0, GetString(STR_Nothing));
546 break;
547 }
548 }
549
550 //
551 // Draw DVD banner data
552 //
553 // Note: In GameCube file viewer, not all the characters appears on screen.
554 // Effective areas are shown as green boxes.
555 //
556
557 DEMOSetFontType(DM_FT_OPQ);
558 DrawRectangle(16, 330, 2 * DVD_BANNER_WIDTH, 2 * DVD_BANNER_HEIGHT, Black);
559 CardUtilDrawIcon(16, 330, 2 * DVD_BANNER_WIDTH,
560 Banner->image,
561 NULL,
562 DVD_BANNER_WIDTH, DVD_BANNER_HEIGHT,
563 CARD_STAT_ICON_RGB5A3);
564
565 DEMOSetFontType(DM_FT_XLU);
566
567 // 'titl', gam_lay 18h, -1, 1ca0h
568 DEMOSetFontType(DM_FT_OPQ);
569 DrawRectangle(16, 200 - FontData->ascent, 458, FontData->leading, Green);
570 DEMOSetFontType(DM_FT_XLU);
571 DEMOSetROMFontSize(24, -1);
572 DEMORFPrintf(16, 200, 0, "%-64.64s", Banner->longTitle);
573
574 // 'makr', gam_lay 14h, -1, 1ca0h
575 DEMOSetFontType(DM_FT_OPQ);
576 DrawRectangle(16, 224 - FontData->ascent, 458, FontData->leading, Green);
577 DEMOSetFontType(DM_FT_XLU);
578 DEMOSetROMFontSize(20, -1);
579 DEMORFPrintf(16, 224, 0, "%-64.64s", Banner->longMaker);
580
581 // 'info', gam_lay 14h, -1, 1ca0h * 2
582 DEMOSetFontType(DM_FT_OPQ);
583 DrawRectangle(16, 250 - FontData->ascent, 458, 2 * FontData->leading + 15, Green);
584 DEMOSetFontType(DM_FT_XLU);
585 DEMOSetROMFontSize(20, -1);
586 DEMORFPutsEx(16, 265, 0, (char*) Banner->comment, 458, sizeof Banner->comment);
587
588 // 'game', lay_gam 12h, -1, 0c00h (jp)
589 // 'game', lay_gam 10h, -2, 0c00h (us)
590 DEMOSetFontType(DM_FT_OPQ);
591 DrawRectangle(220, 354 - FontData->ascent, 192, FontData->leading, Green);
592 DEMOSetFontType(DM_FT_XLU);
593 if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS)
594 {
595 DEMOSetROMFontSize(18, -1);
596 }
597 else
598 {
599 DEMOSetROMFontSize(16, -2);
600 }
601 DEMORFPrintf(220, 354, 0, "%-32.32s", Banner->shortTitle);
602
603 // 'makr', lay_gam 12h, -1, 0c00h (jp)
604 // 'makr', lay_gam 10h, -2, 0c00h (us)
605 DEMOSetFontType(DM_FT_OPQ);
606 DrawRectangle(220, 378 - FontData->ascent, 192, FontData->leading, Green);
607 DEMOSetFontType(DM_FT_XLU);
608 if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS)
609 {
610 DEMOSetROMFontSize(18, -1);
611 }
612 else
613 {
614 DEMOSetROMFontSize(16, -2);
615 }
616 DEMORFPrintf(220, 378, 0, "%-32.32s", Banner->shortMaker);
617
618 DEMOSetROMFontSize((s16) FontData->cellWidth, -1);
619 }
620
621 /*---------------------------------------------------------------------------*
622 Name: ProbeAnimTick
623
624 Description: Switches the current slot selection.
625 Starts the mount operation if A button is pushed.
626 *---------------------------------------------------------------------------*/
ProbeAnimTick(void)627 static void ProbeAnimTick(void)
628 {
629 s32 memSize;
630 s32 sectorSize;
631
632 if (Conts[4].repeat & PAD_BUTTON_UP)
633 {
634 Slot = 0;
635 }
636 else if (Conts[4].repeat & PAD_BUTTON_DOWN)
637 {
638 Slot = 1;
639 }
640 else if ((Conts[4].down & PAD_BUTTON_A) &&
641 CARDProbeEx(Slot, &memSize, §orSize) == CARD_RESULT_READY)
642 {
643 CardUtilMount(Slot, CardWorkArea);
644 List = FALSE;
645 Offset = 0;
646 Current = 0;
647 State = STATE_LIST;
648 SubState = SUBSTATE_SELECT;
649
650 // At first, the program should check the available space in the
651 // memory card.
652 Command = CARDUTIL_CMD_CHECKSPACE;
653 }
654 }
655
656 /*---------------------------------------------------------------------------*
657 Name: DrawProgressBar
658
659 Description: Draw progress bar
660 *---------------------------------------------------------------------------*/
DrawProgressBar(void)661 static void DrawProgressBar(void)
662 {
663 DEMOSetFontType(DM_FT_OPQ);
664 DrawRectangle(16, 250, 300, 25, Black);
665 DrawRectangle(16, 250, 3 * CardUtilGetProgress(Slot), 25, Green);
666 }
667
668 /*---------------------------------------------------------------------------*
669 Name: DrawInstructions
670
671 Description: Draw command instructions on screen.
672 *---------------------------------------------------------------------------*/
DrawInstructions(void)673 static void DrawInstructions(void)
674 {
675 s32 result;
676 int width;
677
678 DEMOSetROMFontSize((s16) FontData->cellWidth, -1);
679 result = CardUtilResultCode();
680 switch (Command)
681 {
682 case CARDUTIL_CMD_SAVE:
683 DEMOSetFontType(DM_FT_RVS);
684 switch (SubState)
685 {
686 case SUBSTATE_COMMAND:
687 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Cancel), NULL);
688 DrawMenu(200, 200, Green, 0, GetString(STR_Save), GetString(STR_Erase), NULL);
689 break;
690 case SUBSTATE_VERIFY:
691 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Cancel), NULL);
692 width = DrawMenu(200, 200, Green, 0, GetString(STR_Save), GetString(STR_Erase), NULL);
693 DrawMenu(200 + 5 + width, 200, Green,
694 YesNo, GetString(STR_Yes), GetString(STR_No), NULL);
695 break;
696 case SUBSTATE_BUSY:
697 DrawProgressBar();
698 DEMOSetFontType(DM_FT_RVS);
699 DrawUsage(Slot, GetString(STR_Null), GetString(STR_Null), GetString(STR_Saving));
700 break;
701 case SUBSTATE_WAIT:
702 DrawProgressBar();
703 DEMOSetFontType(DM_FT_RVS);
704 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Null), NULL);
705 switch (result)
706 {
707 case CARD_RESULT_READY:
708 DrawMessage(16, 200, Green, GetString(STR_Saved));
709 break;
710 case CARD_RESULT_NOENT:
711 case CARD_RESULT_INSSPACE:
712 DrawMessage(16, 200, Red, GetString(STR_NotSaved));
713 break;
714 default:
715 DrawMessage(16, 200, Red, GetString(STR_MayNotSaved));
716 break;
717 }
718 break;
719 }
720 break;
721
722 case CARDUTIL_CMD_ERASE:
723 DEMOSetFontType(DM_FT_RVS);
724 switch (SubState)
725 {
726 case SUBSTATE_COMMAND:
727 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Cancel), NULL);
728 DrawMenu(200, 200, Green, 1, GetString(STR_Save), GetString(STR_Erase), NULL);
729 break;
730 case SUBSTATE_VERIFY:
731 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Cancel), NULL);
732 width = DrawMenu(200, 200, Green, 1, GetString(STR_Save), GetString(STR_Erase), NULL);
733 DrawMenu(200 + 5 + width, 200 + FontData->leading, Green,
734 YesNo, GetString(STR_Yes), GetString(STR_No), NULL);
735 break;
736 case SUBSTATE_BUSY:
737 DrawProgressBar();
738 DEMOSetFontType(DM_FT_RVS);
739 DrawUsage(Slot, GetString(STR_Null), GetString(STR_Null), GetString(STR_Erasing));
740 break;
741 case SUBSTATE_WAIT:
742 DrawProgressBar();
743 DEMOSetFontType(DM_FT_RVS);
744 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Null), NULL);
745 switch (result)
746 {
747 case CARD_RESULT_READY:
748 DrawMessage(16, 200, Green, GetString(STR_Erased));
749 break;
750 default:
751 DrawMessage(16, 200, Red, GetString(STR_MayNotErased));
752 break;
753 }
754 break;
755 }
756 break;
757
758 case CARDUTIL_CMD_FORMAT:
759 switch (SubState)
760 {
761 case SUBSTATE_VERIFY:
762 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Cancel), NULL);
763 DrawMessage(16, 75, Red, GetString(STR_Format));
764 DrawMenu(200, 200, Green, YesNo, GetString(STR_Yes), GetString(STR_No), NULL);
765 break;
766 case SUBSTATE_BUSY:
767 DrawProgressBar();
768 DEMOSetFontType(DM_FT_RVS);
769 DrawUsage(Slot, GetString(STR_Null), GetString(STR_Null), GetString(STR_Formatting));
770 break;
771 case SUBSTATE_WAIT:
772 DrawProgressBar();
773 DEMOSetFontType(DM_FT_RVS);
774 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Null), NULL);
775 switch (result)
776 {
777 case CARD_RESULT_READY:
778 DrawMessage(16, 200, Green, GetString(STR_Formatted));
779 break;
780 default:
781 DrawMessage(16, 200, Red, GetString(STR_MayNotFormatted));
782 break;
783 }
784 break;
785 }
786 break;
787
788 case CARDUTIL_CMD_CHECKSPACE:
789 case CARDUTIL_CMD_IGNORE:
790 case CARDUTIL_CMD_MAIN_MENU:
791 // At the beginning of the program, it should check if the player
792 // has a memory card that can be used to save the game data.
793 switch (SubState)
794 {
795 case SUBSTATE_SELECT: // mounting...
796 DEMOSetFontType(DM_FT_RVS);
797 DrawUsage(Slot, GetString(STR_Null), GetString(STR_Null), GetString(STR_Mounting));
798 break;
799 case SUBSTATE_COMMAND:
800 DEMOSetFontType(DM_FT_RVS);
801 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Cancel), NULL);
802 DrawMessage(16, 75, Red, GetString(STR_InsSpace));
803 DrawMenu(200, 200, Green, Command - CARDUTIL_CMD_CHECKSPACE,
804 GetString(STR_Cancel), GetString(STR_Ignore), GetString(STR_Menu), NULL);
805 break;
806 }
807 break;
808
809 case CARDUTIL_CMD_ERROR:
810 DrawUsage(Slot, GetString(STR_Confirm), GetString(STR_Null), NULL);
811 DrawMessage(16, 69, Red, GetString(STR_Broken));
812 break;
813
814 default:
815 DEMOSetFontType(DM_FT_RVS);
816 DrawUsage(Slot, GetString(STR_Select), GetString(STR_Finish), NULL);
817 break;
818 }
819 }
820
821 /*---------------------------------------------------------------------------*
822 Name: ListDrawTick
823
824 Description: Draw card file directory
825 *---------------------------------------------------------------------------*/
ListDrawTick(void)826 static void ListDrawTick(void)
827 {
828 GXRenderModeObj* rmp;
829 CardUtilDirent* ent;
830 int i;
831 s32 numFiles;
832 s32 numBlocks;
833
834 // Locks directory to prevents card utility thread updates directory behind
835 numFiles = CardUtilLockDirectory();
836
837 // Check if new files can be created.
838 NumEntries = numFiles;
839 numBlocks = GetBlockSize(FILE_SIZE);
840 if (0 < CardUtilFilesNotUsed() &&
841 2 * numBlocks <= CardUtilBlocksNotUsed())
842 {
843 // Last directory entry is used for creating a new data file.
844 ++NumEntries;
845 }
846
847 rmp = DEMOGetRenderModeObj();
848 DEMOInitCaption(DM_FT_XLU, (s16) rmp->fbWidth, (s16) rmp->efbHeight);
849
850 // Updates Current as card utility thread may have deleted directory entries
851 if (NumEntries <= Current && 0 < NumEntries)
852 {
853 Current = NumEntries - 1;
854 if (Current < Offset)
855 {
856 Offset = Current;
857 }
858 }
859
860 // Draw directory
861 for (i = 0; i < LIST_ROW && Offset + i < NumEntries; ++i)
862 {
863 DEMOSetFontType((Current == Offset + i) ? DM_FT_RVS : DM_FT_XLU);
864
865 if (Offset + i == numFiles)
866 {
867 // The last entry for creating new file
868 DEMORFPrintf(60, (s16) (75 + i * 34), 0, "%s (%d)",
869 GetString(STR_Open),
870 CardUtilBlocksNotUsed());
871 continue;
872 }
873
874 ent = &Directory[Offset + i];
875
876 // Note in GameCube file viewer, fileNo and fileName do not appear
877 // on screen. This is program verification only.
878 DEMORFPrintf(60, (s16) (75 + i * 34), 0, "%-.32s (#%d, %d blocks)",
879 ent->stat.fileName,
880 ent->fileNo,
881 ent->stat.length / CardUtilSectorSize());
882
883 // Draw animated icon
884 CardUtilDrawAnimatedIcon(ent, 16, 75 + i * 34 - 29, CARD_ICON_WIDTH);
885 }
886 DEMOSetROMFontSize(20, -1);
887 DEMOSetFontType(DM_FT_XLU);
888 DEMORFPrintf(180, 430, 0, GetString(STR_Stat),
889 CardUtilByteNotUsed() / CardUtilSectorSize(),
890 CardUtilFilesNotUsed());
891
892 if (Current < numFiles)
893 {
894 // Show more detailed current file info
895 ent = &Directory[Current];
896
897 // Draw comment:
898 // Note in GameCube file viewer, not all the characters appears on screen.
899 // Effective areas are shown as green boxes.
900
901 // 'titl', mem_lay 16h, -1, 1420h,
902 DEMOSetFontType(DM_FT_OPQ);
903 DrawRectangle(180, 354 - FontData->ascent, 322, FontData->leading, Green);
904 DEMOSetFontType(DM_FT_XLU);
905 DEMOSetROMFontSize(22, -1);
906 DEMORFPrintf(180, 354, 0, "%-32.32s", ent->comment);
907
908 // 'info', mem_lay 14h, -1, 10d0h
909 DEMOSetFontType(DM_FT_OPQ);
910 DrawRectangle(180, 378 - FontData->ascent, 269, FontData->leading, Green);
911 DEMOSetFontType(DM_FT_XLU);
912 DEMOSetROMFontSize(20, -1);
913 DEMORFPrintf(180, 378, 0, "%-32.32s", &ent->comment[32]);
914 DEMOSetROMFontSize((s16) FontData->cellWidth, -1);
915
916 // Draw banner
917 ent = &Directory[Current];
918 if (CARDGetBannerFormat(&ent->stat) != CARD_STAT_BANNER_NONE)
919 {
920 DEMOSetFontType(DM_FT_OPQ);
921 DrawRectangle(16, 330, DVD_BANNER_WIDTH, DVD_BANNER_HEIGHT, Black);
922 CardUtilDrawIcon(16, 330, CARD_BANNER_WIDTH,
923 (u8*) ent + ent->stat.offsetBanner - ent->stat.iconAddr,
924 (u8*) ent + ent->stat.offsetBannerTlut - ent->stat.iconAddr,
925 CARD_BANNER_WIDTH, CARD_BANNER_HEIGHT,
926 CARDGetBannerFormat(&ent->stat));
927 }
928
929 // Draw all icons for program verification purpose only
930 for (i = 0; i < CARD_ICON_MAX; ++i)
931 {
932 if (CARDGetIconFormat(&ent->stat, i) != CARD_STAT_ICON_NONE)
933 {
934 CardUtilDrawIcon((s16) (16 + (i % 4) * 36), (s16) (330 + 42 + (i / 4) * 36), CARD_ICON_WIDTH,
935 (u8*) ent + ent->stat.offsetIcon[i] - ent->stat.iconAddr,
936 (u8*) ent + ent->stat.offsetIconTlut - ent->stat.iconAddr,
937 CARD_ICON_WIDTH, CARD_ICON_HEIGHT,
938 CARDGetIconFormat(&ent->stat, i));
939 }
940 }
941
942 // Draw animated icon
943 CardUtilDrawAnimatedIcon(ent, 16 + 3 * 36, 330, CARD_ICON_WIDTH);
944 }
945
946 // Unlocks directory so card utility thread can updates directory
947 CardUtilUnlockDirectory();
948
949 // Draw instructions and popup menu
950 DrawInstructions();
951 }
952
953 /*---------------------------------------------------------------------------*
954 Name: NewFileName
955
956 Description: Generates a new file name. This function is only for
957 illustration (no good). XXX
958 *---------------------------------------------------------------------------*/
NewFileName(char * fileName)959 static void NewFileName(char* fileName)
960 {
961 OSTime time;
962 OSCalendarTime ct;
963
964 time = OSGetTime();
965 OSTicksToCalendarTime(time, &ct);
966 sprintf(fileName, "%04d/%02d/%02d %02d:%02d:%02d",
967 ct.year, ct.mon + 1, ct.mday,
968 ct.hour, ct.min, ct.sec);
969 }
970
971 /*---------------------------------------------------------------------------*
972 Name: SaveData
973
974 Description: Layouts banner, icon and comment data and save the file.
975
976 Arguments: fileName filename whose length should be less than
977 CARD_FILENAME_MAX 'cause SaveData() creates
978 a temporary filename by adding '~' before the
979 head of the filename.
980 banner pointer to DVDBanner data
981 tplBanner banner texture image (NULL to use DVDbanner data)
982 tplIcons icon texture images (up to eight)
983 iconSpeed one of CARD_STAT_SPEED_*. Though each icon can
984 use different icon speed if desired, SaveData()
985 assigns the same speed for all icons.
986 iconAnim one of CARD_STAT_ANIM_*
987 description game description (32 bytes)
988
989 Note: Use tplBanner to specify C8 texture image to save
990 the game file size. Otherwise use DVDBanner image.
991 In either case, the graphics should be same as
992 the DVDBanner image.
993
994 Returns: Pointer to game data save area (after icon data)
995 *---------------------------------------------------------------------------*/
SaveData(char * fileName,DVDBanner * banner,TPLPalettePtr tplBanner,TPLPalettePtr tplIcons,u16 iconSpeed,u8 iconAnim,char * description)996 static void* SaveData(char* fileName, DVDBanner* banner,
997 TPLPalettePtr tplBanner,
998 TPLPalettePtr tplIcons, u16 iconSpeed, u8 iconAnim,
999 char* description)
1000 {
1001 TPLPalettePtr tpl = 0;
1002 TPLDescriptorPtr tdp;
1003 int i;
1004 u8* ptr;
1005
1006 ASSERT(banner);
1007
1008 iconSpeed &= CARD_STAT_SPEED_MASK;
1009 iconAnim &= CARD_STAT_ANIM_MASK;
1010
1011 memset(&CardStatTemplate, 0, sizeof CardStatTemplate);
1012 CardStatTemplate.length = (u32) GetBlockSize(FILE_SIZE) * CardUtilSectorSize();
1013
1014 ASSERT(CardData == 0);
1015 CardData = OSAlloc(CardStatTemplate.length);
1016 ASSERT(CardData);
1017 memset(CardData, 0, CardStatTemplate.length);
1018 strncpy(CardStatTemplate.fileName, fileName, CARD_FILENAME_MAX);
1019
1020 ptr = (u8*) CardData;
1021
1022 // Comment
1023 CardStatTemplate.commentAddr = 0;
1024 strncpy((char*) ptr, (char*) banner->shortTitle, CARD_COMMENT_SIZE / 2);
1025 ptr += CARD_COMMENT_SIZE / 2;
1026 strncpy((char*) ptr, description, CARD_COMMENT_SIZE / 2);
1027 ptr += CARD_COMMENT_SIZE / 2;
1028
1029 // Banner
1030 CardStatTemplate.iconAddr = (u32) (ptr - (u8*) CardData);
1031 if (tplBanner == NULL)
1032 {
1033 // Use DVDBanner image
1034 CardStatTemplate.bannerFormat = CARD_STAT_BANNER_RGB5A3;
1035 memcpy(ptr, banner->image,
1036 2 * CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT);
1037 ptr += 2 * CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT;
1038 }
1039 else
1040 {
1041 tdp = TPLGet(tplBanner, 0);
1042
1043 // Update bannerFormat
1044 switch ((GXTexFmt) tdp->textureHeader->format)
1045 {
1046 case GX_TF_RGB5A3:
1047 CardStatTemplate.bannerFormat = CARD_STAT_BANNER_RGB5A3;
1048 break;
1049 case GX_TF_C8:
1050 CardStatTemplate.bannerFormat = CARD_STAT_BANNER_C8;
1051 ASSERT(tdp->CLUTHeader);
1052 break;
1053 default:
1054 OSHalt("Unsupported banner texture formant.");
1055 break;
1056 }
1057
1058 // Copy texture image and tlut
1059 if (CARDGetBannerFormat(&CardStatTemplate) == CARD_STAT_BANNER_RGB5A3)
1060 {
1061 memcpy(ptr, tdp->textureHeader->data,
1062 2 * CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT);
1063 ptr += 2 * CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT;
1064 }
1065 else // CARD_STAT_ICON_C8
1066 {
1067 ASSERT(tdp->CLUTHeader);
1068 ASSERT((GXTlutFmt) tdp->CLUTHeader->format == GX_TL_RGB5A3);
1069 ASSERT(tdp->CLUTHeader->numEntries == 256);
1070
1071 memcpy(ptr, tdp->textureHeader->data,
1072 CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT);
1073 ptr += CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT;
1074 memcpy(ptr, tdp->CLUTHeader->data, 2 * 256);
1075 ptr += 2 * 256;
1076 }
1077 }
1078
1079 // Icon
1080 if (tplIcons)
1081 {
1082 int iconTlut;
1083
1084 // Update iconFormat
1085 for (i = 0; i < tplIcons->numDescriptors && i < CARD_ICON_MAX; i++)
1086 {
1087 tdp = TPLGet(tplIcons, (u32) i);
1088
1089 switch ((GXTexFmt) tdp->textureHeader->format)
1090 {
1091 case GX_TF_RGB5A3:
1092 CARDSetIconFormat(&CardStatTemplate, i, CARD_STAT_ICON_RGB5A3);
1093 break;
1094 case GX_TF_C8:
1095 CARDSetIconFormat(&CardStatTemplate, i, CARD_STAT_ICON_C8);
1096 ASSERT(tdp->CLUTHeader);
1097 break;
1098 default:
1099 OSHalt("Unsupported icon texture formant.");
1100 break;
1101 }
1102 CARDSetIconSpeed(&CardStatTemplate, i, iconSpeed);
1103 }
1104 for (; i < CARD_ICON_MAX; i++)
1105 {
1106 CARDSetIconSpeed(&CardStatTemplate, i, CARD_STAT_SPEED_END);
1107 }
1108
1109 CardStatTemplate.bannerFormat |= iconAnim;
1110
1111 // Copy icon texture images and tlut
1112 iconTlut = -1;
1113 for (i = 0; i < tplIcons->numDescriptors && i < CARD_ICON_MAX; i++)
1114 {
1115 tdp = TPLGet(tplIcons, (u32) i);
1116 switch (CARDGetIconFormat(&CardStatTemplate, i))
1117 {
1118 case CARD_STAT_ICON_RGB5A3:
1119 memcpy(ptr, tdp->textureHeader->data,
1120 2 * CARD_ICON_WIDTH * CARD_ICON_HEIGHT);
1121 ptr += 2 * CARD_ICON_WIDTH * CARD_ICON_HEIGHT;
1122 break;
1123 case CARD_STAT_ICON_C8:
1124 ASSERT(tdp->CLUTHeader);
1125 ASSERT((GXTlutFmt) tdp->CLUTHeader->format == GX_TL_RGB5A3);
1126 ASSERT(tdp->CLUTHeader->numEntries == 256);
1127
1128 memcpy(ptr, tdp->textureHeader->data,
1129 CARD_ICON_WIDTH * CARD_ICON_HEIGHT);
1130 ptr += CARD_ICON_WIDTH * CARD_ICON_HEIGHT;
1131 iconTlut = i;
1132 break;
1133 }
1134 }
1135 if (0 <= iconTlut)
1136 {
1137 tdp = TPLGet(tplIcons, (u32) i);
1138 memcpy(ptr, tdp->CLUTHeader->data, 2 * 256);
1139 ptr += 2 * 256;
1140 }
1141 }
1142
1143 return ptr;
1144 }
1145
1146 /*---------------------------------------------------------------------------*
1147 Name: SelectAnimTick
1148
1149 Description: Selects the directory entry.
1150 Starts command selection if A button is pushed.
1151 Goes back to slot selection if B button is pushed.
1152 *---------------------------------------------------------------------------*/
SelectAnimTick(void)1153 static void SelectAnimTick(void)
1154 {
1155 if (Conts[4].repeat & PAD_BUTTON_UP)
1156 {
1157 if (0 < Current)
1158 {
1159 --Current;
1160 if (Current < Offset)
1161 {
1162 --Offset;
1163 }
1164 }
1165 }
1166 else if (Conts[4].repeat & PAD_BUTTON_DOWN)
1167 {
1168 if (Current < NumEntries - 1)
1169 {
1170 ++Current;
1171 if (Offset + LIST_ROW <= Current)
1172 {
1173 ++Offset;
1174 }
1175 }
1176 }
1177 else if (Conts[4].down & PAD_BUTTON_B)
1178 {
1179 CardUtilUnmount(Slot);
1180 State = STATE_PROBE;
1181 }
1182 else if (Conts[4].down & PAD_BUTTON_A)
1183 {
1184 SubState = SUBSTATE_COMMAND;
1185 Command = CARDUTIL_CMD_SAVE;
1186 }
1187
1188 }
1189
1190 /*---------------------------------------------------------------------------*
1191 Name: CommandAnimTick
1192
1193 Description: Switches the command.
1194 Selects the current command if A button is pushed.
1195 Goes back to file selection if B button is pushed.
1196 *---------------------------------------------------------------------------*/
CommandAnimTick(void)1197 static void CommandAnimTick(void)
1198 {
1199 if (Conts[4].down & PAD_BUTTON_B)
1200 {
1201 switch (Command)
1202 {
1203 case CARDUTIL_CMD_SAVE:
1204 case CARDUTIL_CMD_ERASE:
1205 SubState = SUBSTATE_SELECT;
1206 Command = CARDUTIL_CMD_NONE;
1207 break;
1208 case CARDUTIL_CMD_CHECKSPACE:
1209 case CARDUTIL_CMD_IGNORE:
1210 case CARDUTIL_CMD_MAIN_MENU:
1211 CardUtilUnmount(Slot);
1212 State = STATE_PROBE;
1213 break;
1214 }
1215 }
1216 else if (Conts[4].repeat & PAD_BUTTON_UP)
1217 {
1218 switch (Command)
1219 {
1220 case CARDUTIL_CMD_SAVE:
1221 case CARDUTIL_CMD_ERASE:
1222 Command = CARDUTIL_CMD_SAVE;
1223 break;
1224 case CARDUTIL_CMD_CHECKSPACE:
1225 case CARDUTIL_CMD_IGNORE:
1226 case CARDUTIL_CMD_MAIN_MENU:
1227 if (CARDUTIL_CMD_CHECKSPACE < Command)
1228 {
1229 --Command;
1230 }
1231 break;
1232 }
1233 }
1234 else if (Conts[4].repeat & PAD_BUTTON_DOWN)
1235 {
1236 switch (Command)
1237 {
1238 case CARDUTIL_CMD_SAVE:
1239 case CARDUTIL_CMD_ERASE:
1240 Command = CARDUTIL_CMD_ERASE;
1241 break;
1242 case CARDUTIL_CMD_CHECKSPACE:
1243 case CARDUTIL_CMD_IGNORE:
1244 case CARDUTIL_CMD_MAIN_MENU:
1245 if (Command < CARDUTIL_CMD_MAIN_MENU)
1246 {
1247 ++Command;
1248 }
1249 break;
1250 }
1251 }
1252 else if (Conts[4].down & PAD_BUTTON_A)
1253 {
1254 YesNo = NO;
1255 switch (Command)
1256 {
1257 case CARDUTIL_CMD_SAVE:
1258 // Do not issue save if no space is available
1259 if (IsSpaceAvailable(FILE_SIZE))
1260 {
1261 SubState = SUBSTATE_VERIFY;
1262 }
1263 break;
1264 case CARDUTIL_CMD_ERASE:
1265 // Do not issue erase if no file is selected
1266 if (Current < CardUtilNumFiles())
1267 {
1268 SubState = SUBSTATE_VERIFY;
1269 }
1270 break;
1271 case CARDUTIL_CMD_CHECKSPACE:
1272 CardUtilUnmount(Slot);
1273 State = STATE_PROBE;
1274 break;
1275 case CARDUTIL_CMD_IGNORE:
1276 Command = CARDUTIL_CMD_NONE;
1277 SubState = SUBSTATE_SELECT;
1278 break;
1279 case CARDUTIL_CMD_MAIN_MENU:
1280 ForceMenu = TRUE;
1281 break;
1282 }
1283 }
1284 }
1285
1286 /*---------------------------------------------------------------------------*
1287 Name: VerifyAnimTick
1288
1289 Description: Starts the current command if A button is pushed.
1290 Cancels the current command if B button is pushed.
1291
1292 If both A and B buttons are pushed, B button has a priority.
1293 *---------------------------------------------------------------------------*/
VerifyAnimTick(void)1294 static void VerifyAnimTick(void)
1295 {
1296 char fileName[CARD_FILENAME_MAX + 1];
1297 u8* ptr;
1298
1299 if (Conts[4].down & PAD_BUTTON_B)
1300 {
1301 switch (Command)
1302 {
1303 case CARDUTIL_CMD_SAVE:
1304 case CARDUTIL_CMD_ERASE:
1305 SubState = SUBSTATE_COMMAND;
1306 break;
1307 case CARDUTIL_CMD_FORMAT:
1308 default:
1309 CardUtilUnmount(Slot);
1310 State = STATE_PROBE;
1311 break;
1312 }
1313 }
1314 else if (Conts[4].repeat & PAD_BUTTON_UP)
1315 {
1316 YesNo = YES;
1317 }
1318 else if (Conts[4].repeat & PAD_BUTTON_DOWN)
1319 {
1320 YesNo = NO;
1321 }
1322 else if (Conts[4].down & PAD_BUTTON_A)
1323 {
1324 switch (YesNo)
1325 {
1326 case YES:
1327 switch (Command)
1328 {
1329 case CARDUTIL_CMD_SAVE:
1330 fileName[CARD_FILENAME_MAX] = '\0';
1331 if (CardUtilNumFiles() <= Current)
1332 {
1333 // Create new file name
1334 NewFileName(fileName);
1335 }
1336 else
1337 {
1338 // Keep the current name
1339 strncpy(fileName, Directory[Current].stat.fileName, CARD_FILENAME_MAX);
1340 }
1341 ptr = SaveData(fileName, Banner,
1342 NULL,
1343 TplIcons, CARD_STAT_SPEED_MIDDLE, CARD_STAT_ANIM_LOOP,
1344 "File Description");
1345
1346 //
1347 // Implement your code here
1348 //
1349 // Now ptr points to the game data save area after comment,
1350 // banner and icon data.
1351 //
1352
1353 CardUtilSave(Slot, &CardStatTemplate, CardData);
1354 SubState = SUBSTATE_BUSY;
1355 break;
1356 case CARDUTIL_CMD_ERASE:
1357 CardUtilErase(Slot, Directory[Current].fileNo);
1358 SubState = SUBSTATE_BUSY;
1359 break;
1360 case CARDUTIL_CMD_FORMAT:
1361 CardUtilFormat(Slot);
1362 SubState = SUBSTATE_BUSY;
1363 break;
1364 }
1365 break;
1366 case NO:
1367 switch (Command)
1368 {
1369 case CARDUTIL_CMD_FORMAT:
1370 CardUtilUnmount(Slot);
1371 State = STATE_PROBE;
1372 break;
1373 default:
1374 Command = CARDUTIL_CMD_NONE;
1375 SubState = SUBSTATE_SELECT;
1376 break;
1377 }
1378 break;
1379 }
1380 }
1381 }
1382
1383 /*---------------------------------------------------------------------------*
1384 Name: BusyAnimTick
1385
1386 Description: The function is called when card utility thread gets not-busy.
1387 Moves on to confirm screen.
1388 *---------------------------------------------------------------------------*/
BusyAnimTick(void)1389 static void BusyAnimTick(void)
1390 {
1391 SubState = SUBSTATE_WAIT;
1392 BeginWaitAt = OSGetTime(); // Save current time so confirm screen can
1393 // time-out if desired.
1394 switch (Command)
1395 {
1396 case CARDUTIL_CMD_SAVE:
1397 OSFree(CardData);
1398 CardData = 0;
1399 break;
1400 }
1401 }
1402
1403 /*---------------------------------------------------------------------------*
1404 Name: WaitAnimTick
1405
1406 Description: Goes back to default state after the player confirmed.
1407 Times out in 1.5 sec if the current command was successfully
1408 executed.
1409 *---------------------------------------------------------------------------*/
WaitAnimTick(s32 result)1410 static void WaitAnimTick(s32 result)
1411 {
1412 if (!((Conts[4].down & (PAD_BUTTON_A | PAD_BUTTON_B)) ||
1413 (OSMillisecondsToTicks(1500) < OSGetTime() - BeginWaitAt &&
1414 result == CARD_RESULT_READY)))
1415 {
1416 return;
1417 }
1418
1419 switch (Command)
1420 {
1421 case CARDUTIL_CMD_ERROR:
1422 CardUtilUnmount(Slot);
1423 State = STATE_PROBE;
1424 break;
1425 default:
1426 Command = CARDUTIL_CMD_NONE;
1427 SubState = SUBSTATE_SELECT;
1428 break;
1429 }
1430 }
1431
1432 /*---------------------------------------------------------------------------*
1433 Name: ListAnimTick
1434
1435 Description: Top level animation tick function for the directory screen
1436 *---------------------------------------------------------------------------*/
ListAnimTick(void)1437 static void ListAnimTick(void)
1438 {
1439 s32 result;
1440
1441 result = CardUtilResultCode();
1442
1443 // Listup
1444 if (!List && result == CARD_RESULT_READY)
1445 {
1446 List = TRUE;
1447 CardUtilList(Slot, Directory);
1448 result = CardUtilResultCode();
1449 }
1450
1451 // The current command must not be aborted.
1452 if (result == CARD_RESULT_BUSY)
1453 {
1454 return;
1455 }
1456
1457 // Check space
1458 if (Command == CARDUTIL_CMD_CHECKSPACE)
1459 {
1460 if (IsSpaceAvailable(FILE_SIZE))
1461 {
1462 Command = CARDUTIL_CMD_NONE;
1463 SubState = SUBSTATE_SELECT;
1464 }
1465 else if (result == CARD_RESULT_READY)
1466 {
1467 SubState = SUBSTATE_COMMAND;
1468 }
1469 }
1470
1471 if (SubState < SUBSTATE_BUSY && !CARDProbe(Slot))
1472 {
1473 State = STATE_PROBE;
1474 return;
1475 }
1476
1477 // Process error
1478 if (SubState < SUBSTATE_VERIFY)
1479 {
1480 switch (result)
1481 {
1482 case CARD_RESULT_READY:
1483 case CARD_RESULT_NOFILE:
1484 case CARD_RESULT_EXIST:
1485 case CARD_RESULT_NOPERM:
1486 case CARD_RESULT_LIMIT:
1487 case CARD_RESULT_NAMETOOLONG:
1488 case CARD_RESULT_CANCELED:
1489 break;
1490
1491 case CARD_RESULT_NOENT:
1492 case CARD_RESULT_INSSPACE:
1493 break;
1494
1495 case CARD_RESULT_BROKEN:
1496 case CARD_RESULT_ENCODING:
1497 Command = CARDUTIL_CMD_FORMAT;
1498 YesNo = NO;
1499 SubState = SUBSTATE_VERIFY;
1500 return;
1501
1502 case CARD_RESULT_NOCARD:
1503 State = STATE_PROBE;
1504 return;
1505
1506 default:
1507 case CARD_RESULT_IOERROR:
1508 case CARD_RESULT_FATAL_ERROR:
1509 case CARD_RESULT_WRONGDEVICE:
1510 Command = CARDUTIL_CMD_ERROR;
1511 SubState = SUBSTATE_WAIT;
1512 BeginWaitAt = OSGetTime();
1513 return;
1514 }
1515 }
1516
1517 switch (SubState)
1518 {
1519 case SUBSTATE_SELECT:
1520 SelectAnimTick();
1521 break;
1522 case SUBSTATE_COMMAND:
1523 CommandAnimTick();
1524 break;
1525 case SUBSTATE_VERIFY:
1526 VerifyAnimTick();
1527 break;
1528 case SUBSTATE_BUSY:
1529 BusyAnimTick();
1530 break;
1531 case SUBSTATE_WAIT:
1532 WaitAnimTick(result);
1533 break;
1534 }
1535 }
1536
1537 /*---------------------------------------------------------------------------*
1538 Name: LoadBanner
1539
1540 Description: Load banner file "/opening.bnr"
1541 *---------------------------------------------------------------------------*/
LoadBanner(void)1542 static DVDBanner* LoadBanner(void)
1543 {
1544 static DVDBanner banner ATTRIBUTE_ALIGN(32);
1545 DVDFileInfo fileInfo;
1546 BOOL result;
1547 s32 length;
1548
1549 result = DVDOpen("/" DVD_BANNER_FILENAME, &fileInfo);
1550 if (!result)
1551 return NULL;
1552 length = (s32) OSRoundUp32B(DVDGetLength(&fileInfo));
1553 if (length < sizeof(DVDBanner))
1554 return NULL;
1555 result = DVDRead(&fileInfo, &banner, sizeof(DVDBanner), 0);
1556 if (!result)
1557 return NULL;
1558 if (banner.id != DVD_BANNER_ID)
1559 return NULL;
1560 return &banner;
1561 }
1562
1563 /*---------------------------------------------------------------------------*
1564 Name: main
1565
1566 Description: After loading ROM font and banner and icon textures,
1567 goes into the main loop.
1568 *---------------------------------------------------------------------------*/
main(void)1569 int main(void)
1570 {
1571 static BOOL reset = FALSE; // TRUE if reset is requested
1572
1573 DEMOInit(NULL);
1574 FontData = DEMOInitROMFont(); // Use IPL ROM font
1575 if (FontData == 0)
1576 {
1577 OSHalt("This program requires boot ROM ver 0.8 or later\n");
1578 // NOT REACHED HERE
1579 }
1580
1581 InitCont(0, FALSE);
1582
1583 CardUtilInit(CardStack + sizeof(CardStack), sizeof(CardStack), 18);
1584
1585 // Clear EFB
1586 GXSetCopyClear(Blue, 0x00ffffff);
1587 GXCopyDisp(DEMOGetCurrentBuffer(), GX_TRUE);
1588
1589 // Load banner file "/opening.bnr"
1590 Banner = LoadBanner();
1591 if (Banner == 0)
1592 {
1593 OSHalt("\"" DVD_BANNER_FILENAME "\" is not found in the root directory.\n");
1594 // NOT REACHED HERE
1595 }
1596
1597 // Load banner and icon texture palettes
1598 // banner.tpl should contain a single 96x32 C8 or RGB5A3 texture image.
1599 // icon.tpl should contain from one to eight 32x32 C8 or RGB5A3 texture images.
1600 TPLGetPalette(&TplBanner, "/carddemo/banner.tpl");
1601 TPLGetPalette(&TplIcons, "/carddemo/icon.tpl");
1602
1603 for (;;)
1604 {
1605 DEMOBeforeRender();
1606 ReadCont();
1607 InterfaceTable[State].DrawTick();
1608 InterfaceTable[State].AnimTick();
1609 DEMODoneRender();
1610
1611 if (ForceMenu && SubState != SUBSTATE_BUSY) // Do not reset while saving data, etc.
1612 {
1613 // Use hot reset to start GameCube main menu
1614 OSResetSystem(OS_RESET_HOTRESET, 0x01, TRUE);
1615 }
1616
1617 // Handle reset button
1618 if (OSGetResetButtonState())
1619 {
1620 reset = TRUE;
1621 }
1622 else if (reset && SubState != SUBSTATE_BUSY) // Do not reset while saving data, etc.
1623 {
1624 // Restart
1625 OSResetSystem(OS_RESET_RESTART, 0x00, FALSE);
1626 }
1627 }
1628
1629 return 0; // lint
1630 }
1631