mirror of
https://github.com/wavemotion-dave/NINTV-DS.git
synced 2025-06-18 13:55:33 -04:00
658 lines
26 KiB
C++
658 lines
26 KiB
C++
// =====================================================================================
|
|
// Copyright (c) 2021-2025 Dave Bernazzani (wavemotion-dave)
|
|
//
|
|
// Copying and distribution of this emulator, its source code and associated
|
|
// readme files, with or without modification, are permitted in any medium without
|
|
// royalty provided the this copyright notice is used and wavemotion-dave (NINTV-DS)
|
|
// and Kyle Davis (BLISS) are thanked profusely.
|
|
//
|
|
// The NINTV-DS emulator is offered as-is, without any warranty.
|
|
// =====================================================================================
|
|
|
|
#include <nds.h>
|
|
#include <stdio.h>
|
|
#include <fat.h>
|
|
#include <dirent.h>
|
|
#include <unistd.h>
|
|
#include "nintv-ds.h"
|
|
#include "highscore.h"
|
|
#include "bgMenu-Green.h"
|
|
#include "bgMenu-White.h"
|
|
#include "bgBottom.h"
|
|
#include "printf.h"
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// With only 125 released games plus 25-50 prototypes and 100-ish homebrews,
|
|
// this ~300 game limit should be more than enough to handle the entire library.
|
|
// ------------------------------------------------------------------------------
|
|
#define MAX_HS_GAMES 285 // Just enough to fill 64K (2 sectors on the SD)
|
|
#define HS_VERSION 0x0003 // Changing this will wipe high scores on the next install
|
|
|
|
// --------------------------------------------------------------------------
|
|
// We allow sorting on various criteria. By default sorting is high-to-low.
|
|
// --------------------------------------------------------------------------
|
|
#define HS_OPT_SORTMASK 0x0003
|
|
#define HS_OPT_SORTLOW 0x0001
|
|
#define HS_OPT_SORTTIME 0x0002
|
|
#define HS_OPT_SORTASCII 0x0003
|
|
|
|
#pragma pack(1) // Keep things tight...
|
|
|
|
// ---------------------------------------------------------
|
|
// Each score has this stuff... Initials, score and date.
|
|
// ---------------------------------------------------------
|
|
struct score_t
|
|
{
|
|
char initials[4]; // With NULL this is only 3 ascii characters
|
|
char score[7]; // Six digits of score
|
|
char reserved[5]; // For the future...
|
|
uint16 year; // Date score was achieved. We'll auto-fill this from DS time
|
|
uint8 month;
|
|
uint8 day;
|
|
};
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
// We have up to 10 scores for each game... along with some notes and the sorting options...
|
|
// -------------------------------------------------------------------------------------------
|
|
struct highscore_t
|
|
{
|
|
UINT32 crc;
|
|
char notes[21];
|
|
uint16 options;
|
|
struct score_t scores[10];
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------------
|
|
// We save up to 300 games worth of scores. We also have a spot for default initials
|
|
// so we can re-use the last initials for the last high-score entered. Saves time
|
|
// for most people who are always the ones using their DS system.
|
|
// -----------------------------------------------------------------------------------
|
|
struct highscore_full_t
|
|
{
|
|
uint16 version;
|
|
char last_initials[4];
|
|
struct highscore_t highscore_table[MAX_HS_GAMES];
|
|
uint32 checksum;
|
|
} highscores;
|
|
|
|
|
|
// -----------------------------------------------------
|
|
// A single score entry and high-score line to edit...
|
|
// -----------------------------------------------------
|
|
struct score_t score_entry;
|
|
char hs_line[33];
|
|
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// Run through the entire highscores data and get a checksum. Mostly to make sure
|
|
// that it hasn't been tampered with or corrupted on disk.
|
|
// ------------------------------------------------------------------------------------
|
|
uint32 highscore_checksum(void)
|
|
{
|
|
char *ptr = (char *)&highscores;
|
|
uint32 sum = 0;
|
|
|
|
for (int i=0; i<(int)sizeof(highscores) - 4; i++)
|
|
{
|
|
sum = *ptr++;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Read the high score file, if it exists. If it doesn't exist or if the file
|
|
// is not the right version and/or is corrupt (crc check), reset to defaults.
|
|
// ------------------------------------------------------------------------------
|
|
void highscore_init(void)
|
|
{
|
|
bool create_defaults = 0;
|
|
FILE *fp;
|
|
|
|
strcpy(highscores.last_initials, " ");
|
|
|
|
// --------------------------------------------------------------
|
|
// See if the NINTV-DS high score file exists... if so, read it!
|
|
// --------------------------------------------------------------
|
|
fp = fopen("/data/NINTV-DS.hi", "rb");
|
|
if (fp != NULL)
|
|
{
|
|
fread(&highscores, sizeof(highscores), 1, fp);
|
|
fclose(fp);
|
|
|
|
// --------------------------------------------
|
|
// If the high score version is wrong or if
|
|
// the checksum is wrong, reset to defaults
|
|
// --------------------------------------------
|
|
if (highscores.version == 0x0002)
|
|
{
|
|
highscore_save(); // Just convert to V3
|
|
}
|
|
else
|
|
{
|
|
if (highscores.version != HS_VERSION) create_defaults = 1;
|
|
if (highscore_checksum() != highscores.checksum) create_defaults = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
create_defaults = 1;
|
|
}
|
|
|
|
if (create_defaults) // Doesn't exist yet or is invalid... create defaults and save it...
|
|
{
|
|
strcpy(highscores.last_initials, " ");
|
|
|
|
for (int i=0; i<MAX_HS_GAMES; i++)
|
|
{
|
|
highscores.highscore_table[i].crc = 0x00000000;
|
|
strcpy(highscores.highscore_table[i].notes, " ");
|
|
highscores.highscore_table[i].options = 0x0000;
|
|
for (int j=0; j<10; j++)
|
|
{
|
|
strcpy(highscores.highscore_table[i].scores[j].score, "000000");
|
|
strcpy(highscores.highscore_table[i].scores[j].initials, " ");
|
|
strcpy(highscores.highscore_table[i].scores[j].reserved, " ");
|
|
highscores.highscore_table[i].scores[j].year = 0;
|
|
highscores.highscore_table[i].scores[j].month = 0;
|
|
highscores.highscore_table[i].scores[j].day = 0;
|
|
}
|
|
}
|
|
highscore_save();
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
// Save the high score file to disc. This gets saved in the /data directory and this
|
|
// directory is created if it doesn't exist (mostly likely does if using TWL++)
|
|
// ------------------------------------------------------------------------------------
|
|
void highscore_save(void)
|
|
{
|
|
FILE *fp;
|
|
|
|
DIR* dir = opendir("/data");
|
|
if (dir)
|
|
{
|
|
closedir(dir); // Directory exists... close it out and move on.
|
|
}
|
|
else
|
|
{
|
|
mkdir("/data", 0777); // Otherwise create the directory...
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// Set our current highscore file version and checksum...
|
|
// --------------------------------------------------------
|
|
highscores.version = HS_VERSION;
|
|
highscores.checksum = highscore_checksum();
|
|
|
|
// -------------------------------------------------------
|
|
// Open file in binary mode... overwrite if it exists...
|
|
// -------------------------------------------------------
|
|
fp = fopen("/data/NINTV-DS.hi", "wb+");
|
|
if (fp != NULL)
|
|
{
|
|
// -----------------------------------------
|
|
// And write the whole shebang!
|
|
// -----------------------------------------
|
|
fwrite(&highscores, sizeof(highscores), 1, fp);
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
// We provide 4 different sorting options... show them for the user...
|
|
// Note: the default is high-to-low which does to show clarification text.
|
|
// ------------------------------------------------------------------------
|
|
void highscore_showoptions(uint16 options)
|
|
{
|
|
if ((options & HS_OPT_SORTMASK) == HS_OPT_SORTLOW)
|
|
{
|
|
dsPrintValue(22,3,0, (char*)"[LOWSC]");
|
|
}
|
|
else if ((options & HS_OPT_SORTMASK) == HS_OPT_SORTTIME)
|
|
{
|
|
dsPrintValue(22,3,0, (char*)"[TIME] ");
|
|
}
|
|
else if ((options & HS_OPT_SORTMASK) == HS_OPT_SORTASCII)
|
|
{
|
|
dsPrintValue(22,3,0, (char*)"[ALPHA]");
|
|
}
|
|
else
|
|
{
|
|
dsPrintValue(22,3,0, (char*)" ");
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------
|
|
// Show the 10 scores for this game...
|
|
// -----------------------------------------------------
|
|
void show_scores(short foundIdx, bool bShowLegend)
|
|
{
|
|
dsPrintValue(3,3,0, (char*)highscores.highscore_table[foundIdx].notes);
|
|
for (int i=0; i<10; i++)
|
|
{
|
|
if ((highscores.highscore_table[foundIdx].options & HS_OPT_SORTMASK) == HS_OPT_SORTTIME)
|
|
{
|
|
sprintf(hs_line, "%04d-%02d-%02d %-3s %c%c:%c%c.%c%c", highscores.highscore_table[foundIdx].scores[i].year, highscores.highscore_table[foundIdx].scores[i].month,highscores.highscore_table[foundIdx].scores[i].day,
|
|
highscores.highscore_table[foundIdx].scores[i].initials, highscores.highscore_table[foundIdx].scores[i].score[0], highscores.highscore_table[foundIdx].scores[i].score[1],
|
|
highscores.highscore_table[foundIdx].scores[i].score[2], highscores.highscore_table[foundIdx].scores[i].score[3], highscores.highscore_table[foundIdx].scores[i].score[4],
|
|
highscores.highscore_table[foundIdx].scores[i].score[5]);
|
|
}
|
|
else
|
|
{
|
|
sprintf(hs_line, "%04d-%02d-%02d %-3s %-6s ", highscores.highscore_table[foundIdx].scores[i].year, highscores.highscore_table[foundIdx].scores[i].month,highscores.highscore_table[foundIdx].scores[i].day,
|
|
highscores.highscore_table[foundIdx].scores[i].initials, highscores.highscore_table[foundIdx].scores[i].score);
|
|
}
|
|
dsPrintValue(3,4+i, 0, hs_line);
|
|
}
|
|
|
|
if (bShowLegend)
|
|
{
|
|
dsPrintValue(3,14,0, (char*)" ");
|
|
dsPrintValue(3,17,0, (char*)"PRESS X FOR NEW HI SCORE ");
|
|
dsPrintValue(3,18,0, (char*)"PRESS Y FOR NOTES/OPTIONS ");
|
|
dsPrintValue(3,19,0, (char*)"PRESS B TO EXIT ");
|
|
dsPrintValue(3,20,0, (char*)"SCORES AUTO SORT AFTER ENTRY ");
|
|
}
|
|
highscore_showoptions(highscores.highscore_table[foundIdx].options);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// We need to sort the scores according to the sorting options. We are using a
|
|
// very simple bubblesort which is very slow but with only 10 scores, this is
|
|
// still blazingly fast on the NDS.
|
|
// -------------------------------------------------------------------------------
|
|
char cmp1[21];
|
|
char cmp2[21];
|
|
void highscore_sort(short foundIdx)
|
|
{
|
|
// Bubblesort!!
|
|
for (int i=0; i<9; i++)
|
|
{
|
|
for (int j=0; j<9; j++)
|
|
{
|
|
if (((highscores.highscore_table[foundIdx].options & HS_OPT_SORTMASK) == HS_OPT_SORTLOW) || ((highscores.highscore_table[foundIdx].options & HS_OPT_SORTMASK) == HS_OPT_SORTTIME))
|
|
{
|
|
if (strcmp(highscores.highscore_table[foundIdx].scores[j+1].score, "000000") == 0)
|
|
strcpy(cmp1, "999999");
|
|
else
|
|
strcpy(cmp1, highscores.highscore_table[foundIdx].scores[j+1].score);
|
|
if (strcmp(highscores.highscore_table[foundIdx].scores[j].score, "000000") == 0)
|
|
strcpy(cmp2, "999999");
|
|
else
|
|
strcpy(cmp2, highscores.highscore_table[foundIdx].scores[j].score);
|
|
if (strcmp(cmp1, cmp2) < 0)
|
|
{
|
|
// Swap...
|
|
memcpy(&score_entry, &highscores.highscore_table[foundIdx].scores[j], sizeof(score_entry));
|
|
memcpy(&highscores.highscore_table[foundIdx].scores[j], &highscores.highscore_table[foundIdx].scores[j+1], sizeof(score_entry));
|
|
memcpy(&highscores.highscore_table[foundIdx].scores[j+1], &score_entry, sizeof(score_entry));
|
|
}
|
|
}
|
|
else if ((highscores.highscore_table[foundIdx].options & HS_OPT_SORTMASK) == HS_OPT_SORTASCII)
|
|
{
|
|
if (strcmp(highscores.highscore_table[foundIdx].scores[j+1].score, "000000") == 0)
|
|
strcpy(cmp1, "------");
|
|
else
|
|
strcpy(cmp1, highscores.highscore_table[foundIdx].scores[j+1].score);
|
|
if (strcmp(highscores.highscore_table[foundIdx].scores[j].score, "000000") == 0)
|
|
strcpy(cmp2, "------");
|
|
else
|
|
strcpy(cmp2, highscores.highscore_table[foundIdx].scores[j].score);
|
|
|
|
if (strcmp(cmp1, cmp2) > 0)
|
|
{
|
|
// Swap...
|
|
memcpy(&score_entry, &highscores.highscore_table[foundIdx].scores[j], sizeof(score_entry));
|
|
memcpy(&highscores.highscore_table[foundIdx].scores[j], &highscores.highscore_table[foundIdx].scores[j+1], sizeof(score_entry));
|
|
memcpy(&highscores.highscore_table[foundIdx].scores[j+1], &score_entry, sizeof(score_entry));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(highscores.highscore_table[foundIdx].scores[j+1].score, highscores.highscore_table[foundIdx].scores[j].score) > 0)
|
|
{
|
|
// Swap...
|
|
memcpy(&score_entry, &highscores.highscore_table[foundIdx].scores[j], sizeof(score_entry));
|
|
memcpy(&highscores.highscore_table[foundIdx].scores[j], &highscores.highscore_table[foundIdx].scores[j+1], sizeof(score_entry));
|
|
memcpy(&highscores.highscore_table[foundIdx].scores[j+1], &score_entry, sizeof(score_entry));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Let the user enter a new highscore. We look for up/down and other entry
|
|
// keys and show the new score on the screen. This is old-school up/down to
|
|
// "dial-in" the score by moving from digit to digit. Much like the Arcade.
|
|
// -------------------------------------------------------------------------
|
|
void highscore_entry(short foundIdx, UINT32 crc)
|
|
{
|
|
char bEntryDone = 0;
|
|
char blink=0;
|
|
unsigned short entry_idx=0;
|
|
char dampen=0;
|
|
time_t unixTime = time(NULL);
|
|
struct tm* timeStruct = gmtime((const time_t *)&unixTime);
|
|
|
|
dsPrintValue(3,17,0, (char*)"UP/DN/LEFT/RIGHT ENTER SCORE");
|
|
dsPrintValue(3,18,0, (char*)"PRESS START TO SAVE SCORE ");
|
|
dsPrintValue(3,19,0, (char*)"PRESS SELECT TO CANCEL ");
|
|
dsPrintValue(3,20,0, (char*)" ");
|
|
|
|
strcpy(score_entry.score, "000000");
|
|
strcpy(score_entry.initials, highscores.last_initials);
|
|
score_entry.year = timeStruct->tm_year +1900;
|
|
score_entry.month = timeStruct->tm_mon+1;
|
|
score_entry.day = timeStruct->tm_mday;
|
|
while (!bEntryDone)
|
|
{
|
|
swiWaitForVBlank();
|
|
if (keysCurrent() & KEY_SELECT) {bEntryDone=1;}
|
|
|
|
if (keysCurrent() & KEY_START)
|
|
{
|
|
strcpy(highscores.last_initials, score_entry.initials);
|
|
memcpy(&highscores.highscore_table[foundIdx].scores[9], &score_entry, sizeof(score_entry));
|
|
highscores.highscore_table[foundIdx].crc = crc;
|
|
highscore_sort(foundIdx);
|
|
highscore_save();
|
|
bEntryDone=1;
|
|
}
|
|
|
|
if (dampen == 0)
|
|
{
|
|
if ((keysCurrent() & KEY_RIGHT) || (keysCurrent() & KEY_A))
|
|
{
|
|
if (entry_idx < 8) entry_idx++;
|
|
blink=25;
|
|
dampen=15;
|
|
}
|
|
|
|
if (keysCurrent() & KEY_LEFT)
|
|
{
|
|
if (entry_idx > 0) entry_idx--;
|
|
blink=25;
|
|
dampen=15;
|
|
}
|
|
|
|
if (keysCurrent() & KEY_UP)
|
|
{
|
|
if (entry_idx < 3) // This is the initials
|
|
{
|
|
if (score_entry.initials[entry_idx] == ' ')
|
|
score_entry.initials[entry_idx] = 'A';
|
|
else if (score_entry.initials[entry_idx] == 'Z')
|
|
score_entry.initials[entry_idx] = ' ';
|
|
else score_entry.initials[entry_idx]++;
|
|
}
|
|
else // This is the score...
|
|
{
|
|
if ((highscores.highscore_table[foundIdx].options & HS_OPT_SORTMASK) == HS_OPT_SORTASCII)
|
|
{
|
|
if (score_entry.score[entry_idx-3] == ' ')
|
|
score_entry.score[entry_idx-3] = 'A';
|
|
else if (score_entry.score[entry_idx-3] == 'Z')
|
|
score_entry.score[entry_idx-3] = '0';
|
|
else if (score_entry.score[entry_idx-3] == '9')
|
|
score_entry.score[entry_idx-3] = ' ';
|
|
else score_entry.score[entry_idx-3]++;
|
|
}
|
|
else
|
|
{
|
|
score_entry.score[entry_idx-3]++;
|
|
if (score_entry.score[entry_idx-3] > '9') score_entry.score[entry_idx-3] = '0';
|
|
}
|
|
}
|
|
blink=0;
|
|
dampen=10;
|
|
}
|
|
|
|
if (keysCurrent() & KEY_DOWN)
|
|
{
|
|
if (entry_idx < 3) // // This is the initials
|
|
{
|
|
if (score_entry.initials[entry_idx] == ' ')
|
|
score_entry.initials[entry_idx] = 'Z';
|
|
else if (score_entry.initials[entry_idx] == 'A')
|
|
score_entry.initials[entry_idx] = ' ';
|
|
else score_entry.initials[entry_idx]--;
|
|
}
|
|
else // This is the score...
|
|
{
|
|
if ((highscores.highscore_table[foundIdx].options & HS_OPT_SORTMASK) == HS_OPT_SORTASCII)
|
|
{
|
|
if (score_entry.score[entry_idx-3] == ' ')
|
|
score_entry.score[entry_idx-3] = '9';
|
|
else if (score_entry.score[entry_idx-3] == '0')
|
|
score_entry.score[entry_idx-3] = 'Z';
|
|
else if (score_entry.score[entry_idx-3] == 'A')
|
|
score_entry.score[entry_idx-3] = ' ';
|
|
else score_entry.score[entry_idx-3]--;
|
|
}
|
|
else
|
|
{
|
|
score_entry.score[entry_idx-3]--;
|
|
if (score_entry.score[entry_idx-3] < '0') score_entry.score[entry_idx-3] = '9';
|
|
}
|
|
}
|
|
blink=0;
|
|
dampen=10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dampen--;
|
|
}
|
|
|
|
sprintf(hs_line, "%04d-%02d-%02d %-3s %-6s", score_entry.year, score_entry.month, score_entry.day, score_entry.initials, score_entry.score);
|
|
if ((++blink % 60) > 30)
|
|
{
|
|
if (entry_idx < 3)
|
|
hs_line[13+entry_idx] = '_';
|
|
else
|
|
hs_line[16+entry_idx] = '_';
|
|
}
|
|
dsPrintValue(3,14, 0, (char*)hs_line);
|
|
}
|
|
|
|
show_scores(foundIdx, true);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Let the user enter options and notes for the current game...
|
|
// ----------------------------------------------------------------
|
|
void highscore_options(short foundIdx, UINT32 crc)
|
|
{
|
|
uint16 options = 0x0000;
|
|
char notes[21];
|
|
char bEntryDone = 0;
|
|
char blink=0;
|
|
unsigned short entry_idx=0;
|
|
char dampen=0;
|
|
|
|
dsPrintValue(3,14,0, (char*)"NOTE: ");
|
|
dsPrintValue(3,17,0, (char*)"UP/DN/LEFT/RIGHT ENTER NOTES");
|
|
dsPrintValue(3,18,0, (char*)"X=TOGGLE SORT, L+R=CLR SCORE");
|
|
dsPrintValue(3,19,0, (char*)"PRESS START TO SAVE OPTIONS ");
|
|
dsPrintValue(3,20,0, (char*)"PRESS SELECT TO CANCEL ");
|
|
|
|
strcpy(notes, highscores.highscore_table[foundIdx].notes);
|
|
options = highscores.highscore_table[foundIdx].options;
|
|
|
|
while (!bEntryDone)
|
|
{
|
|
swiWaitForVBlank();
|
|
if (keysCurrent() & KEY_SELECT) {bEntryDone=1;}
|
|
|
|
if (keysCurrent() & KEY_START)
|
|
{
|
|
strcpy(highscores.highscore_table[foundIdx].notes, notes);
|
|
highscores.highscore_table[foundIdx].options = options;
|
|
highscores.highscore_table[foundIdx].crc = crc;
|
|
highscore_sort(foundIdx);
|
|
highscore_save();
|
|
bEntryDone=1;
|
|
}
|
|
|
|
if (dampen == 0)
|
|
{
|
|
if ((keysCurrent() & KEY_RIGHT) || (keysCurrent() & KEY_A))
|
|
{
|
|
if (entry_idx < 19) entry_idx++;
|
|
blink=25;
|
|
dampen=15;
|
|
}
|
|
|
|
if (keysCurrent() & KEY_LEFT)
|
|
{
|
|
if (entry_idx > 0) entry_idx--;
|
|
blink=25;
|
|
dampen=15;
|
|
}
|
|
|
|
if (keysCurrent() & KEY_UP)
|
|
{
|
|
if (notes[entry_idx] == ' ')
|
|
notes[entry_idx] = 'A';
|
|
else if (notes[entry_idx] == 'Z')
|
|
notes[entry_idx] = '0';
|
|
else if (notes[entry_idx] == '9')
|
|
notes[entry_idx] = ' ';
|
|
else notes[entry_idx]++;
|
|
blink=0;
|
|
dampen=10;
|
|
}
|
|
|
|
if (keysCurrent() & KEY_DOWN)
|
|
{
|
|
if (notes[entry_idx] == ' ')
|
|
notes[entry_idx] = '9';
|
|
else if (notes[entry_idx] == '0')
|
|
notes[entry_idx] = 'Z';
|
|
else if (notes[entry_idx] == 'A')
|
|
notes[entry_idx] = ' ';
|
|
else notes[entry_idx]--;
|
|
blink=0;
|
|
dampen=10;
|
|
}
|
|
|
|
if (keysCurrent() & KEY_X)
|
|
{
|
|
if ((options & HS_OPT_SORTMASK) == HS_OPT_SORTLOW)
|
|
{
|
|
options &= (uint16)~HS_OPT_SORTMASK;
|
|
options |= HS_OPT_SORTTIME;
|
|
}
|
|
else if ((options & HS_OPT_SORTMASK) == HS_OPT_SORTTIME)
|
|
{
|
|
options &= (uint16)~HS_OPT_SORTMASK;
|
|
options |= HS_OPT_SORTASCII;
|
|
}
|
|
else if ((options & HS_OPT_SORTMASK) == HS_OPT_SORTASCII)
|
|
{
|
|
options &= (uint16)~HS_OPT_SORTMASK;
|
|
}
|
|
else
|
|
{
|
|
options |= (uint16)HS_OPT_SORTLOW;
|
|
}
|
|
highscore_showoptions(options);
|
|
dampen=15;
|
|
}
|
|
|
|
// Clear the entire game of scores...
|
|
if ((keysCurrent() & KEY_L) && (keysCurrent() & KEY_R))
|
|
{
|
|
highscores.highscore_table[foundIdx].crc = 0x00000000;
|
|
highscores.highscore_table[foundIdx].options = 0x0000;
|
|
strcpy(highscores.highscore_table[foundIdx].notes, " ");
|
|
strcpy(notes, " ");
|
|
for (int j=0; j<10; j++)
|
|
{
|
|
strcpy(highscores.highscore_table[foundIdx].scores[j].score, "000000");
|
|
strcpy(highscores.highscore_table[foundIdx].scores[j].initials, " ");
|
|
strcpy(highscores.highscore_table[foundIdx].scores[j].reserved, " ");
|
|
highscores.highscore_table[foundIdx].scores[j].year = 0;
|
|
highscores.highscore_table[foundIdx].scores[j].month = 0;
|
|
highscores.highscore_table[foundIdx].scores[j].day = 0;
|
|
}
|
|
show_scores(foundIdx, false);
|
|
highscore_save();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dampen--;
|
|
}
|
|
|
|
sprintf(hs_line, "%-20s", notes);
|
|
if ((++blink % 60) > 30)
|
|
{
|
|
hs_line[entry_idx] = '_';
|
|
}
|
|
dsPrintValue(9,14, 0, (char*)hs_line);
|
|
}
|
|
|
|
show_scores(foundIdx, true);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Entry point for the high score table. We are passed in the crc of the
|
|
// current game. We use the crc to check the high score database and see
|
|
// if there is already saved highscore data for this game. At the point
|
|
// where this is called, the high score init has already been called.
|
|
// ------------------------------------------------------------------------
|
|
void highscore_display(UINT32 crc)
|
|
{
|
|
short foundIdx = -1;
|
|
short firstBlank = -1;
|
|
char bDone = 0;
|
|
|
|
dsShowBannerScreen();
|
|
swiWaitForVBlank();
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
// Check if the current CRC32 is in our High Score database...
|
|
// ---------------------------------------------------------------------------------
|
|
for (int i=0; i<MAX_HS_GAMES; i++)
|
|
{
|
|
if (firstBlank == -1)
|
|
{
|
|
if ((highscores.highscore_table[i].crc) == 0)
|
|
{
|
|
firstBlank = i;
|
|
}
|
|
}
|
|
|
|
if (highscores.highscore_table[i].crc == crc)
|
|
{
|
|
foundIdx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (foundIdx == -1)
|
|
{
|
|
foundIdx = firstBlank;
|
|
}
|
|
|
|
show_scores(foundIdx, true);
|
|
|
|
while (!bDone)
|
|
{
|
|
if (keysCurrent() & KEY_A) bDone=1;
|
|
if (keysCurrent() & KEY_B) bDone=1;
|
|
if (keysCurrent() & KEY_X) highscore_entry(foundIdx, crc);
|
|
if (keysCurrent() & KEY_Y) highscore_options(foundIdx, crc);
|
|
}
|
|
}
|
|
|
|
|
|
// End of file
|