Compare commits

...

17 Commits
2.0 ... master

Author SHA1 Message Date
Jeremy Rand 59dc11e516 Make the timeouts configurable with net scores. 2023-06-11 23:33:47 -04:00
Jeremy Rand 6afbf4eb85 Finish reworking the network high score code to be independent of BuGS itself so it can be put into its own library. 2023-06-11 22:51:21 -04:00
Jeremy Rand 2f53df9eb0 Update the project settings to eliminate some Xcode warnings. 2023-06-09 00:07:36 -04:00
Jeremy Rand 3660b47fd3 Rename globalScores to netScores to work towards moving it to NetScoresGS 2023-06-08 20:04:22 -04:00
Jeremy Rand 1be8d217f1 Cleanup parse errors which appear in the latest Xcode. 2023-06-08 01:15:54 -04:00
Jeremy Rand 0ae5fa1b54 More global high score rework towards making it generic. 2023-06-07 19:53:14 -04:00
Jeremy Rand 37faafb698 More work isolating the global high score code from the game so it can be made a generic library. 2022-05-25 22:58:53 -04:00
Jeremy Rand b8b9089aa2 Start trying to extract the global high scores code so it can be turned into a generic library. 2022-05-25 21:50:38 -04:00
Jeremy Rand f1a80c792a Update the Uthernet link layer used in testing from emulators to the latest. 2022-03-29 23:48:51 -04:00
Jeremy Rand a8bf46bcac Update bootable net image with the latest version of Marinetti. 2021-07-30 23:46:40 -04:00
Jeremy Rand e5b0432991 Change the polarity of the stereo default. I used to default to "bad stereo" which matched the behaviour of mame, GSPlus and the 4soniq card but was against the Apple standard. The mame code has since been fixed and it seems like all other stereo cards are correct (I am unaware of any others that are backwards). So, by default, BuGS will start in the Apple standard L/R mode. If you have saved your settings previously, your option will be preserved correctly. Also, the display considers Apple standard stereo to be L:R while the non-standard to be R:L in the UI. 2021-07-23 23:59:11 -04:00
Jeremy Rand a7aeb5c142 Fix the URLs for the download links. 2021-07-08 22:31:18 -04:00
Jeremy Rand c76cd3d100 Update the readme for the v2.0.1 release. 2021-07-08 22:30:08 -04:00
Jeremy Rand 25a8fbeacd Display a better message when a score upload fails so it is more clear what happened. 2021-07-08 00:13:26 -04:00
Jeremy Rand 40da3b3434 Do not consider a network connection problem a soft error. Bump the version number for an upcoming bug fix release. 2021-07-07 20:11:05 -04:00
Jeremy Rand bf35d817eb Update the build environment for this project to the latest. 2021-07-06 17:04:25 -04:00
Jeremy Rand 72a65f53a7 Fix links in the readme. 2021-07-04 23:35:08 -04:00
33 changed files with 2040 additions and 1261 deletions

View File

@ -2,6 +2,7 @@ BUGS
=======
This is a list of the software bugs (as opposed to the bugs in the game that you shoot) that still need attention:
* Should detect when running on system 5 or lower and quit gracefully. Today, the game crashes.
FIXED

View File

