Finish reworking the network high score code to be independent of BuGS itself so it can be put into its own library.

This commit is contained in:
Jeremy Rand 2023-06-11 22:51:21 -04:00
parent 2f53df9eb0
commit 6afbf4eb85
8 changed files with 247 additions and 150 deletions

View File

@ -224,53 +224,53 @@ _dirtyNonGameTile_skip&SYSCNT anop
macro
_globalHighScoreRow &nthScore
ldy #2+&nthScore*SETTINGS_HIGH_SCORE_SIZE
lda highScoreResponse,y
ldy #&nthScore*SETTINGS_HIGH_SCORE_SIZE
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
@ -278,17 +278,17 @@ _dirtyNonGameTile_skip&SYSCNT anop
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
iny
lda highScoreResponse,y
lda globalHighScores,y
jsl asciiToTileType
jsl setGameTile
mend

View File

@ -195,7 +195,6 @@ collisionAddr dc i2'0'
numSegments dc i2'0'
displayGlobalHighScores dc i2'0'
shouldQuit dc i2'1'
scoreIndex dc i2'0'
tileJumpTable dc a4'solid0'

View File

@ -26,6 +26,8 @@
/* Defines and macros */
#define GLOBAL_SCORE_REFRESH_TIME (15 * 60 * 60)
#define TOOLFAIL(string) \
if (toolerror()) SysFailMgr(toolerror(), (Pointer)"\p" string "\n\r Error Code -> $");
@ -38,6 +40,11 @@ unsigned int randomSeed;
// This symbol is used also from assembly directly so be careful with it...
char globalScoreInfo[GAME_NUM_TILES_WIDE + 1];
tNSGSHighScores globalHighScores;
Boolean hasGlobalHighScores = FALSE;
Word globalScoreAge = 0;
unsigned int scoreIndex = 0;
/* Implementation */
@ -50,7 +57,7 @@ word randomMushroomOffset(void)
}
void uploadSpin(int val)
static void uploadSpin(int val)
{
switch (val)
{
@ -73,7 +80,7 @@ void uploadSpin(int val)
}
void scorePosition(unsigned int position, unsigned int numberOfScores)
static void scorePosition(unsigned int position, unsigned int numberOfScores)
{
int i;
@ -87,16 +94,118 @@ void scorePosition(unsigned int position, unsigned int numberOfScores)
for (i = 6 * 60; i > 0; i--) {
waitForVbl();
}
globalScoreAge = 0;
}
void showConnectionString(BOOLEAN display)
static void showConnectionString(BOOLEAN display)
{
if (display)
displayConnectionString();
}
static char hexDigitToAscii(Word digit)
{
digit &= 0xf;
if (digit < 10)
return '0' + digit;
if (digit > 15)
return 'X';
return 'A' + digit - 10;
}
static void displayString(Word row, char * string)
{
strcpy(&(globalHighScores.score[row].scoreText[2]), string);
}
static void displayNetworkError(char * line1, char * line2, unsigned int errorCode)
{
Word row;
Word column;
for (row = 0; row < sizeof(globalHighScores.score) / sizeof(globalHighScores.score[0]); row++) {
for (column = 0;
column < sizeof(globalHighScores.score[0].scoreText) / sizeof(globalHighScores.score[0].scoreText[0]);
column++) {
globalHighScores.score[row].scoreText[column] = ' ';
}
for (column = 0;
column < sizeof(globalHighScores.score[0].who) / sizeof(globalHighScores.score[0].who[0]);
column++) {
globalHighScores.score[row].who[column] = ' ';
}
}
displayString(1, "NETWORK");
displayString(2, "PROBLEM");
displayString(4, line1);
displayString(5, line2);
globalHighScores.score[7].scoreText[0] = 'C';
globalHighScores.score[7].scoreText[1] = 'O';
globalHighScores.score[7].scoreText[2] = 'D';
globalHighScores.score[7].scoreText[3] = 'E';
globalHighScores.score[7].scoreText[4] = ':';
globalHighScores.score[7].scoreText[5] = ' ';
globalHighScores.score[7].scoreText[6] = hexDigitToAscii(errorCode >> 12);
globalHighScores.score[7].scoreText[7] = hexDigitToAscii(errorCode >> 8);
globalHighScores.score[7].scoreText[8] = hexDigitToAscii(errorCode >> 4);
globalHighScores.score[7].scoreText[9] = hexDigitToAscii(errorCode);
hasGlobalHighScores = TRUE;
globalScoreAge = 0;
}
static void displayError(tNSGSErrorType errorType, unsigned int errorCode)
{
switch (errorType) {
case NSGS_CONNECT_ERROR:
displayNetworkError("CONNECT", "FAILED", errorCode);
break;
case NSGS_LOOKUP_ERROR:
displayNetworkError("LOOKUP", "FAILED", errorCode);
break;
case NSGS_SOCKET_ERROR:
displayNetworkError("SOCKET", "ERROR", errorCode);
break;
case NSGS_PROTOCOL_ERROR:
displayNetworkError("PROTOCOL", "FAILED", errorCode);
break;
}
}
static void setHighScores(const tNSGSHighScores * highScores)
{
memcpy(&globalHighScores, highScores, sizeof(globalHighScores));
hasGlobalHighScores = TRUE;
globalScoreAge = GLOBAL_SCORE_REFRESH_TIME;
}
static BOOLEAN shouldRefreshHighScores(void)
{
return globalScoreAge == 0;
}
BOOLEAN sendHighScore(void)
{
const tNSGSHighScore * highScore = getHighScore(scoreIndex / sizeof(tNSGSHighScore));
return NSGS_SendHighScore(highScore->who, highScore->score);
}
int main(void)
{
static tNSGSHighScoreInitParams highScoreInitParams;
@ -137,6 +246,8 @@ int main(void)
highScoreInitParams.waitForVbl = waitForVbl;
highScoreInitParams.uploadSpin = uploadSpin;
highScoreInitParams.scorePosition = scorePosition;
highScoreInitParams.displayError = displayError;
highScoreInitParams.setHighScores = setHighScores;
NSGS_InitNetwork(&highScoreInitParams);

View File

@ -29,7 +29,6 @@
#define RESPONSE_TYPE_SCORES 1
#define RESPONSE_TYPE_STATUS 2
#define GLOBAL_SCORE_REFRESH_TIME (15 * 60 * 60)
#define SHUTDOWN_NETWORK_TIMEOUT (2 * 60)
#define TCP_CONNECT_TIMEOUT (8 * 60)
#define READ_NETWORK_TIMEOUT (5 * 60)
@ -89,21 +88,6 @@ typedef struct tStatusResponse {
} tStatusResponse;
typedef enum tProtocolErrors {
TCP_CONNECT_TIMEOUT_ERROR = 1,
HELLO_TIMEOUT_ERROR,
HELLO_TOO_BIG_ERROR,
HELLO_UNEXPECTED_RESPONSE_ERROR,
HIGH_SCORE_TIMEOUT_ERROR,
HIGH_SCORE_TOO_BIG_ERROR,
HIGH_SCORE_UNEXPECTED_RESPONSE_ERROR,
SET_SCORE_TIMEOUT_ERROR,
SET_SCORE_TOO_BIG_ERROR,
SET_SCORE_UNEXPECTED_RESPONSE_ERROR,
SET_SCORE_FAILED_ERROR,
} tProtocolErrors;
typedef enum tGameNetworkState {
GAME_NETWORK_CONNECT_FAILED = 0,
GAME_NETWORK_UNCONNECTED,
@ -155,10 +139,13 @@ typedef struct tGameNetworkGlobals {
md5WorkBlock hashWorkBlock;
uint32_t secrets[3];
tHighScoreRequestWithHash highScoreRequest;
tScoresResponse highScoreResponse;
Boolean hasHighScoreToSend;
tSetHighScoreRequestWithHash setHighScoreRequest;
tStatusResponse setHighScoreResponse;
uint16_t errorCode;
uint16_t timeout;
Boolean hasGlobalHighScores;
} tGameNetworkGlobals;
// Forward declarations
@ -216,14 +203,6 @@ static tGameNetworkStateHandler handlers[NUM_GAME_NETWORK_STATES] = {
// detected.
static tGameNetworkGlobals * networkGlobals = NULL;
// The following globals are accessed by name from assembly so are not in the
// tGameNetworkGlobals structure.
// TODO - Make real interfaces for these things.
Boolean hasGlobalHighScores = FALSE;
tScoresResponse highScoreResponse;
Word globalScoreAge = 0; // TODO - Replace this with a call to a MiscTool function?
tSetHighScoreRequestWithHash setHighScoreRequest;
// Implementation
@ -284,8 +263,9 @@ void NSGS_InitNetwork(tNSGSHighScoreInitParams * params)
networkGlobals->secrets[1] = params->secret2;
networkGlobals->hasHighScoreToSend = FALSE;
networkGlobals->hasGlobalHighScores = FALSE;
setHighScoreRequest.setHighScoreRequest.is60Hz = !ReadBParam(hrtz50or60);
networkGlobals->setHighScoreRequest.setHighScoreRequest.is60Hz = !ReadBParam(hrtz50or60);
}
@ -324,76 +304,21 @@ void NSGS_DisconnectNetwork(void)
networkGlobals->timeout = SHUTDOWN_NETWORK_TIMEOUT;
}
while (networkGlobals->gameNetworkState > GAME_NETWORK_TCP_UNCONNECTED) {
networkGlobals->initParams.waitForVbl();
NSGS_PollNetwork();
}
}
while ((networkGlobals->gameNetworkState != GAME_NETWORK_TCP_UNCONNECTED) &&
(networkGlobals->gameNetworkState != GAME_NETWORK_FAILURE)) {
networkGlobals->initParams.waitForVbl();
NSGS_PollNetwork();
}
}
static char hexDigitToAscii(Word digit)
{
digit &= 0xf;
if (digit < 10)
return '0' + digit;
if (digit > 15)
return 'X';
return 'A' + digit - 10;
}
static void displayString(Word row, char * string)
{
strcpy(&(highScoreResponse.highScores.score[row].scoreText[2]), string);
}
static void displayNetworkError(char * line1, char * line2)
{
Word row;
Word column;
networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE;
for (row = 0; row < sizeof(highScoreResponse.highScores) / sizeof(highScoreResponse.highScores.score[0]); row++) {
for (column = 0;
column < sizeof(highScoreResponse.highScores.score[0].scoreText) / sizeof(highScoreResponse.highScores.score[0].scoreText[0]);
column++) {
highScoreResponse.highScores.score[row].scoreText[column] = ' ';
}
for (column = 0;
column < sizeof(highScoreResponse.highScores.score[0].who) / sizeof(highScoreResponse.highScores.score[0].who[0]);
column++) {
highScoreResponse.highScores.score[row].who[column] = ' ';
}
}
displayString(1, "NETWORK");
displayString(2, "PROBLEM");
displayString(4, line1);
displayString(5, line2);
highScoreResponse.highScores.score[7].scoreText[0] = 'C';
highScoreResponse.highScores.score[7].scoreText[1] = 'O';
highScoreResponse.highScores.score[7].scoreText[2] = 'D';
highScoreResponse.highScores.score[7].scoreText[3] = 'E';
highScoreResponse.highScores.score[7].scoreText[4] = ':';
highScoreResponse.highScores.score[7].scoreText[5] = ' ';
highScoreResponse.highScores.score[7].scoreText[6] = hexDigitToAscii(networkGlobals->errorCode >> 12);
highScoreResponse.highScores.score[7].scoreText[7] = hexDigitToAscii(networkGlobals->errorCode >> 8);
highScoreResponse.highScores.score[7].scoreText[8] = hexDigitToAscii(networkGlobals->errorCode >> 4);
highScoreResponse.highScores.score[7].scoreText[9] = hexDigitToAscii(networkGlobals->errorCode);
globalScoreAge = 0;
hasGlobalHighScores = TRUE;
}
static void handleConnectFailed(void)
{
displayNetworkError("CONNECT", "FAILED");
if (networkGlobals->initParams.displayError != NULL)
networkGlobals->initParams.displayError(NSGS_CONNECT_ERROR, networkGlobals->errorCode);
networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE;
}
static void handleUnconnected(void)
@ -406,6 +331,7 @@ static void handleUnconnected(void)
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECTED;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECT_FAILED;
networkGlobals->errorCode = toolerror();
}
if (networkGlobals->initParams.displayConnectionString != NULL)
networkGlobals->initParams.displayConnectionString(FALSE);
@ -437,19 +363,25 @@ static void handleResolvingName(void)
static void handleLookupFailed(void)
{
displayNetworkError("LOOKUP", "FAILED");
if (networkGlobals->initParams.displayError != NULL)
networkGlobals->initParams.displayError(NSGS_LOOKUP_ERROR, networkGlobals->errorCode);
networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE;
}
static void handleSocketError(void)
{
displayNetworkError("SOCKET", "ERROR");
if (networkGlobals->initParams.displayError != NULL)
networkGlobals->initParams.displayError(NSGS_SOCKET_ERROR, networkGlobals->errorCode);
networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE;
networkGlobals->timeout = NETWORK_RETRY_TIMEOUT;
}
static void handleProtocolFailed(void)
{
abortConnection();
displayNetworkError("PROTOCOL", "FAILED");
if (networkGlobals->initParams.displayError != NULL)
networkGlobals->initParams.displayError(NSGS_PROTOCOL_ERROR, networkGlobals->errorCode);
networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE;
networkGlobals->timeout = NETWORK_RETRY_TIMEOUT;
}
@ -466,10 +398,14 @@ static void handleFailure(void)
static void handleTcpUnconnected(void)
{
if ((hasGlobalHighScores) &&
(globalScoreAge > 0) &&
(!networkGlobals->hasHighScoreToSend))
return;
if ((networkGlobals->hasGlobalHighScores) &&
(!networkGlobals->hasHighScoreToSend)) {
if (networkGlobals->initParams.shouldRefreshHighScores == NULL)
return;
if (!networkGlobals->initParams.shouldRefreshHighScores())
return;
}
networkGlobals->ipid = TCPIPLogin(networkGlobals->initParams.userId, networkGlobals->domainNameResolution.DNRIPaddress, networkGlobals->initParams.scorePort, 0, 64);
if (toolerror()) {
@ -502,7 +438,7 @@ static void handleWaitingForTcp(void)
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = TCP_CONNECT_TIMEOUT_ERROR;
networkGlobals->errorCode = NSGS_TCP_CONNECT_TIMEOUT_ERROR;
}
return;
}
@ -537,28 +473,29 @@ static void handleWaitingForHello(void)
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HELLO_TIMEOUT_ERROR;
networkGlobals->errorCode = NSGS_HELLO_TIMEOUT_ERROR;
}
return;
}
if (networkGlobals->bytesRead > sizeof(networkGlobals->helloResponse)) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HELLO_TOO_BIG_ERROR;
networkGlobals->errorCode = NSGS_HELLO_TOO_BIG_ERROR;
return;
}
if (networkGlobals->helloResponse.responseType != RESPONSE_TYPE_HELLO) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HELLO_UNEXPECTED_RESPONSE_ERROR;
networkGlobals->errorCode = NSGS_HELLO_UNEXPECTED_RESPONSE_ERROR;
return;
}
networkGlobals->secrets[2] = networkGlobals->helloResponse.nonce;
if (networkGlobals->hasHighScoreToSend) {
networkGlobals->gameNetworkState = GAME_NETWORK_SET_HIGH_SCORE;
} else if ((!hasGlobalHighScores) ||
(globalScoreAge == 0)) {
} else if ((!networkGlobals->hasGlobalHighScores) ||
((networkGlobals->initParams.shouldRefreshHighScores != NULL) &&
(networkGlobals->initParams.shouldRefreshHighScores()))) {
networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES;
} else {
TCPIPCloseTCP(networkGlobals->ipid);
@ -591,8 +528,8 @@ static void handleRequestScores(void)
static void handleWaitingForScores(void)
{
networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0,
((uint32_t)(&highScoreResponse)) + networkGlobals->bytesRead,
sizeof(highScoreResponse) - networkGlobals->bytesRead,
((uint32_t)(&networkGlobals->highScoreResponse)) + networkGlobals->bytesRead,
sizeof(networkGlobals->highScoreResponse) - networkGlobals->bytesRead,
&(networkGlobals->readResponseBuf));
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
@ -601,30 +538,31 @@ static void handleWaitingForScores(void)
}
networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount;
if (networkGlobals->bytesRead < sizeof(highScoreResponse)) {
if (networkGlobals->bytesRead < sizeof(networkGlobals->highScoreResponse)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HIGH_SCORE_TIMEOUT_ERROR;
networkGlobals->errorCode = NSGS_HIGH_SCORE_TIMEOUT_ERROR;
}
return;
}
if (networkGlobals->bytesRead > sizeof(highScoreResponse)) {
if (networkGlobals->bytesRead > sizeof(networkGlobals->highScoreResponse)) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HIGH_SCORE_TOO_BIG_ERROR;
networkGlobals->errorCode = NSGS_HIGH_SCORE_TOO_BIG_ERROR;
return;
}
if (highScoreResponse.responseType != RESPONSE_TYPE_SCORES) {
if (networkGlobals->highScoreResponse.responseType != RESPONSE_TYPE_SCORES) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HIGH_SCORE_UNEXPECTED_RESPONSE_ERROR;
networkGlobals->errorCode = NSGS_HIGH_SCORE_UNEXPECTED_RESPONSE_ERROR;
return;
}
globalScoreAge = GLOBAL_SCORE_REFRESH_TIME;
hasGlobalHighScores = TRUE;
networkGlobals->hasGlobalHighScores = TRUE;
if (networkGlobals->initParams.setHighScores != NULL)
networkGlobals->initParams.setHighScores(&(networkGlobals->highScoreResponse.highScores));
TCPIPCloseTCP(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP;
@ -633,15 +571,15 @@ static void handleWaitingForScores(void)
static void handleSetHighScore(void)
{
setHighScoreRequest.setHighScoreRequest.requestType = REQUEST_TYPE_SET_SCORE;
setHighScoreRequest.setHighScoreRequest.who[3] = '\0';
networkGlobals->setHighScoreRequest.setHighScoreRequest.requestType = REQUEST_TYPE_SET_SCORE;
networkGlobals->setHighScoreRequest.setHighScoreRequest.who[3] = '\0';
md5Init(&(networkGlobals->hashWorkBlock));
md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->secrets), sizeof(networkGlobals->secrets));
md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(setHighScoreRequest.setHighScoreRequest), sizeof(setHighScoreRequest.setHighScoreRequest));
md5Finish(&(networkGlobals->hashWorkBlock), (Pointer)&(setHighScoreRequest.md5Digest[0]));
md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->setHighScoreRequest.setHighScoreRequest), sizeof(networkGlobals->setHighScoreRequest.setHighScoreRequest));
md5Finish(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->setHighScoreRequest.md5Digest[0]));
networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&setHighScoreRequest, sizeof(setHighScoreRequest), FALSE, FALSE);
networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&(networkGlobals->setHighScoreRequest), sizeof(networkGlobals->setHighScoreRequest), FALSE, FALSE);
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
@ -671,31 +609,30 @@ static void handleWaitingForScoreAck(void)
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = SET_SCORE_TIMEOUT_ERROR;
networkGlobals->errorCode = NSGS_SET_SCORE_TIMEOUT_ERROR;
}
return;
}
if (networkGlobals->bytesRead > sizeof(networkGlobals->setHighScoreResponse)) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = SET_SCORE_TOO_BIG_ERROR;
networkGlobals->errorCode = NSGS_SET_SCORE_TOO_BIG_ERROR;
return;
}
if (networkGlobals->setHighScoreResponse.responseType != RESPONSE_TYPE_STATUS) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = SET_SCORE_UNEXPECTED_RESPONSE_ERROR;
networkGlobals->errorCode = NSGS_SET_SCORE_UNEXPECTED_RESPONSE_ERROR;
return;
}
if (!networkGlobals->setHighScoreResponse.success) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = SET_SCORE_FAILED_ERROR;
networkGlobals->errorCode = NSGS_SET_SCORE_FAILED_ERROR;
return;
}
networkGlobals->hasHighScoreToSend = FALSE;
globalScoreAge = 0;
networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES;
}
@ -744,11 +681,16 @@ BOOLEAN NSGS_CanSendHighScore(void)
return TRUE;
}
BOOLEAN NSGS_SendHighScore(void)
BOOLEAN NSGS_SendHighScore(const char * who, unsigned long score)
{
uint16_t cycleCount = 0;
if (strlen(who) != 3)
return FALSE;
networkGlobals->hasHighScoreToSend = TRUE;
memcpy(networkGlobals->setHighScoreRequest.setHighScoreRequest.who, who, sizeof(networkGlobals->setHighScoreRequest.setHighScoreRequest.who));
networkGlobals->setHighScoreRequest.setHighScoreRequest.score = score;
if (networkGlobals->gameNetworkState < GAME_NETWORK_TCP_UNCONNECTED)
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;

View File

@ -12,6 +12,29 @@
#include <TYPES.h>
typedef enum tNSGSErrorType
{
NSGS_CONNECT_ERROR,
NSGS_LOOKUP_ERROR,
NSGS_SOCKET_ERROR,
NSGS_PROTOCOL_ERROR
} tNSGSErrorType;
typedef enum ttNSGSProtocolErrors {
NSGS_TCP_CONNECT_TIMEOUT_ERROR = 1,
NSGS_HELLO_TIMEOUT_ERROR,
NSGS_HELLO_TOO_BIG_ERROR,
NSGS_HELLO_UNEXPECTED_RESPONSE_ERROR,
NSGS_HIGH_SCORE_TIMEOUT_ERROR,
NSGS_HIGH_SCORE_TOO_BIG_ERROR,
NSGS_HIGH_SCORE_UNEXPECTED_RESPONSE_ERROR,
NSGS_SET_SCORE_TIMEOUT_ERROR,
NSGS_SET_SCORE_TOO_BIG_ERROR,
NSGS_SET_SCORE_UNEXPECTED_RESPONSE_ERROR,
NSGS_SET_SCORE_FAILED_ERROR,
} ttNSGSProtocolErrors;
typedef struct tNSGSHighScore
{
@ -75,6 +98,22 @@ typedef struct tNSGSHighScoreInitParams
called by NSGS_SendHighScore().
*/
void (*scorePosition)(unsigned int position, unsigned int numberOfScores);
/* This function is only called from NSGS_PollNetwork() when something unexpected has occurred.
The meaning of the error code depends on the error type. For a protocol error, the error code
is one of tNSGSProtocolErrors. For other error codes, they come from Marinetti error codes.
if the error code > $8000, then the error code is the socket state or-ed with $8000. */
void (*displayError)(tNSGSErrorType errorType, unsigned int errorCode);
/* This function is only called from NSGS_PollNetwork() when new scores have been downloaded.
The scores passed should be copied because the pointer is not guaranteed to be valid after
the callback returns. */
void (*setHighScores)(const tNSGSHighScores * scores);
/* This function is called to ask if it is time to refresh the global high score list. This should
be based on watching the elapsed time and it should return true if say 5 minutes has elapsed
since high scores have been updated. */
BOOLEAN (*shouldRefreshHighScores)(void);
} tNSGSHighScoreInitParams;
@ -117,7 +156,7 @@ extern BOOLEAN NSGS_CanSendHighScore(void);
TODO - Pass the score as an argument rather than through globals.
*/
extern BOOLEAN NSGS_SendHighScore(void);
extern BOOLEAN NSGS_SendHighScore(const char * who, unsigned long score);
#endif /* define _GUARD_PROJECTNetScoresGS_FILEnetScores_ */

View File

@ -438,10 +438,8 @@ checkHighScore_doneCopy anop
tax
lda gameScore,x
sta settings+SETTINGS_HIGH_SCORE_OFFSET+HIGH_SCORE_SCORE_OFFSET,y
sta setHighScoreRequest+6
lda gameScore+2,x
sta settings+SETTINGS_HIGH_SCORE_OFFSET+HIGH_SCORE_SCORE_OFFSET+2,y
sta setHighScoreRequest+8
lda playerNum
cmp #PLAYER_ONE
@ -782,10 +780,6 @@ checkHighScore_isInvalid anop
checkHighScore_doneInitials anop
_overwriteGameTile TILE_EMPTY
lda settings+SETTINGS_HIGH_SCORE_OFFSET+HIGH_SCORE_WHO_OFFSET-3,y
sta setHighScoreRequest+2
lda settings+SETTINGS_HIGH_SCORE_OFFSET+HIGH_SCORE_WHO_OFFSET-1,y
sta setHighScoreRequest+4
jsl saveSettings
jsl NSGS_CanSendHighScore
bne checkHighScore_retry
@ -814,7 +808,7 @@ checkHighScore_retry anop
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
jsl NSGS_SendHighScore
jsl sendHighScore
beq checkHighScore_retryPrompt
brl checkHighScore_doneNetwork

View File

@ -69,6 +69,14 @@ static Handle filenameHandle = NULL;
segment "settings";
#endif
const tNSGSHighScore * getHighScore(unsigned int index)
{
if (index >= NUM_HIGH_SCORES)
return NULL;
return &(settings.highScores[index]);
}
static void allocateFilenameHandle(void)
{
if (filenameHandle == NULL)

View File

@ -12,11 +12,15 @@
#include <TYPES.h>
typedef struct tNSGSHighScore tNSGSHighScore;
extern unsigned int myUserId;
extern void saveSettings(void);
BOOLEAN loadSettings(void);
extern BOOLEAN loadSettings(void);
extern void swapStereoSettings(void);
extern const tNSGSHighScore * getHighScore(unsigned int index);
#endif /* define _GUARD_PROJECTBuGS_FILEsettings_ */