Compare commits

...

2 Commits

10 changed files with 208 additions and 55 deletions

View File

@ -116,7 +116,7 @@
9DE37B3E2694E0B0005FC562 /* globalScores.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = globalScores.h; sourceTree = "<group>"; };
9DE37B3F2694E0B0005FC562 /* globals.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = globals.s; sourceTree = "<group>"; };
9DE37B402694E0B0005FC562 /* gameSegments.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = gameSegments.s; sourceTree = "<group>"; };
9DE37B412694E0B0005FC562 /* score.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = score.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9DE37B412694E0B0005FC562 /* score.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = score.s; sourceTree = "<group>"; };
9DE37B422694E0B0005FC562 /* gamePlayer.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = gamePlayer.s; sourceTree = "<group>"; };
9DE37B432694E0B0005FC562 /* Read.Me.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Read.Me.md; sourceTree = "<group>"; };
9DE37B442694E0B0005FC562 /* global.macros */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = global.macros; sourceTree = "<group>"; };
@ -234,9 +234,9 @@
9DE37B412694E0B0005FC562 /* score.s */,
9DE37B482694E0B0005FC562 /* settings.c */,
9DE37B462694E0B0005FC562 /* settings.h */,
9DE37B342694E0B0005FC562 /* tileConvert.s */,
9DE37B5C2694E0B0005FC562 /* sound */,
9DE37B4A2694E0B0005FC562 /* sprites */,
9DE37B342694E0B0005FC562 /* tileConvert.s */,
9DE37AF62694E070005FC562 /* Makefile */,
9DE37AF82694E070005FC562 /* make */,
9DE37B112694E070005FC562 /* Supporting Files */,

View File

@ -22,12 +22,12 @@
<key>DiskImage.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
<integer>1</integer>
</dict>
<key>doNotBuild.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
<integer>2</integer>
</dict>
</dict>
</dict>

View File

@ -149,7 +149,7 @@ COPYBOOTDIRS=
# By default, the build uses these arguments with mame:
# apple2gs -skip_gameinfo -mouse -window -resolution 1408x1056 -ramsize 4M -sl7 cffa202
# If you would like to use different arguments, specify that here.
MAMEARGS=apple2gs -skip_gameinfo -mouse -window -resolution 1408x1056 -ramsize 4M -sl3 uthernet -sl7 cffa2
MAMEARGS=apple2gs -skip_gameinfo -mouse -window -resolution 1408x1056 -ramsize 4M -sl3 uthernet -sl7 scsi
# For a desktop application, it can operate in 640x200 or 320x200
# resolution. This setting is used to define which horizontal

View File

@ -9,11 +9,22 @@
#ifndef _GUARD_PROJECTBuGS_FILEgame_
#define _GUARD_PROJECTBuGS_FILEgame_
#include "tileData.h"
// These are globals used from assembly.
extern char globalScoreInfo[GAME_NUM_TILES_WIDE + 1];
// These are assembly functions called from C.
extern void game(void);
extern void randInit(void);
extern void waitForVbl(void);
extern void uploadSpin1(void);
extern void uploadSpin2(void);
extern void uploadSpin3(void);
extern void displayConnectionString(void);
extern void displayScorePosition(void);
extern void swapStereoChannels(void);

View File

@ -223,7 +223,6 @@ updateScorpion_explosionDone anop
setScorpionSpeed entry
; TODO - Call this code with each level to set the scorpion speed
cmp #SPRITE_SPEED_FAST
beq setScorpionSpeed_fast

View File

@ -23,12 +23,14 @@ _drawDirtyGameRow_wait&rowNum anop
; offset numbers.
;
; Also according to that technote, it looks like these numbers are different
; in PAL mode. TODO - Do I need something here to handle PAL correctly? I
; switched my GS to 50Hz mode (startup/reboot with option held down to get the
; menu) and I didnt't detect any graphics glitches at all. I did notice that
; the game is noticably easier because things run a bit slower. If I do an
; online score system, I should record whether a score was gotten at 50Hz vs
; 60Hz.
; in PAL mode. Do I need something here to handle PAL correctly? I switched
; my GS to 50Hz mode (startup/reboot with option held down to get the menu)
; and I didnt't detect any graphics glitches at all. I did notice that the
; game is noticably easier because things run a bit slower. If I do an online
; score system, I should record whether a score was gotten at 50Hz vs 60Hz.
; (and in fact, I have since implemented online high scores and record the
; frequency at which the game was played)
lda >VERTICAL_COUNTER ; load the counter value
and #$80ff ; mask out the VBL bits
asl a ; shift the word around