@ -3,142 +3,173 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 53;
objects = {
/* Begin PBXBuildFile section */
9D0DFAFA2669D85F00BDBD04 /* settings.c in Sources */ = {isa = PBXBuildFile; fileRef = 9D0DFAF92669D85F00BDBD04 /* settings.c */; };
9D0DFB002669DA5700BDBD04 /* loadSounds.c in Sources */ = {isa = PBXBuildFile; fileRef = 9D0DFAFF2669DA5700BDBD04 /* loadSounds.c */; };
9D17168F2491C49300C83148 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 9D17168E2491C49300C83148 /* main.c */; };
9D1716922491C49300C83148 /* main.rez in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D1716912491C49300C83148 /* main.rez */; };
9D1716942491C49300C83148 /* Makefile in Sources */ = {isa = PBXBuildFile; fileRef = 9D1716932491C49300C83148 /* Makefile */; };
9D1716972491C49300C83148 /* config.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D1716962491C49300C83148 /* config.txt */; };
9D1716992491C49300C83148 /* createDiskImage in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D1716982491C49300C83148 /* createDiskImage */; };
9D17169B2491C49300C83148 /* head.mk in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D17169A2491C49300C83148 /* head.mk */; };
9D17169D2491C49300C83148 /* launchEmulator in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D17169C2491C49300C83148 /* launchEmulator */; };
9D17169F2491C49300C83148 /* orca-asm in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D17169E2491C49300C83148 /* orca-asm */; };
9D1716A12491C49300C83148 /* orca-cc in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D1716A02491C49300C83148 /* orca-cc */; };
9D1716A32491C49300C83148 /* orca-rez in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D1716A22491C49300C83148 /* orca-rez */; };
9D1716A52491C49300C83148 /* system601.2mg in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D1716A42491C49300C83148 /* system601.2mg */; };
9D1716A72491C49300C83148 /* tail.mk in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D1716A62491C49300C83148 /* tail.mk */; };
9D1716AA2491C49300C83148 /* BuGS.xcscheme in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9D1716A92491C49300C83148 /* BuGS.xcscheme */; };
9DB90E80265AD04A003461C1 /* globalScores.c in Sources */ = {isa = PBXBuildFile; fileRef = 9DB90E7F265AD04A003461C1 /* globalScores.c */; };
9DE37AF72694E070005FC562 /* Makefile in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37AF62694E070005FC562 /* Makefile */; };
9DE37AFA2694E070005FC562 /* config.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37AF92694E070005FC562 /* config.txt */; };
9DE37AFC2694E070005FC562 /* createDiskImage in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37AFB2694E070005FC562 /* createDiskImage */; };
9DE37AFE2694E070005FC562 /* head.mk in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37AFD2694E070005FC562 /* head.mk */; };
9DE37B002694E070005FC562 /* launchEmulator in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37AFF2694E070005FC562 /* launchEmulator */; };
9DE37B022694E070005FC562 /* md2teach in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37B012694E070005FC562 /* md2teach */; };
9DE37B042694E070005FC562 /* orca-asm in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37B032694E070005FC562 /* orca-asm */; };
9DE37B062694E070005FC562 /* orca-cc in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37B052694E070005FC562 /* orca-cc */; };
9DE37B082694E070005FC562 /* orca-rez in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37B072694E070005FC562 /* orca-rez */; };
9DE37B0A2694E070005FC562 /* system601.2mg in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37B092694E070005FC562 /* system601.2mg */; };
9DE37B0E2694E070005FC562 /* tar in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37B0D2694E070005FC562 /* tar */; };
9DE37B102694E070005FC562 /* tail.mk in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37B0F2694E070005FC562 /* tail.mk */; };
9DE37B132694E070005FC562 /* BuGS.xcscheme in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9DE37B122694E070005FC562 /* BuGS.xcscheme */; };
9DE37B742694E0B0005FC562 /* level.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B332694E0B0005FC562 /* level.s */; };
9DE37B752694E0B0005FC562 /* tileConvert.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B342694E0B0005FC562 /* tileConvert.s */; };
9DE37B762694E0B0005FC562 /* gameSpider.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B362694E0B0005FC562 /* gameSpider.s */; };
9DE37B772694E0B0005FC562 /* netScores.c in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B372694E0B0005FC562 /* netScores.c */; };
9DE37B782694E0B0005FC562 /* game.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B382694E0B0005FC562 /* game.s */; };
9DE37B792694E0B0005FC562 /* gameShot.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B3A2694E0B0005FC562 /* gameShot.s */; };
9DE37B7A2694E0B0005FC562 /* loadSounds.c in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B3B2694E0B0005FC562 /* loadSounds.c */; };
9DE37B7B2694E0B0005FC562 /* gameMushroom.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B3D2694E0B0005FC562 /* gameMushroom.s */; };
9DE37B7C2694E0B0005FC562 /* globals.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B3F2694E0B0005FC562 /* globals.s */; };
9DE37B7D2694E0B0005FC562 /* gameSegments.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B402694E0B0005FC562 /* gameSegments.s */; };
9DE37B7E2694E0B0005FC562 /* score.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B412694E0B0005FC562 /* score.s */; };
9DE37B7F2694E0B0005FC562 /* gamePlayer.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B422694E0B0005FC562 /* gamePlayer.s */; };
9DE37B802694E0B0005FC562 /* gameFlea.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B452694E0B0005FC562 /* gameFlea.s */; };
9DE37B812694E0B0005FC562 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B472694E0B0005FC562 /* main.c */; };
9DE37B822694E0B0005FC562 /* settings.c in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B482694E0B0005FC562 /* settings.c */; };
9DE37B832694E0B0005FC562 /* colour.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B492694E0B0005FC562 /* colour.s */; };
9DE37B842694E0B0005FC562 /* ship.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B4B2694E0B0005FC562 /* ship.s */; };
9DE37B852694E0B0005FC562 /* solid.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B4C2694E0B0005FC562 /* solid.s */; };
9DE37B862694E0B0005FC562 /* numbers.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B4D2694E0B0005FC562 /* numbers.s */; };
9DE37B872694E0B0005FC562 /* symbols.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B4E2694E0B0005FC562 /* symbols.s */; };
9DE37B882694E0B0005FC562 /* segments.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B502694E0B0005FC562 /* segments.s */; };
9DE37B892694E0B0005FC562 /* fleas.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B512694E0B0005FC562 /* fleas.s */; };
9DE37B8A2694E0B0005FC562 /* spiders.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B522694E0B0005FC562 /* spiders.s */; };
9DE37B8B2694E0B0005FC562 /* scores.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B532694E0B0005FC562 /* scores.s */; };
9DE37B8C2694E0B0005FC562 /* explosions.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B542694E0B0005FC562 /* explosions.s */; };
9DE37B8D2694E0B0005FC562 /* scorpions.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B552694E0B0005FC562 /* scorpions.s */; };
9DE37B8E2694E0B0005FC562 /* shot.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B562694E0B0005FC562 /* shot.s */; };
9DE37B8F2694E0B0005FC562 /* letters.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B582694E0B0005FC562 /* letters.s */; };
9DE37B902694E0B0005FC562 /* mushrooms.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B592694E0B0005FC562 /* mushrooms.s */; };
9DE37B912694E0B0005FC562 /* random.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B5A2694E0B0005FC562 /* random.s */; };
9DE37B922694E0B0005FC562 /* gameScorpion.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B5B2694E0B0005FC562 /* gameScorpion.s */; };
9DE37B932694E0B0005FC562 /* gameSound.s in Sources */ = {isa = PBXBuildFile; fileRef = 9DE37B722694E0B0005FC562 /* gameSound.s */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9D17168A2491C49300C83148 /* CopyFiles */ = {
9DE37AED2694E070005FC562 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
9D17169D2491C49300C83148 /* launchEmulator in CopyFiles */,
9D1716AA2491C49300C83148 /* BuGS.xcscheme in CopyFiles */,
9D1716A12491C49300C83148 /* orca-cc in CopyFiles */,
9D1716992491C49300C83148 /* createDiskImage in CopyFiles */,
9D1716A32491C49300C83148 /* orca-rez in CopyFiles */,
9D1716972491C49300C83148 /* config.txt in CopyFiles */,
9D1716A52491C49300C83148 /* system601.2mg in CopyFiles */,
9D17169F2491C49300C83148 /* orca-asm in CopyFiles */,
9D1716922491C49300C83148 /* main.rez in CopyFiles */,
9D17169B2491C49300C83148 /* head.mk in CopyFiles */,
9D1716A72491C49300C83148 /* tail.mk in CopyFiles */,
9DE37B022694E070005FC562 /* md2teach in CopyFiles */,
9DE37B082694E070005FC562 /* orca-rez in CopyFiles */,
9DE37B102694E070005FC562 /* tail.mk in CopyFiles */,
9DE37B002694E070005FC562 /* launchEmulator in CopyFiles */,
9DE37B042694E070005FC562 /* orca-asm in CopyFiles */,
9DE37B132694E070005FC562 /* BuGS.xcscheme in CopyFiles */,
9DE37AFC2694E070005FC562 /* createDiskImage in CopyFiles */,
9DE37B0E2694E070005FC562 /* tar in CopyFiles */,
9DE37AFA2694E070005FC562 /* config.txt in CopyFiles */,
9DE37AFE2694E070005FC562 /* head.mk in CopyFiles */,
9DE37B062694E070005FC562 /* orca-cc in CopyFiles */,
9DE37B0A2694E070005FC562 /* system601.2mg in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
9D0CF93D25B553430035D329 /* createRaw */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = createRaw; sourceTree = "<group>"; };
9D0CF93E25B553CB0035D329 /* segments.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = segments.wav; sourceTree = "<group>"; };
9D0CF93F25B553DE0035D329 /* bonus.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = bonus.wav; sourceTree = "<group>"; };
9D0CF94025B553FE0035D329 /* death.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = death.wav; sourceTree = "<group>"; };
9D0CF94125B554490035D329 /* fire.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = fire.wav; sourceTree = "<group>"; };
9D0CF94225B5547B0035D329 /* kill.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = kill.wav; sourceTree = "<group>"; };
9D0CF94325B554910035D329 /* spider.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = spider.wav; sourceTree = "<group>"; };
9D0CF94425B554A10035D329 /* extralife.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = extralife.wav; sourceTree = "<group>"; };
9D0CF94525B554BC0035D329 /* flea_loop_256b.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = flea_loop_256b.wav; sourceTree = "<group>"; };
9D0CF94625B554CE0035D329 /* scorpion.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = scorpion.wav; sourceTree = "<group>"; };
9D0DC8EF258C715E00DE9E87 /* extralife.raw */ = {isa = PBXFileReference; lastKnownFileType = text; path = extralife.raw; sourceTree = "<group>"; };
9D0DFAF82669D85F00BDBD04 /* settings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = settings.h; sourceTree = "<group>"; };
9D0DFAF92669D85F00BDBD04 /* settings.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = settings.c; sourceTree = "<group>"; };
9D0DFAFE2669DA5700BDBD04 /* loadSounds.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = loadSounds.h; sourceTree = "<group>"; };
9D0DFAFF2669DA5700BDBD04 /* loadSounds.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = loadSounds.c; sourceTree = "<group>"; };
9D0DFB0A266DBD9000BDBD04 /* md2teach */ = {isa = PBXFileReference; lastKnownFileType = file; path = md2teach; sourceTree = "<group>"; };
9D0DFB11266DC03E00BDBD04 /* Read.Me.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Read.Me.md; sourceTree = "<group>"; };
9D1553DE257ACA1800657188 /* ACKNOWLEDGEMENTS.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ACKNOWLEDGEMENTS.md; sourceTree = "<group>"; };
9D1553E9257F3E5200657188 /* fire.raw */ = {isa = PBXFileReference; lastKnownFileType = file; path = fire.raw; sourceTree = "<group>"; };
9D1553EA257F3E5200657188 /* bonus.raw */ = {isa = PBXFileReference; lastKnownFileType = file; path = bonus.raw; sourceTree = "<group>"; };
9D1553EB257F3E5200657188 /* death.raw */ = {isa = PBXFileReference; lastKnownFileType = file; path = death.raw; sourceTree = "<group>"; };
9D1553EC257F3E5200657188 /* kill.raw */ = {isa = PBXFileReference; lastKnownFileType = text; path = kill.raw; sourceTree = "<group>"; };
9D1553ED257F3E5200657188 /* segments.raw */ = {isa = PBXFileReference; lastKnownFileType = text; path = segments.raw; sourceTree = "<group>"; };
9D1553EE257F3E5200657188 /* spider.raw */ = {isa = PBXFileReference; lastKnownFileType = text; path = spider.raw; sourceTree = "<group>"; };
9D159805258A6BCB00BA42DF /* gameSound.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gameSound.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9D1716842491C49300C83148 /* BuGS */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BuGS; sourceTree = BUILT_PRODUCTS_DIR; };
9D1716872491C49300C83148 /* BuGS.2mg */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BuGS.2mg; sourceTree = BUILT_PRODUCTS_DIR; };
9D17168C2491C49300C83148 /* doNotBuild */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = doNotBuild; sourceTree = BUILT_PRODUCTS_DIR; };
9D17168E2491C49300C83148 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
9D1716902491C49300C83148 /* main.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = "<group>"; };
9D1716912491C49300C83148 /* main.rez */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = main.rez; sourceTree = "<group>"; };
9D1716932491C49300C83148 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
9D1716962491C49300C83148 /* config.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = config.txt; sourceTree = "<group>"; };
9D1716982491C49300C83148 /* createDiskImage */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = createDiskImage; sourceTree = "<group>"; };
9D17169A2491C49300C83148 /* head.mk */ = {isa = PBXFileReference; lastKnownFileType = text; path = head.mk; sourceTree = "<group>"; };
9D17169C2491C49300C83148 /* launchEmulator */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = launchEmulator; sourceTree = "<group>"; };
9D17169E2491C49300C83148 /* orca-asm */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "orca-asm"; sourceTree = "<group>"; };
9D1716A02491C49300C83148 /* orca-cc */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "orca-cc"; sourceTree = "<group>"; };
9D1716A22491C49300C83148 /* orca-rez */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "orca-rez"; sourceTree = "<group>"; };
9D1716A42491C49300C83148 /* system601.2mg */ = {isa = PBXFileReference; lastKnownFileType = file; path = system601.2mg; sourceTree = "<group>"; };
9D1716A62491C49300C83148 /* tail.mk */ = {isa = PBXFileReference; lastKnownFileType = text; path = tail.mk; sourceTree = "<group>"; };
9D1716A92491C49300C83148 /* BuGS.xcscheme */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = BuGS.xcscheme; path = ../../BuGS.xcodeproj/xcshareddata/xcschemes/BuGS.xcscheme; sourceTree = "<group>"; };
9D2FF6DA24C4C79A000181E5 /* random.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = random.s; sourceTree = "<group>"; };
9D3396F424AECB1D003222B3 /* explosions.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = explosions.s; sourceTree = "<group>"; };
9D3396F524AECBB1003222B3 /* spiders.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = spiders.s; sourceTree = "<group>"; };
9D3396F624AECC40003222B3 /* scorpions.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = scorpions.s; sourceTree = "<group>"; };
9D3396F724AECCAC003222B3 /* scores.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = scores.s; sourceTree = "<group>"; };
9D3396F824AECD11003222B3 /* fleas.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = fleas.s; sourceTree = "<group>"; };
9D3396F924AECD7A003222B3 /* numbers.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = numbers.s; sourceTree = "<group>"; };
9D3396FA24AECDE9003222B3 /* solid.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = solid.s; sourceTree = "<group>"; };
9D3396FB24AECF7C003222B3 /* symbols.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = symbols.s; sourceTree = "<group>"; };
9D3396FC24AECFBB003222B3 /* letters.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = letters.s; sourceTree = "<group>"; };
9D3396FD24AECFF5003222B3 /* mushrooms.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = mushrooms.s; sourceTree = "<group>"; };
9D3396FF24AED09D003222B3 /* sprites.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = sprites.md; sourceTree = "<group>"; };
9D33970024AEFBF2003222B3 /* segments.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = segments.s; sourceTree = "<group>"; };
9D33970124AF9D55003222B3 /* sprites.macros */ = {isa = PBXFileReference; lastKnownFileType = text; path = sprites.macros; sourceTree = "<group>"; };
9D40049726575A8100478FB2 /* system601_net.2mg */ = {isa = PBXFileReference; lastKnownFileType = file; path = system601_net.2mg; sourceTree = "<group>"; };
9D47CBE02547BEDB00CDA5CB /* gameMushroom.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gameMushroom.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9D47CC14254A698900CDA5CB /* gamePlayer.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gamePlayer.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9D47CCBA25525C1A00CDA5CB /* genData.pl */ = {isa = PBXFileReference; lastKnownFileType = text.script.perl; path = genData.pl; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.perl; };
9D4EF43E25D7006A001BEDB0 /* tar */ = {isa = PBXFileReference; lastKnownFileType = file; path = tar; sourceTree = "<group>"; };
9D4EF46925D9D171001BEDB0 /* BuGS.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = BuGS.png; sourceTree = "<group>"; };
9D53E5B32562320300E10169 /* gameShot.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gameShot.s; sourceTree = "<group>"; };
9D53E6472565939300E10169 /* BUGS.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = BUGS.md; sourceTree = "<group>"; };
9D62AF3B249871A300348F45 /* colour.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = colour.s; sourceTree = "<group>"; };
9D62AF3F2499CD1E00348F45 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
9D62AF402499CD3A00348F45 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
9D6DB0AE2591A67700CDBF05 /* flea.raw */ = {isa = PBXFileReference; lastKnownFileType = file; path = flea.raw; sourceTree = "<group>"; };
9D6DB0B825932CA600CDBF05 /* scorpion.raw */ = {isa = PBXFileReference; lastKnownFileType = text; path = scorpion.raw; sourceTree = "<group>"; };
9D6DB164259D759C00CDBF05 /* tileConvert.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = tileConvert.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9D6DB18625A411DA00CDBF05 /* BuGS.2mg */ = {isa = PBXFileReference; lastKnownFileType = file; path = BuGS.2mg; sourceTree = "<group>"; };
9D8AF0B72535542400C10E3C /* level.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = level.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9D8AF0B82535543000C10E3C /* score.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = score.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9D8FFC602491CA28005C9327 /* game.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = game.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9D8FFC612491CAF0005C9327 /* game.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = game.h; sourceTree = "<group>"; };
9D9F07F92553AB3800875B29 /* TODO.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = TODO.md; sourceTree = "<group>"; };
9DB1505024C3801100558B87 /* gameFlea.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gameFlea.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9DB1505124C6875C00558B87 /* gameScorpion.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gameScorpion.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9DB1505224C7495400558B87 /* globals.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = globals.s; sourceTree = "<group>"; };
9DB1505324C9E54C00558B87 /* gameSpider.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gameSpider.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9DB1505424D3BF6C00558B87 /* gameSegments.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = gameSegments.s; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.asm.orcam; };
9DB1505524D3BFCE00558B87 /* global.macros */ = {isa = PBXFileReference; lastKnownFileType = text; path = global.macros; sourceTree = "<group>"; };
9DB90E7E265AD04A003461C1 /* globalScores.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = globalScores.h; sourceTree = "<group>"; };
9DB90E7F265AD04A003461C1 /* globalScores.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = globalScores.c; sourceTree = "<group>"; };
9DC4D7BD24B7652100BACF4B /* ship.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = ship.s; sourceTree = "<group>"; };
9DC4D7BE24B80C9600BACF4B /* shot.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = shot.s; sourceTree = "<group>"; };
9DE37AE52694E070005FC562 /* BuGS */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BuGS; sourceTree = BUILT_PRODUCTS_DIR; };
9DE37AE82694E070005FC562 /* BuGS.2mg */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BuGS.2mg; sourceTree = BUILT_PRODUCTS_DIR; };
9DE37AEA2694E070005FC562 /* BuGS.shk */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BuGS.shk; sourceTree = BUILT_PRODUCTS_DIR; };
9DE37AEF2694E070005FC562 /* doNotBuild */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = doNotBuild; sourceTree = BUILT_PRODUCTS_DIR; };
9DE37AF62694E070005FC562 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
9DE37AF92694E070005FC562 /* config.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = config.txt; sourceTree = "<group>"; };
9DE37AFB2694E070005FC562 /* createDiskImage */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = createDiskImage; sourceTree = "<group>"; };
9DE37AFD2694E070005FC562 /* head.mk */ = {isa = PBXFileReference; lastKnownFileType = text; path = head.mk; sourceTree = "<group>"; };
9DE37AFF2694E070005FC562 /* launchEmulator */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = launchEmulator; sourceTree = "<group>"; };
9DE37B012694E070005FC562 /* md2teach */ = {isa = PBXFileReference; lastKnownFileType = file; path = md2teach; sourceTree = "<group>"; };
9DE37B032694E070005FC562 /* orca-asm */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "orca-asm"; sourceTree = "<group>"; };
9DE37B052694E070005FC562 /* orca-cc */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "orca-cc"; sourceTree = "<group>"; };
9DE37B072694E070005FC562 /* orca-rez */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "orca-rez"; sourceTree = "<group>"; };
9DE37B092694E070005FC562 /* system601.2mg */ = {isa = PBXFileReference; lastKnownFileType = file; path = system601.2mg; sourceTree = "<group>"; };
9DE37B0D2694E070005FC562 /* tar */ = {isa = PBXFileReference; lastKnownFileType = file; path = tar; sourceTree = "<group>"; };
9DE37B0F2694E070005FC562 /* tail.mk */ = {isa = PBXFileReference; lastKnownFileType = text; path = tail.mk; sourceTree = "<group>"; };
9DE37B122694E070005FC562 /* BuGS.xcscheme */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = BuGS.xcscheme; path = ../../BuGS.xcodeproj/xcshareddata/xcschemes/BuGS.xcscheme; sourceTree = "<group>"; };
9DE37B292694E088005FC562 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
9DE37B2A2694E088005FC562 /* BuGS.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = BuGS.png; sourceTree = "<group>"; };
9DE37B2B2694E088005FC562 /* BUGS.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = BUGS.md; sourceTree = "<group>"; };
9DE37B2C2694E088005FC562 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
9DE37B2D2694E088005FC562 /* TODO.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = TODO.md; sourceTree = "<group>"; };
9DE37B2E2694E088005FC562 /* ACKNOWLEDGEMENTS.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ACKNOWLEDGEMENTS.md; sourceTree = "<group>"; };
9DE37B332694E0B0005FC562 /* level.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = level.s; sourceTree = "<group>"; };
9DE37B342694E0B0005FC562 /* tileConvert.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = tileConvert.s; sourceTree = "<group>"; };
9DE37B352694E0B0005FC562 /* main.rez */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.rez; path = main.rez; sourceTree = "<group>"; };
9DE37B362694E0B0005FC562 /* gameSpider.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = gameSpider.s; sourceTree = "<group>"; };
9DE37B372694E0B0005FC562 /* netScores.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = netScores.c; sourceTree = "<group>"; };
9DE37B382694E0B0005FC562 /* game.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = game.s; sourceTree = "<group>"; };
9DE37B392694E0B0005FC562 /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = "<group>"; };
9DE37B3A2694E0B0005FC562 /* gameShot.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = gameShot.s; sourceTree = "<group>"; };
9DE37B3B2694E0B0005FC562 /* loadSounds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = loadSounds.c; sourceTree = "<group>"; };
9DE37B3C2694E0B0005FC562 /* loadSounds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loadSounds.h; sourceTree = "<group>"; };
9DE37B3D2694E0B0005FC562 /* gameMushroom.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = gameMushroom.s; sourceTree = "<group>"; };
9DE37B3E2694E0B0005FC562 /* netScores.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = netScores.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>"; };
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>"; };
9DE37B452694E0B0005FC562 /* gameFlea.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = gameFlea.s; sourceTree = "<group>"; };
9DE37B462694E0B0005FC562 /* settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = settings.h; sourceTree = "<group>"; };
9DE37B472694E0B0005FC562 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
9DE37B482694E0B0005FC562 /* settings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = settings.c; sourceTree = "<group>"; };
9DE37B492694E0B0005FC562 /* colour.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = colour.s; sourceTree = "<group>"; };
9DE37B4B2694E0B0005FC562 /* ship.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = ship.s; sourceTree = "<group>"; };
9DE37B4C2694E0B0005FC562 /* solid.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = solid.s; sourceTree = "<group>"; };
9DE37B4D2694E0B0005FC562 /* numbers.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = numbers.s; sourceTree = "<group>"; };
9DE37B4E2694E0B0005FC562 /* symbols.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = symbols.s; sourceTree = "<group>"; };
9DE37B4F2694E0B0005FC562 /* sprites.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = sprites.md; sourceTree = "<group>"; };
9DE37B502694E0B0005FC562 /* segments.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = segments.s; sourceTree = "<group>"; };
9DE37B512694E0B0005FC562 /* fleas.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = fleas.s; sourceTree = "<group>"; };
9DE37B522694E0B0005FC562 /* spiders.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = spiders.s; sourceTree = "<group>"; };
9DE37B532694E0B0005FC562 /* scores.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = scores.s; sourceTree = "<group>"; };
9DE37B542694E0B0005FC562 /* explosions.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = explosions.s; sourceTree = "<group>"; };
9DE37B552694E0B0005FC562 /* scorpions.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = scorpions.s; sourceTree = "<group>"; };
9DE37B562694E0B0005FC562 /* shot.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = shot.s; sourceTree = "<group>"; };
9DE37B572694E0B0005FC562 /* sprites.macros */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sprites.macros; sourceTree = "<group>"; };
9DE37B582694E0B0005FC562 /* letters.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = letters.s; sourceTree = "<group>"; };
9DE37B592694E0B0005FC562 /* mushrooms.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = mushrooms.s; sourceTree = "<group>"; };
9DE37B5A2694E0B0005FC562 /* random.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = random.s; sourceTree = "<group>"; };
9DE37B5B2694E0B0005FC562 /* gameScorpion.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = gameScorpion.s; sourceTree = "<group>"; };
9DE37B5D2694E0B0005FC562 /* flea.raw */ = {isa = PBXFileReference; lastKnownFileType = file; path = flea.raw; sourceTree = "<group>"; };
9DE37B5E2694E0B0005FC562 /* segments.raw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = segments.raw; sourceTree = "<group>"; };
9DE37B5F2694E0B0005FC562 /* scorpion.raw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = scorpion.raw; sourceTree = "<group>"; };
9DE37B602694E0B0005FC562 /* death.raw */ = {isa = PBXFileReference; lastKnownFileType = file; path = death.raw; sourceTree = "<group>"; };
9DE37B612694E0B0005FC562 /* kill.raw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = kill.raw; sourceTree = "<group>"; };
9DE37B622694E0B0005FC562 /* spider.raw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = spider.raw; sourceTree = "<group>"; };
9DE37B632694E0B0005FC562 /* fire.raw */ = {isa = PBXFileReference; lastKnownFileType = file; path = fire.raw; sourceTree = "<group>"; };
9DE37B652694E0B0005FC562 /* extralife.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = extralife.wav; sourceTree = "<group>"; };
9DE37B662694E0B0005FC562 /* bonus.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = bonus.wav; sourceTree = "<group>"; };
9DE37B672694E0B0005FC562 /* kill.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = kill.wav; sourceTree = "<group>"; };
9DE37B682694E0B0005FC562 /* spider.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = spider.wav; sourceTree = "<group>"; };
9DE37B692694E0B0005FC562 /* fire.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = fire.wav; sourceTree = "<group>"; };
9DE37B6A2694E0B0005FC562 /* segments.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = segments.wav; sourceTree = "<group>"; };
9DE37B6B2694E0B0005FC562 /* scorpion.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = scorpion.wav; sourceTree = "<group>"; };
9DE37B6C2694E0B0005FC562 /* createRaw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = createRaw; sourceTree = "<group>"; };
9DE37B6D2694E0B0005FC562 /* death.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = death.wav; sourceTree = "<group>"; };
9DE37B6E2694E0B0005FC562 /* flea_loop_256b.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = flea_loop_256b.wav; sourceTree = "<group>"; };
9DE37B6F2694E0B0005FC562 /* extralife.raw */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = extralife.raw; sourceTree = "<group>"; };
9DE37B702694E0B0005FC562 /* bonus.raw */ = {isa = PBXFileReference; lastKnownFileType = file; path = bonus.raw; sourceTree = "<group>"; };
9DE37B712694E0B0005FC562 /* game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = game.h; sourceTree = "<group>"; };
9DE37B722694E0B0005FC562 /* gameSound.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = gameSound.s; sourceTree = "<group>"; };
9DE37B732694E0B0005FC562 /* genData.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = genData.pl; sourceTree = "<group>"; };
9DE37B982694E0DF005FC562 /* system601_net.2mg */ = {isa = PBXFileReference; lastKnownFileType = file; path = system601_net.2mg; sourceTree = "<group>"; };
9DE37B9D2694E105005FC562 /* empty.2mg */ = {isa = PBXFileReference; lastKnownFileType = file; path = empty.2mg; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
9D1716892491C49300C83148 /* Frameworks */ = {
9DE37AEC2694E070005FC562 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
@ -148,161 +179,162 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9D0CF93C25B5531F0035D329 /* sources */ = {
9DE37ADE2694E070005FC562 = {
isa = PBXGroup;
children = (
9D0CF93E25B553CB0035D329 /* segments.wav */,
9D0CF93F25B553DE0035D329 /* bonus.wav */,
9D0CF94025B553FE0035D329 /* death.wav */,
9D0CF94125B554490035D329 /* fire.wav */,
9D0CF94225B5547B0035D329 /* kill.wav */,
9D0CF94325B554910035D329 /* spider.wav */,
9D0CF94425B554A10035D329 /* extralife.wav */,
9D0CF94525B554BC0035D329 /* flea_loop_256b.wav */,
9D0CF94625B554CE0035D329 /* scorpion.wav */,
9D0CF93D25B553430035D329 /* createRaw */,
);
path = sources;
sourceTree = "<group>";
};
9D1553E8257F3DC600657188 /* sound */ = {
isa = PBXGroup;
children = (
9D0CF93C25B5531F0035D329 /* sources */,
9D1553EA257F3E5200657188 /* bonus.raw */,
9D6DB0AE2591A67700CDBF05 /* flea.raw */,
9D0DC8EF258C715E00DE9E87 /* extralife.raw */,
9D1553EB257F3E5200657188 /* death.raw */,
9D6DB0B825932CA600CDBF05 /* scorpion.raw */,
9D1553E9257F3E5200657188 /* fire.raw */,
9D1553EC257F3E5200657188 /* kill.raw */,
9D1553ED257F3E5200657188 /* segments.raw */,
9D1553EE257F3E5200657188 /* spider.raw */,
);
path = sound;
sourceTree = "<group>";
};
9D17167D2491C49300C83148 = {
isa = PBXGroup;
children = (
9D62AF3F2499CD1E00348F45 /* LICENSE */,
9D62AF402499CD3A00348F45 /* README.md */,
9D9F07F92553AB3800875B29 /* TODO.md */,
9D53E6472565939300E10169 /* BUGS.md */,
9D4EF46925D9D171001BEDB0 /* BuGS.png */,
9D1553DE257ACA1800657188 /* ACKNOWLEDGEMENTS.md */,
9D17168D2491C49300C83148 /* BuGS */,
9D1716852491C49300C83148 /* Products */,
9DE37B2E2694E088005FC562 /* ACKNOWLEDGEMENTS.md */,
9DE37B2B2694E088005FC562 /* BUGS.md */,
9DE37B2A2694E088005FC562 /* BuGS.png */,
9DE37B292694E088005FC562 /* LICENSE */,
9DE37B2C2694E088005FC562 /* README.md */,
9DE37B2D2694E088005FC562 /* TODO.md */,
9DE37AF02694E070005FC562 /* BuGS */,
9DE37AE62694E070005FC562 /* Products */,
);
sourceTree = "<group>";
};
9D1716852491C49300C83148 /* Products */ = {
9DE37AE62694E070005FC562 /* Products */ = {
isa = PBXGroup;
children = (
9D1716842491C49300C83148 /* BuGS */,
9D1716872491C49300C83148 /* BuGS.2mg */,
9D17168C2491C49300C83148 /* doNotBuild */,
9DE37AE52694E070005FC562 /* BuGS */,
9DE37AE82694E070005FC562 /* BuGS.2mg */,
9DE37AEA2694E070005FC562 /* BuGS.shk */,
9DE37AEF2694E070005FC562 /* doNotBuild */,
);
name = Products;
sourceTree = "<group>";
};
9D17168D2491C49300C83148 /* BuGS */ = {
9DE37AF02694E070005FC562 /* BuGS */ = {
isa = PBXGroup;
children = (
9D17168E2491C49300C83148 /* main.c */,
9D1716902491C49300C83148 /* main.h */,
9D0DFAF82669D85F00BDBD04 /* settings.h */,
9D0DFAF92669D85F00BDBD04 /* settings.c */,
9D0DFAFE2669DA5700BDBD04 /* loadSounds.h */,
9D0DFAFF2669DA5700BDBD04 /* loadSounds.c */,
9DB90E7E265AD04A003461C1 /* globalScores.h */,
9DB90E7F265AD04A003461C1 /* globalScores.c */,
9D8FFC602491CA28005C9327 /* game.s */,
9D8FFC612491CAF0005C9327 /* game.h */,
9DB1505024C3801100558B87 /* gameFlea.s */,
9DB1505124C6875C00558B87 /* gameScorpion.s */,
9DB1505324C9E54C00558B87 /* gameSpider.s */,
9DB1505424D3BF6C00558B87 /* gameSegments.s */,
9D47CBE02547BEDB00CDA5CB /* gameMushroom.s */,
9D47CC14254A698900CDA5CB /* gamePlayer.s */,
9D53E5B32562320300E10169 /* gameShot.s */,
9D159805258A6BCB00BA42DF /* gameSound.s */,
9D6DB164259D759C00CDBF05 /* tileConvert.s */,
9D8AF0B72535542400C10E3C /* level.s */,
9D8AF0B82535543000C10E3C /* score.s */,
9D62AF3B249871A300348F45 /* colour.s */,
9D2FF6DA24C4C79A000181E5 /* random.s */,
9DB1505224C7495400558B87 /* globals.s */,
9DB1505524D3BFCE00558B87 /* global.macros */,
9D47CCBA25525C1A00CDA5CB /* genData.pl */,
9D0DFB11266DC03E00BDBD04 /* Read.Me.md */,
9D1553E8257F3DC600657188 /* sound */,
9D3396F324AECACC003222B3 /* sprites */,
9D1716912491C49300C83148 /* main.rez */,
9D1716932491C49300C83148 /* Makefile */,
9D1716952491C49300C83148 /* make */,
9D1716A82491C49300C83148 /* Supporting Files */,
9DE37B492694E0B0005FC562 /* colour.s */,
9DE37B712694E0B0005FC562 /* game.h */,
9DE37B382694E0B0005FC562 /* game.s */,
9DE37B452694E0B0005FC562 /* gameFlea.s */,
9DE37B3D2694E0B0005FC562 /* gameMushroom.s */,
9DE37B422694E0B0005FC562 /* gamePlayer.s */,
9DE37B5B2694E0B0005FC562 /* gameScorpion.s */,
9DE37B402694E0B0005FC562 /* gameSegments.s */,
9DE37B3A2694E0B0005FC562 /* gameShot.s */,
9DE37B722694E0B0005FC562 /* gameSound.s */,
9DE37B362694E0B0005FC562 /* gameSpider.s */,
9DE37B732694E0B0005FC562 /* genData.pl */,
9DE37B442694E0B0005FC562 /* global.macros */,
9DE37B3F2694E0B0005FC562 /* globals.s */,
9DE37B372694E0B0005FC562 /* netScores.c */,
9DE37B3E2694E0B0005FC562 /* netScores.h */,
9DE37B332694E0B0005FC562 /* level.s */,
9DE37B3B2694E0B0005FC562 /* loadSounds.c */,
9DE37B3C2694E0B0005FC562 /* loadSounds.h */,
9DE37B472694E0B0005FC562 /* main.c */,
9DE37B392694E0B0005FC562 /* main.h */,
9DE37B352694E0B0005FC562 /* main.rez */,
9DE37B5A2694E0B0005FC562 /* random.s */,
9DE37B432694E0B0005FC562 /* Read.Me.md */,
9DE37B412694E0B0005FC562 /* score.s */,
9DE37B482694E0B0005FC562 /* settings.c */,
9DE37B462694E0B0005FC562 /* settings.h */,
9DE37B342694E0B0005FC562 /* tileConvert.s */,
9DE37B5C2694E0B0005FC562 /* sound */,
9DE37B4A2694E0B0005FC562 /* sprites */,
9DE37AF62694E070005FC562 /* Makefile */,
9DE37AF82694E070005FC562 /* make */,
9DE37B112694E070005FC562 /* Supporting Files */,
);
path = BuGS;
sourceTree = "<group>";
};
9D1716952491C49300C83148 /* make */ = {
9DE37AF82694E070005FC562 /* make */ = {
isa = PBXGroup;
children = (
9D1716962491C49300C83148 /* config.txt */,
9D1716982491C49300C83148 /* createDiskImage */,
9D17169A2491C49300C83148 /* head.mk */,
9D4EF43E25D7006A001BEDB0 /* tar */,
9D17169C2491C49300C83148 /* launchEmulator */,
9D0DFB0A266DBD9000BDBD04 /* md2teach */,
9D6DB18625A411DA00CDBF05 /* BuGS.2mg */,
9D17169E2491C49300C83148 /* orca-asm */,
9D1716A02491C49300C83148 /* orca-cc */,
9D1716A22491C49300C83148 /* orca-rez */,
9D1716A42491C49300C83148 /* system601.2mg */,
9D40049726575A8100478FB2 /* system601_net.2mg */,
9D1716A62491C49300C83148 /* tail.mk */,
9DE37AF92694E070005FC562 /* config.txt */,
9DE37AFB2694E070005FC562 /* createDiskImage */,
9DE37AFD2694E070005FC562 /* head.mk */,
9DE37AFF2694E070005FC562 /* launchEmulator */,
9DE37B012694E070005FC562 /* md2teach */,
9DE37B032694E070005FC562 /* orca-asm */,
9DE37B052694E070005FC562 /* orca-cc */,
9DE37B072694E070005FC562 /* orca-rez */,
9DE37B9D2694E105005FC562 /* empty.2mg */,
9DE37B092694E070005FC562 /* system601.2mg */,
9DE37B982694E0DF005FC562 /* system601_net.2mg */,
9DE37B0D2694E070005FC562 /* tar */,
9DE37B0F2694E070005FC562 /* tail.mk */,
);
path = make;
sourceTree = "<group>";
};
9D1716A82491C49300C83148 /* Supporting Files */ = {
9DE37B112694E070005FC562 /* Supporting Files */ = {
isa = PBXGroup;
children = (
9D1716A92491C49300C83148 /* BuGS.xcscheme */,
9DE37B122694E070005FC562 /* BuGS.xcscheme */,
);
path = "Supporting Files";
sourceTree = "<group>";
};
9D3396F324AECACC003222B3 /* sprites */ = {
9DE37B4A2694E0B0005FC562 /* sprites */ = {
isa = PBXGroup;
children = (
9D3396FF24AED09D003222B3 /* sprites.md */,
9D33970124AF9D55003222B3 /* sprites.macros */,
9D3396F424AECB1D003222B3 /* explosions.s */,
9D3396F524AECBB1003222B3 /* spiders.s */,
9D3396F624AECC40003222B3 /* scorpions.s */,
9D3396F724AECCAC003222B3 /* scores.s */,
9D3396F824AECD11003222B3 /* fleas.s */,
9D3396F924AECD7A003222B3 /* numbers.s */,
9D3396FA24AECDE9003222B3 /* solid.s */,
9D3396FB24AECF7C003222B3 /* symbols.s */,
9D3396FC24AECFBB003222B3 /* letters.s */,
9D3396FD24AECFF5003222B3 /* mushrooms.s */,
9D33970024AEFBF2003222B3 /* segments.s */,
9DC4D7BD24B7652100BACF4B /* ship.s */,
9DC4D7BE24B80C9600BACF4B /* shot.s */,
9DE37B4B2694E0B0005FC562 /* ship.s */,
9DE37B4C2694E0B0005FC562 /* solid.s */,
9DE37B4D2694E0B0005FC562 /* numbers.s */,
9DE37B4E2694E0B0005FC562 /* symbols.s */,
9DE37B4F2694E0B0005FC562 /* sprites.md */,
9DE37B502694E0B0005FC562 /* segments.s */,
9DE37B512694E0B0005FC562 /* fleas.s */,
9DE37B522694E0B0005FC562 /* spiders.s */,
9DE37B532694E0B0005FC562 /* scores.s */,
9DE37B542694E0B0005FC562 /* explosions.s */,
9DE37B552694E0B0005FC562 /* scorpions.s */,
9DE37B562694E0B0005FC562 /* shot.s */,
9DE37B572694E0B0005FC562 /* sprites.macros */,
9DE37B582694E0B0005FC562 /* letters.s */,
9DE37B592694E0B0005FC562 /* mushrooms.s */,
);
path = sprites;
sourceTree = "<group>";
};
9DE37B5C2694E0B0005FC562 /* sound */ = {
isa = PBXGroup;
children = (
9DE37B5D2694E0B0005FC562 /* flea.raw */,
9DE37B5E2694E0B0005FC562 /* segments.raw */,
9DE37B5F2694E0B0005FC562 /* scorpion.raw */,
9DE37B602694E0B0005FC562 /* death.raw */,
9DE37B612694E0B0005FC562 /* kill.raw */,
9DE37B622694E0B0005FC562 /* spider.raw */,
9DE37B632694E0B0005FC562 /* fire.raw */,
9DE37B642694E0B0005FC562 /* sources */,
9DE37B6F2694E0B0005FC562 /* extralife.raw */,
9DE37B702694E0B0005FC562 /* bonus.raw */,
);
path = sound;
sourceTree = "<group>";
};
9DE37B642694E0B0005FC562 /* sources */ = {
isa = PBXGroup;
children = (
9DE37B652694E0B0005FC562 /* extralife.wav */,
9DE37B662694E0B0005FC562 /* bonus.wav */,
9DE37B672694E0B0005FC562 /* kill.wav */,
9DE37B682694E0B0005FC562 /* spider.wav */,
9DE37B692694E0B0005FC562 /* fire.wav */,
9DE37B6A2694E0B0005FC562 /* segments.wav */,
9DE37B6B2694E0B0005FC562 /* scorpion.wav */,
9DE37B6C2694E0B0005FC562 /* createRaw */,
9DE37B6D2694E0B0005FC562 /* death.wav */,
9DE37B6E2694E0B0005FC562 /* flea_loop_256b.wav */,
);
path = sources;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXLegacyTarget section */
9D1716822491C49300C83148 /* BuGS */ = {
9DE37AE32694E070005FC562 /* BuGS */ = {
isa = PBXLegacyTarget;
buildArgumentsString = "-C BuGS $(ACTION)";
buildConfigurationList = 9D1716AD2491C49300C83148 /* Build configuration list for PBXLegacyTarget "BuGS" */;
buildConfigurationList = 9DE37B162694E070005FC562 /* Build configuration list for PBXLegacyTarget "BuGS" */;
buildPhases = (
);
buildToolPath = /usr/bin/make;
@ -315,9 +347,9 @@
/* End PBXLegacyTarget section */
/* Begin PBXNativeTarget section */
9D1716832491C49300C83148 /* Binary */ = {
9DE37AE42694E070005FC562 /* Binary */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9D1716B02491C49300C83148 /* Build configuration list for PBXNativeTarget "Binary" */;
buildConfigurationList = 9DE37B192694E070005FC562 /* Build configuration list for PBXNativeTarget "Binary" */;
buildPhases = (
);
buildRules = (
@ -326,12 +358,12 @@
);
name = Binary;
productName = Binary;
productReference = 9D1716842491C49300C83148 /* BuGS */;
productReference = 9DE37AE52694E070005FC562 /* BuGS */;
productType = "com.apple.product-type.tool";
};
9D1716862491C49300C83148 /* DiskImage */ = {
9DE37AE72694E070005FC562 /* DiskImage */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9D1716B32491C49300C83148 /* Build configuration list for PBXNativeTarget "DiskImage" */;
buildConfigurationList = 9DE37B1C2694E070005FC562 /* Build configuration list for PBXNativeTarget "DiskImage" */;
buildPhases = (
);
buildRules = (
@ -340,16 +372,30 @@
);
name = DiskImage;
productName = DiskImage;
productReference = 9D1716872491C49300C83148 /* BuGS.2mg */;
productReference = 9DE37AE82694E070005FC562 /* BuGS.2mg */;
productType = "com.apple.product-type.tool";
};
9D17168B2491C49300C83148 /* doNotBuild */ = {
9DE37AE92694E070005FC562 /* Archive */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9D1716B62491C49300C83148 /* Build configuration list for PBXNativeTarget "doNotBuild" */;
buildConfigurationList = 9DE37B1F2694E070005FC562 /* Build configuration list for PBXNativeTarget "Archive" */;
buildPhases = (
9D1716882491C49300C83148 /* Sources */,
9D1716892491C49300C83148 /* Frameworks */,
9D17168A2491C49300C83148 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = Archive;
productName = Archive;
productReference = 9DE37AEA2694E070005FC562 /* BuGS.shk */;
productType = "com.apple.product-type.tool";
};
9DE37AEE2694E070005FC562 /* doNotBuild */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9DE37B222694E070005FC562 /* Build configuration list for PBXNativeTarget "doNotBuild" */;
buildPhases = (
9DE37AEB2694E070005FC562 /* Sources */,
9DE37AEC2694E070005FC562 /* Frameworks */,
9DE37AED2694E070005FC562 /* CopyFiles */,
);
buildRules = (
);
@ -357,33 +403,36 @@
);
name = doNotBuild;
productName = doNotBuild;
productReference = 9D17168C2491C49300C83148 /* doNotBuild */;
productReference = 9DE37AEF2694E070005FC562 /* doNotBuild */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
9D17167E2491C49300C83148 /* Project object */ = {
9DE37ADF2694E070005FC562 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1130;
ORGANIZATIONNAME = "Jeremy Rand";
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1430;
TargetAttributes = {
9D1716822491C49300C83148 = {
CreatedOnToolsVersion = 11.3.1;
9DE37AE32694E070005FC562 = {
CreatedOnToolsVersion = 12.4;
};
9D1716832491C49300C83148 = {
CreatedOnToolsVersion = 11.3.1;
9DE37AE42694E070005FC562 = {
CreatedOnToolsVersion = 12.4;
};
9D1716862491C49300C83148 = {
CreatedOnToolsVersion = 11.3.1;
9DE37AE72694E070005FC562 = {
CreatedOnToolsVersion = 12.4;
};
9D17168B2491C49300C83148 = {
CreatedOnToolsVersion = 11.3.1;
9DE37AE92694E070005FC562 = {
CreatedOnToolsVersion = 12.4;
};
9DE37AEE2694E070005FC562 = {
CreatedOnToolsVersion = 12.4;
};
};
};
buildConfigurationList = 9D1716812491C49300C83148 /* Build configuration list for PBXProject "BuGS" */;
buildConfigurationList = 9DE37AE22694E070005FC562 /* Build configuration list for PBXProject "BuGS" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
@ -391,36 +440,65 @@
en,
Base,
);
mainGroup = 9D17167D2491C49300C83148;
productRefGroup = 9D1716852491C49300C83148 /* Products */;
mainGroup = 9DE37ADE2694E070005FC562;
productRefGroup = 9DE37AE62694E070005FC562 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
9D1716822491C49300C83148 /* BuGS */,
9D1716832491C49300C83148 /* Binary */,
9D1716862491C49300C83148 /* DiskImage */,
9D17168B2491C49300C83148 /* doNotBuild */,
9DE37AE32694E070005FC562 /* BuGS */,
9DE37AE42694E070005FC562 /* Binary */,
9DE37AE72694E070005FC562 /* DiskImage */,
9DE37AE92694E070005FC562 /* Archive */,
9DE37AEE2694E070005FC562 /* doNotBuild */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
9D1716882491C49300C83148 /* Sources */ = {
9DE37AEB2694E070005FC562 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9D0DFAFA2669D85F00BDBD04 /* settings.c in Sources */,
9DB90E80265AD04A003461C1 /* globalScores.c in Sources */,
9D0DFB002669DA5700BDBD04 /* loadSounds.c in Sources */,
9D1716942491C49300C83148 /* Makefile in Sources */,
9D17168F2491C49300C83148 /* main.c in Sources */,
9DE37B892694E0B0005FC562 /* fleas.s in Sources */,
9DE37B912694E0B0005FC562 /* random.s in Sources */,
9DE37B832694E0B0005FC562 /* colour.s in Sources */,
9DE37B842694E0B0005FC562 /* ship.s in Sources */,
9DE37B8F2694E0B0005FC562 /* letters.s in Sources */,
9DE37B7E2694E0B0005FC562 /* score.s in Sources */,
9DE37B8A2694E0B0005FC562 /* spiders.s in Sources */,
9DE37B8E2694E0B0005FC562 /* shot.s in Sources */,
9DE37B802694E0B0005FC562 /* gameFlea.s in Sources */,
9DE37B7F2694E0B0005FC562 /* gamePlayer.s in Sources */,
9DE37B882694E0B0005FC562 /* segments.s in Sources */,
9DE37B7B2694E0B0005FC562 /* gameMushroom.s in Sources */,
9DE37B742694E0B0005FC562 /* level.s in Sources */,
9DE37B812694E0B0005FC562 /* main.c in Sources */,
9DE37B7D2694E0B0005FC562 /* gameSegments.s in Sources */,
9DE37B7A2694E0B0005FC562 /* loadSounds.c in Sources */,
9DE37AF72694E070005FC562 /* Makefile in Sources */,
9DE37B852694E0B0005FC562 /* solid.s in Sources */,
9DE37B7C2694E0B0005FC562 /* globals.s in Sources */,
9DE37B872694E0B0005FC562 /* symbols.s in Sources */,
9DE37B772694E0B0005FC562 /* netScores.c in Sources */,
9DE37B8B2694E0B0005FC562 /* scores.s in Sources */,
9DE37B932694E0B0005FC562 /* gameSound.s in Sources */,
9DE37B922694E0B0005FC562 /* gameScorpion.s in Sources */,
9DE37B762694E0B0005FC562 /* gameSpider.s in Sources */,
9DE37B822694E0B0005FC562 /* settings.c in Sources */,
9DE37B902694E0B0005FC562 /* mushrooms.s in Sources */,
9DE37B8C2694E0B0005FC562 /* explosions.s in Sources */,
9DE37B8D2694E0B0005FC562 /* scorpions.s in Sources */,
9DE37B752694E0B0005FC562 /* tileConvert.s in Sources */,
9DE37B792694E0B0005FC562 /* gameShot.s in Sources */,
9DE37B862694E0B0005FC562 /* numbers.s in Sources */,
9DE37B782694E0B0005FC562 /* game.s in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
9D1716AB2491C49300C83148 /* Debug */ = {
9DE37B142694E070005FC562 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
@ -446,6 +524,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -453,6 +532,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -476,7 +556,7 @@
};
name = Debug;
};
9D1716AC2491C49300C83148 /* Release */ = {
9DE37B152694E070005FC562 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
@ -502,6 +582,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -509,6 +590,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -525,10 +607,11 @@
};
name = Release;
};
9D1716AE2491C49300C83148 /* Debug */ = {
9DE37B172694E070005FC562 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEBUGGING_SYMBOLS = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = VD9FGCW36C;
@ -540,10 +623,11 @@
};
name = Debug;
};
9D1716AF2491C49300C83148 /* Release */ = {
9DE37B182694E070005FC562 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = VD9FGCW36C;
OTHER_CFLAGS = "";
@ -552,50 +636,77 @@
};
name = Release;
};
9D1716B12491C49300C83148 /* Debug */ = {
9DE37B1A2694E070005FC562 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = VD9FGCW36C;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = BuGS;
};
name = Debug;
};
9D1716B22491C49300C83148 /* Release */ = {
9DE37B1B2694E070005FC562 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = VD9FGCW36C;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = BuGS;
};
name = Release;
};
9D1716B42491C49300C83148 /* Debug */ = {
9DE37B1D2694E070005FC562 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = VD9FGCW36C;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = BuGS.2mg;
};
name = Debug;
};
9D1716B52491C49300C83148 /* Release */ = {
9DE37B1E2694E070005FC562 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = VD9FGCW36C;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = BuGS.2mg;
};
name = Release;
};
9D1716B72491C49300C83148 /* Debug */ = {
9DE37B202694E070005FC562 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = VD9FGCW36C;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = BuGS.shk;
};
name = Debug;
};
9DE37B212694E070005FC562 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = VD9FGCW36C;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = BuGS.shk;
};
name = Release;
};
9DE37B232694E070005FC562 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = VD9FGCW36C;
ENABLE_HARDENED_RUNTIME = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
@ -614,10 +725,11 @@
};
name = Debug;
};
9D1716B82491C49300C83148 /* Release */ = {
9DE37B242694E070005FC562 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = VD9FGCW36C;
ENABLE_HARDENED_RUNTIME = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
@ -639,52 +751,61 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
9D1716812491C49300C83148 /* Build configuration list for PBXProject "BuGS" */ = {
9DE37AE22694E070005FC562 /* Build configuration list for PBXProject "BuGS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9D1716AB2491C49300C83148 /* Debug */,
9D1716AC2491C49300C83148 /* Release */,
9DE37B142694E070005FC562 /* Debug */,
9DE37B152694E070005FC562 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9D1716AD2491C49300C83148 /* Build configuration list for PBXLegacyTarget "BuGS" */ = {
9DE37B162694E070005FC562 /* Build configuration list for PBXLegacyTarget "BuGS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9D1716AE2491C49300C83148 /* Debug */,
9D1716AF2491C49300C83148 /* Release */,
9DE37B172694E070005FC562 /* Debug */,
9DE37B182694E070005FC562 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9D1716B02491C49300C83148 /* Build configuration list for PBXNativeTarget "Binary" */ = {
9DE37B192694E070005FC562 /* Build configuration list for PBXNativeTarget "Binary" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9D1716B12491C49300C83148 /* Debug */,
9D1716B22491C49300C83148 /* Release */,
9DE37B1A2694E070005FC562 /* Debug */,
9DE37B1B2694E070005FC562 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9D1716B32491C49300C83148 /* Build configuration list for PBXNativeTarget "DiskImage" */ = {
9DE37B1C2694E070005FC562 /* Build configuration list for PBXNativeTarget "DiskImage" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9D1716B42491C49300C83148 /* Debug */,
9D1716B52491C49300C83148 /* Release */,
9DE37B1D2694E070005FC562 /* Debug */,
9DE37B1E2694E070005FC562 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9D1716B62491C49300C83148 /* Build configuration list for PBXNativeTarget "doNotBuild" */ = {
9DE37B1F2694E070005FC562 /* Build configuration list for PBXNativeTarget "Archive" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9D1716B72491C49300C83148 /* Debug */,
9D1716B82491C49300C83148 /* Release */,
9DE37B202694E070005FC562 /* Debug */,
9DE37B212694E070005FC562 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9DE37B222694E070005FC562 /* Build configuration list for PBXNativeTarget "doNotBuild" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9DE37B232694E070005FC562 /* Debug */,
9DE37B242694E070005FC562 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 9D17167E2491C49300C83148 /* Project object */;
rootObject = 9DE37ADF2694E070005FC562 /* Project object */;
}

View File

@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "self:BuGS.xcodeproj">
location = "self:">
</FileRef>
</Workspace>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0830"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -14,7 +14,7 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9D1716822491C49300C83148"
BlueprintIdentifier = "9DE37AE32694E070005FC562"
BuildableName = "BuGS"
BlueprintName = "BuGS"
ReferencedContainer = "container:BuGS.xcodeproj">
@ -47,7 +47,7 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9D1716822491C49300C83148"
BlueprintIdentifier = "9DE37AE32694E070005FC562"
BuildableName = "BuGS"
BlueprintName = "BuGS"
ReferencedContainer = "container:BuGS.xcodeproj">
@ -59,7 +59,7 @@
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "$PROJECT_DIR/BuGS"
argument = "&quot;$PROJECT_DIR/BuGS&quot;"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
@ -89,7 +89,7 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9D1716822491C49300C83148"
BlueprintIdentifier = "9DE37AE32694E070005FC562"
BuildableName = "BuGS"
BlueprintName = "BuGS"
ReferencedContainer = "container:BuGS.xcodeproj">

View File

@ -4,10 +4,15 @@
<dict>
<key>SchemeUserState</key>
<dict>
<key>Archive.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
</dict>
<key>Binary.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
<integer>1</integer>
</dict>
<key>BuGS.xcscheme_^#shared#^_</key>
<dict>
@ -17,12 +22,12 @@
<key>DiskImage.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
<integer>4</integer>
</dict>
<key>doNotBuild.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
<integer>2</integer>
</dict>
</dict>
</dict>

View File

@ -28,6 +28,22 @@ TARGETTYPE=desktop
# TARGETTYPE=nda
# TARGETTYPE=xcmd
# Uncomment one of the following lines to force a particular GS emulator.
# By default, specific paths are tested for these emulators in the below
# order and the first found is what will be used. You can overrride that
# here:
#
# EMULATOR=gsplus
EMULATOR=mame
# EMULATOR=gsport
# By default, the build provides a single boot environment to test with.
# You can put other .2mg files into the make directory and override this
# variable to change what boot disk you want to use when you launch the
# emulator. The disk image you specify must be found in the make directory:
#
BOOTIMAGE=system601_net.2mg
# Add any other directories where you are putting C or assembly source
# files to this list:
SRCDIRS+=sprites $(GENDIR)
@ -62,12 +78,17 @@ ASMFLAGS+=
# Add any arguments you want passed to the linker to this variable:
LDFLAGS+=
MD_SRCS=Read.Me.md
# Uncomment the following line if you want to build against the GNO libraries
# export ORCA=$(ORCA_BINDIR)/gno
# If you want to copy one or more files or directories to the target disk
# Add any markdown files to the MD_SRCS variable to specify which files to
# convert to a Teach text file format during the build. Using this, you can
# write your documentation in markdown in your project and at build time,
# that documentation is converted to a format that is good to package with
# your software and can be opened on a GS.
MD_SRCS=Read.Me.md
# If you want to copy one or more files or directories to the distribution disk
# image, add the root directory to this variable. Any directories under
# the source directory which don't exist in the target disk image will be
# created. All files will be copied from the source to the target using
@ -75,23 +96,61 @@ MD_SRCS=Read.Me.md
#
# For example, if you set COPYDIRS to dir and in your project you have
# the following files:
# dir/Icons/myIconFile
# dir/newDir/anotherFile
# Then, during the copy phase, myIconFile will be copied into the Icons
# folder and a folder newDir will be created and anotherFile will be copied
# into there.
COPYDIRS=
# If you want to copy one or more files or directories to the boot disk
# image, add the root directory to this variable. Any directories under
# the source directory which don't exist in the boot disk image will be
# created. All files will be copied from the source to the target using
# the same path from the source.
#
# For example, if you set COPYBOOTDIRS to dir and in your project you have
# the following files:
# dir/System/mySystemFile
# dir/newDir/anotherFile
# Then, during the copy phase, mySystemFile will be copied into the System
# folder and a folder newDir will be created and anotherFile will be copied
# into there.
COPYDIRS=
COPYBOOTDIRS=
# By default, the build expects that you have GSplus in the path:
# /Applications/GSplus.app/Contents/MacOS/gsplus
# If you have it in a different location, specify that here.
# GSPLUS=/Applications/GSplus.app/Contents/MacOS/gsplus
# By default, the build uses no arguments with GSplus. If you would like to
# use different arguments, specify that here.
# GSPLUSARGS=
# By default, the build expects that you have GSport in the path:
# /Applications/GSport/GSport.app/Contents/MacOS/GSport
# If you have it in a different location, specify that here.
# GSPORT=/Applications/GSport/GSport.app/Contents/MacOS/GSport
# By default, the build uses no arguments with GSport. If you would like to
# use different arguments, specify that here.
# GSPORTARGS=
# By default, the build expects that you have Ample/mame in the path:
# /Applications/Ample.app/Contents/MacOS/mame64
# If you have it in a different location, specify that here.
# MAME=/Applications/Ample.app/Contents/MacOS/mame64
# By default, the build expects that you have the mame ROMs/libs in the path:
# $(HOME)/Library/Application Support/Ample
# If you have it in a different location, specify that here.
# MAMELIB=$(HOME)/Library/Application Support/Ample
# 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 scsi
# For a desktop application, it can operate in 640x200 or 320x200
# resolution. This setting is used to define which horizontal
# resolution you want to use for a desktop application. Other

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

@ -97,7 +97,7 @@ gameLoop_skipPreload anop
; The following is the network poll code which runs when not playing a game
lda gameState
bne gameLoop_skipNetwork
jsl pollNetwork
jsl NSGS_PollNetwork
lda hasGlobalHighScores
beq gameLoop_skipNetwork
lda highScoreCountdown
@ -247,7 +247,7 @@ startGame_singlePlayer anop
jsl spiderInitGame
jsl levelInit
jsl soundInit
jsl disconnectNetwork
jsl NSGS_DisconnectNetwork
; Fall through intentionally here...
startLevel entry
jsl segmentsInitLevel
@ -1170,7 +1170,7 @@ staticGameBoard_Options anop
_setGameTile TILE_EMPTY
lda settings+SETTINGS_SWAP_STEREO_OFFSET
bne staticGameBoard_swapped
beq staticGameBoard_swapped
_setGameTile TILE_LETTER_L
_setGameTile TILE_SYMBOL_COLON
_setGameTile TILE_LETTER_R

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

@ -33,8 +33,11 @@ SOUND_ONE_SHOT_MODE equ 2
; $10 should be the left. But based on GSPlus and mame, I see the opposite. Still need
; to check on my HW. But in the end, it could be that some HW demultiplexed them backwards
; so there could be either out there in the wild.
SOUND_RIGHT_SPEAKER equ $10
SOUND_LEFT_SPEAKER equ $00
;
; Now I am changing my mind about this. mame has been fixed. I think the 4soniq and GSplus
; are the only ones which are wrong. So, going with the Apple standard here.
SOUND_RIGHT_SPEAKER equ $00
SOUND_LEFT_SPEAKER equ $10
; OSC 16 - 19 for L/R channels in swap mode
SPIDER_SOUND_ADDR equ $0000

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
@ -222,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
@ -276,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

@ -1,730 +0,0 @@
/*
* globalScores.c
* BuGS
*
* Created by Jeremy Rand on 2021-05-23.
* Copyright © 2021 Jeremy Rand. All rights reserved.
*/
#include <Hash.h>
#include <locator.h>
#include <misctool.h>
#include <stdint.h>
#include <tcpip.h>
#include <types.h>
#include <stdio.h>
#include <stdlib.h>
#include "game.h"
#include "globalScores.h"
#include "tileData.h"
// Defines
#define REQUEST_TYPE_GET_HIGH_SCORES 0
#define REQUEST_TYPE_SET_SCORE 1
#define RESPONSE_TYPE_HELLO 0
#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)
#define NETWORK_RETRY_TIMEOUT (3 * 60 * 60)
// Types
typedef struct tSessionSecrets {
uint32_t secret;
uint32_t nonce;
} tSessionSecrets;
typedef struct tHighScoreRequest {
uint16_t requestType;
} tHighScoreRequest;
typedef struct tHighScoreRequestWithHash {
tHighScoreRequest highScoreRequest;
uint8_t md5Digest[16];
} tHighScoreRequestWithHash;
typedef struct tSetHighScoreRequest {
uint16_t requestType;
char who[4];
uint32_t score;
Word is60Hz;
} tSetHighScoreRequest;
typedef struct tSetHighScoreRequestWithHash {
tSetHighScoreRequest setHighScoreRequest;
uint8_t md5Digest[16];
} tSetHighScoreRequestWithHash;
typedef struct tHelloResponse {
uint16_t responseType;
uint32_t nonce;
} tHelloResponse;
typedef struct tScoresResponse {
uint16_t responseType;
tHighScore highScores[10];
} tScoresResponse;
typedef struct tStatusResponse {
uint16_t responseType;
Boolean success;
uint16_t position;
uint16_t numberOfScores;
} 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,
/* All states below this should have Marinetti disconnected */
GAME_NETWORK_CONNECTED,
GAME_NETWORK_RESOLVING_NAME,
/* These are all of the error states. Marinetti is still connected but the
TCP connection is closed and ipid released. */
GAME_NETWORK_LOOKUP_FAILED,
GAME_NETWORK_SOCKET_ERROR,
GAME_NETWORK_PROTOCOL_FAILED,
GAME_NETWORK_FAILURE,
/* This is the state we are in during a game on a machine with a working network
(other possible states are fail states). */
GAME_NETWORK_TCP_UNCONNECTED,
/* All of these states below here have an ipid open and the TCP connection is
open and in some state. */
GAME_NETWORK_WAITING_FOR_TCP,
/* All of these states below this point have the TCP connection established
and the score protocol is exchanging information. */
GAME_NETWORK_WAITING_FOR_HELLO,
GAME_NETWORK_REQUEST_SCORES,
GAME_NETWORK_WAITING_FOR_SCORES,
GAME_NETWORK_SET_HIGH_SCORE,
GAME_NETWORK_WAITING_FOR_SCORE_ACK,
GAME_NETWORK_CLOSING_TCP,
} tGameNetworkState;
typedef struct tGameNetworkGlobals {
Boolean networkStartedConnected;
tGameNetworkState gameNetworkState;
dnrBuffer domainNameResolution;
srBuff tcpStatus;
Word ipid;
rrBuff readResponseBuf;
tHelloResponse helloResponse;
uint32_t bytesRead;
md5WorkBlock hashWorkBlock;
uint32_t secrets[3];
tHighScoreRequestWithHash highScoreRequest;
Boolean hasHighScoreToSend;
tStatusResponse setHighScoreResponse;
uint16_t errorCode;
uint16_t timeout;
} tGameNetworkGlobals;
// Globals
// I am running out of space in the main segment so I am moving these globals into
// a dynamically allocated struct. It is only allocated if network capabilities are
// detected.
static tGameNetworkGlobals * networkGlobals = NULL;
// The following globals are accessed by name from assembly so are not in the
// tGameNetworkGlobals structure.
Boolean hasGlobalHighScores = FALSE;
tScoresResponse highScoreResponse;
Word globalScoreAge = 0;
tSetHighScoreRequestWithHash setHighScoreRequest;
char globalScoreInfo[GAME_NUM_TILES_WIDE + 1];
// Implementation
segment "highscores";
void initNetwork(void)
{
networkGlobals = NULL;
if ((NETWORK_SERVER == NULL) ||
(NETWORK_SERVERPORT == 0))
return;
LoadOneTool(54, 0x200); // Load Marinetti
if (toolerror())
return;
LoadOneTool(128, 0x103); // Load the Hash toolset
if (toolerror()) {
UnloadOneTool(54);
return;
}
TCPIPStartUp();
if (toolerror()) {
UnloadOneTool(128);
UnloadOneTool(54);
return;
}
hashStartUp();
if (toolerror()) {
TCPIPShutDown();
UnloadOneTool(128);
UnloadOneTool(54);
return;
}
networkGlobals = malloc(sizeof(tGameNetworkGlobals));
if (networkGlobals == NULL) {
hashShutDown();
TCPIPShutDown();
UnloadOneTool(128);
UnloadOneTool(54);
return;
}
networkGlobals->networkStartedConnected = TCPIPGetConnectStatus();
if (networkGlobals->networkStartedConnected) {
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECTED;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_UNCONNECTED;
}
networkGlobals->secrets[0] = NETWORK_SERVERSECRET1;
networkGlobals->secrets[1] = NETWORK_SERVERSECRET2;
networkGlobals->hasHighScoreToSend = FALSE;
setHighScoreRequest.setHighScoreRequest.is60Hz = !ReadBParam(hrtz50or60);
}
void shutdownNetwork(void)
{
if ((!networkGlobals->networkStartedConnected) &&
(networkGlobals->gameNetworkState > GAME_NETWORK_UNCONNECTED)) {
TCPIPDisconnect(TRUE, NULL);
}
free(networkGlobals);
hashShutDown();
TCPIPShutDown();
UnloadOneTool(128); // Unload the Hash toolset
UnloadOneTool(54); // Unload Marinetti
}
static void abortConnection(void)
{
TCPIPAbortTCP(networkGlobals->ipid);
TCPIPLogout(networkGlobals->ipid);
}
void disconnectNetwork(void)
{
if (networkGlobals == NULL)
return;
if (networkGlobals->gameNetworkState > GAME_NETWORK_TCP_UNCONNECTED) {
if (networkGlobals->gameNetworkState < GAME_NETWORK_CLOSING_TCP) {
TCPIPCloseTCP(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP;
networkGlobals->timeout = SHUTDOWN_NETWORK_TIMEOUT;
}
while (networkGlobals->gameNetworkState > GAME_NETWORK_TCP_UNCONNECTED) {
waitForVbl();
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[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[0]); row++) {
for (column = 0;
column < sizeof(highScoreResponse.highScores[0].scoreText) / sizeof(highScoreResponse.highScores[0].scoreText[0]);
column++) {
highScoreResponse.highScores[row].scoreText[column] = ' ';
}
for (column = 0;
column < sizeof(highScoreResponse.highScores[0].who) / sizeof(highScoreResponse.highScores[0].who[0]);
column++) {
highScoreResponse.highScores[row].who[column] = ' ';
}
}
displayString(1, "NETWORK");
displayString(2, "PROBLEM");
displayString(4, line1);
displayString(5, line2);
highScoreResponse.highScores[7].scoreText[0] = 'C';
highScoreResponse.highScores[7].scoreText[1] = 'O';
highScoreResponse.highScores[7].scoreText[2] = 'D';
highScoreResponse.highScores[7].scoreText[3] = 'E';
highScoreResponse.highScores[7].scoreText[4] = ':';
highScoreResponse.highScores[7].scoreText[5] = ' ';
highScoreResponse.highScores[7].scoreText[6] = hexDigitToAscii(networkGlobals->errorCode >> 12);
highScoreResponse.highScores[7].scoreText[7] = hexDigitToAscii(networkGlobals->errorCode >> 8);
highScoreResponse.highScores[7].scoreText[8] = hexDigitToAscii(networkGlobals->errorCode >> 4);
highScoreResponse.highScores[7].scoreText[9] = hexDigitToAscii(networkGlobals->errorCode);
globalScoreAge = 0;
hasGlobalHighScores = TRUE;
}
void pollNetwork(void)
{
if (networkGlobals == NULL)
return;
TCPIPPoll();
switch (networkGlobals->gameNetworkState) {
case GAME_NETWORK_SOCKET_ERROR:
displayNetworkError("SOCKET", "ERROR");
networkGlobals->timeout = NETWORK_RETRY_TIMEOUT;
break;
case GAME_NETWORK_LOOKUP_FAILED:
displayNetworkError("LOOKUP", "FAILED");
break;
case GAME_NETWORK_CONNECT_FAILED:
displayNetworkError("CONNECT", "FAILED");
networkGlobals->timeout = NETWORK_RETRY_TIMEOUT;
break;
case GAME_NETWORK_PROTOCOL_FAILED:
abortConnection();
displayNetworkError("PROTOCOL", "FAILED");
networkGlobals->timeout = NETWORK_RETRY_TIMEOUT;
break;
case GAME_NETWORK_FAILURE:
// All of the different failure modes except protocol failure above end up here ultimately. And the state
// machine stays here once it arrives here.
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
if (networkGlobals->timeout == 0)
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
}
break;
case GAME_NETWORK_UNCONNECTED:
displayConnectionString();
TCPIPConnect(NULL);
if ((!toolerror()) &&
(TCPIPGetConnectStatus())) {
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECTED;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECT_FAILED;
}
break;
case GAME_NETWORK_CONNECTED:
TCPIPDNRNameToIP("\p" NETWORK_SERVER, &(networkGlobals->domainNameResolution));
if (toolerror()) {
networkGlobals->gameNetworkState = GAME_NETWORK_LOOKUP_FAILED;
networkGlobals->errorCode = toolerror();
} else
networkGlobals->gameNetworkState = GAME_NETWORK_RESOLVING_NAME;
break;
case GAME_NETWORK_RESOLVING_NAME:
if (networkGlobals->domainNameResolution.DNRstatus == DNR_Pending)
break;
if (networkGlobals->domainNameResolution.DNRstatus != DNR_OK) {
networkGlobals->gameNetworkState = GAME_NETWORK_LOOKUP_FAILED;
networkGlobals->errorCode = networkGlobals->domainNameResolution.DNRstatus;
break;
}
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
break;
case GAME_NETWORK_TCP_UNCONNECTED:
if ((hasGlobalHighScores) &&
(globalScoreAge > 0) &&
(!networkGlobals->hasHighScoreToSend))
break;
networkGlobals->ipid = TCPIPLogin(myUserId, networkGlobals->domainNameResolution.DNRIPaddress, NETWORK_SERVERPORT, 0, 64);
if (toolerror()) {
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
networkGlobals->errorCode = toolerror();
break;
}
networkGlobals->errorCode = TCPIPOpenTCP(networkGlobals->ipid);
if (networkGlobals->errorCode != tcperrOK) {
TCPIPLogout(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
break;
}
networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_TCP;
networkGlobals->timeout = TCP_CONNECT_TIMEOUT;
break;
case GAME_NETWORK_WAITING_FOR_TCP:
networkGlobals->errorCode = TCPIPStatusTCP(networkGlobals->ipid, &(networkGlobals->tcpStatus));
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
break;
}
if ((networkGlobals->tcpStatus.srState == TCPSSYNSENT) ||
(networkGlobals->tcpStatus.srState == TCPSSYNRCVD)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = TCP_CONNECT_TIMEOUT_ERROR;
}
break;
}
if (networkGlobals->tcpStatus.srState != TCPSESTABLISHED) {
abortConnection();
networkGlobals->errorCode = networkGlobals->tcpStatus.srState | 0x8000;
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
break;
}
networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_HELLO;
networkGlobals->timeout = READ_NETWORK_TIMEOUT;
networkGlobals->bytesRead = 0;
break;
case GAME_NETWORK_WAITING_FOR_HELLO:
networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0,
((uint32_t)(&(networkGlobals->helloResponse))) + networkGlobals->bytesRead,
sizeof(networkGlobals->helloResponse) - networkGlobals->bytesRead,
&(networkGlobals->readResponseBuf));
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
break;
}
networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount;
if (networkGlobals->bytesRead < sizeof(networkGlobals->helloResponse)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HELLO_TIMEOUT_ERROR;
}
break;
}
if (networkGlobals->bytesRead > sizeof(networkGlobals->helloResponse)) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HELLO_TOO_BIG_ERROR;
break;
}
if (networkGlobals->helloResponse.responseType != RESPONSE_TYPE_HELLO) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HELLO_UNEXPECTED_RESPONSE_ERROR;
break;
}
networkGlobals->secrets[2] = networkGlobals->helloResponse.nonce;
if (networkGlobals->hasHighScoreToSend) {
networkGlobals->gameNetworkState = GAME_NETWORK_SET_HIGH_SCORE;
} else if ((!hasGlobalHighScores) ||
(globalScoreAge == 0)) {
networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES;
} else {
TCPIPCloseTCP(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP;
networkGlobals->timeout = SHUTDOWN_NETWORK_TIMEOUT;
}
break;
case GAME_NETWORK_REQUEST_SCORES:
networkGlobals->highScoreRequest.highScoreRequest.requestType = REQUEST_TYPE_GET_HIGH_SCORES;
md5Init(&(networkGlobals->hashWorkBlock));
md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->secrets), sizeof(networkGlobals->secrets));
md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->highScoreRequest.highScoreRequest), sizeof(networkGlobals->highScoreRequest.highScoreRequest));
md5Finish(&(networkGlobals->hashWorkBlock), &(networkGlobals->highScoreRequest.md5Digest[0]));
networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&(networkGlobals->highScoreRequest), sizeof(networkGlobals->highScoreRequest), FALSE, FALSE);
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
break;
}
networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_SCORES;
networkGlobals->timeout = READ_NETWORK_TIMEOUT;
networkGlobals->bytesRead = 0;
break;
case GAME_NETWORK_WAITING_FOR_SCORES:
networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0,
((uint32_t)(&highScoreResponse)) + networkGlobals->bytesRead,
sizeof(highScoreResponse) - networkGlobals->bytesRead,
&(networkGlobals->readResponseBuf));
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
break;
}
networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount;
if (networkGlobals->bytesRead < sizeof(highScoreResponse)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HIGH_SCORE_TIMEOUT_ERROR;
}
break;
}
if (networkGlobals->bytesRead > sizeof(highScoreResponse)) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HIGH_SCORE_TOO_BIG_ERROR;
break;
}
if (highScoreResponse.responseType != RESPONSE_TYPE_SCORES) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = HIGH_SCORE_UNEXPECTED_RESPONSE_ERROR;
break;
}
globalScoreAge = GLOBAL_SCORE_REFRESH_TIME;
hasGlobalHighScores = TRUE;
TCPIPCloseTCP(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP;
networkGlobals->timeout = SHUTDOWN_NETWORK_TIMEOUT;
break;
case GAME_NETWORK_SET_HIGH_SCORE:
setHighScoreRequest.setHighScoreRequest.requestType = REQUEST_TYPE_SET_SCORE;
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), &(setHighScoreRequest.md5Digest[0]));
networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&setHighScoreRequest, sizeof(setHighScoreRequest), FALSE, FALSE);
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
break;
}
networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_SCORE_ACK;
networkGlobals->timeout = READ_NETWORK_TIMEOUT;
networkGlobals->bytesRead = 0;
break;
case GAME_NETWORK_WAITING_FOR_SCORE_ACK:
networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0,
((uint32_t)(&(networkGlobals->setHighScoreResponse))) + networkGlobals->bytesRead,
sizeof(networkGlobals->setHighScoreResponse) - networkGlobals->bytesRead,
&(networkGlobals->readResponseBuf));
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
break;
}
networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount;
if (networkGlobals->bytesRead < sizeof(networkGlobals->setHighScoreResponse)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = SET_SCORE_TIMEOUT_ERROR;
}
break;
}
if (networkGlobals->bytesRead > sizeof(networkGlobals->setHighScoreResponse)) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = SET_SCORE_TOO_BIG_ERROR;
break;
}
if (networkGlobals->setHighScoreResponse.responseType != RESPONSE_TYPE_STATUS) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = SET_SCORE_UNEXPECTED_RESPONSE_ERROR;
break;
}
if (!networkGlobals->setHighScoreResponse.success) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = SET_SCORE_FAILED_ERROR;
break;
}
networkGlobals->hasHighScoreToSend = FALSE;
globalScoreAge = 0;
networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES;
break;
case GAME_NETWORK_CLOSING_TCP:
networkGlobals->errorCode = TCPIPStatusTCP(networkGlobals->ipid, &(networkGlobals->tcpStatus));
if ((networkGlobals->tcpStatus.srState != TCPSCLOSED) &&
(networkGlobals->tcpStatus.srState != TCPSTIMEWAIT)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
}
break;
}
TCPIPLogout(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
break;
}
}
BOOLEAN canSendHighScore(void)
{
if (networkGlobals == NULL)
return FALSE;
if (networkGlobals->gameNetworkState < GAME_NETWORK_TCP_UNCONNECTED) {
if ((networkGlobals->gameNetworkState == GAME_NETWORK_FAILURE) &&
(networkGlobals->timeout > 0))
return TRUE;
return FALSE;
}
return TRUE;
}
BOOLEAN sendHighScore(void)
{
uint16_t cycleCount = 0;
networkGlobals->hasHighScoreToSend = TRUE;
if (networkGlobals->gameNetworkState < GAME_NETWORK_TCP_UNCONNECTED)
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
do {
waitForVbl();
pollNetwork();
cycleCount++;
if ((cycleCount & 0x7) == 0) {
switch (cycleCount & 0x18) {
case 0x00:
uploadSpin1();
break;
case 0x08:
uploadSpin2();
break;
case 0x10:
uploadSpin3();
break;
case 0x18:
uploadSpin2();
break;
}
}
} while (networkGlobals->gameNetworkState > GAME_NETWORK_TCP_UNCONNECTED);
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();
}
return TRUE;
}

View File

@ -1,43 +0,0 @@
/*
* globalScores.h
* BuGS
*
* Created by Jeremy Rand on 2021-05-23.
* Copyright © 2021 Jeremy Rand. All rights reserved.
*/
#ifndef _GUARD_PROJECTBuGS_FILEglobalScores_
#define _GUARD_PROJECTBuGS_FILEglobalScores_
#include <types.h>
#include "tileData.h"
typedef struct tHighScore
{
char scoreText[10];
char who[4];
unsigned long score;
} tHighScore;
extern char globalScoreInfo[GAME_NUM_TILES_WIDE + 1];
extern unsigned int myUserId;
extern void initNetwork(void);
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);
#endif /* define _GUARD_PROJECTBuGS_FILEglobalScores_ */

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

@ -14,13 +14,16 @@
#include "main.h"
#if __ORCAC__
segment "loadSounds";
#endif
static void loadSound(Word addr, Word soundNum)
{
Handle handle = LoadResource(rRawSound, soundNum);
HLock(handle);
WriteRamBlock(*handle, addr, GetHandleSize(handle));
WriteRamBlock(*handle, addr, (Word)GetHandleSize(handle));
HUnlock(handle);
}

View File

@ -10,7 +10,7 @@
#define _GUARD_PROJECTBuGS_FILEloadSounds_
#include <types.h>
#include <TYPES.h>
extern void loadSpiderSound(Word addr);