View File

@ -16,9 +16,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "game.h"
#include "globalScores.h"
#include "tileData.h"
// Defines
@ -142,6 +140,7 @@ typedef enum tGameNetworkState {
typedef struct tGameNetworkGlobals {
Boolean networkStartedConnected;
tHighScoreInitParams initParams;
tGameNetworkState gameNetworkState;
dnrBuffer domainNameResolution;
srBuff tcpStatus;
@ -168,11 +167,11 @@ 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;
Word globalScoreAge = 0; // TODO - Replace this with a call to a MiscTool function?
tSetHighScoreRequestWithHash setHighScoreRequest;
char globalScoreInfo[GAME_NUM_TILES_WIDE + 1];
// Implementation
@ -180,12 +179,13 @@ char globalScoreInfo[GAME_NUM_TILES_WIDE + 1];
segment "highscores";
void initNetwork(void)
void initNetwork(tHighScoreInitParams * params)
{
networkGlobals = NULL;
if ((NETWORK_SERVER == NULL) ||
(NETWORK_SERVERPORT == 0))
if ((params->scoreServer == NULL) ||
(params->scorePort == 0) ||
(params->waitForVbl == NULL))
return;
LoadOneTool(54, 0x200); // Load Marinetti
@ -223,6 +223,8 @@ void initNetwork(void)
}
memcpy(&(networkGlobals->initParams), params, sizeof(networkGlobals->initParams));
networkGlobals->networkStartedConnected = TCPIPGetConnectStatus();
if (networkGlobals->networkStartedConnected) {
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECTED;
@ -230,8 +232,8 @@ void initNetwork(void)
networkGlobals->gameNetworkState = GAME_NETWORK_UNCONNECTED;
}
networkGlobals->secrets[0] = NETWORK_SERVERSECRET1;
networkGlobals->secrets[1] = NETWORK_SERVERSECRET2;
networkGlobals->secrets[0] = params->secret1;
networkGlobals->secrets[1] = params->secret2;
networkGlobals->hasHighScoreToSend = FALSE;
@ -275,7 +277,7 @@ void disconnectNetwork(void)
}
while (networkGlobals->gameNetworkState > GAME_NETWORK_TCP_UNCONNECTED) {
waitForVbl();
networkGlobals->initParams.waitForVbl();
pollNetwork();
}
}
@ -380,7 +382,8 @@ void pollNetwork(void)
break;
case GAME_NETWORK_UNCONNECTED:
displayConnectionString();
if (networkGlobals->initParams.displayConnectionString != NULL)
networkGlobals->initParams.displayConnectionString(TRUE);
TCPIPConnect(NULL);
if ((!toolerror()) &&
(TCPIPGetConnectStatus())) {
@ -388,10 +391,12 @@ void pollNetwork(void)
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECT_FAILED;
}
if (networkGlobals->initParams.displayConnectionString != NULL)
networkGlobals->initParams.displayConnectionString(FALSE);
break;
case GAME_NETWORK_CONNECTED:
TCPIPDNRNameToIP("\p" NETWORK_SERVER, &(networkGlobals->domainNameResolution));
TCPIPDNRNameToIP(networkGlobals->initParams.scoreServer, &(networkGlobals->domainNameResolution));
if (toolerror()) {
networkGlobals->gameNetworkState = GAME_NETWORK_LOOKUP_FAILED;
networkGlobals->errorCode = toolerror();
@ -418,7 +423,7 @@ void pollNetwork(void)
(!networkGlobals->hasHighScoreToSend))
break;
networkGlobals->ipid = TCPIPLogin(myUserId, networkGlobals->domainNameResolution.DNRIPaddress, NETWORK_SERVERPORT, 0, 64);
networkGlobals->ipid = TCPIPLogin(networkGlobals->initParams.userId, networkGlobals->domainNameResolution.DNRIPaddress, networkGlobals->initParams.scorePort, 0, 64);
if (toolerror()) {
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
networkGlobals->errorCode = toolerror();
@ -686,26 +691,30 @@ BOOLEAN sendHighScore(void)
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
do {
waitForVbl();
networkGlobals->initParams.waitForVbl();
pollNetwork();
cycleCount++;
if ((cycleCount & 0x7) == 0) {
switch (cycleCount & 0x18) {
case 0x00:
uploadSpin1();
if (networkGlobals->initParams.uploadSpin != NULL)
networkGlobals->initParams.uploadSpin(0);
break;
case 0x08:
uploadSpin2();
if (networkGlobals->initParams.uploadSpin != NULL)
networkGlobals->initParams.uploadSpin(1);
break;
case 0x10:
uploadSpin3();
if (networkGlobals->initParams.uploadSpin != NULL)
networkGlobals->initParams.uploadSpin(2);
break;
case 0x18:
uploadSpin2();
if (networkGlobals->initParams.uploadSpin != NULL)
networkGlobals->initParams.uploadSpin(3);
break;
}
}
@ -714,16 +723,9 @@ BOOLEAN sendHighScore(void)
if (networkGlobals->gameNetworkState != GAME_NETWORK_TCP_UNCONNECTED)
return FALSE;
sprintf(globalScoreInfo, " %u OF %u SCORES", networkGlobals->setHighScoreResponse.position, networkGlobals->setHighScoreResponse.numberOfScores);
for (cycleCount = strlen(globalScoreInfo); cycleCount < sizeof(globalScoreInfo); cycleCount++) {
globalScoreInfo[cycleCount] = ' ';
}
globalScoreInfo[GAME_NUM_TILES_WIDE] = '\0';
displayScorePosition();
for (cycleCount = 4 * 60; cycleCount > 0; cycleCount--) {
waitForVbl();
}
if (networkGlobals->initParams.scorePosition != NULL)
networkGlobals->initParams.scorePosition(networkGlobals->setHighScoreResponse.position,
networkGlobals->setHighScoreResponse.numberOfScores);
return TRUE;
}

View File

@ -12,7 +12,6 @@
#include <types.h>
#include "tileData.h"
typedef struct tHighScore
{
@ -21,23 +20,100 @@ typedef struct tHighScore
unsigned long score;
} tHighScore;
extern char globalScoreInfo[GAME_NUM_TILES_WIDE + 1];
extern unsigned int myUserId;
typedef struct tHighScoreInitParams
{
/* This structure is initialized by the game and passed by pointer to the high score code. It consists of
a series of data members and a series of callbacks which are provided by the game.
*/
/* This is the memory manager ID of the game. */
unsigned int userId;
/* This is a Pascal string (not a C string) of the hostname of the score server to connect to. */
const char * scoreServer;
/* This is the TCP port number of the score server to connect to. */
unsigned int scorePort;
/* These two 32-bit values are the shared secrets used by the connect between the game and the score server
which is used to try to reduce the amount of game score hacking.
*/
unsigned long secret1;
unsigned long secret2;
/* This function should display a message to the user that the network is being brought up and they should
be patient when the argument is TRUE and when the argument is FALSE, it should clear that message. This
function shouldn't block and just put something on the screen to say that the connection is being brought
up or clear that message. It is called sometimes (rarely) by pollNetwork(). It is called with argument
TRUE and will always be called with FALSE sometime after that.
*/
void (*displayConnectionString)(BOOLEAN display);
/* This function should wait for the next VBL and is used to poll the network and limit upload time for a
high score.
*/
void (*waitForVbl)(void);
/* This argument iterates over 0, 1, 2, 3 and then back to 0, 1, 2, etc and is intended to show some kind
of spinner to the user while uploading a high score to the server. This function shouldn't block for
any real amount of time and just cause something on the screen to change to make sure the player doesn't
think something has hung while the upload is in progress. It is called when sendHighScore() is called
by the game.
*/
void (*uploadSpin)(int);
/* When a score is successfully uploaded to the server, this function will be called with the position
of this player's score among the total number of scores recorded for this game. This information
should be displayed to the user. The function can block while this information is being displayed
and that message should be cleaned up before the function returns to the caller. This function is
called by sendHighScore().
*/
void (*scorePosition)(unsigned int position, unsigned int numberOfScores);
} tHighScoreInitParams;
extern void initNetwork(void);
/* Call this function once at launch. The pointer to the parameters is copied so the structure does not need
to remain valid after the call to this function.
*/
extern void initNetwork(tHighScoreInitParams * params);
/* Call this when a game is about to start. It will interrupt any network operation in progress and get ready for
a quiet period where polling will stop until the game is over. That way, all CPU time can be focused on the game.
This function may call the waitForVbl() callback.
*/
extern void disconnectNetwork(void);
extern void pollNetwork(void);
extern void shutdownNetwork(void);
extern BOOLEAN canSendHighScore(void);
extern BOOLEAN sendHighScore(void);
// These are actually assembly functions called from the C code.
extern void uploadSpin1(void);
extern void uploadSpin2(void);
extern void uploadSpin3(void);
extern void displayConnectionString(void);
extern void displayScorePosition(void);
/* Call this every frame refresh period when a game is _not_ in progress. This does any network operations required
to download high scores. During this function call, the displayConnectionString() callback may be called.
*/
extern void pollNetwork(void);
/* Call this function once when the game is quitting. */
extern void shutdownNetwork(void);
/* Call this function when the player has a high score that should be recorded online. This function will return
TRUE if the network is up and a high score can be sent and if so, the game should call sendHighScore() to send
the high score. If FALSE is returned, then the user is playing while offline and no attempt should be made to
send the high score.
*/
extern BOOLEAN canSendHighScore(void);
/* Assuming canSendHighScore() returned TRUE, the game can call this function to actually try to send the high score
to the server. If this function returns TRUE, then the score was successfully sent to the server. If FALSE
is returned, then an error has occurred. The game can offer the user the option to retry to the upload of the
score and if the user would like to retry, just call sendHighScore() again. During this function call, the
waitForVbl(), uploadSpin() and scorePosition() callbacks may be called.
TODO - Pass the score as an argument rather than through globals.
*/
extern BOOLEAN sendHighScore(void);
#endif /* define _GUARD_PROJECTBuGS_FILEglobalScores_ */

View File

@ -31,6 +31,9 @@
unsigned int myUserId;
unsigned int randomSeed;
// This symbol is used also from assembly directly so be careful with it...
char globalScoreInfo[GAME_NUM_TILES_WIDE + 1];
/* Implementation */
@ -43,9 +46,56 @@ word randomMushroomOffset(void)
}
void uploadSpin(int val)
{
switch (val)
{
case 0:
uploadSpin1();
break;
case 1:
uploadSpin2();
break;
case 2:
uploadSpin3();
break;
case 3:
uploadSpin2();
break;
}
}
void scorePosition(unsigned int position, unsigned int numberOfScores)
{
int i;
sprintf(globalScoreInfo, " %u OF %u SCORES", position, numberOfScores);
for (i = strlen(globalScoreInfo); i < sizeof(globalScoreInfo); i++) {
globalScoreInfo[i] = ' ';
}
globalScoreInfo[GAME_NUM_TILES_WIDE] = '\0';
displayScorePosition();
for (i = 6 * 60; i > 0; i--) {
waitForVbl();
}
}
void showConnectionString(BOOLEAN display)
{
if (display)
displayConnectionString();
}
int main(void)
{
static tHighScoreInitParams highScoreInitParams;
int event;
Ref toolStartupRef;
@ -73,7 +123,18 @@ int main(void)
InitMouse(0);
SetMouse(transparent);
initNetwork();
highScoreInitParams.userId = myUserId;
highScoreInitParams.scoreServer = "\p" NETWORK_SERVER;
highScoreInitParams.scorePort = NETWORK_SERVERPORT;
highScoreInitParams.secret1 = NETWORK_SERVERSECRET1;
highScoreInitParams.secret2 = NETWORK_SERVERSECRET2;
highScoreInitParams.displayConnectionString = showConnectionString;
highScoreInitParams.waitForVbl = waitForVbl;
highScoreInitParams.uploadSpin = uploadSpin;
highScoreInitParams.scorePosition = scorePosition;
initNetwork(&highScoreInitParams);
if (!loadSettings())
saveSettings();

View File

@ -12,6 +12,8 @@
#include <types.h>
extern unsigned int myUserId;
extern void saveSettings(void);
BOOLEAN loadSettings(void);
extern void swapStereoSettings(void);