View File

@ -7,23 +7,33 @@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <orca.h>
#include <Memory.h>
#include <Locator.h>
#include <MiscTool.h>
#include "main.h"
#include "game.h"
#include "globalScores.h"
#include "netScores.h"
#include "settings.h"
#include "tileData.h"
/* Defines and macros */
#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)
#define NETWORK_RETRY_TIMEOUT (3 * 60 * 60)
#define TOOLFAIL(string) \
if (toolerror()) SysFailMgr(toolerror(), "\p" string "\n\r Error Code -> $");
if (toolerror()) SysFailMgr(toolerror(), (Pointer)"\p" string "\n\r Error Code -> $");
/* Globals */
@ -31,6 +41,14 @@
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];
tNSGSHighScores globalHighScores;
Boolean hasGlobalHighScores = FALSE;
Word globalScoreAge = 0;
unsigned int scoreIndex = 0;
/* Implementation */
@ -43,9 +61,158 @@ word randomMushroomOffset(void)
}
static void uploadSpin(int val)
{
switch (val)
{
case 0:
uploadSpin1();
break;
case 1:
uploadSpin2();
break;
case 2:
uploadSpin3();
break;
case 3:
uploadSpin2();
break;
}
}
static void scorePosition(unsigned int position, unsigned int numberOfScores)
{
int i;
sprintf(globalScoreInfo, " %u OF %u SCORES", position, numberOfScores);
for (i = (int)strlen(globalScoreInfo); i < sizeof(globalScoreInfo); i++) {
globalScoreInfo[i] = ' ';
}
globalScoreInfo[GAME_NUM_TILES_WIDE] = '\0';
displayScorePosition();
for (i = 6 * 60; i > 0; i--) {
waitForVbl();
}
globalScoreAge = 0;
}
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;
int event;
Ref toolStartupRef;
@ -73,14 +240,31 @@ int main(void)
InitMouse(0);
SetMouse(transparent);
initNetwork();
highScoreInitParams.userId = myUserId;
highScoreInitParams.scoreServer = (const char *)"\p" NETWORK_SERVER;
highScoreInitParams.scorePort = NETWORK_SERVERPORT;
highScoreInitParams.secret1 = NETWORK_SERVERSECRET1;
highScoreInitParams.secret2 = NETWORK_SERVERSECRET2;
highScoreInitParams.shutdownTimeout = SHUTDOWN_NETWORK_TIMEOUT;
highScoreInitParams.connectTimeout = TCP_CONNECT_TIMEOUT;
highScoreInitParams.readTimeout = READ_NETWORK_TIMEOUT;
highScoreInitParams.retryTimeout = NETWORK_RETRY_TIMEOUT;
highScoreInitParams.displayConnectionString = showConnectionString;
highScoreInitParams.waitForVbl = waitForVbl;
highScoreInitParams.uploadSpin = uploadSpin;
highScoreInitParams.scorePosition = scorePosition;
highScoreInitParams.displayError = displayError;
highScoreInitParams.setHighScores = setHighScores;
NSGS_InitNetwork(&highScoreInitParams);
if (!loadSettings())
saveSettings();
game();
shutdownNetwork();
NSGS_ShutdownNetwork();
ShutDownTools(refIsHandle, toolStartupRef);
TOOLFAIL("Unable to shutdown tools");

View File

@ -40,7 +40,7 @@ resource rPString (DOWNLOAD_URL_STR, $0000) {
resource rPString (ARCHIVE_STR, $0000) {
"BuGS200.shk"
"BuGS201.shk"
};
@ -63,7 +63,7 @@ resource rVersion (1) {
{
2, /* Major version number in BCD */
0, /* Minor version number in BCD */
0, /* Bug version number in BCD */
1, /* Bug version number in BCD */
release, /* Development phase */
0 /* Release number */
},

View File

@ -1,23 +1,22 @@
# GSplus configuration file version 0.14
# GSport configuration file version 0.31
s5d1 = /Users/jrand/Library/Developer/Xcode/DerivedData/BuGS-bffpexoblaghkzcbtjtzxeulnuto/Build/Products/Debug/BuGS.2mg
s5d1 =
s5d2 =
s6d1 =
s6d2 =
s7d1 = /Users/jrand/Coding/AppleCoding/Apple2GS/BuGS/BuGS/make/system601_net.2mg
s7d1 =
g_ethernet = 1
g_limit_speed = 3
g_ethernet = 1
g_joystick_type = 0
g_limit_speed = 0
bram1[00] = 00 00 00 01 00 00 0d 06 02 01 01 00 01 00 00 00
bram1[10] = 00 00 07 06 02 01 01 00 00 00 0f 06 06 00 05 06
bram1[20] = 01 00 00 00 00 00 00 01 00 00 00 00 03 02 02 02
bram1[30] = 00 00 00 01 00 00 00 00 00 00 01 02 03 04 05 06
bram1[40] = 07 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d
bram1[30] = 00 00 00 00 00 00 00 00 08 00 01 02 03 04 05 06
bram1[40] = 07 0a 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d
bram1[50] = 0e 0f ff ff ff ff ff ff ff 00 ff ff ff ff ff 81
bram1[60] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
bram1[70] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
@ -28,7 +27,7 @@ bram1[b0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
bram1[c0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
bram1[d0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
bram1[e0] = ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
bram1[f0] = ff ff ff ff ff ff ff ff ff ff ff ff 41 f8 eb 52
bram1[f0] = ff ff ff ff ff ff ff ff ff ff ff ff 52 06 f8 ac
bram3[00] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bram3[10] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

View File

@ -2,136 +2,247 @@
if [ $# -lt 3 ]
then
echo USAGE: $0 diskimage file directory
echo USAGE: $0 diskimage bootimage file [bootdest]
exit 1
fi
DISKIMAGE="$1"
shift
DESTBOOTIMAGE="$1"
shift
FILE="$1"
shift
DISKIMAGEDEST="$1"
shift
COPYDIRS=$*
BOOTCOPYPATH="$1"
PROGRAM=`basename "$FILE"`
TMPDIR=/tmp/a2gs_mount.$$
MOUNTDIR="${TMPDIR}/$PROGRAM"
TMPDISKIMAGE=/tmp/a2gs_diskimage_$$.2mg
TMPBOOTIMAGE=/tmp/a2gs_bootimage_$$.2mg
TMPARCHIVE=/tmp/s2gs_archive_$$.shk
TEMPLATEDISKIMAGE="make/${PROGRAM}.2mg"
TEMPLATEDISKIMAGE="make/empty.2mg"
TEMPLATEBOOTIMAGE="make/$BOOTIMAGE"
ARCHIVE=`dirname "$DISKIMAGE"`/"${PROGRAM}.shk"
DEST="${MOUNTDIR}/${DISKIMAGEDEST}"
cleanupAndExit()
# It looks like on Linux, the cp command needs a special argument to preserve the resource fork. This isn't ideal
# but for now, if uname is Darwin, then this is MacOS and we don't need any cp args. If not Darwin, then assume
# this is Linux and ask for extended attributes to be preserved through the copy.
#
# Ultimately, it could be that other platforms (BSD, does Solaris still exist?) or even other Linux versions or
# distributions need different arguments for this rather special thing. If true, this may need to be a build time
# option which can be set.
if [ "`uname`" = Darwin ]
then
CPARGS=""
else
CPARGS="--preserve=xattr"
fi
printErrorAndExit()
{
echo "`pwd`/Makefile:0:0: error: $*" >&2
umount "$MOUNTDIR" 2> /dev/null
rm -f "$TMPDISKIMAGE" 2> /dev/null
rm -f "$TMPBOOTIMAGE" 2> /dev/null
rm -f "$TMPARCHIVE" 2> /dev/null
rm -f "$DISKIMAGE" 2> /dev/null
rmdir "$MOUNTDIR" 2> /dev/null
rm -f "$DESTBOOTIMAGE" 2> /dev/null
rm -rf "$TMPDIR" 2> /dev/null
exit 1
}
unmount()
{
RETRIES=0
while [ $RETRIES -lt 5 ]
do
umount "$1"
if [ $? -eq 0 ]
then
break
fi
RETRIES=`expr $RETRIES + 1`
sleep 1
done
if [ $RETRIES -ge 5 ]
then
printErrorAndExit "Unable to unmount the disk image."
fi
}
validateProDOSName()
{
NAME=`basename $1`
echo $NAME | egrep '^[a-zA-Z][a-zA-Z0-9.]{0,14}$' > /dev/null
}
mkdirProDOS()
{
validateProDOSName "$1"
if [ $? -ne 0 ]
then
printErrorAndExit "Invalid ProDOS name of directory `basename $1`. ProDOS names must be 1 to 15 characters, start with a letter and only letters, numbers and a period can be used in the name."
fi
mkdir -p "$1"
if [ $? -ne 0 ]
then
printErrorAndExit "Unable to create directory $1"
fi
}
cpProDOS()
{
validateProDOSName "$2"
if [ $? -ne 0 ]
then
printErrorAndExit "Invalid ProDOS name of file `basename $2`. ProDOS names must be 1 to 15 characters, start with a letter and only letters, numbers and a period can be used in the name."
fi
cp $CPARGS "$1" "$2"
if [ $? -ne 0 ]
then
printErrorAndExit "Unable to create directory $1"
fi
}
copyDirs()
{
OLDDIR=`pwd`
for COPYDIR in $*
do
cd "$COPYDIR"
if [ $? != 0 ]
then
printErrorAndExit "Unable to find $COPYDIR"
fi
find . -print | while read FILEORDIR
do
if [ "$FILEORDIR" = "." ]
then
continue
fi
if [ -d "$FILEORDIR" ]
then
mkdirProDOS "${MOUNTDIR}/$FILEORDIR"
elif [ -f "$FILEORDIR" ]
then
cpProDOS "$FILEORDIR" "${MOUNTDIR}/$FILEORDIR"
fi
done
cd "$OLDDIR"
done
}
if [ ! -f "$TEMPLATEDISKIMAGE" ]
then
echo Unable to find the template disk image, $TEMPLATEDISKIMAGE
cleanupAndExit
printErrorAndExit "Unable to find the template disk image, $TEMPLATEDISKIMAGE"
fi
if [ ! -f "$TEMPLATEBOOTIMAGE" ]
then
printErrorAndExit "Unable to find the template boot image, $TEMPLATEBOOTIMAGE"
fi
mkdir "$TMPDIR"
if [ $? != 0 ]
then
printErrorAndExit "Unable to create the mount directory."
fi
mkdir "$MOUNTDIR"
if [ $? != 0 ]
then
printErrorAndExit "Unable to create the mount directory."
fi
cp "$TEMPLATEBOOTIMAGE" "$TMPBOOTIMAGE"
if [ $? != 0 ]
then
printErrorAndExit "Unable to copy template boot image."
fi
if [ ! -z "$COPYBOOTDIRS" ] || [ ! -z "BOOTCOPYPATH" ]
then
profuse -orw "$TMPBOOTIMAGE" "$MOUNTDIR"
if [ $? != 0 ]
then
printErrorAndExit "Unable to mount the boot image."
fi
if [ ! -z "$BOOTCOPYPATH" ]
then
cpProDOS "$FILE" "$MOUNTDIR/$BOOTCOPYPATH"
if [ $? != 0 ]
then
printErrorAndExit "Unable to copy the file to the boot image."
fi
fi
copyDirs $COPYBOOTDIRS
unmount "$MOUNTDIR"
fi
cp "$TEMPLATEDISKIMAGE" "$TMPDISKIMAGE"
if [ $? != 0 ]
then
echo Unable to copy template disk image.
cleanupAndExit
fi
mkdir "$TMPDIR"
mkdir "$MOUNTDIR"
if [ $? != 0 ]
then
echo Unable to create the mount directory.
cleanupAndExit
printErrorAndExit "Unable to copy template disk image."
fi
profuse -orw "$TMPDISKIMAGE" "$MOUNTDIR"
if [ $? != 0 ]
then
echo Unable to mount the disk image.
cleanupAndExit
printErrorAndExit "Unable to mount the disk image."
fi
cp "$FILE" "$DEST"
cpProDOS "$FILE" "$MOUNTDIR"
if [ $? != 0 ]
then
echo Unable to copy the file to the disk image.
cleanupAndExit
printErrorAndExit "Unable to copy the file to the disk image."
fi
copyDirs $COPYDIRS
OLDDIR=`pwd`
for COPYDIR in $COPYDIRS
do
cd "$COPYDIR"
if [ $? != 0 ]
then
echo Unable to find $COPYDIR
cleanupAndExit
fi
find . -print | while read FILEORDIR
do
if [ -d "$FILEORDIR" ]
then
mkdir -p "${MOUNTDIR}/$FILEORDIR"
elif [ -f "$FILEORDIR" ]
then
cp "$FILEORDIR" "${MOUNTDIR}/$FILEORDIR"
fi
done
done
cd "$TMPDIR"
$ORCA "$OLDDIR/make/tar" cf "$TMPARCHIVE" "$PROGRAM"
if [ $? != 0 ]
then
echo Unable to create archive.
cleanupAndExit
printErrorAndExit "Unable to create archive."
fi
cd "$OLDDIR"
RETRIES=0
while [ $RETRIES -lt 5 ]
do
umount "$MOUNTDIR"
if [ $? -eq 0 ]
then
break
fi
RETRIES=`expr $RETRIES + 1`
sleep 1
done
if [ $RETRIES -ge 5 ]
then
echo Unable to unmount the disk image.
cleanupAndExit
fi
unmount "$MOUNTDIR"
cp "$TMPDISKIMAGE" "$DISKIMAGE"
if [ $? != 0 ]
then
echo Unable to copy the disk image to the destination.
cleanupAndExit
printErrorAndExit "Unable to copy the disk image to the destination."
fi
cp "$TMPBOOTIMAGE" "$DESTBOOTIMAGE"
if [ $? != 0 ]
then
printErrorAndExit "Unable to copy the boot image to the destination."
fi
cp "$TMPARCHIVE" "$ARCHIVE"
if [ $? != 0 ]
then
echo Unable to copy the archive to the destination.
cleanupAndExit
printErrorAndExit "Unable to copy the archive to the destination."
fi
# This is a special case for my personal build environment. If I can find my home directory
@ -144,6 +255,7 @@ then
fi
rm -f "$TMPDISKIMAGE"
rm -f "$TMPBOOTIMAGE"
rm -f "$TMPARCHIVE"
rm -rf "$TMPDIR"
exit 0

View File

@ -72,10 +72,40 @@ DESKTOP_RES_MODE=640
MESSAGE_CENTER=0
GSPLUS=/Applications/GSplus.app/Contents/MacOS/gsplus
GSPLUSARGS=
GSPORT=/Applications/GSport/GSport.app/Contents/MacOS/GSport
GSPORTARGS=
MAME=/Applications/Ample.app/Contents/MacOS/mame64
MAMELIB=$(HOME)/Library/Application Support/Ample
MAMEARGS=apple2gs -skip_gameinfo -speed 2 -mouse -window -resolution 1408x1056 -ramsize 4M -sl7 cffa202
export GSPLUS
export GSPLUSARGS
export GSPORT
export GSPORTARGS
export MAME
export MAMELIB
export MAMEARGS
ifneq (,$(wildcard $GSPLUS))
EMULATOR=gsplus
else ifneq (,$(wildcard $MAME))
EMULATOR=mame
else ifneq (,$(wildcard $GSPORT))
EMULATOR=gsport
else
EMULATOR=gsplus
endif
export EMULATOR
BOOTIMAGE=system601.2mg
export BOOTIMAGE
COPYDIRS=
export COPYDIRS
COPYBOOTDIRS=
export COPYBOOTDIRS
XCODE_PATH=/Applications/Xcode.app
XCODE_INFO=$(XCODE_PATH)/Contents/Info.plist
@ -90,6 +120,6 @@ XCODE_PLUGIN_COMPATIBILITY=DVTPlugInCompatibilityUUID
all:
$(MKDIR) $(OBJDIR) $(GENDIR) $(TARGETDIR)
@make gen
@make build
@make -f $(firstword $(MAKEFILE_LIST)) gen
@make -f $(firstword $(MAKEFILE_LIST)) build

View File

@ -1,48 +1,84 @@
#!/bin/sh
if [ ! -z "$GSPLUS" ] && [ -x "$GSPLUS" ]
then
EMULATORPATH="$GSPLUS"
elif [ ! -z "$GSPORT" ] && [ -x "$GSPORT" ]
then
EMULATORPATH="$GSPORT"
fi
TMPDIR="/tmp/a2gs_emulator.$$"
if [ -z "$EMULATORPATH" ]
cleanupAndExit()
{
cd
if [ ! -z $PID ]
then
kill $PID 2> /dev/null
fi
rm -rf $TMPDIR
exit 0
}
createConfigTxt()
{
mkdir "$TMPDIR"
sed "s:^s7d1 *=.*$:s7d1 = $BOOTIMAGE:
s:^s5d1 *=.*:s5d1 = $DISKIMAGE:" < make/config.txt > "$TMPDIR/config.txt"
}
if [ $# -ne 2 ]
then
echo Unable to find GSplus or GSport at these locations.
echo " GSPLUS=$GSPLUS"
echo " GSPORT=$GSPORT"
echo USAGE $0: diskimage bootimage
exit 1
fi
BOOTIMAGE="$1"
if echo $BOOTIMAGE | grep -v '^/' > /dev/null
then
BOOTIMAGE="$PWD/$BOOTIMAGE"
fi
DISKIMAGE="$2"
DISKIMAGE="$1"
if echo $DISKIMAGE | grep -v '^/' > /dev/null
then
DISKIMAGE="$PWD/$DISKIMAGE"
fi
# This magic ensures that clicking stop in Xcode results in the emulator terminating.
if false
BOOTIMAGE="$2"
if echo $BOOTIMAGE | grep -v '^/' > /dev/null
then
cd make
sed -i "" "s:^s7d1 *=.*$:s7d1 = $BOOTIMAGE:
s:^s5d1 *=.*:s5d1 = $DISKIMAGE:" config.txt
$EMULATORPATH -fullscreen -mem 1572864 &
PID=$!
else
cd "/Users/jrand/Library/Application Support/Ample"
/Applications/Ample.app/Contents/MacOS/mame64 apple2gs -skip_gameinfo -mouse -window -resolution 1408x1056 -ramsize 4M -sl3 uthernet -sl7 cffa2 -hard1 "$BOOTIMAGE" -flop3 "$DISKIMAGE" &
PID=$!
BOOTIMAGE="$PWD/$BOOTIMAGE"
fi
trap 'kill $PID' SIGTERM SIGINT SIGHUP EXIT
wait
case "$EMULATOR" in
gsplus)
EMULATORPATH="$GSPLUS"
EMULATORARGS="$GSPLUSARGS"
EMULATORDIR="$TMPDIR"
createConfigTxt
;;
gsport)
EMULATORPATH="$GSPORT"
EMULATORARGS="$GSPORTARGS"
EMULATORDIR="$TMPDIR"
createConfigTxt
;;
mame)
EMULATORPATH="$MAME"
EMULATORARGS="$MAMEARGS -hard1 "$BOOTIMAGE" -flop3 "$DISKIMAGE""
EMULATORDIR="$MAMELIB"
;;
*)
echo Invalid emulator specified, \"$EMULATOR\"
exit 1
;;
esac
exit 0
if [ ! -x "$EMULATORPATH" ]
then
echo Unable to find $EMULATOR at $EMULATORPATH
exit 1
fi
if [ ! -d "$EMULATORDIR" ]
then
echo Unable to find $EMULATOR library at $EMULATORDIR
exit 1
fi
cd "$EMULATORDIR"
# This magic ensure that clicking stop in Xcode results in the emulator terminating.
"$EMULATORPATH" $EMULATORARGS &
PID=$!
trap cleanupAndExit SIGTERM SIGINT SIGHUP EXIT
wait

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,9 +7,11 @@ export PATH := $(PATH):$(ORCA_BIN)
CWD=$(shell pwd)
DISKIMAGE=$(TARGETDIR)/$(PGM).2mg
ARCHIVE=$(TARGETDIR)/$(PGM).shk
DESTBOOTIMAGE=$(TARGETDIR)/$(BOOTIMAGE)
BUILDTARGET=$(DISKIMAGE)
EXECTARGET=executeGUI
DISKIMAGEDEST=.
BOOTCOPYPATH=
AUXTYPE=
CFLAGS+=-i$(GENDIR)
@ -31,18 +33,18 @@ else ifeq ($(TARGETTYPE),desktop)
REZFLAGS+=rez='-d MESSAGE_CENTER=$(MESSAGE_CENTER)'
else ifeq ($(TARGETTYPE),cda)
FILETYPE=cda
DISKIMAGEDEST=System/Desk.Accs
BOOTCOPYPATH=System/Desk.Accs
else ifeq ($(TARGETTYPE),cdev)
BINTARGET=$(TARGETDIR)/$(PGM).bin
FILETYPE=199
DISKIMAGEDEST=System/CDevs
BOOTCOPYPATH=System/CDevs
REZFLAGS+=rez='-d BINTARGET="$(BINTARGET)"'
else ifeq ($(TARGETTYPE),nba)
FILETYPE=exe
BUILDTARGET=$(TARGETDIR)/$(PGM)
else ifeq ($(TARGETTYPE),nda)
FILETYPE=nda
DISKIMAGEDEST=System/Desk.Accs
BOOTCOPYPATH=System/Desk.Accs
else ifeq ($(TARGETTYPE),xcmd)
FILETYPE=exe
BUILDTARGET=$(TARGETDIR)/$(PGM)
@ -101,7 +103,7 @@ build: $(BUILDTARGET)
gen: xcodefix
xcodefix:
defaults write "$(ORCAM_PLUGIN_INFO)" $(XCODE_PLUGIN_COMPATIBILITY)s -array `defaults read "$(XCODE_INFO)" $(XCODE_PLUGIN_COMPATIBILITY)` || true
[ "`uname`" = Darwin ] && defaults write "$(ORCAM_PLUGIN_INFO)" $(XCODE_PLUGIN_COMPATIBILITY)s -array `defaults read "$(XCODE_INFO)" $(XCODE_PLUGIN_COMPATIBILITY)` || true
clean: genclean
$(RM) "$(TARGETDIR)/$(PGM)" $(BINTARGET)
@ -110,6 +112,8 @@ clean: genclean
$(RM) $(ALL_DEPS)
$(RM) $(ASM_MACROS)
$(RM) "$(DISKIMAGE)"
$(RM) "$(DESTBOOTIMAGE)"
$(RM) "$(ARCHIVE)"
createPackage:
pkg/createPackage
@ -130,7 +134,7 @@ ifneq ($(REZ_OBJS),)
$(RM) $(TARGETDIR)/$(PGM)
$(CP) $(REZ_OBJS) $(TARGETDIR)/$(PGM)
endif
cd $(OBJDIR); $(LINK) $(LDFLAGS) $(patsubst $(OBJDIR)/%, %, $(BUILD_OBJS_NOSUFFIX)) --keep=$(TARGETDIR)/$(PGM)
cd $(OBJDIR); $(LINK) $(LDFLAGS) $(patsubst $(OBJDIR)/%, %, $(BUILD_OBJS_NOSUFFIX)) keep="$(abspath $(TARGETDIR)/$(PGM))"
$(CHTYP) -t $(FILETYPE) $(AUXTYPE) $(TARGETDIR)/$(PGM)
endif
@ -159,7 +163,7 @@ else
# resource compile will read the $(PGM).bin binary and load it into the
# resources also.
$(BINTARGET): $(BUILD_OBJS)
cd $(OBJDIR); $(LINK) $(LDFLAGS) $(patsubst $(OBJDIR)/%, %, $(BUILD_OBJS_NOSUFFIX)) --keep=$(BINTARGET)
cd $(OBJDIR); $(LINK) $(LDFLAGS) $(patsubst $(OBJDIR)/%, %, $(BUILD_OBJS_NOSUFFIX)) keep="$(abspath $(BINTARGET))"
endif
@ -183,13 +187,13 @@ $(TARGETDIR)/$(PGM): $(REZ_OBJS)
endif
$(DISKIMAGE): $(TARGETDIR)/$(PGM)
make/createDiskImage "$(DISKIMAGE)" "$(TARGETDIR)/$(PGM)" "$(DISKIMAGEDEST)" $(COPYDIRS)
$(DISKIMAGE): $(TARGETDIR)/$(PGM) make/empty.2mg make/$(BOOTIMAGE)
make/createDiskImage "$(DISKIMAGE)" $(DESTBOOTIMAGE) "$(TARGETDIR)/$(PGM)" $(BOOTCOPYPATH)
execute: $(EXECTARGET)
executeGUI: all
make/launchEmulator make/system601_net.2mg $(DISKIMAGE)
make/launchEmulator "$(DISKIMAGE)" "$(DESTBOOTIMAGE)"
executeShell: all
$(ORCA) $(TARGETDIR)/$(PGM)
@ -228,7 +232,7 @@ $(GENDIR)/Teach/%: %.md
$(MKDIR) "$(GENDIR)/Teach"
$(ORCA) make/md2teach "$<" "$@"
$(ALL_OBJS): Makefile
$(OBJS): Makefile
# Include the C and rez dependencies which were generated from the last build
# so we recompile correctly on .h file changes.

745
BuGS/netScores.c Normal file
View File

@ -0,0 +1,745 @@
/*
* netScores.c
* NetScoresGS
*
* Created by Jeremy Rand on 2021-05-23.
* Copyright © 2021 Jeremy Rand. All rights reserved.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <Hash.h>
#include <locator.h>
#include <misctool.h>
#include <orca.h>
#include <tcpip.h>
#include "netScores.h"
// Defines
#define REQUEST_TYPE_GET_HIGH_SCORES 0
#define REQUEST_TYPE_SET_SCORE 1
#define RESPONSE_TYPE_HELLO 0
#define RESPONSE_TYPE_SCORES 1
#define RESPONSE_TYPE_STATUS 2
#define DEFAULT_SHUTDOWN_NETWORK_TIMEOUT (2 * 60)
#define DEFAULT_TCP_CONNECT_TIMEOUT (8 * 60)
#define DEFAULT_READ_NETWORK_TIMEOUT (5 * 60)
#define DEFAULT_NETWORK_RETRY_TIMEOUT (3 * 60 * 60)
// Types
typedef struct tSessionSecrets {
uint32_t secret;
uint32_t nonce;
} tSessionSecrets;
typedef struct tHighScoreRequest {
uint16_t requestType;
} tHighScoreRequest;
typedef struct tHighScoreRequestWithHash {
tHighScoreRequest highScoreRequest;
uint8_t md5Digest[16];
} tHighScoreRequestWithHash;
typedef struct tSetHighScoreRequest {
uint16_t requestType;
char who[4];
uint32_t score;
Word is60Hz;
} tSetHighScoreRequest;
typedef struct tSetHighScoreRequestWithHash {
tSetHighScoreRequest setHighScoreRequest;
uint8_t md5Digest[16];
} tSetHighScoreRequestWithHash;
typedef struct tHelloResponse {
uint16_t responseType;
uint32_t nonce;
} tHelloResponse;
typedef struct tScoresResponse {
uint16_t responseType;
tNSGSHighScores highScores;
} tScoresResponse;
typedef struct tStatusResponse {
uint16_t responseType;
Boolean success;
uint16_t position;
uint16_t numberOfScores;
} tStatusResponse;
typedef enum tGameNetworkState {
GAME_NETWORK_CONNECT_FAILED = 0,
GAME_NETWORK_UNCONNECTED,
/* All states below this should have Marinetti disconnected */
GAME_NETWORK_CONNECTED,
GAME_NETWORK_RESOLVING_NAME,
/* These are all of the error states. Marinetti is still connected but the
TCP connection is closed and ipid released. */
GAME_NETWORK_LOOKUP_FAILED,
GAME_NETWORK_SOCKET_ERROR,
GAME_NETWORK_PROTOCOL_FAILED,
GAME_NETWORK_FAILURE,
/* This is the state we are in during a game on a machine with a working network
(other possible states are fail states). */
GAME_NETWORK_TCP_UNCONNECTED,
/* All of these states below here have an ipid open and the TCP connection is
open and in some state. */
GAME_NETWORK_WAITING_FOR_TCP,
/* All of these states below this point have the TCP connection established
and the score protocol is exchanging information. */
GAME_NETWORK_WAITING_FOR_HELLO,
GAME_NETWORK_REQUEST_SCORES,
GAME_NETWORK_WAITING_FOR_SCORES,
GAME_NETWORK_SET_HIGH_SCORE,
GAME_NETWORK_WAITING_FOR_SCORE_ACK,
GAME_NETWORK_CLOSING_TCP,
NUM_GAME_NETWORK_STATES
} tGameNetworkState;
typedef void (*tGameNetworkStateHandler)(void);
typedef struct tGameNetworkGlobals {
Boolean networkStartedConnected;
tNSGSHighScoreInitParams initParams;
tGameNetworkState gameNetworkState;
dnrBuffer domainNameResolution;
srBuff tcpStatus;
Word ipid;
rrBuff readResponseBuf;
tHelloResponse helloResponse;
uint32_t bytesRead;
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
static void handleConnectFailed(void);
static void handleUnconnected(void);
static void handleConnected(void);
static void handleResolvingName(void);
static void handleLookupFailed(void);
static void handleSocketError(void);
static void handleProtocolFailed(void);
static void handleFailure(void);
static void handleTcpUnconnected(void);
static void handleWaitingForTcp(void);
static void handleWaitingForHello(void);
static void handleRequestScores(void);
static void handleWaitingForScores(void);
static void handleSetHighScore(void);
static void handleWaitingForScoreAck(void);
static void handleClosingTcp(void);
// Globals
#if __ORCAC__
segment "highscores";
#endif
static tGameNetworkStateHandler handlers[NUM_GAME_NETWORK_STATES] = {
handleConnectFailed,
handleUnconnected,
handleConnected,
handleResolvingName,
handleLookupFailed,
handleSocketError,
handleProtocolFailed,
handleFailure,
handleTcpUnconnected,
handleWaitingForTcp,
handleWaitingForHello,
handleRequestScores,
handleWaitingForScores,
handleSetHighScore,
handleWaitingForScoreAck,
handleClosingTcp
};
// I am running out of space in the main segment so I am moving these globals into
// a dynamically allocated struct. It is only allocated if network capabilities are
// detected.
static tGameNetworkGlobals * networkGlobals = NULL;
// Implementation
void NSGS_InitNetwork(tNSGSHighScoreInitParams * params)
{
networkGlobals = NULL;
if ((params->scoreServer == NULL) ||
(params->scorePort == 0) ||
(params->waitForVbl == NULL))
return;
LoadOneTool(54, 0x200); // Load Marinetti
if (toolerror())
return;
LoadOneTool(128, 0x103); // Load the Hash toolset
if (toolerror()) {
UnloadOneTool(54);
return;
}
TCPIPStartUp();
if (toolerror()) {
UnloadOneTool(128);
UnloadOneTool(54);
return;
}
hashStartUp();
if (toolerror()) {
TCPIPShutDown();
UnloadOneTool(128);
UnloadOneTool(54);
return;
}
networkGlobals = malloc(sizeof(tGameNetworkGlobals));
if (networkGlobals == NULL) {
hashShutDown();
TCPIPShutDown();
UnloadOneTool(128);
UnloadOneTool(54);
return;
}
memcpy(&(networkGlobals->initParams), params, sizeof(networkGlobals->initParams));
if (networkGlobals->initParams.shutdownTimeout == 0)
networkGlobals->initParams.shutdownTimeout = DEFAULT_SHUTDOWN_NETWORK_TIMEOUT;
if (networkGlobals->initParams.connectTimeout == 0)
networkGlobals->initParams.connectTimeout = DEFAULT_TCP_CONNECT_TIMEOUT;
if (networkGlobals->initParams.readTimeout == 0)
networkGlobals->initParams.readTimeout = DEFAULT_READ_NETWORK_TIMEOUT;
if (networkGlobals->initParams.retryTimeout == 0)
networkGlobals->initParams.retryTimeout = DEFAULT_NETWORK_RETRY_TIMEOUT;
networkGlobals->networkStartedConnected = TCPIPGetConnectStatus();
if (networkGlobals->networkStartedConnected) {
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECTED;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_UNCONNECTED;
}
networkGlobals->secrets[0] = params->secret1;
networkGlobals->secrets[1] = params->secret2;
networkGlobals->hasHighScoreToSend = FALSE;
networkGlobals->hasGlobalHighScores = FALSE;
networkGlobals->setHighScoreRequest.setHighScoreRequest.is60Hz = !ReadBParam(hrtz50or60);
}
void NSGS_ShutdownNetwork(void)
{
if ((!networkGlobals->networkStartedConnected) &&
(networkGlobals->gameNetworkState > GAME_NETWORK_UNCONNECTED)) {
TCPIPDisconnect(TRUE, NULL);
}
free(networkGlobals);
hashShutDown();
TCPIPShutDown();
UnloadOneTool(128); // Unload the Hash toolset
UnloadOneTool(54); // Unload Marinetti
}
static void abortConnection(void)
{
TCPIPAbortTCP(networkGlobals->ipid);
TCPIPLogout(networkGlobals->ipid);
}
void NSGS_DisconnectNetwork(void)
{
if (networkGlobals == NULL)
return;
if (networkGlobals->gameNetworkState > GAME_NETWORK_TCP_UNCONNECTED) {
if (networkGlobals->gameNetworkState < GAME_NETWORK_CLOSING_TCP) {
TCPIPCloseTCP(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP;
networkGlobals->timeout = networkGlobals->initParams.shutdownTimeout;
}
}
while ((networkGlobals->gameNetworkState != GAME_NETWORK_TCP_UNCONNECTED) &&
(networkGlobals->gameNetworkState != GAME_NETWORK_FAILURE)) {
networkGlobals->initParams.waitForVbl();
NSGS_PollNetwork();
}
}
static void handleConnectFailed(void)
{
if (networkGlobals->initParams.displayError != NULL)
networkGlobals->initParams.displayError(NSGS_CONNECT_ERROR, networkGlobals->errorCode);
networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE;
}
static void handleUnconnected(void)
{
if (networkGlobals->initParams.displayConnectionString != NULL)
networkGlobals->initParams.displayConnectionString(TRUE);
TCPIPConnect(NULL);
if ((!toolerror()) &&
(TCPIPGetConnectStatus())) {
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECTED;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_CONNECT_FAILED;
networkGlobals->errorCode = toolerror();
}
if (networkGlobals->initParams.displayConnectionString != NULL)
networkGlobals->initParams.displayConnectionString(FALSE);
}
static void handleConnected(void)
{
TCPIPDNRNameToIP((char *)networkGlobals->initParams.scoreServer, &(networkGlobals->domainNameResolution));
if (toolerror()) {
networkGlobals->gameNetworkState = GAME_NETWORK_LOOKUP_FAILED;
networkGlobals->errorCode = toolerror();
} else
networkGlobals->gameNetworkState = GAME_NETWORK_RESOLVING_NAME;
}
static void handleResolvingName(void)
{
if (networkGlobals->domainNameResolution.DNRstatus == DNR_Pending)
return;
if (networkGlobals->domainNameResolution.DNRstatus != DNR_OK) {
networkGlobals->gameNetworkState = GAME_NETWORK_LOOKUP_FAILED;
networkGlobals->errorCode = networkGlobals->domainNameResolution.DNRstatus;
return;
}
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
}
static void handleLookupFailed(void)
{
if (networkGlobals->initParams.displayError != NULL)
networkGlobals->initParams.displayError(NSGS_LOOKUP_ERROR, networkGlobals->errorCode);
networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE;
}
static void handleSocketError(void)
{
if (networkGlobals->initParams.displayError != NULL)
networkGlobals->initParams.displayError(NSGS_SOCKET_ERROR, networkGlobals->errorCode);
networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE;
networkGlobals->timeout = networkGlobals->initParams.retryTimeout;
}
static void handleProtocolFailed(void)
{
abortConnection();
if (networkGlobals->initParams.displayError != NULL)
networkGlobals->initParams.displayError(NSGS_PROTOCOL_ERROR, networkGlobals->errorCode);
networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE;
networkGlobals->timeout = networkGlobals->initParams.retryTimeout;
}
static void handleFailure(void)
{
// All of the different failure modes except protocol failure above end up here ultimately. And the state
// machine stays here once it arrives here.
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
if (networkGlobals->timeout == 0)
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
}
}
static void handleTcpUnconnected(void)
{
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()) {
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
networkGlobals->errorCode = toolerror();
return;
}
networkGlobals->errorCode = TCPIPOpenTCP(networkGlobals->ipid);
if (networkGlobals->errorCode != tcperrOK) {
TCPIPLogout(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
return;
}
networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_TCP;
networkGlobals->timeout = networkGlobals->initParams.connectTimeout;
}
static void handleWaitingForTcp(void)
{
networkGlobals->errorCode = TCPIPStatusTCP(networkGlobals->ipid, &(networkGlobals->tcpStatus));
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
return;
}
if ((networkGlobals->tcpStatus.srState == TCPSSYNSENT) ||
(networkGlobals->tcpStatus.srState == TCPSSYNRCVD)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_TCP_CONNECT_TIMEOUT_ERROR;
}
return;
}
if (networkGlobals->tcpStatus.srState != TCPSESTABLISHED) {
abortConnection();
networkGlobals->errorCode = networkGlobals->tcpStatus.srState | 0x8000;
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
return;
}
networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_HELLO;
networkGlobals->timeout = networkGlobals->initParams.readTimeout;
networkGlobals->bytesRead = 0;
}
static void handleWaitingForHello(void)
{
networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0,
((uint32_t)(&(networkGlobals->helloResponse))) + networkGlobals->bytesRead,
sizeof(networkGlobals->helloResponse) - networkGlobals->bytesRead,
&(networkGlobals->readResponseBuf));
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
return;
}
networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount;
if (networkGlobals->bytesRead < sizeof(networkGlobals->helloResponse)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_HELLO_TIMEOUT_ERROR;
}
return;
}
if (networkGlobals->bytesRead > sizeof(networkGlobals->helloResponse)) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_HELLO_TOO_BIG_ERROR;
return;
}
if (networkGlobals->helloResponse.responseType != RESPONSE_TYPE_HELLO) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
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 ((!networkGlobals->hasGlobalHighScores) ||
((networkGlobals->initParams.shouldRefreshHighScores != NULL) &&
(networkGlobals->initParams.shouldRefreshHighScores()))) {
networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES;
} else {
TCPIPCloseTCP(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP;
networkGlobals->timeout = networkGlobals->initParams.shutdownTimeout;
}
}
static void handleRequestScores(void)
{
networkGlobals->highScoreRequest.highScoreRequest.requestType = REQUEST_TYPE_GET_HIGH_SCORES;
md5Init(&(networkGlobals->hashWorkBlock));
md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->secrets), sizeof(networkGlobals->secrets));
md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->highScoreRequest.highScoreRequest), sizeof(networkGlobals->highScoreRequest.highScoreRequest));
md5Finish(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->highScoreRequest.md5Digest[0]));
networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&(networkGlobals->highScoreRequest), sizeof(networkGlobals->highScoreRequest), FALSE, FALSE);
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
return;
}
networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_SCORES;
networkGlobals->timeout = networkGlobals->initParams.readTimeout;
networkGlobals->bytesRead = 0;
}
static void handleWaitingForScores(void)
{
networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0,
((uint32_t)(&networkGlobals->highScoreResponse)) + networkGlobals->bytesRead,
sizeof(networkGlobals->highScoreResponse) - networkGlobals->bytesRead,
&(networkGlobals->readResponseBuf));
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
return;
}
networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount;
if (networkGlobals->bytesRead < sizeof(networkGlobals->highScoreResponse)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_HIGH_SCORE_TIMEOUT_ERROR;
}
return;
}
if (networkGlobals->bytesRead > sizeof(networkGlobals->highScoreResponse)) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_HIGH_SCORE_TOO_BIG_ERROR;
return;
}
if (networkGlobals->highScoreResponse.responseType != RESPONSE_TYPE_SCORES) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_HIGH_SCORE_UNEXPECTED_RESPONSE_ERROR;
return;
}
networkGlobals->hasGlobalHighScores = TRUE;
if (networkGlobals->initParams.setHighScores != NULL)
networkGlobals->initParams.setHighScores(&(networkGlobals->highScoreResponse.highScores));
TCPIPCloseTCP(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP;
networkGlobals->timeout = networkGlobals->initParams.shutdownTimeout;
}
static void handleSetHighScore(void)
{
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)&(networkGlobals->setHighScoreRequest.setHighScoreRequest), sizeof(networkGlobals->setHighScoreRequest.setHighScoreRequest));
md5Finish(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->setHighScoreRequest.md5Digest[0]));
networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&(networkGlobals->setHighScoreRequest), sizeof(networkGlobals->setHighScoreRequest), FALSE, FALSE);
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
return;
}
networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_SCORE_ACK;
networkGlobals->timeout = networkGlobals->initParams.readTimeout;
networkGlobals->bytesRead = 0;
}
static void handleWaitingForScoreAck(void)
{
networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0,
((uint32_t)(&(networkGlobals->setHighScoreResponse))) + networkGlobals->bytesRead,
sizeof(networkGlobals->setHighScoreResponse) - networkGlobals->bytesRead,
&(networkGlobals->readResponseBuf));
if (networkGlobals->errorCode != tcperrOK) {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR;
return;
}
networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount;
if (networkGlobals->bytesRead < sizeof(networkGlobals->setHighScoreResponse)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_SET_SCORE_TIMEOUT_ERROR;
}
return;
}
if (networkGlobals->bytesRead > sizeof(networkGlobals->setHighScoreResponse)) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_SET_SCORE_TOO_BIG_ERROR;
return;
}
if (networkGlobals->setHighScoreResponse.responseType != RESPONSE_TYPE_STATUS) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_SET_SCORE_UNEXPECTED_RESPONSE_ERROR;
return;
}
if (!networkGlobals->setHighScoreResponse.success) {
networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED;
networkGlobals->errorCode = NSGS_SET_SCORE_FAILED_ERROR;
return;
}
networkGlobals->hasHighScoreToSend = FALSE;
networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES;
}
static void handleClosingTcp(void)
{
networkGlobals->errorCode = TCPIPStatusTCP(networkGlobals->ipid, &(networkGlobals->tcpStatus));
if ((networkGlobals->tcpStatus.srState != TCPSCLOSED) &&
(networkGlobals->tcpStatus.srState != TCPSTIMEWAIT)) {
if (networkGlobals->timeout > 0) {
networkGlobals->timeout--;
} else {
abortConnection();
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
}
return;
}
TCPIPLogout(networkGlobals->ipid);
networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED;
}
void NSGS_PollNetwork(void)
{
if (networkGlobals == NULL)
return;
TCPIPPoll();
handlers[networkGlobals->gameNetworkState]();
}
BOOLEAN NSGS_CanSendHighScore(void)
{
if (networkGlobals == NULL)
return FALSE;
if (networkGlobals->gameNetworkState < GAME_NETWORK_TCP_UNCONNECTED) {
if ((networkGlobals->gameNetworkState == GAME_NETWORK_FAILURE) &&
(networkGlobals->timeout > 0))
return TRUE;
return FALSE;
}
return TRUE;
}
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;
do {
networkGlobals->initParams.waitForVbl();
NSGS_PollNetwork();
cycleCount++;
if ((cycleCount & 0x7) == 0) {
switch (cycleCount & 0x18) {
case 0x00:
if (networkGlobals->initParams.uploadSpin != NULL)
networkGlobals->initParams.uploadSpin(0);
break;
case 0x08:
if (networkGlobals->initParams.uploadSpin != NULL)
networkGlobals->initParams.uploadSpin(1);
break;
case 0x10:
if (networkGlobals->initParams.uploadSpin != NULL)
networkGlobals->initParams.uploadSpin(2);
break;
case 0x18:
if (networkGlobals->initParams.uploadSpin != NULL)
networkGlobals->initParams.uploadSpin(3);
break;
}
}
} while (networkGlobals->gameNetworkState > GAME_NETWORK_TCP_UNCONNECTED);
if (networkGlobals->gameNetworkState != GAME_NETWORK_TCP_UNCONNECTED)
return FALSE;
if (networkGlobals->initParams.scorePosition != NULL)
networkGlobals->initParams.scorePosition(networkGlobals->setHighScoreResponse.position,
networkGlobals->setHighScoreResponse.numberOfScores);
return TRUE;
}

182
BuGS/netScores.h Normal file
View File

@ -0,0 +1,182 @@
/*
* netScores.h
* NetScoresGS
*
* Created by Jeremy Rand on 2021-05-23.
* Copyright © 2021 Jeremy Rand. All rights reserved.
*/
#ifndef _GUARD_PROJECTNetScoresGS_FILEnetScores_
#define _GUARD_PROJECTNetScoresGS_FILEnetScores_
#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
{
char scoreText[10];
char who[4];
unsigned long score;
} tNSGSHighScore;
typedef struct tNSGSHighScores
{
tNSGSHighScore score[10];
} tNSGSHighScores;
typedef struct tNSGSHighScoreInitParams
{
/* 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;
/* Each of these timeouts are measured in poll periods. So, if you call NSGS_PollNetwork() every 60th of a
second, then you would use 60 to set the timeout to 1 second. If these are zero, then the "good value"
in the comment will be used as a default.
The shutdown timeout controls how long we wait for a clean TCP disconnection before forcing an abort of
the connection. Two seconds is a good value for this timeout. */
unsigned int shutdownTimeout;
/* The connect timeout is the amount of time we wait for a TCP connection to come up before declaring a
timeout protocol error. Eight seconds is a good value for this timeout. */
unsigned int connectTimeout;
/* The read timeout is the amount of time we wait for a response from the server after we have made a
request of it, whether that is getting the high score list or setting a new high score. Five seconds
is a good value for this timeout. */
unsigned int readTimeout;
/* The retry timeout is the amount of time we wait in an error state before retrying. This only happens
for "soft" errors where a retry is worthwhile. Three minutes is a good value for this timeout. */
unsigned int retryTimeout;
/* 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 NSGS_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 NSGS_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 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;
/* 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 NSGS_InitNetwork(tNSGSHighScoreInitParams * 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 NSGS_DisconnectNetwork(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 NSGS_PollNetwork(void);
/* Call this function once when the game is quitting. */
extern void NSGS_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 NSGS_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 NSGS_CanSendHighScore(void);
/* Assuming NSGS_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 NSGS_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 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,12 +780,8 @@ 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 canSendHighScore
jsl NSGS_CanSendHighScore
bne checkHighScore_retry
brl checkHighScore_doneNetwork
@ -821,6 +815,18 @@ checkHighScore_retry anop
checkHighScore_retryPrompt anop
ldx #GAME_NUM_TILES_WIDE*22+2
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_LETTER_S
_overwriteGameTile TILE_LETTER_C
_overwriteGameTile TILE_LETTER_O
_overwriteGameTile TILE_LETTER_R
_overwriteGameTile TILE_LETTER_E
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_LETTER_U
_overwriteGameTile TILE_LETTER_P
_overwriteGameTile TILE_LETTER_L
_overwriteGameTile TILE_LETTER_O
_overwriteGameTile TILE_LETTER_A
_overwriteGameTile TILE_LETTER_D
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_LETTER_F
_overwriteGameTile TILE_LETTER_A
@ -828,7 +834,9 @@ checkHighScore_retryPrompt anop
_overwriteGameTile TILE_LETTER_L
_overwriteGameTile TILE_LETTER_E
_overwriteGameTile TILE_LETTER_D
_overwriteGameTile TILE_SYMBOL_COLON
_overwriteGameTile TILE_EMPTY
ldx #GAME_NUM_TILES_WIDE*24+2
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_LETTER_R
_overwriteGameTile TILE_LETTER_E
@ -836,10 +844,19 @@ checkHighScore_retryPrompt anop
_overwriteGameTile TILE_LETTER_R
_overwriteGameTile TILE_LETTER_Y
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_LETTER_U
_overwriteGameTile TILE_LETTER_P
_overwriteGameTile TILE_LETTER_L
_overwriteGameTile TILE_LETTER_O
_overwriteGameTile TILE_LETTER_A
_overwriteGameTile TILE_LETTER_D
_overwriteGameTile TILE_SYMBOL_COLON
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_LETTER_Y
_overwriteGameTile TILE_SYMBOL_COLON
_overwriteGameTile TILE_LETTER_N
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_SOLID2
_overwriteGameTile TILE_EMPTY
jsl waitForKey
@ -847,15 +864,37 @@ checkHighScore_retryPrompt anop
cmp #'N'
beq checkHighScore_doneNetwork
cmp #'Y'
bne checkHighScore_doRetry
brl checkHighScore_retry
checkHighScore_doRetry anop
beq checkHighScore_doRetry
brl checkHighScore_retryPrompt
checkHighScore_doneNetwork anop
jsl updateHighScore
sec
rtl
checkHighScore_doRetry anop
ldx #GAME_NUM_TILES_WIDE*24+2
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_EMPTY
brl checkHighScore_retry
uploadSpin1 entry

View File

@ -6,11 +6,14 @@
* Copyright © 2021 Jeremy Rand. All rights reserved.
*/
#include <string.h>
#include <gsos.h>
#include <orca.h>
#include <Memory.h>
#include "globalScores.h"
#include "game.h"
#include "netScores.h"
#include "settings.h"
#include "tileData.h"
@ -26,8 +29,8 @@ typedef struct tSettingsData
{
char magic[4];
int version;
Boolean swapStereo;
tHighScore highScores[NUM_HIGH_SCORES];
Boolean stereoCorrect;
tNSGSHighScore highScores[NUM_HIGH_SCORES];
} tSettingsData;
@ -36,7 +39,7 @@ typedef struct tSettingsData
tSettingsData settings = {
{ 'B', 'u', 'G', 'S' },
0,
FALSE,
TRUE,
{
{ { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '0'}, { 'A', 'A', 'A' }, 0},
{ { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '0'}, { 'A', 'A', 'A' }, 0},
@ -62,8 +65,17 @@ static Handle filenameHandle = NULL;
// Implementation
#if __ORCAC__
segment "settings";
#endif
const tNSGSHighScore * getHighScore(unsigned int index)
{
if (index >= NUM_HIGH_SCORES)
return NULL;
return &(settings.highScores[index]);
}
static void allocateFilenameHandle(void)
{
@ -183,7 +195,7 @@ BOOLEAN loadSettings(void)
if (success)
{
if (settings.swapStereo)
if (!settings.stereoCorrect)
{
swapStereoChannels();
}
@ -196,6 +208,6 @@ BOOLEAN loadSettings(void)
void swapStereoSettings(void)
{
swapStereoChannels();
settings.swapStereo = !settings.swapStereo;
settings.stereoCorrect = !settings.stereoCorrect;
saveSettings();
}

View File

@ -9,12 +9,18 @@
#ifndef _GUARD_PROJECTBuGS_FILEsettings_
#define _GUARD_PROJECTBuGS_FILEsettings_
#include <types.h>
#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_ */

View File

@ -11,8 +11,8 @@ This game runs at 60 frames per second on a standard Apple //gs without an accel
[Video of game run on mame](https://www.rand-emonium.com/wp-content/uploads/2021/02/BuGS_video.mp4)
[Download a disk image](https://github.com/jeremysrand/BuGS/releases/download/1.0/BuGS_200.2mg)
[Download a disk image](https://github.com/jeremysrand/BuGS/releases/download/2.0.1/BuGS_201.2mg)
[Download a SHK archive](https://github.com/jeremysrand/BuGS/releases/download/1.0/BuGS200.shk)
[Download a SHK archive](https://github.com/jeremysrand/BuGS/releases/download/2.0.1/BuGS201.shk)
[BuGS Readme from the SW distribution](/BuGS/Read.Me.md)